# 11. Prompt Engineering
# 11.1 原理
Prompt Engineering 关注“如何表达任务与约束,使模型稳定地产生期望行为”。在 Agent 中至少有五层 Prompt:
- System:模型身份、通用安全和最高优先级行为。
- Developer/Policy:产品工作流、工具使用原则、权限与格式约束。
- User:当前目标与反馈。
- Tool Schema/Description:可执行动作与参数契约。
- Runtime-generated context:环境、计划、记忆、Skill、工具结果。
高质量 Prompt 的核心不是堆叠“请认真”,而是:
- 明确目标、完成定义和非目标;
- 给出决策边界:何时调用工具、何时提问、何时停止;
- 使用结构化输出或 Tool Schema 承载机器可执行意图;
- 给关键规则提供正例/反例,但控制长度;
- 把动态事实放入上下文数据,不写死在长期系统 Prompt;
- 为失败提供恢复协议,如“工具失败先诊断,不重复同一动作”。
# 11.2 与源码的关系
Claude Code 将 Tool 描述、Skill 内容、压缩 Prompt、Plan Mode 指令分别构造;压缩结束后显式恢复 Plan/Skill/Hook 上下文,说明 Prompt 不是一段字符串,而是可重建的上下文组件:compact.ts:1471、SkillTool.ts:1077。
Codex 将各种模型可见片段定义成独立 Context 类型,Turn 每个 Step 记录 world state 变化后再构造 Prompt History;这减少了随意拼接字符串造成的重复与不可追踪:turn.rs:329、context/mod.rs。
# 11.3 面试题
问:Prompt Engineering 如何做版本和回归?
Prompt 必须有版本/hash;记录模型、工具版本、上下文选择和随机参数;离线使用固定任务集比较成功率、步骤数、成本和安全违规;线上灰度并用 trace 做失败分层。只比较最终文本相似度不够。
# 11.4 原理深化:Prompt 应像编译产物,而不是字符串模板
Agent Prompt 的构造更接近编译器:不同来源先被解析成带 role/type/source/hash 的中间表示,按优先级和稳定顺序链接,经过模型能力适配、去重与预算裁剪,最后生成 Provider 请求。这样才能回答某条指令来自哪里、为何出现在本 Step、压缩后如何恢复,以及修改哪一段导致 Prompt Cache 失效。直接用字符串拼接会丢失来源、边界和可测试性。
Codex 的 build_prompt 接收规范化历史、工具定义和 BaseInstructions,Turn 在采样前从 History 生成 for_prompt 投影,并把同一 Prompt 对象交给模型客户端和 Trace;这比在网络层临时拼接更容易保证“实际发送内容 = 可观测内容”:turn.rs:1288、turn.rs:1329、turn.rs:1361。Claude Code 在压缩后重新注入 Plan、Skill 和 Hook 状态,同样证明这些是可重建 Prompt 组件,而非摘要模型必须记住的普通文本。
Prompt 分层还必须保持权威边界:ToolResult、仓库文档、Skill 和 Memory 即使使用 developer/user 形式承载,也不能覆盖真正的系统策略;外部内容应加来源包装,明确“这是数据而不是指令”。版本回归要保存组件级 hash,而非只保存最终大字符串,这样 cache miss、行为变化和安全回归才能归因到具体片段。