上下文工程
上下文工程不是"写更好的 Prompt",而是设计更好的信息系统。 Andrej Karpathy 在 2025 年指出,Prompt Engineering 关注措辞技巧,而 Context Engineering 关注的是:什么信息在什么时候以什么形式出现在上下文窗口中。随着模型能力提升,瓶颈已经从"如何说服模型做事"转移到"给模型提供什么信息"。
上下文窗口是一个有结构的空间
上下文窗口不是一个平铺的文本框,而是有层次的信息架构。 一次典型的 LLM 调用,上下文大致分为几个功能区:
System Prompt(角色、规则、工具定义)
↓
Retrieved Context(RAG 检索结果、长期记忆)
↓
Few-shot Examples(格式示例、行为示范)
↓
Conversation History(对话历史、工具调用结果)
↓
Current User Message(当前输入)
每个区域的作用不同。System Prompt 声明稳定的规则和身份;检索上下文动态注入外部知识;Few-shot 示例校准输出格式和风格;对话历史维持任务状态;当前消息触发本次推理。这个结构是需要主动设计的,而不是随意堆叠的。
信息在上下文中的位置和内容同等重要。 Liu 等人 2023 年的研究证明,当关键信息位于长上下文的开头或结尾时,模型表现最好;位于中间时,表现会显著下降,呈现 U 型曲线——这是 Transformer 注意力机制的结构性特征,不因模型变大而消失。这意味着重要的约束和关键文档,应该放在上下文的头部或紧邻当前消息的位置,而不是随便放在中间。
上下文还存在近因偏差。 模型对最近出现的信息赋予更高权重。在多轮对话中,最近几轮的内容对模型行为影响最大;在提示词里,后出现的指令往往会部分压过前面的约束。这既是风险(早期规则可能被覆盖),也是可以利用的特性(在关键用户消息附近重申约束,效果优于只写在系统提示里)。
Few-shot 的真正作用
Few-shot 示例的核心价值不是"教"模型新任务,而是校准格式、分布和风格。 Min 等人 2022 年的研究发现了一个反直觉结论:Few-shot 示例中标签的正确性对性能影响有限,随机错误标签的 Few-shot 仍然比 Zero-shot 好很多。真正起作用的是三件事:告诉模型期望的输出格式、限定"什么是合理输出"的范围、校准语气和详细程度。
一个好的 Few-shot 示例需要满足:相关性、多样性、格式一致性。 示例应该在语义上接近目标任务,示例集合应该覆盖输入空间的不同情况,所有示例必须使用完全一致的格式标记——格式不统一会让模型在格式选择上消耗额外注意力。示例数量上,1-8 个通常足够,超过 20 个的边际收益快速递减。对于经过指令微调的模型,Zero-shot 通常已经足够,Few-shot 主要用于格式和风格校准。
Chain-of-Thought 的本质是展开计算路径,而不是让模型"思考"。 CoT 让中间推理步骤占据 token,使注意力头在每一步只需做更简单的推理。研究发现,CoT 效果在参数量超过约 100B 的模型上才稳定显现——对于较小模型,强制输出推理链反而可能有害。"Let's think step by step"这类 Zero-shot CoT 触发短语,对经过 RLHF 的大模型效果尤为稳定。
System Prompt 的设计原则
System Prompt 不只是"角色设定",它是整个对话的协议层。 经过 RLHF 训练的模型被训练为"信任"系统提示中的指令,这使得系统提示在权限声明、持久约束和行为规范上比用户消息更有效。一个结构完整的 System Prompt 通常包含:角色与能力边界、工具使用规则、输出格式规范、关键行为示例。
正向声明优于负向禁止,具体示例优于抽象描述。 "回复控制在 200 字以内"优于"不要啰嗦";展示一个真实输出示例,优于用文字描述格式要求。原子化规则——每条规则只声明一件事,避免"规则里的规则"——能减少模型解释歧义的概率。
System Prompt 有一个实际的工程优势:KV Cache。 上下文中的固定前缀部分,在多次请求之间会被 API 缓存复用,不需要重复计算。Anthropic 的 Prompt Caching 在缓存命中后可以将输入 token 成本降低 90%、延迟减少 85%。这意味着 System Prompt 写得详尽在成本上几乎是免费的——但前提是它必须放在上下文的最前面,保持前缀稳定,因为 KV Cache 基于前缀匹配工作。
RAG:把知识检索变成上下文注入
RAG 的本质是动态上下文构建,而不只是"搜索 + 回答"。 模型的参数知识有截止日期、有幻觉风险、无法访问私有数据。RAG 解决这些问题的方式是:把知识存在外部,每次推理前检索相关内容,注入上下文,让模型基于当前上下文生成答案,而不是依赖参数记忆。
Chunk 策略决定检索质量的上限。 文档切分过小,单个 chunk 缺乏上下文导致语义残缺;切分过大,检索到的内容包含太多噪音。层次化切分是当前效果最好的方向:用小 chunk(256-512 tokens)做精确检索,检索命中后返回其父级大 chunk(1024-2048 tokens)提供完整上下文,兼顾检索精度和上下文完整性。Chunk 之间保留 10-20% 的重叠,防止边界信息丢失。
向量检索之后需要精排(Reranking)。 初始向量检索基于语义相似度,容易把"语义相近但答案不相关"的内容检索进来。用 Cross-encoder Reranker 对初始 Top-30 结果精排,取 Top-5 注入上下文,通常能提升系统准确率 5-15%。查询增强同样重要:对复杂查询先让 LLM 生成"假设答案文档"再用它检索(HyDE),或生成 3-5 个改写版本分别检索再合并去重(Multi-Query),都能显著提升召回率。
上下文压缩与多轮管理
随着对话推进,上下文会不断增长,需要主动管理。 早期信息会被"迷失在中间",token 成本随长度线性增长,且模型无法区分哪些历史真正重要。解决方案不是无限扩大上下文窗口,而是分层管理:最近几轮完整保留(工作记忆),更早的历史滚动摘要(压缩为情节记忆),关键事实和决策提取到结构化存储(语义记忆),按需检索注入。
可以丢弃的和必须保留的有明确优先级。 可以优先丢弃:礼貌用语和确认语句、同样信息的重复陈述、CoT 的中间推理步骤(只保留结论)。必须保留:用户明确表达的偏好和约束、已确认的事实和决策、对话的核心目标、错误和纠正记录——后者尤其重要,防止 Agent 在多轮中重复同样的错误。
上下文压缩有损,但有工程手段可以控制损失。 Microsoft Research 的 LLMLingua 通过小型语言模型评估每个 token 的信息量,移除困惑度低的冗余 token,压缩比可达 2-20x,精度损失通常低于 5%。对于需要高效处理极长 Prompt 的场景,这类压缩工具是实用的工程选项。
上下文工程的第一性原理
理解上下文工程,有三个核心命题:
上下文是程序,不是文本。 每次 LLM 调用的上下文,是在运行时动态组装的程序产物。检索什么文档、选哪些历史轮次、注入什么工具结果,都是需要精心设计的决策,而不是随意拼接的文字。
信息的放置和信息的内容同等重要。 相同的内容放在不同位置会产生显著不同的效果。位置、顺序、格式标记——这些是上下文工程的核心设计变量。
Token 预算是稀缺资源,需要工程化管理。 固定内容前置利用 KV Cache,动态内容后置减少缓存失效,关键信息首尾放置避免注意力洼地,检索内容精排减少噪音——这些是系统层面的设计决策,不是事后优化的细节。