数据截至 (上游 commit 6692a1b5195b)
系统提示词:每一轮都从零重建
30 秒导读: CowAgent 的模型每一轮都看到一份当场现拼的系统提示词——不是启动时定好、之后不变的常量,而是每次请求前从磁盘重读
AGENT.md/USER.md/RULE.md、刷新技能/工具/时间后,按"重要性顺序"拼出来的一大段文字。本章讲清楚:模型到底看到了什么,以及这个"每轮重建"的设计带来了什么。
本章只讲这些东西如何进入 prompt。技能、记忆、知识各自的运行时实现,分别见 05-skills-tools-mcp.md、04-memory-knowledge.md;整个对话循环怎么转见 01-agent-loop.md。
1. 这是什么(零基础也能懂)
一句话定义: 系统 提示词(system prompt)是每次调用大模型时放在最前面、不属于对话内容的"给模型的开场说明"。CowAgent 把它做成了每一轮都重新生成的东西。
它解决什么问题? 想象你有一个 AI 管家,住在一个叫"工作空间"的文件夹里。这个文件夹里有几份文件定义它是谁(AGENT.md)、你是谁(USER.md)、这个家的规矩(RULE.md)。
现在问题来了:如果你在对话中说"以后叫你小牛吧",AI 用 edit 把 AGENT.md 里的名字改了——下一句话它还记得自己叫小牛吗?
- 如果系统提示词是启动时生成、之后一直缓存的常量 → 不记得,得重启进程才生效。
- CowAgent 的答案:下一轮请求前,它会把
AGENT.md重新从磁盘读一遍,所以改动立刻生效。
一句话直觉: 别的 agent 常把"人格"当成开机时定死的启动参数;CowAgent 把它当成每轮都重新加载的配置文件。就像一个 Web 服务器开了"热重载"——你改了配置文件,不用重启,下一个请求就用上了。
用起来什么样? 你完全感知不到这个机制在跑。它藏在每次 agent.run_stream(...) 调用的第一步里:
# 示意,非源码:一轮对话开始时发生的第一件事
response1 = agent.run_stream("以后就叫你小牛") # 这轮里 AI 把 AGENT.md 的名字改成"小牛"
response2 = agent.run_stream("你叫什么?") # 这轮开始时重读 AGENT.md → 已经看到"小牛"
# 重点看:两轮之间没有重启,改动却生效了——因为每轮 prompt 都是现拼的
2. 顶层全景(它大概怎么转)
2.1 两个主角
整个机制就两个文件在唱主角:
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
get_full_system_prompt | 每轮的"总指挥":刷新技能、重读上下文文件、定语言,然后叫 builder 拼装 | agent/protocol/agent.py:202 |
build_agent_system_prompt | 真正的"拼装工":把工具/技能/记忆/知识/工作空间/身份/上下文/运行时按顺序拼成一大段 | agent/prompt/builder.py:82 |
load_context_files | 从磁盘读 AGENT.md/USER.md/RULE.md/MEMORY.md/BOOTSTRAP.md | agent/prompt/workspace.py:111 |
2.2 怎么读这张图
从上到下是一轮请求里"prompt 从无到有"的时间顺序;命中即往下走。
每次 agent.run_stream(user_message) 被调用
│
▼
┌──────────────────────────────────────────────┐
│ get_full_system_prompt() agent.py:166 │ ← 每轮的入口,不用缓存
│ ① 刷新技能 refresh_skills() │
│ ② 从磁盘重读上下文文件 load_context_files() │ → AGENT/USER/RULE/MEMORY/BOOTSTRAP
│ ③ 定回复骨架语言 i18n.get_language() │
│ ④ 叫拼装工干活 ↓ │
└───────────────────────┬──────────────────────┘
▼
┌──────────────────────────────────────────────┐
│ build_agent_system_prompt() builder.py:80 │ ← 按"重要性顺序"拼分节
│ 1 工具 → 2 技能 → 3 记忆 → 3.5 知识 │
│ → 4 工作空间 → 5 用户身份 → 6 项目上下文文件 │
│ → 7 运行时(时间/模型) → 8 回复语言 │
└───────────────────────┬──────────────────────┘
▼
拼好的一大段字符串
│
⑤ 若有 extra_system_suffix 就叠加在最后
▼
作为 system 传给模型,开始这一轮推理
主线一句话: 每轮请求 → get_full_system_prompt 现读现拼 → 得到反映"此刻磁盘状态 + 当前时间"的 prompt → 喂给模型。下一轮再来一遍。