Home Projects Blog Resume Contact 中文
Back to list
2026年7月2日 4,515 words 10 min read

03:Prompt System:Claude Code 如何让 Agent 按协议行动

上一篇把工具系统当成 Claude Code 的执行层来看。

#Claude Code#Coding Agent#工程化#Agent Runtime

03:Prompt System:Claude Code 如何让 Agent 按协议行动

上一篇把工具系统当成 Claude Code 的执行层来看。

工具让 agent 有了行动能力:它可以读文件、搜代码、改内容、跑命令、拿到验证结果。但工具一旦能接触真实项目,新的问题马上出现:

模型为什么知道自己该怎样使用这些工具、遵守哪些项目规则、用什么方式和用户协作?

这篇就接着看 Prompt System。

我现在更愿意把它叫作“行为协议层”。它把系统提示、项目规则、工具描述、用户指令和运行时补充信息装配在一起,让 agent 每一轮行动前都有一套默认规则:自己是谁,能做什么,先看什么,怎样使用工具,哪些边界交给权限和运行时。

这篇文章要拆的主线:Agent 的行为协议从哪里来

这一篇回答的问题是:

Claude Code 如何把系统提示、项目规则、工具描述、用户指令和运行时注入,组织成 agent 每轮行动前看到的行为协议?

这个问题容易被压缩成“prompt 怎么写”。但 Claude Code 这类 coding agent 面对的是更大的工程问题。

普通聊天里,prompt 主要影响回答方式。Coding agent 里,prompt 会影响整个任务推进方式:

  • 它会决定 agent 是先解释,还是先观察项目。
  • 它会决定 agent 什么时候读文件,什么时候搜索,什么时候跑验证。
  • 它会决定 agent 怎样理解工具描述、项目规则和用户当前目标。
  • 它会决定 agent 遇到风险时先说明、先请求确认,还是换一条低风险路径。

所以提示词系统的重点,已经从“让模型答得更好”升级成“让 agent 行为更稳定”。

用一句话概括:

Prompt System 是 coding agent 的行为协议装配层。

它给工具系统套上行动规则,也给后面的记忆、上下文、计划、权限、hook 和 subagent 留出接口。记忆系统会在第 04 篇展开,上下文管理放到第 05 篇,权限第 07 篇讲,hook 和扩展第 10 篇讲,subagent 第 11 篇讲。

提示词系统解决的工程问题:让 agent 行为稳定

LLM 会顺着当前上下文调整行为,这正是它好用的地方。用户说“解释这段代码”,它可以像讲解者;用户说“帮我修构建错误”,它可以像开发者;用户说“审一下这段 diff”,它可以像 reviewer。

放到 agent 里,这种适配能力需要一套稳定边界托住。

没有稳定的行为协议,容易出现几类问题:

  1. 身份漂移。
    同一个 agent 一会儿像教程老师,一会儿像命令执行器,一会儿像产品助手。用户很难形成稳定预期。

  2. 工具误用。
    模型知道有工具,还需要知道工具适合什么场景、参数怎么填、结果回来后怎样理解。

  3. 项目规则被冲淡。
    真实仓库里有测试命令、目录约定、生成文件禁区、代码风格和团队习惯。这些规则靠用户每轮重复,任务会很快变散。

  4. 软规则盖过硬边界。
    “避免读取密钥文件”写进 prompt 可以提醒模型,但敏感路径、危险命令和审批策略更适合交给权限系统。

  5. 协作方式忽左忽右。
    同样是修 bug,有时需要先列计划,有时可以直接最小修改,有时要先问用户业务选择。协议层要把这些分歧变成可判断的入口。

提示词系统要做的,就是把这些默认行为收束起来:基础身份由系统提示承载,项目约定由 CLAUDE.md 和 rules 承载,工具使用由工具描述承载,当前任务由用户输入承载,硬边界由运行时机制承载。

这样后面要调整行为时,才知道该改哪里。

提示词不是一段话,而是一组可组合 section

几篇源码分析文章都提到一个共同点:Claude Code 的系统提示更像一条组装管线,而非一段静态长文本。[1],[2],[3]

这对我理解 Prompt System 很关键。

如果 system prompt 只是一段手写文本,那维护方式很简单:改文字、调措辞、加规则。但 Claude Code 这种工具要面对不同项目、不同工具集合、不同 output style、不同 MCP 状态、不同用户任务。它需要按当前运行环境装配出一轮可用的提示上下文。

可以把它想成几类 section:

section 类型主要放什么变化频率
基础身份agent 是软件工程任务助手,怎样和用户沟通
行为规则读文件、最小改动、验证、输出方式
工具说明可用工具、参数、使用边界
项目规则CLAUDE.md、目录规则、项目命令
动态环境当前目录、shell、git 状态、日期、MCP 状态
当前任务用户本轮目标、临时限制、工具结果反馈

Siddhant Khare 的分析里提到,Claude Code 有稳定区和动态区的边界,也有用于构造 section 的内部接口;其中有一类显眼命名的动态 section,会提示开发者它会破坏缓存,需要给出理由。[1] 这类函数名本身不是本文重点,真正值得学的是背后的工程原则:

每一段提示都应该知道自己的来源、作用域、稳定性和成本。

这让 prompt 从“一锅文本”变成了可维护的配置系统。

稳定前缀和动态注入:哪些规则适合长期存在

提示词系统里有一条很重要的边界:哪些内容适合长期稳定,哪些内容应该按需注入。

稳定内容适合放在前面,例如基础身份、通用行为规则、常驻工具说明和输出约定。它们变化少,模型每轮都需要看到,适合形成稳定前缀。

动态内容更适合放在后面,例如当前目录、git 状态、临时 MCP 信息、用户本轮目标、工具结果和会话反馈。它们变化快,放进稳定前缀会增加缓存成本,也会让行为边界跟着环境频繁抖动。

David Breunig 的文章把 Claude Code 的 system prompt 拆成很多组件:有些始终进入,有些按条件进入,有些随 output style 或工具集合变化。[2]

Piebald-AI 的提示词仓库也能看到类似现象:Claude Code 相关提示并非只有一份,工具描述、subagent 提示、utility prompts、compact prompt 等都会随版本演进。[5]

所以 prompt system 的工程问题可以这样理解:

稳定规则要稳定,动态事实要动态,临时信息要有明确注入位置。

这条边界后面会在上下文管理里继续展开。这里先记住一件事:提示词系统既影响行为,也影响成本和缓存命中。

多来源提示:system、CLAUDE.md、output style、command、skill、hook

Agiflow 通过抓取 API payload,把 Claude Code 里几类提示增强机制分成了不同注入点:output style 改系统层,CLAUDE.md、slash command、skill 进入消息层,hook 作用在工具生命周期,subagent 开新会话。[4]

这张地图很有价值,因为它说明这些入口是分工关系。它们各自适合解决不同问题。

来源注入位置适合放什么后文展开
system prompt系统层基础身份、通用行为、工具使用总规则本篇
output style系统层补充表达风格、解释深度、角色口吻本篇
CLAUDE.md / rules消息层或项目上下文项目约定、命令、架构说明、目录规则第 05 篇连到上下文
slash command单轮消息注入可复用流程、检查清单、固定任务模板第 10 篇
skill按需注入专门领域流程、复杂能力说明第 10 篇
hook工具生命周期工具前后补充、拦截、审计、自动化第 10 篇
subagent独立会话大范围探索、专业任务、上下文隔离第 11 篇

这张表也解释了为什么 CLAUDE.md 很重要,但它不适合承载所有规则。

项目级规则适合写进 CLAUDE.md:测试命令、目录结构、代码风格、生成文件说明、常见坑。临时任务指令适合放在用户当前 prompt。持续表达偏好适合 output style。需要自动执行或拦截的规则更适合 hook。需要隔离大块上下文的任务更适合 subagent。

这样分开以后,prompt system 就像一个带作用域的配置系统。每类规则都有自己的入口,行为异常时也更容易排查。

工具描述也是行为协议

02 里已经讲过,工具系统是一条从工具请求到结果回流的执行链。

到了 Prompt System 这里,要换个角度看工具:工具描述本身也是提示词。

模型会根据工具说明判断该不该用工具,根据参数 schema 判断怎么填输入,根据输出格式理解结果。工具描述写得清楚,agent 更容易选对工具;工具描述含糊,agent 就会靠猜。

比如搜索工具的描述,如果只说“搜索文件”,模型很难判断它和 shell 里的 grep 有什么区别。更好的说明应该让模型知道:

  • 这个工具适合找路径、函数名、错误文本和调用点。
  • 返回值包含路径、行号和命中片段。
  • 命中很多时先缩小关键词,再读关键文件。
  • 搜索结果只是候选证据,最终判断要回到文件内容。

命令工具也是一样。它需要说明工作目录、超时、退出码、stdout/stderr、可能副作用和失败格式。这样主循环拿到结果以后,才知道下一轮该继续定位、重新验证,还是停止总结。

所以工具协议和提示词系统之间有一条很直接的连接:

工具描述决定模型如何理解行动选项。

这也是为什么工具越多,提示词系统越需要治理。工具说明本身会占上下文,工具集合变化也会影响稳定前缀。工具膨胀和延迟加载在第 02 篇已经点到,后面第 05 篇会从上下文成本继续讲。

Prompt 和 runtime 的边界:软规则与硬边界

提示词系统很容易被写成万能开关:把规则写进去,模型就会照做。

工程上更稳的划分是:

Prompt 负责表达意图和协作方式,runtime 负责动作许可和硬边界。

有些规则天然适合 prompt:

  • 回答要简洁。
  • 修改前先读相关文件。
  • 尽量做最小改动。
  • 总结时说明验证结果。
  • 遇到不确定业务选择时询问用户。

这些规则影响行为风格和工作方式,属于软约束。

另一些规则适合 runtime:

  • 禁止读取 .env、密钥、证书。
  • 删除文件前需要确认。
  • 危险 shell 命令需要审批。
  • 每次工具调用要记录审计。
  • 某些 hook 必须在编辑前后运行。

这些规则涉及副作用、安全和组织策略,需要硬边界。Prompt 可以提醒 agent 如何解释这些规则,但最终放行、拒绝、拦截和记录,应该交给权限、settings、hook 或工具层。

Agiflow 对 hook 的观察也能支撑这个边界:hook 发生在工具生命周期里,可以确定性地注入信息、拦截动作或补充结果。[4]

这类能力适合做运行时控制,第 10 篇再展开。

冲突和优先级:多条规则同时出现时怎么办

提示词系统真正麻烦的地方,是多来源规则会同时出现。

用户当前要求可能是“直接修掉”。项目 CLAUDE.md 可能要求“涉及多文件先列计划”。output style 可能偏向详细讲解。工具描述可能建议先搜索再读文件。权限系统又可能拦住某个写入或命令。

这时需要一套简单的分层判断。

冲突类型更稳的处理方式
软偏好冲突让更具体、更近期的指令优先
项目规则冲突在项目规则里写清覆盖关系
工具使用冲突按工具描述和当前证据选择低成本路径
安全边界冲突交给权限、hook、managed policy
输出风格冲突当前任务需要优先,例如修 bug 总结可以短,教学场景可以长

比如用户说“直接改”,而项目规则说“多文件改动先列计划”。如果只改一个 Markdown frontmatter,agent 可以直接做最小修改;如果牵涉多个模块,就应该先说明修改范围。

再比如用户让 agent “顺手清理一下所有旧文件”,这属于高风险范围扩张。Prompt 可以让 agent 解释风险,权限系统决定实际动作能否执行。

这个分层能减少模型猜测,也能让用户更容易理解 agent 为什么这样做。

案例分析:构建失败时行为协议如何生效

继续沿用前两篇的例子:用户说“博客页面构建失败了,帮我修一下”。

工具系统会负责读 package.json、跑构建、搜索报错、读文件、编辑和验证。提示词系统负责约束这些动作怎样发生。

可以把这次任务里的行为协议写成一条事件流:

用户目标:修复博客构建失败
  -> 基础行为:先观察项目,再做最小范围修改
  -> 项目规则:遵守博客目录、frontmatter 和写作约定
  -> 工具契约:先用搜索和读取定位证据,再编辑目标文件
  -> 运行时边界:写文件看 diff,高风险命令交给权限
  -> 验收方式:重新运行构建,返回错误原因、改动和验证结果

这个例子里,用户只给了一个目标。真正让 agent 稳定行动的,是多层协议一起生效:

  • 系统提示让它保持软件工程任务助手的身份。
  • 项目规则告诉它博客文章和构建约定。
  • 工具描述告诉它怎样读文件、搜索、编辑、运行命令。
  • 用户当前指令给出任务目标和完成方向。
  • 权限与运行时边界控制有副作用的动作。

这样一来,“帮我修一下”就不再是一个模糊请求,而是被组织成一条可执行、可验证、可解释的行动路径。

对我写 Agent 的启发:把 prompt 当成可维护配置

如果以后自己写一个 coding agent,我会先把 prompt system 当成配置系统来设计,而不是当成一段长字符串。

我会拆出几个区域:

区域放什么谁维护
base promptagent 身份、协作方式、默认工程原则产品或平台
tool contracts工具说明、参数、返回格式、错误含义工具开发者
project rules项目命令、目录约定、代码风格项目团队
user preferences长期表达偏好、协作偏好用户
task prompt当前目标、限制、验收标准当前用户
runtime guardrails权限、hook、敏感路径、审批策略平台或管理员
feedback context工具结果、测试失败、用户纠正agent loop

每条规则进入系统前,都要问五个问题:

  1. 它的作用域是什么:全局、项目、目录、任务,还是单次工具调用?
  2. 它的 owner 是谁:平台、项目、用户,还是工具作者?
  3. 它的稳定性如何:适合长期前缀,还是适合动态注入?
  4. 它是软偏好,还是硬边界?
  5. 它有没有验证方式:能否通过日志、测试、权限结果或 hook 复盘?

这样做的好处是,agent 行为变差时可以定位原因。是 output style 太啰嗦,还是工具描述让模型误解,还是 CLAUDE.md 写了过期命令,还是 runtime guardrail 没有兜住风险。

我也会让提示词版本可追踪。Piebald-AI 的仓库把 Claude Code 的提示片段、工具描述、subagent prompt 和 utility prompt 按版本整理出来,这一点很有启发。[5] 对自己的 agent 来说,prompt 变化也应该像代码变化一样能 diff、能回滚、能解释。

最后是规则写法。

“请谨慎”这类空泛表达帮助有限。更好的规则应该能落到行为:

  1. 修改前先读目标文件和相邻测试。
  2. 多文件改动先列范围。
  3. 写入后运行最小相关验证。
  4. 验证失败时保留失败摘要和下一步假设。
  5. 涉及删除、迁移、批量替换时先说明风险。

这种规则才能真正改变 agent loop。

参考资料

Claude Code 源码与提示词分析

[1] The plumbing behind Claude Code - Siddhant Khare
本文主要参考它关于 system prompt 分段组装、稳定区和动态区边界、动态 section 影响缓存的分析。

[2] How Claude Code Builds a System Prompt - David Breunig
本文主要参考它对 Claude Code system prompt 组件化装配方式的可视化拆解。

[3] Inside the Claude Code source - Haseeb Qureshi
本文主要参考它关于可组合 prompt function、缓存边界和权限反馈链路的整理。

[4] Claude Code Internals: Reverse Engineering Prompt Augmentation Mechanisms - Agiflow
本文主要参考它关于 CLAUDE.md、output style、slash command、skill、hook、subagent 不同注入位置的分析。

[5] Piebald-AI/claude-code-system-prompts
本文主要参考它对 Claude Code 多类提示片段、工具描述、subagent prompt 和 utility prompt 的版本化整理。

下一篇:Memory System

这一篇先把提示词系统理解成 Claude Code 的行为协议装配层。

核心结论是:

工具让 agent 能行动,提示词系统决定 agent 按什么身份、项目规则、工具契约和协作方式行动。

但行为协议解决的是“本轮怎么行动”。任务一旦跨越多轮、多天、多个项目,agent 还需要沉淀长期偏好、项目经验和反复出现的用户要求。

所以下一篇继续追的问题是:

Claude Code 如何把一次任务里的经验,变成后续任务可以召回的记忆?