第 2 章:用 Markdown 定义 Bot
目标:通过编辑 Markdown 文件,定制 Bot 的性格、行为和对你的认知。
2.1 四个文件,定义一个 Bot
nanobot 的个性化设计非常优雅——四个 Markdown 文件就定义了一个 Bot 的全部"灵魂":
| 文件 | 作用 | 比喻 |
|---|---|---|
SOUL.md |
性格、价值观、沟通风格 | Bot 的"人格" |
AGENTS.md |
行为指令、工作流规则 | Bot 的"岗位职责" |
USER.md |
用户信息、偏好设定 | Bot 对"主人"的认知 |
TOOLS.md |
工具使用的注意事项 | Bot 的"操作手册" |
这些文件都在工作区 ~/.nanobot/workspace/ 下,是纯 Markdown 格式,用任何文本编辑器都能修改。
先记住这条分工原则:别写混
| 你想表达的内容 | 应该写到哪里 | 为什么 |
|---|---|---|
| Bot 的气质、语气、价值观 | SOUL.md |
这是“像谁”的问题 |
| 回答步骤、工作流、禁止事项 | AGENTS.md |
这是“怎么做事”的问题 |
| 用户是谁、偏好什么、长期背景是什么 | USER.md |
这是“Bot 如何理解你”的问题 |
| 工具使用偏好、软约束、注意事项 | TOOLS.md |
这是“怎么使用工具更合适”的问题 |
| 需要长期记住的事实 | memory/MEMORY.md |
这是动态记忆,不是静态人格 |
第一次定制时,宁可写得少一点,也不要把不同层次的内容混在一个文件里。
2.2 实操:打造一个"海盗风格"助手
我们先做一个夸张的例子来直观感受效果。
编辑 ~/.nanobot/workspace/SOUL.md:
然后测试效果:
你会发现 Bot 的回复风格完全变了。你没有修改任何代码,只是编辑了一个 Markdown 文件。
2.3 实操:做一个专业的"财务顾问"Bot
把 SOUL.md 换成正经的内容:
再编辑 ~/.nanobot/workspace/USER.md 来告诉 Bot 你的背景:
现在 Bot 不仅知道"自己是谁",还知道"用户是谁"。它会根据你的收入水平和风险偏好来调整建议。
2.4 用 AGENTS.md 定义行为规则
AGENTS.md 比 SOUL.md 更偏向"做事的规则"。比如你希望财务顾问 Bot 遵守特定流程:
2.5 用 TOOLS.md 控制工具行为
TOOLS.md 可以限制或引导 Bot 使用工具的方式:
哪些内容不要写在这 4 个文件里
下面这些内容,经常被初学者放错位置:
- 很长的命令流程或领域操作说明:更适合写成 Skill
- 稳定、重复执行的确定性逻辑:更适合下沉成脚本或 Tool
- “禁止访问系统目录”这类硬权限:不要只指望
TOOLS.md,真正的限制还要靠配置和工具层 - 临时一次性的任务要求:直接放在当前提问里,不要污染长期的人格和规则文件
一个简单判断法:
- 这是 Bot 长期都该像这样 → 优先写
SOUL.md - 这是 Bot 长期都该按这个流程做事 → 优先写
AGENTS.md - 这是 Bot 关于你应该记住的背景 → 优先写
USER.md - 这是 Bot 调用工具时的提醒 → 优先写
TOOLS.md - 这是 Bot 只在某个领域、某类任务里才需要的知识 → 更可能是 Skill
原理:System Prompt 是怎么组装的?
这四个文件是怎么影响 Bot 行为的?可以从 nanobot/agent/context.py 的 system prompt 组装逻辑开始看:
其中 _load_bootstrap_files 就是读取那四个文件:
如果你更习惯先看结构图,可以先把它理解成这样:
flowchart TD
identity["固定身份<br/>nanobot"] --> prompt["发送给 LLM 的 System Prompt"]
agents["AGENTS.md<br/>行为指令"] --> prompt
soul["SOUL.md<br/>人格"] --> prompt
user["USER.md<br/>用户画像"] --> prompt
tools["TOOLS.md<br/>工具规则"] --> prompt
memory["Memory<br/>长期记忆"] --> prompt
skills["Skills<br/>技能摘要 / 按需加载的技能内容"] --> prompt
也就是说,四个 Markdown 文件当然重要,但它们并不是发给模型的全部内容。真正送进 LLM 的,是这些层被拼起来之后的完整 system prompt。
所以最终发给 LLM 的 System Prompt 长这样:
这里同样做了教学上的简化。真实实现里通常还会包含运行时上下文、平台信息、always skills 等内容,但主干结构就是“身份 + bootstrap 文件 + 记忆 + skills”。
为什么这么设计?
- 纯文本 = 零门槛:不需要学 Python,不需要懂 API,编辑 Markdown 就能改行为
- 关注点分离:性格(SOUL)、规则(AGENTS)、用户认知(USER)、工具约束(TOOLS)各司其职,改一个不影响其他
- 透明可审计:你能看到发给 LLM 的完整 prompt,知道 Bot 为什么这么回答
记忆系统如何工作?
除了四个静态文件,nanobot 还有一个动态的分层记忆系统(nanobot/agent/memory.py):
| 层 | 文件 | 特点 |
|---|---|---|
| 长期记忆 | memory/MEMORY.md |
每次对话都加载到上下文中,存放重要事实 |
| 历史摘要归档 | memory/history.jsonl |
追加式 JSONL,不直接当作最终记忆,可用 grep / jq 搜索 |
| Dream 游标 | memory/.cursor / memory/.dream_cursor |
记录摘要写入位置和 Dream 已处理到哪里 |
当对话变长时,nanobot 会先用 Consolidator 把旧对话压缩成摘要,追加到 history.jsonl。随后 Dream 会周期性读取这些新摘要,再谨慎地编辑 SOUL.md、USER.md 和 MEMORY.md:
- 旧对话摘要 → 追加到
memory/history.jsonl - 稳定事实 / 偏好 / 项目背景 → 由 Dream 整理进长期文件
- Dream 修改长期文件后,会用轻量 Git 历史记录变化,方便查看和恢复
从理解上,你可以把它看成“旧对话被折叠进记忆层”。但具体实现不一定是直接删除历史消息;当前版本更接近“保留原始消息,同时只把未整合部分继续送进上下文”。
这样既不浪费上下文窗口,又不丢失重要信息。
你也可以手动编辑 memory/MEMORY.md,写入任何你想让 Bot 永远记住的信息:
小结
| 你想改什么 | 编辑哪个文件 |
|---|---|
| Bot 的性格和说话风格 | SOUL.md |
| Bot 做事的规则和流程 | AGENTS.md |
| Bot 对你的了解 | USER.md |
| Bot 使用工具的方式 | TOOLS.md |
| Bot 需要永远记住的事 | memory/MEMORY.md |
改完文件后不需要重启——下一次对话自动生效(因为每次对话都重新读取这些文件)。
2.6 验证与排障
完成本章修改后,可以做三个快速验证:
- 修改
SOUL.md后运行nanobot agent -m "请用一句话介绍你自己",预期回复里出现你写进人格文件的独特称呼、口头禅或语气,而不是泛泛自我介绍 - 修改
AGENTS.md后运行nanobot agent -m "我每个月能存 3000 元,先给建议",预期回复先复述问题,再列出假设或关键信息,而不是直接跳到结论 - 修改
USER.md后运行nanobot agent -m "按我的风险偏好,给我三个优先关注方向",预期回复明确引用你的偏好设定,并按你要求的币种或格式输出
常见问题:
- 改了文件但风格没变化:通常是改动太弱,或提问场景不足以触发这些指令
- Bot 没按
AGENTS.md的流程回答:先检查规则是否冲突、是否过长、是否过于抽象 TOOLS.md不生效:工具使用约束属于提示词引导,不是强权限控制;真正的硬限制还要看工具层和配置层
如果你已经分不清问题是在 Markdown 文件分工、提问方式,还是底层工具约束上,先看附录:常见坑与排障。