(OpenClaw前置知识)System Prompt 在 Agent 系统中承载了哪些职责?如果 System Prompt 越来越长,你会怎么处理?

魏远标 Lv7

参考答案

System Prompt 就是 Agent 的”操作系统”,所有行为的底层规则都写在这里面。

简单理解:每次你跟 ChatGPT、Cursor 这类 AI 工具对话时,你看到的只是 User Prompt(你的提问),但在你看不见的地方,开发者已经预先塞了一大段”隐藏指令”告诉模型该怎么表现,这段隐藏指令就是 System Prompt。Agent 系统比普通聊天复杂得多,所以它的 System Prompt 也更长、职责更重。

它承载的职责可以归成五类:

1)角色定义和行为准则:告诉模型”你是谁”,比如你是一个编程助手、客服机器人还是数据分析师,同时约束它的语气、风格和边界。

2)工具使用规范和约束:Agent 最核心的能力是”能调用工具”(读文件、跑命令、搜索网页等),System Prompt 要告诉模型有哪些工具可用、每个工具怎么调、什么场景该用哪个。

3)输出格式要求:规定模型以什么格式回复,比如 JSON、还是 markdown?消息标签怎么打、多通道消息怎么路由、静默回复用什么标记等。

4)安全与权限控制:设定模型不能做什么,比如不能执行危险命令、不能泄露内部配置、不能擅自做破坏性操作等。这相当于给 AI 划红线。

5)上下文信息补充:把当前运行环境的关键信息(工作目录、当前时间、用户身份、技能清单)告诉模型,让它的回答更贴合当前场景。

至于 System Prompt 越来越长怎么办,核心策略就三个字:拆、选、扔

  • 拆,是把 System Prompt 按职责拆成独立模块,每个模块管一件事。
  • 选,是根据当前任务场景只注入相关模块,不需要的不塞进去。
  • 扔,是把稳定不变的知识从 prompt 里移出去,放到外部文件或知识库里,让 Agent 需要的时候通过工具调用自己去读。

扩展知识

模块化组装方案

以 OpenClaw 为例,它的 System Prompt 不是一整坨字符串,而是拆成了十几个独立模块,每次请求时按需拼接。

这些模块可以分成三层来理解:

第一层:基础身份与安全(每次必加)

  • 身份声明:一句话告诉模型”你是谁”,这是整个 prompt 的锚点
  • 安全红线:写明不能自我复制、不能绕过安全机制、不能追求超出用户请求的目标
  • 工具列表:根据权限策略过滤后,列出当前可用的工具及调用规范
  • 工具调用风格:低风险操作不用解释直接调、敏感操作要先跟用户确认

第二层:场景能力模块(按需加载)

  • 技能提示:告诉 Agent “你有哪些预装技能可以激活”,类似手机里的 App 列表
  • 记忆召回:指导模型在回答前先搜索历史记忆,避免”失忆”
  • 消息路由:跨通道(Signal、Telegram、Discord 等)发消息的规则
  • 语音合成:只有开启了 TTS 功能才注入

第三层:动态运行时上下文(每次请求动态生成)

  • 当前时间、工作目录、操作系统、shell 类型等环境信息
  • 授权白名单用户列表
  • 沙箱信息(如果 Agent 跑在 Docker 里,要告诉它路径映射关系)
  • 项目配置文件的内容(行为规则、人格语气、用户偏好等)

还有个关键设计:分级加载

OpenClaw 用一个加载级别参数控制注入哪些模块:

  • 完整模式:加载全部模块,主 Agent 用
  • 精简模式:只保留工具列表、工作目录、运行时信息等核心模块,子 Agent 用(子 Agent 不需要消息路由、心跳这些能力)
  • 最小模式:只返回一句身份声明

这样同一套代码就能服务不同角色,子 Agent 不用背负主 Agent 那几千 token 的冗余指令。

这种拆法的好处:每个模块独立维护、独立测试。加一个新功能不用在一个几千行的字符串里找位置插入,直接新增一个模块就行。

插件化扩展机制

除了内置模块,OpenClaw 还支持第三方插件向 System Prompt 注入内容

原理是在 System Prompt 即将拼装完成时,系统广播一个信号:”我要构建 prompt 了,谁想加点东西?” 注册了这个钩子(Hook)的插件就能在这时候把自己的内容塞进去。

插件有四种注入方式:

  • 替换系统提示:直接覆盖整个 System Prompt(后注册的覆盖先注册的)
  • 系统提示头部追加:拼到 System Prompt 开头,适合静态指令,能被 LLM 的 prompt cache 缓存
  • 系统提示尾部追加:拼到 System Prompt 末尾,同样可缓存
  • 对话层注入:放到用户消息前面,适合每轮可能变化的动态上下文

比如一个”代码规范检查”插件,可以通过钩子把当前项目的编码规范注入到 System Prompt 里,Agent 写代码时就会自动遵守这些规范。不需要改任何核心代码。

长 System Prompt 的性能影响

System Prompt 越长,每次请求消耗的 token 就越多,响应延迟也会上去。

所以”按需加载”不只是架构上好看,在成本上也是刚需。

一个代码审查任务根本不需要知道消息路由规范,一个简单问答也不需要加载完整的工具列表。模块化拼接 + 分级加载,能让子 Agent 的 prompt 比主 Agent 短得多,直接节省 token 开销。

同时,prompt cache(提示缓存)也是降本的重要手段。

很多 LLM 提供商(如 Anthropic、OpenAI)支持对 System Prompt 中不变的部分做缓存,第二次请求如果 prompt 前缀没变,就不重复计算 token 费用。

所以插件注入方式才区分了”系统提示层”和”对话层”:把稳定内容放系统提示里吃缓存,动态内容走对话层每轮注入。

业界其他方案的对比

Cursor 的做法是把大量规则写进 System Prompt,然后靠模型的长上下文能力硬扛,简单粗暴但有效。它的 System Prompt 非常长(包含工具说明、代码引用格式、提交规范等等),但因为 Cursor 面向的场景相对单一(代码编辑),所以每次都全量加载也还能接受。

Devin 走的是另一个极端,把很多行为规则编码成代码逻辑而不是自然语言 prompt,减少对 System Prompt 的依赖,但灵活性就差一些,改规则要改代码,不像改 prompt 那样随时能调。

LangChain 的 Agent 框架用模板化的方式组装 prompt,跟 OpenClaw 思路类似,也有 Callbacks 系统可以在生命周期各节点插入逻辑,但它的 Callbacks 更偏”观测”(日志、追踪),在 prompt 注入这个环节的灵活度不如 OpenClaw 的四字段钩子精细。

其实模块化组装 + 按需加载已经成了 Agent 系统处理 System Prompt 的主流方案,OpenClaw 在这个基础上加了分级加载(promptMode)和四字段插件钩子,算是做到了比较好的平衡。

面试官追问

提问:System Prompt 里的安全规则真的靠谱吗?用户通过 prompt injection 绕过去怎么办?

回答:纯靠 System Prompt 写安全规则肯定不够,模型层面的 prompt injection(用户故意构造输入来”欺骗”模型忽略之前的指令)防不胜防。所以关键操作必须在代码层面做硬校验,比如文件操作要做路径白名单检查,危险命令要在执行层面拦截,不能只靠 System Prompt 里写一句”禁止执行 rm -rf”就完事了。OpenClaw 的做法就是这样分层的:System Prompt 里有 Safety 模块写明安全红线(第一道防线,降低模型主动犯错的概率),但真正的保障在工具执行层。比如 before_tool_call 钩子可以在工具真正执行前拦截或修改参数,exec 工具有审批机制(用户要 /approve 才能执行敏感命令)。

提问:模块化拼接 System Prompt 的时候,模块之间的顺序会影响模型的行为吗?

回答:会的,研究表明模型对 System Prompt 开头和结尾的内容关注度更高,中间部分容易被”稀释”(这跟人类阅读习惯类似)。所以最核心的身份定义和安全规则一般放在最前面,工具列表和格式要求放中间,动态上下文信息放后面。OpenClaw 的模块拼接顺序是固定写在 buildAgentSystemPrompt 函数里的:Identity → Tooling → Safety 在最前面,Skills → Memory 等能力模块在中间,Runtime 信息放最后。这个顺序符合”重要内容靠前”的通用原则。

提问:如果把知识移到外部文件让 Agent 按需读取,模型读文件这个动作本身不也消耗 token 吗?怎么判断什么时候该放 prompt 里,什么时候该放外部?

回答:判断标准就两条。第一看频率,每次请求都需要用到的信息放 prompt 里,偶尔才用到的放外部。第二看体积,几十个 token 的信息直接放 prompt 里没关系,但如果是几千 token 的编码规范文档,放外部按需读取更划算。读文件虽然也消耗 token,但它是”用到才花钱”,比每次请求都带上要省得多。一般来说,超过 500 token 且使用频率低于 30% 的信息,放外部就更经济。OpenClaw 的 Skills 模块就是这个思路:System Prompt 里只放一个技能目录(很短),模型判断需要某个技能时再通过 read 工具去读完整的 SKILL.md 文件。

提问:多个插件同时通过钩子注入 System Prompt,有没有冲突的可能?怎么解决?

回答:完全可能冲突。比如两个插件一个要求”输出格式用 JSON”,另一个要求”输出格式用 Markdown”,模型就懵了。OpenClaw 的解决方案是 优先级机制:每个钩子注册时可以指定 priority 数值,数值越大优先级越高,执行越靠前。对于 systemPrompt 字段,合并逻辑是”后执行的覆盖先执行的”(即低优先级插件的 systemPrompt 会被高优先级的覆盖);对于 prependContextprependSystemContextappendSystemContext 这些拼接型字段,则是按优先级顺序依次拼接,不存在覆盖。所以插件开发者需要注意:如果你要覆盖核心 prompt,就设高优先级 + 用 systemPrompt 字段;如果只是追加上下文,用拼接型字段就不会跟别人冲突。

目录
(OpenClaw前置知识)System Prompt 在 Agent 系统中承载了哪些职责?如果 System Prompt 越来越长,你会怎么处理?