进阶教程
AI提示词
Nanobot源码
Nanobot源码解析:平替OpenClaw的Markdown系统提示词
摘要
在上一篇里,我们拆解了 nanobot 的 agent 命令运行原理。今天的话题更有意思:一个 Agent 的
在上一篇里,我们拆解了 nanobot 的 agent 命令运行原理。今天的话题更有意思:一个 Agent 的“三观”和“人设”是怎么来的?没错,就是那个关键的**系统提示词(System Prompts)**。
如果用过其他 Agent 框架,不难发现它们的提示词要么硬编码在 Python 文件里,要么藏在复杂的数据库配置中。但 nanobot 再次选择了那条与众不同的路:它把 Agent 的灵魂交给了一份 Markdown 文档。
### 1. 为什么是 Markdown? 在nanobot/agent/context.py 里有一个常量,非常能说明问题:
BOOTSTRAP_FILES = ["AGENTS.md", "SOUL.md", "USER.md", "TOOLS.md"]
这四个文件构成了 nanobot 的核心身份标识。那问题来了——为什么偏偏是 Markdown?
三个理由很扎实:
* **人类可读(Human-Readable)**:不需要懂 Python,只要会写字,就能修改 Agent 的性格。门槛直接降到地板。
* **版本控制(Version Control)**:Agent 的每次进化,都留在了 git commit 的历史里。调试、回溯、复盘,都很方便。
* **极简定制**:想让 Agent 变幽默?改 SOUL.md。想让它记住你的偏好?改 USER.md。分而治之,干净利落。
这种设计,让 AI 从一个冷冰冰的黑盒,变成了一块可以被亲手雕琢的“数字粘土”。
### 2. ContextBuilder:提示词的“缝纫机”
ContextBuilder 类是 nanobot 里负责“缝合”提示词的核心组件。它的 build_system_prompt 方法,就像一台精密缝纫机,把碎片化的信息缝成一件完整的“思想外衣”。
def build_system_prompt(self, skill_names: list[str] | None = None) -> str:
parts = [self._get_identity()]
bootstrap = self._load_bootstrap_files()
if bootstrap:
parts.append(bootstrap)
memory = self.memory.get_memory_context()
if memory:
parts.append(f"# Memory\n\n{memory}")
always_skills = self.skills.get_always_skills()
if always_skills:
always_content = self.skills.load_skills_for_context(always_skills)
if always_content:
parts.append(f"# Active Skills\n\n{always_content}")
skills_summary = self.skills.build_skills_summary()
if skills_summary:
parts.append(...)
return "\n\n---\n\n".join(parts)
它不仅加载了静态的 Markdown 文件,还动态注入了我们在上一篇聊过的长期记忆。这意味着,你的 Agent 每跟你交互一次,它都在变得更懂你。
### 3. 赋予“灵魂”:SOUL.md 与 USER.md
在 nanobot 的模板里,SOUL.md 定义了 Agent 的“性格”和“价值观”。比如:
* “Concise and to the point”(简洁明了)
* “Accuracy over speed”(准确重于速度)
而 USER.md 则是 AI 认识你的窗口。它记录你的名字、时区、编程偏好,甚至是当前的工作上下文。
这种“灵魂”与“用户画像”的分离,让 nanobot 能够实现真正的个性化。它不只是一个通用聊天机器人,更像是你的私人秘书——前提是,你得把自己介绍给它。
### 4. 运行时上下文:让 AI 睁开眼看世界
除了静态的身份,AI 还得知道自己所处的“时空”。这是 _build_runtime_context 在做的事情:
def _build_runtime_context(channel: str | None, chat_id: str | None) -> str:
now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)")
tz = time.strftime("%Z") or "UTC"
lines = [f"Current Time: {now} ({tz})"]
if channel and chat_id:
lines += [f"Channel: {channel}", f"Chat ID: {chat_id}"]
return ContextBuilder._RUNTIME_CONTEXT_TAG + "\n" + "\n".join(lines)
每当你发送一条消息,nanobot 都会悄悄在你消息前面注入这段元数据。AI 瞬间就能感知到:
* “哦,现在是周二下午 3 点。”
* “用户是在 Telegram 上找我,而不是在终端。”
### 5. 平台策略(Platform Policy):抹平系统差异
这个设计相当贴心。在 _get_identity() 方法中,它会自动判断当前是 Windows 还是 macOS/Linux。
system = platform.system()
if system == "Windows":
platform_policy = """## Platform Policy (Windows)
- You are running on Windows. Do not assume GNU tools like `grep`, `sed`, or `awk` exist.
- Prefer Windows-native commands or file tools when they are more reliable.
- If terminal output is garbled, retry with UTF-8 output enabled."""
else:
platform_policy = """## Platform Policy (POSIX)
- You are running on a POSIX system. Prefer UTF-8 and standard shell tools.
- Use file tools when they are simpler or more reliable than shell commands."""
这直接解决了一个 AI 助手的常见痛点:在 Windows 上给你写 Linux 命令。通过注入平台策略,nanobot 确保 AI 给出的建议,在你的系统上真正能用,而不是一句空话。
### 最终提示词
最后生成的系统提示词包含五个部分:
* 身份、平台、工作目录
* 四个 md 文件(灵魂、用户、工具、Agent指令)
* 长期记忆
* 主动技能(每次执行)
* 被动技能(触发后才执行)

/nanobot/skills 文件夹中:

AGENTS.md、SOUL.md、USER.md、TOOLS.md,接着是内存和技能描述。层次清晰,职责分明。
### 总结
nanobot 的系统提示词设计,再次印证了它的极简哲学:最好的配置,就是文档本身。
通过 Markdown 驱动身份,通过运行时注入感知环境,nanobot 成功打造了一个既有稳定“灵魂”,又能灵活应对复杂环境的 AI 助手。这大概就是“形散而神不散”的工程实现。 来源:互联网
免责声明
本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。