第七章 Prompt Engineering:约束、装配与制度化

核心命题:Prompt 设计的核心逻辑,在本书的三个理论框架下各自清晰起来:从问题空间理论看,Prompt 是 Harness 压缩分支因子 bb 的首要工具——在 Agent 的每个决策点,精确的约束缩小了”合法考虑”的操作维度,使 O(bd)O(b^d) 搜索成本收敛到可行域;从委托代理理论看,System Prompt 是委托人(人类)与代理人(Agent)之间的合约文本,可观察性与激励相容性是最优合约的两个结构性条件;从信息论看,Few-shot 示例的价值由其携带的互信息量 I(示例;目标行为)I(\text{示例}; \text{目标行为}) 决定,选择原则是覆盖多样性优先于数量堆砌。本章各节从这三个框架出发,分析 Prompt Engineering 中的具体设计决策。

7.1 问题空间视角:Prompt 如何压缩分支因子

第三章建立的问题空间模型(P=S,O,s0,GP = \langle \mathcal{S}, \mathcal{O}, s_0, \mathcal{G} \rangle)将 Agent 的工作刻画为在状态空间中寻路——每个状态下可选的操作数量即分支因子 bb,路径深度 dd 决定搜索层数,总成本为 O(bd)O(b^d)。Prompt 是 Harness 在推理层压缩这一代价的首要工具,其作用在工具权限约束(第十章)生效之前就已发生。

压缩分支因子的机制:精确的约束在每个决策节点缩小 Agent”合法考虑”的操作集维度。一个”只输出 JSON,不输出解释文本”的约束,将输出格式维度的分支因子从开放空间压缩到单一结构;一个”只修改指定模块内的文件”的约束,将文件操作的分支因子从全代码树压缩到局部子空间。约束的作用是收窄 Agent 的有效操作集,使搜索在更低维的流形上进行。

双重作用的统一理解:Prompt 同时在两个层面发挥作用:

  • 知识激活:角色描述、领域定义、风格约束,选择 LLM 内部的哪些”压缩规律”被激活——决定解的质量上限
  • 操作集约束:明确的行为规则与限制,直接压缩有效 bb——决定搜索的可行性与成本

前者影响”能找到多好的解”,后者影响”在可行成本内能否找到解”。两者共同决定了 Prompt 在 Q/T/C 约束内的有效性。

约束悖论的问题空间解释:更多约束往往产生更好的输出,这在直觉上反常,但在问题空间框架中是直接推论——约束将指数大的解空间压缩到低维可行域,有效解在这个域中的密度远高于原始空间,Agent 搜索到有效解的概率更高,路径也更短。约束不只是质量工具(高密度解的区域),也是成本工具(bb 减小,O(bd)O(b^d) 降低)。

7.2 System Prompt 的合约设计:委托代理理论视角

第二章确立了委托代理理论作为分析 Agent 系统的核心框架:委托人(人类)与代理人(Agent)之间存在信息不对称,约束机制必须在这种不对称条件下保证行为对齐。System Prompt 不是”指令集合”,而是这一不对称条件下的合约文本——它的有效性取决于最优合约设计的两个结构性条件是否满足。

合约条件一:可观察性(Observability)。能被验证的约束才有约束力。“不要产生有害内容”这类规则难以在运行时自动验证,约束力弱;“所有输出必须包含结构化的信心评分字段”则可通过 Hook 计算型传感器验证,约束力强。System Prompt 中的每一条规则,应当能在 Harness 其他层找到对应的验证机制——否则它只是未经执行的意向声明,合约价值为零。设计检验:对每一条规则问”谁在验证这条规则是否被遵守?“——若无法回答,这条规则需要在 Harness 其他层建立验证机制,或被删除。

合约条件二:激励相容性(Incentive Compatibility)。规则必须让”遵守规则”成为 Agent 完成任务的自然路径,而非强行限制。激励相容的规则使约束与任务目标方向一致;不相容的规则会让 Agent 在遵守约束与完成任务之间产生内在张力,最终以不可预期的方式绕过约束。典型反例:要求 Agent 在每次调用工具前输出中文解释——这对任务没有直接帮助,在 token 资源紧张时会被模型自然降权。设计检验:对每一条规则问”在完成任务的压力下,Agent 会主动遵守这条规则吗?“——若答案为否,规则需要重新设计,而非加更多强调语。

合约框架下的内容组织:System Prompt 的内容不是随机的指令清单,而是合约的结构化条款——角色定义(能力边界声明)、行为准则(激励相容的正向约束)、禁止行为(可观察的红线)、输出规范(可验证的格式要求)。这个结构使每一条内容都可以被追问:它满足哪个合约条件?

System Prompt 设计模板

# 角色定义
你是[角色],专注于[领域]。

# 能力边界
你可以:[列举允许的操作]
你不可以:[列举禁止的操作]

# 工作原则
1. [优先级最高的原则]
2. [次要原则]

# 输出规范
[格式要求]

7.3 信息密度视角:Few-shot 选择原则与问题分解

Few-shot 的信息密度优化

Few-shot 示例的基本形式假设读者已熟悉;此处的核心问题是:给定 n 个候选示例,如何选择其中的 k 个放入 Context?从信息论出发,每个示例的工程价值由它对目标行为的互信息量 I(示例;目标行为)I(\text{示例}; \text{目标行为}) 决定——而非其数量、长度或直觉上的”典型性”。

低信息量示例的两个典型来源

  • 冗余示例:两个示例演示了本质相同的情形(不同表面形式,相同的决策逻辑)——后者的边际信息量接近零,只带来 token 成本
  • 分布过于集中:所有示例来自解空间的同一区域,覆盖范围窄,对边界情况和非典型输入没有约束力

选择原则:覆盖多样性优先于数量。最大化互信息的选择策略倾向于使示例集合覆盖解空间的关键区域——典型情形、边界情形、容易出错的情形各一个,比从典型情形中选五个更有效。在 token 预算约束下,这个原则的形式化表达是:选择使 I(示例集;目标行为)I(\text{示例集}; \text{目标行为}) 最大的子集,而非使 示例集|\text{示例集}| 最大的子集。

问题分解的问题空间含义

问题分解在 Prompt 中的体现,是将”当前步骤应该做什么”这个大问题转化为”先做 A,再做 B,最后做 C”的显式结构——在问题空间层面,这将一个高深度 dd 的单一搜索路径替换为若干低深度的串联子路径,使每个子路径的搜索空间单独可管理。

分解粒度遵循同样的问题空间原则:每个子步骤应对应一个在当前 Context 预算内可以独立完成的子问题(与 §9.2 的 Plan 粒度设计一致)。过粗的分解导致每个步骤仍有过高的 bb;过细的分解在 Prompt 层引入不必要的规划开销。最优粒度与任务的自然分解单元对齐。

7.4 Chain-of-Thought 与路径约束

CoT 不只是让模型”慢慢想”,而是将推理路径纳入约束范围。从问题空间理论看,CoT 使搜索路径从隐式(直接输出答案)变为显式(逐步推理)——显式路径可以被约束、被检验、被 Hook 截获,这是 CoT 提升可靠性的核心机制,而非”思考更多”的表面效果。CoT 会增加 token 消耗,但通常以超线性比例提升复杂任务的质量——在帕累托曲面上向质量优先方向移动。

7.5 从 Prompt 到制度:CLAUDE.md / AGENTS.md

当 Prompt 需要在多个会话、多个 Agent 实例之间保持一致时,它升格为”制度”——可版本管理、可审计、可迭代的工程制度。制度化的另一个价值:一次精心设计的 AGENTS.md,其设计成本分摊到每一次 Agent 调用上,边际成本趋向于零。

7.6 反模式:过度 Prompt 的代价

当约束过于精细,解空间收缩到只剩一条路,模型成了确定性脚本的包装器,失去了 LLM 最有价值的泛化推理能力。另一个代价:极度精细的 System Prompt 会随代码库演进迅速过期,产生大量”Prompt 技术债”。

Anti-pattern 清单:重复性约束、相互冲突的规则、将工具调用细节写入 System Prompt。

委托代理视角解释最后一条反模式:从合约设计的角度,System Prompt 是激励机制层(定义目标与边界),Tool Schema 是执行实现层(规定具体操作格式)。将工具调用细节写入 System Prompt,是将激励机制层与执行实现层混合——这产生了合约层次混乱(Contract Hierarchy Confusion):激励机制不应规定执行细节,否则每次工具更新都会导致 System Prompt 失效,合约因环境变化而频繁崩溃。这就解释了为什么这一反模式不只是”代码组织问题”,而是架构性错误。

章末案例剖析

同一个代码审查任务,经历了三次 Prompt 迭代。每次迭代的失败或成功,都对应本章的某个理论节点——不是随机的工程碰运气,而是在可预测的设计空间中的系统性探索。

任务设定:对一个 Python 后端 PR(约 400 行改动,8 个文件)进行代码审查。要求识别安全漏洞、逻辑错误和性能问题;不评论风格问题。将每个版本独立运行 10 次,记录 Bug 检出率、输出结构一致性、token 消耗和任务失败率。


v1:过度自由

# System Prompt v1
你是一个代码审查助手。请审查提交的代码,给出有帮助的反馈。

设计分析

角色描述”代码审查助手”没有激活任何特定的知识域(§7.1:知识激活未定向)——模型不知道是偏重安全、性能还是风格,在下一个决策节点面对全部可能的审查维度,分支因子 bb 未被压缩。“有帮助”满足零个合约条件(§7.2):既不可观察(谁来验证”有帮助”是否达标?),也不激励相容(模型的”有帮助”解与用户期望的”有帮助”解存在分布偏移)。输出格式完全开放,后处理无法标准化。

Q/T/C 指标(10 次运行均值)

  • Q(质量):漏洞检出率 38%;10 次输出中 3 次是泛泛的风格建议(未发现任何 Bug),4 次混合了风格与逻辑问题但结构各异,2 次识别出 Bug 但无修改建议,1 次输出较完整。可操作建议率 25%。质量均值 32/100,方差极大
  • T(时间):生成耗时约 4 秒(无规划步骤,响应快但因格式不稳定后处理成本高)。
  • C(成本):input token 约 80,output token 约 450(大量无关内容)。人类注意力成本高——需要人工解析每次格式不同的输出。

核心问题:分支因子 bb 未压缩,模型在输出维度上随机游走,每次运行的结果几乎来自不同的解空间区域。


v2:过度约束

# System Prompt v2
你是代码审查员,负责识别安全漏洞、性能问题和代码规范合规性。

你必须按照以下流程执行:
1. 按文件顺序逐一审查,先列出文件名
2. 对每个文件逐行扫描,不得跳过任何行
3. 每个问题必须包含:行号 / 问题类型(安全/性能/规范)/ 严重程度(高/中/低)/ 
   问题描述(不超过 50 字)/ 修改建议(不超过 100 字)
4. 安全类问题必须引用相关 CVE 编号(若存在)
5. 性能问题必须估算算法复杂度影响(O(n)、O(n²) 等)
6. 不得评论命名风格(由 linter 处理)
7. 不得评论空格与缩进(由 formatter 处理)
8. 每条描述必须以动词开头
9. 如某文件无问题,输出"[文件名]: 无问题"
10. 最后输出按严重程度排序的 Markdown 汇总表

设计分析

规则 4(CVE 编号)和规则 5(算法复杂度估算)是激励不相容约束(§7.2)——在 PR 中大多数安全问题并无已知 CVE,大多数性能问题也无法从代码片段推断精确复杂度。这迫使模型在两个糟糕选项间选择:捏造数据以满足格式要求,或跳过规则(违反约束)以给出诚实输出。两个选项都是失败模式。

规则 1 的”逐行扫描不得跳过”将 Prompt 从激励层混入了执行层(§7.6 反模式:将工具调用细节写入 System Prompt 的延伸——此处是将执行策略而非输出规范写入合约)。规则 8(描述必须以动词开头)对任务质量贡献为零,是典型的无效约束(§7.1:它并未压缩任何与质量相关的分支因子,只增加了约束数量的表象)。规则 6、7 是负向约束——要求模型主动抑制自然行为,不如在 System Prompt 中明确正向允许范围,让模型在边界内自然工作。

整体效果:分支因子被过度压缩,模型丧失了灵活性——解空间缩小到只剩一种固定的输出路径,但这条路径包含了若干模型无法合理履行的强制步骤。

Q/T/C 指标(10 次运行均值)

  • Q(质量):输出结构一致性 90%(格式确实稳定了);但 70% 的输出含有捏造的 CVE 编号或虚构的复杂度估算(激励不相容的直接后果);漏洞检出率 55%(部分提升来自结构化迫使模型”走完”每个文件)。去除幻觉污染后,可信输出质量 45/100。
  • T(时间):生成耗时约 11 秒(逐行扫描策略极大增加了输出长度,大量 token 被强制生成用于格式合规)。
  • C(成本):input token 约 380(长 Prompt),output token 约 1,800(逐行结构膨胀)。成本是 v1 的 4 倍,但可信质量反而低于 v1 的最好情况。

核心问题:过度约束产生了 §7.6 描述的两个代价——模型退化为”确定性脚本的包装器”,且激励不相容规则主动诱发了幻觉。


v3:最优平衡

# System Prompt v3
## 角色定义
你是专注于安全与正确性的代码审查员,不评论风格问题(linter 负责)。

## 能力边界
你可以:识别安全漏洞、逻辑错误、性能陷阱、接口契约违规
你不可以:评论命名风格、格式化风格、注释规范

## 工作原则
1. 发现真实问题优先于全面覆盖——宁可漏报低风险问题,不可误报
2. 每个问题必须给出可操作的修改建议(具体到代码层面)

## 输出规范
每个问题使用以下 JSON 结构:
{"severity": "high|medium|low", "location": "文件名:行号区间", 
 "description": "...", "suggestion": "..."}
末行附汇总:发现 N 个问题(H 高 / M 中 / L 低)。

设计分析

逐一验证两个合约条件(§7.2):

可观察性severity 字段可由 Post-Hook Schema 校验;location 格式(文件名:行号)可通过正则验证;suggestion 字段是否存在可自动检测;汇总行格式可解析。每条规则都有对应的验证机制——合约可执行。

激励相容性:“发现真实问题优先于全面覆盖”与任务目标方向一致——在 token 资源紧张时,模型的自然倾向(聚焦高确信度问题)与规则要求方向相同,不产生内在张力。JSON 输出规范是正向约束而非逐步流程,模型有充分自由度在格式边界内调整推理策略。

分支因子压缩(§7.1):severity 三选一(bseverity=3b_{\text{severity}} = 3),location 格式固定(bformat=1b_{\text{format}} = 1),问题类型由能力边界隐式约束(btypeb_{\text{type}} 从全类别降至安全/正确性相关)——但不规定逐行顺序(保留推理灵活性)。压缩了关键维度,保留了搜索能力。

无 CVE 编号要求(排除激励不相容)、无”动词开头”(排除零价值约束)、无逐行扫描规定(排除执行层混入合约层)。

Q/T/C 指标(10 次运行均值)

  • Q(质量):漏洞检出率 82%;可操作建议率 91%;输出结构一致性 98%(Post-Hook 校验通过率);零幻觉(无捏造 CVE 或虚构复杂度)。质量均值 79/100,方差极小
  • T(时间):生成耗时约 5 秒,与 v1 相近,Post-Hook 解析耗时 < 0.1 秒(结构化输出的直接收益)。
  • C(成本):input token 约 145,output token 约 620。人类注意力成本近零(结构化输出可直接导入 PR comment 工具)。

三个版本的 Q/T/C 对比

指标v1(过度自由)v2(过度约束)v3(最优平衡)
漏洞检出率38%55%(含幻觉污染)82%
可信输出质量32/100(高方差)45/100(低方差但含幻觉)79/100(低方差无幻觉)
生成时间 T~4s~11s(↑175%)~5s
Input tokens C~80~380(↑375%)~145
Output tokens C~450~1,800(↑300%)~620
人类注意力成本极高(格式不稳定)中(结构化但含幻觉需核查)极低(自动化可解析)
主要失败模式随机游走,质量不可预测激励不相容诱发幻觉无系统性失败模式

迭代轨迹的理论映射

v1 → v2 的错误:误将”输出不稳定”诊断为”约束不够多”,于是堆砌约束——但真正的问题是约束类型错误(不可观察 + 激励不相容),而非数量不足。增加不满足合约条件的约束,只会增加 token 消耗和幻觉风险,不会提升质量。

v2 → v3 的修正:将约束从”过程控制”(逐行扫描、逐步流程)退回”结果约束”(JSON 输出格式、可操作建议);将不可履行的规则(CVE 编号)替换为可验证的输出结构;将零价值的语言风格约束全部删除。这不是”削减约束”,而是将约束集从不满足合约条件的规则替换为满足合约条件的规则——规则数量减少了 60%,但每一条都有效。

v3 的设计是 §7.5 描述的制度化(AGENTS.md)的候选:它足够稳定、足够可维护、适用于所有 Python 代码审查场景,值得跨会话复用。v1 和 v2 则不具备这一性质——v1 因输出不稳定,v2 因工具细节过度耦合(如果工具描述变更,v2 的逐步流程需要同步更新)。

本案例的核心工程结论:Prompt 迭代的方向不是”越多约束越好”,而是每条约束是否同时满足可观察性与激励相容性——这两个条件是 §7.2 给出的充分分析标准,用它们检查每一条规则,v1→v2 的错误方向可以在动笔之前就被排除。