这是《深入理解 AI Agent》精读专题的第七篇,走第 2 章三条线索中的第一条:提示词怎么写、怎么防劫持。读的是李博杰的开源书第二章的提示工程与提示注入部分。
本章思维导图见 专题页 · 章节思维导图
先记住一个检验标准
原文给系统提示词设计了一个实用的检验标准:如果一个聪明的新员工读完你的系统提示词还不知道该怎么做,Agent 也一样不知道。
这一篇的所有技巧,都是这句话的展开——因为模型在训练中学习了人类的语言和思维模式,针对人类降低认知负担的方法,对模型同样有效。
用带实习员工的方式写提示词
书里有个小观察:大写强调(”NEVER do X”)比 “Please avoid doing X” 更能引起模型的注意,过度使用还会稀释效果——Claude Code 的工具定义里就有 “NEVER invoke grep or rg as a Bash command”。
但这类命令式标记我不喜欢。我更认可的姿态是像教导实习员工(甚至小白)一样去提示模型:它是聪明但完全不了解你业务的新人——讲清楚业务背景,给正例也给反例,给标准流程,而不是堆一堆 NEVER 和 MUST 指望它自己悟。这也和全书的比喻一致:系统提示词是员工手册,流程是 SOP,好培训从来不是「你很聪明,自己看着办」。
示例是规则表达不了时的替代品。 当期望的输出难以用规则精确描述——文案风格、报告格式、语气分寸——给两三个高质量示例,胜过等量篇幅的抽象规则。数量不是越多越好:两三个覆盖边界情况的,胜过十个大同小异的(后者还会稀释模型对规则本身的注意力)。正例之外最好配反例,并写清适用范围——这是 Skill 写作里的明确建议。
示例的位置有缓存约束。 示例放在系统提示词里就成了静态前缀的一部分,处于上下文靠前的区域——一旦确定就要字节级稳定。按请求动态检索「最相关」的示例,等于每次改写前缀,缓存持续失效。生产系统的做法是为每类任务准备固定示例集,而不是逐请求挑选。
结构化:XML + Markdown 双层
模型对结构化输入显著敏感(训练数据里就有大量结构化内容)。书里的方案是两种格式配合:
- XML 负责精确语义:
<working_directory>这个标签名本身就告诉模型「这是工作目录信息」,纯文本「当前目录:/Users/project/src」则需要模型额外思考冒号前后的关系 - Markdown 负责层次组织:
#、##标题让人一眼看出结构,人机共读
这个设计有消融数据背书:保留所有规则的内容、只打乱组织结构,任务成功率下降超过 30%——「先验证身份再处理退款」被拆散后,Agent 有时跳过身份验证直接退款;而去掉工具的描述性文本,工具调用错误率增加 45%。
所以这一篇的标题就是原文实验的结论:对人类友好的信息组织方式,对模型同样友好。
流程驱动优于规则堆砌
给新员工一份上百条零散规则的手册,没有流程图、没有优先级——多条规则同时适用时怎么选?规则没覆盖时怎么办?最聪明的人也会困惑,模型也一样。
流程驱动的提示词是标准操作流程(SOP):模型在任何时刻都清楚自己处于哪个阶段、当前步骤的目标是什么、完成后进哪一步;遇到异常时按当前阶段处理,而不是遍历所有规则找匹配项。
配套的是业务规则要细化到可执行的程度。书里打电话砍价的 Agent 例子:模糊的「根据任务情况选择合适的计费类型」会让行为极不稳定(退衣服算省钱吗?取消订阅算吗?),必须写死成 NEVER use percentage_based_one_time for refunds。设计哲学是:模型的优势在遵循复杂指令,不该在业务规则上有自由裁量权——好培训不是「你很聪明,自己看着办」,而是 SOP + 明确框架。
工具定义也开始渐进式披露
上一篇刚说过第一章的设计模式「渐进式披露」,这一节看到它落到了 API 层:静态前缀里只保留工具的名称和简述,模型搜索到要调用时,再把完整的 schema 注入到上下文末尾。OpenAI 的 tool_search、Anthropic 的 Tool Search、Codex CLI(默认开启)都是这个机制。
为什么追加到末尾不破坏缓存?这是 KV Cache 前缀性质的直接推论:因果注意力决定了每个 token 的键值对只依赖它之前的 token——在末尾追加不改任何已缓存内容。而且 schema 只在被发现的那一轮注入一次,之后固定在轨迹原位,不是每轮重新搬运。
有一条硬约束:模型必须在训练中见过「工具定义出现在对话中间」这种模式——所以目前只有较新的模型(GPT-5.4+、Claude 4.5+ 系列)支持,自托管开源模型需要专门训练。
提示注入:上下文层的三道防御
威胁的本质:攻击者通过 Agent 处理的外部内容(网页、邮件、文档)把伪装成系统指令的文本混入上下文,劫持 Agent 行为。Agent 有工具调用能力,比普通聊天机器人危险得多——被注入的指令可能导致文件删除、发送邮件、泄露隐私。注入入口包括网页不可见元素、PDF 元数据、甚至图片的 EXIF 信息。
上下文层的防御核心是帮模型分清「指令」与「数据」:
- 来源标记:外部内容注入前用明确的标记包裹并标注来源(
<external_content source="webpage">...</external_content>),提示模型其中出现的「指令」不应执行 - 结构化角色:严格利用 Chat Template 的角色体系(system/user/assistant/tool)传递信息,让模型依据训练时建立的优先级区分可信指令与外部数据——把工具结果混入 user 消息,等于亲手抹掉模型辨别来源的依据
- 输入清洗:过滤外部内容中的可疑模式(如「忽略之前的指令」)——容易被措辞变体绕过,只能作为辅助手段
原文泼了两盆冷水,都很清醒:
- 上下文层防御只是第一道防线——只能降低攻击成功率,无法万无一失。执行层的权限控制、沙盒隔离在第四、五章展开
- Skill 本身就是新的注入面——Skill 的本质是「把外部内容当作指令加载」的制度化形式,第三方 Skill 藏的恶意指令比网页隐藏文本更直接。安装来源不明的 Skill 之前必须审查内容,如同审查将要执行的代码
下一步
- 线索二:Agent 状态栏(尾部注入运行时元信息);线索三:上下文压缩
prompt-engineering实验(Tau-Bench 消融)找时间跑
参考来源
- 《深入理解 AI Agent:设计原理与工程实践》第 2 章「上下文工程」,李博杰著,GitHub 开源——本篇覆盖「提示工程:优化系统提示词」「工具定义的设计」「提示注入:上下文安全的核心威胁」
- OpenAI Tool Search 文档与 Anthropic MCP tool search——工具渐进式披露的 API 原生实现
- Anthropic: Building effective agents——第一章引用过的工程经验,与本章流程驱动的思路一脉相承