← 返回文章选择

提示词写清任务,上下文保存当前事实

提示词说清要什么,上下文给对材料;JSON 要逐层验证,冲突、污染、过期分开修。

提示词笔记的前半部分是角色、受众、格式和示例,后半部分是历史截断、工具输出和状态外置。两半要解决的问题不同:前者说明希望得到什么,后者让执行时拿到合适的材料。

先交代任务,再挑表达方式

不同任务要交代的东西不一样:

任务 需要交代
写作 读者画像、用途、文字风格
编码 当前代码、相关版本、预期行为
研究 问题范围、可回查的来源
决策支持 明确的比较标准

一个通用角色提示很难把这些差异交代清楚。Anthropic 的提示词最佳实践把模型比作一个聪明但不了解你们规矩的新同事;在 system prompt 里设角色,管的是行为和语气。任务本身要什么、为什么要,还得另外说。

示例能说明格式和粒度,但要和要求一致。示例里带着旧日期或旧字段,正文却要求另一种输出,执行者就会碰上冲突。编辑已有材料时,还要说清哪些内容必须保留。

同一页文档给了示例的配方:3–5 个,贴近真实用例,彼此要有差异、覆盖边界,免得模型学到你没想教的模式,再用 <example> 标签包起来。顺序也是变量。Lu 等人的论文发现,同一批示例换个排列,成绩能从接近最好跌到随机猜的水平,而且一个模型上的好排列换到另一个模型就不灵了。

准备提示词时,可以按下面的顺序逐项检查。

从任务目标到结果检查,按具体问题修订并返回生成流程

查看 Mermaid 源码
flowchart TD
task["任务目标与使用场景"] --> audience["读者、角色与范围"]
audience --> materials["必要材料和可用工具"]
materials --> constraints["约束、示例与输出格式"]
constraints --> result["生成结果"]
result --> evaluation["用事先确定的标准检查"]
evaluation --> revise["按具体问题修订提示或材料"]
revise --> constraints

要求 JSON 和验证 JSON 是两件事

结构化输出涉及提示词要求、解析失败重试和 schema 约束。文字里写了“返回 JSON”,调用方仍要逐层检查,每层的检查方式不一样:

  1. 解析:只看文本合不合语法;
  2. schema:字段齐不齐、类型对不对;
  3. 内容:事实和业务要求是否满足,通过了 schema 不等于这一层也对。

schema 能表达字段结构,但接口支持哪些约束,要查对应产品的文档;这篇只保留概念,不给出某个 SDK 的调用方式。XML 也一样,外层标签齐全不代表里面的信息正确。

拿两家的文档对一下,就知道“查文档”具体要查什么:

要查的点 Claude OpenAI
不支持的约束 数值范围、字符串长度、递归 schema、外部 $ref 都不支持,用了直接返回 400(文档) 资料里没整理到,用前查文档
拒答时 拒答信息优先于 schema,输出可以不符合 schema 拒答不一定遵守 response_format 里的 schema(文档)
其他失败 被 max_tokens 截断时同样可能不合规;enum 大小写不保证 输入本身产不出合法响应时,提示词里要写清该怎么办

也就是说,就算开了 schema 约束,解析那一层也不能省:拒答和截断会直接把格式打破。

上下文里每份材料都该有用途

任务指令、示例、文档、工具说明、schema、记忆、历史和工作草稿,构成一份上下文材料清单。这里按用途整理,具体的消息优先级要遵循所用接口的规则。

按用途展开,得到下面这张分类图。连线表示组成关系,不表示消息权限或发送顺序。

上下文的五类材料及参考材料、当前工作状态的组成

查看 Mermaid 源码
flowchart TD
context["本次调用的上下文"] --> instructions["任务指令与行为约束"]
context --> reference["参考材料"]
context --> interfaces["工具说明与输出 Schema"]
context --> state["当前工作状态"]
context --> user["本次用户输入"]
reference --> examples["示例与文档"]
state --> memory["相关记忆与历史"]
state --> scratch["工作草稿 Scratchpad"]

可以逐份问它解决什么问题:示例说明输出该长什么样,文档提供事实,工具说明限定能做哪些操作,历史保存已经发生的交互,状态记录承接当前的工作。无关材料越多,后续维护时越难判断哪些已经过期。

代价其实不用等到维护时才付。Anthropic 那篇上下文工程文章说,模型读上下文有一份会被消耗的“注意力预算”,输入越长,召回越不稳。多塞一份无关材料,当下这次调用就可能变差。

控制篇幅的手段有四种:总结已完成的子任务、裁剪工具输出、外置状态、限制保留的历史。执行时要留住影响下一步的事实,比如错误信息、尚未满足的条件和明确的用户约束。压缩后这些丢了,摘要再通顺也接不下去。

这四种手段,官方都有现成做法,可以对照着看:

  • 总结子任务:同一篇文章里,compaction 总结后开新窗口,保留架构决策、未解决的 bug 和实现细节,丢掉冗余的工具输出;子 agent 只回传 1,000–2,000 token 的摘要。
  • 裁剪工具输出:写工具的文章提到 Claude Code 默认把工具响应限在 25,000 token,超了就分页、过滤或截断,截断时要留指引;错误信息要写成具体可执行的改进建议。
  • 外置状态:结构化笔记写到上下文窗口之外,需要时再读回来。
  • 限制历史:API 的上下文编辑默认在超过 100,000 token 时清工具结果,保留最近 3 组,清掉的位置换成占位文本,让模型知道那里删过东西。

对照下来,“错误信息”在官方做法里也是要留的那类东西,和上面那句判断一致。

冲突、污染、过期,分开处理

三种情况的来源不一样:

情况 是什么 怎么处理
冲突 同一件事出现了不同要求 先定哪条有效
污染 多半是错误或无关的内容混进了材料 回到材料本身去找
过期 先前成立的事实被新状态替代 改那份状态

混着修,容易只改到一半:把过期的材料删掉,不等于要求冲突就解决了。

多轮对话也要守住目标。探索范围变了,可以借助分支对话或阶段总结重新整理输入。别只把旧对话越叠越长,指望模型自己找出所有变更。Laban 等人在六类生成任务上测过,多轮对话比单轮平均差 39%,掉的主要是可靠性:模型前几轮就做了假设、过早给答案,走错之后回不来。所以用分支对话和阶段总结,主要是为了防掉分,整洁倒在其次。

改完提示词,回到同一组样例

笔记列了成对比较、评分标准、LLM 评价和评估集污染,几项指向同一个判断:读着更顺的提示词,未必在所有任务上都更好。改完回看同一组典型输入,比较哪些输出改善、哪些退步。输入换了,改动的效果就和输入本身的差别分不开了。另外,评测答案不要放进上下文。

“读着更顺”会骗人,至少有两个原因:

变量 发现 出处
技巧适用面 思维链主要在数学和逻辑类任务上有用,MMLU 上直接作答和用思维链准确率几乎一样 Sprague 等,ICLR 2025
评委偏差 LLM 评委有位置、啰嗦、偏爱自己输出的偏差;GPT-4 级评委和人类偏好的一致率超过 80% Zheng 等,NeurIPS 2023

第二行要读准:80% 的一致率说的是和人的偏好接近,不等于任务做对了。用 LLM 评价可以,评分标准最好写成能逐条核对的几项,再留一小部分样例人工看。

留下几句话 读者来信

读到这里,有什么想法?欢迎留下你的看法。