第 12 章《ContextBuilder 系统 Prompt》· 3 段式 ContextBuilder:bootstrap 引导文件 + skills + memory 注入实战(nanobo
本文回答什么问题:nanobot 的 System Prompt 怎么拼接?为什么有 8 段?bootstrap 文件 (AGENTS.md / SOUL.md / USER.md) 起什么作用?Skills / Memory / Tools 怎么注入?
目标读者:LLM Agent 开发者 / 想自定义 System Prompt 的工程师
预计阅读时间:14 分钟
源码版本:GitHub HKUDS/nanobot main 分支主线代码(仓库相对路径)
ContextBuilder.build_system_prompt()(nanobot/agent/context.py)是 nanobot 最长的方法——把 8 段内容拼成最终 system prompt,每段都有特定语义。本章逐段拆解。
1. 整体定位:为什么 System Prompt 要拆 8 段
LLM 的 system prompt 长度有限 + 不能塞太多东西。nanobot 拆 8 段是按优先级 + 模块化:
- 优先级:identity > bootstrap > tool_contract > memory > skills > history
- 模块化:每段可独立测试 / 替换 / 自定义
核心要点速查(建议收藏)
- 核心文件:
nanobot/agent/context.py(约 400 行) - 8 段拼接:identity / bootstrap / tool_contract / memory / always_skills / skills_summary / recent_history / session_summary
- 3 个 bootstrap 文件:
AGENTS.md/SOUL.md/USER.md(workspace 内,可编辑) - SkillsLoader 从
nanobot/skills/+~/.nanobot/skills/自发现 - Memory 来自
MemoryStore.get_recent()(详见第 15 章)
2. 8 段拼接
# nanobot/agent/context.py L80-L121
def build_system_prompt(self, ctx: TurnContext) -> str:
sections = []
# 1. identity(角色身份,~50 tokens)
sections.append(self._build_identity(ctx))
# 2. bootstrap 文件(workspace 内的 AGENTS.md / SOUL.md / USER.md,通常 500-2000 tokens)
sections.append(self._build_bootstrap(ctx))
# 3. tool_contract(工具清单 + OpenAI schema,~2000 tokens)
sections.append(self._build_tool_contract(ctx))
# 4. memory(最近的 MEMORY.md 摘要,~500 tokens)
sections.append(self._build_memory(ctx))
# 5. always_skills(默认开启的 skill,~200 tokens)
sections.append(self._build_always_skills(ctx))
# 6. skills_summary(所有 skill 的描述摘要,~300 tokens)
sections.append(self._build_skills_summary(ctx))
# 7. recent_history(最近 N 条消息,N=50)
sections.append(self._build_recent_history(ctx))
# 8. session_summary(AutoCompact 生成的旧会话摘要)
sections.append(self._build_session_summary(ctx))
return "\n\n".join(sections)
每段约几百到 2000 tokens,总长 ~4000-5000 tokens——Claude / GPT-4 都能装下。
3. 逐段详解
3.1 identity(L123-L138)
def _build_identity(self, ctx):
return f"""你是 nanobot,一个轻量自托管 AI Agent 框架的代理。
当前通道:{ctx.msg.channel} 当前会话:{ctx.msg.chat_id}
工作区:{ctx.workspace} session_key:{ctx.session_key}"""
作用:告诉 LLM"你是谁,当前在哪个上下文"。简短,不可替换。
3.2 bootstrap 文件(L158-L185)
def _build_bootstrap(self, ctx):
files = ["AGENTS.md", "SOUL.md", "USER.md"]
sections = []
for f in files:
path = ctx.workspace / f
if path.exists():
sections.append(f"## {f}\n\n{path.read_text(encoding='utf-8')}")
return "\n\n".join(sections) if sections else "(no bootstrap files)"
3 个 bootstrap 文件作用:
- AGENTS.md:Agent 角色定义(“你是一个 Python 工程师助手”)
- SOUL.md:人格 / 语气(“回答简洁,不要用 emoji”)
- USER.md:用户信息(“用户是 5 年经验的 Python 开发者”)
完全可编辑——放 ~/.nanobot/workspaces/<key>/ 即可。
3.3 tool_contract(L190-L230)
def _build_tool_contract(self, ctx):
tools = ctx.tools.list() # ToolRegistry.list()
lines = ["## 可用工具\n"]
for tool in tools:
lines.append(f"### {tool.name}\n{tool.description}\n")
lines.append("Parameters:\n" + json.dumps(tool.parameters_schema, indent=2, ensure_ascii=False))
return "\n".join(lines)
作用:让 LLM 知道有哪些工具可用,每个工具的参数 schema。
3.4 memory(L240-L260)
def _build_memory(self, ctx):
memory = self._memory_store.get_recent(ctx.session_key, max_chars=2000)
return f"## 长期记忆\n\n{memory}" if memory else ""
memory 来源:nanobot/agent/memory.py 的 MemoryStore(详见第 15 章),通常来自 ~/.nanobot/memory/MEMORY.md。
3.5 always_skills(L265-L285)
def _build_always_skills(self, ctx):
skills = self._skills_loader.load_always(ctx.workspace)
return "\n\n".join(s.sk_prompt() for s in skills) if skills else ""
always skills 在 ~/.nanobot/skills/<name>/SKILL.md 里设 always: true,默认注入。
3.6 skills_summary(L290-L310)
def _build_skills_summary(self, ctx):
skills = self._skills_loader.load_all(ctx.workspace)
if not skills:
return ""
lines = ["## 可用 Skills(用 skill 工具按需加载)\n"]
for s in skills:
lines.append(f"- **{s.name}**: {s.description[:100]}")
return "\n".join(lines)
作用:不直接注入 SKILL.md 内容,只注入清单——按需用 skill 工具加载。
3.7 recent_history(L315-L340)
def _build_recent_history(self, ctx):
history = self._session_manager.get_recent(ctx.session_key, n=50)
lines = ["## 最近对话\n"]
for msg in history:
lines.append(f"- [{msg.role}] {msg.content[:200]}")
return "\n".join(lines)
最近 50 条消息——超过用 AutoCompact 摘要(详见第 16 章)。
3.8 session_summary(L345-L365)
def _build_session_summary(self, ctx):
summary = self._session_manager.get_summary(ctx.session_key)
return f"## 早期会话摘要\n\n\n{summary}" if summary else ""
AutoCompact 生成的旧消息摘要——避免 history 50 条不够用时丢上下文。
4. 实战:自定义 bootstrap
# ~/.nanobot/workspaces/telegram:123/AGENTS.md
cat > AGENTS.md <<EOF
你是一个 Python 后端工程师助手。
擅长 FastAPI / SQLAlchemy / PostgreSQL。
回答时给出代码示例 + 简短解释。
EOF
# SOUL.md
cat > SOUL.md <<EOF
语气:简洁专业,不用 emoji。
回答长度:每个问题 200 字以内。
EOF
# USER.md
cat > USER.md <<EOF
用户:张三,Python 5 年经验。
当前项目:用 FastAPI 重构老的 Flask 接口。
EOF
下次进入该 workspace,AgentLoop 自动读取这 3 个文件。
5. 常见问题 / 避坑
Q:bootstrap 文件不生效?
A:文件必须放在 ~/.nanobot/workspaces/<session_key>/ 下,文件名严格 AGENTS.md / SOUL.md / USER.md(大写敏感)。
Q:system prompt 太长导致 LLM 报错?
A:检查 8 段总和。建议:
- bootstrap 文件每个 ≤ 1000 tokens
- recent_history n=50 → 改为 30
- skills 关闭不用的(在
~/.nanobot/skills/<name>/SKILL.md设always: false)
Q:怎么调试当前 system prompt?
A:nanobot chat --show-prompt 或 nanobot chat --verbose(部分版本支持)。
6. 小结
- 8 段拼接:identity / bootstrap / tool_contract / memory / always_skills / skills_summary / recent_history / session_summary
- 3 个 bootstrap 文件:AGENTS.md / SOUL.md / USER.md
- 总长 ~4000-5000 tokens
- 可定制:bootstrap + skills + memory 三处可编辑
本文要点速查
- 8 段拼接 见 §2 + §3
- 3 个 bootstrap 文件 决定 Agent 角色 + 人格 + 用户信息
- 可定制 点:bootstrap / skills / memory
- 下一步:第 13 章《Hook 系统》—— 在 build_messages 之前/之后做什么
按角色推荐
- LLM Agent 开发者:必读(自定义 workspace / Agent 角色必读)
- 系统架构师:选读(知道 ContextBuilder 流程即可)
- LLM Provider 适配者:选读(知道 provider 拿到的 messages 是什么样)
- 聊天通道开发者:选读
- Tool / MCP 工具开发者:选读
下一步
- 第 13 章《Hook 系统》 —— 在回合的 5 个时机插入钩子(主题群"Agent 核心",第 3 周)
- 第 15 章《记忆与 Dream 整合》 —— 8 段中的 memory 怎么生成(主题群"Agent 核心",第 3 周)
- 第 16 章《自动压缩 AutoCompact》 —— 8 段中的 session_summary 怎么生成(主题群"Agent 核心",第 3 周)
tags:#nanobot #AI Agent #LLM #Python #源码解析 #ContextBuilder #SystemPrompt
更多推荐

所有评论(0)