主题
专题 01 上下文工程与结构化输出
本专题面向“会调模型,但结果不稳定”的前端工程师。它解决的问题不是“怎么把 Prompt 写得更花”,而是怎么把一个概率型系统控制到可复现、可调试、可接入业务流程。
1. 为什么这个专题关键
很多 AI Agent 项目第一次失败,不是失败在模型能力本身,而是失败在上下文组织方式。 同样的模型、同样的用户问题,只要系统指令、知识片段、工具返回、历史消息的排列方式不同,最终输出就可能差很多。
对前端工程师来说,这一层非常像状态管理与数据装配:
- 页面最终呈现什么,不只取决于接口返回,也取决于状态来源、更新顺序和约束条件。
- Agent 最终输出什么,也不只取决于模型参数,更取决于上下文输入结构是否清晰。
如果不做上下文工程,常见后果是:
- 回答忽好忽坏,难以复现。
- 模型输出结构不稳定,前端难以解析和展示。
- RAG、工具调用、记忆系统彼此打架,系统越做越乱。
2. 前端工程师最容易踩的误区
2.1 把 Prompt 当成唯一控制手段
很多前端同学一开始会把 Prompt 当成“大总管”,试图把所有约束都塞进一大段文字里。 这会导致两个问题:一是维护困难,二是约束优先级不清晰。
更好的做法是分层管理上下文:
- 系统层:角色、边界、输出规则。
- 任务层:本轮目标、用户意图、输入数据。
- 证据层:检索片段、工具结果、历史摘要。
- 输出层:结构化 schema、字段含义、失败回退策略。
2.2 只关心“回答像不像”,不关心“能不能消费”
在真实业务里,很多输出不是给人直接看的,而是给前端组件、工作流节点或下游服务消费的。 如果输出格式漂移,链路就会断。
所以结构化输出不是锦上添花,而是工程基础设施。
2.3 盲目塞满上下文窗口
上下文越多不一定越好。无关信息太多会降低注意力密度,增加模型误判和延迟。 很多系统不是“信息不够”,而是“噪音太多”。
3. 上下文工程的核心组成
3.1 指令层级
一个稳定系统需要明确以下层级:
- 全局系统指令:定义角色、边界、风格和禁止事项。
- 工作流节点指令:定义某一步该完成什么。
- 用户输入:表达本轮需求。
- 外部证据:来自 RAG、工具、数据库或人工输入。
- 输出契约:规定返回 JSON、字段约束、错误码或拒答格式。
设计原则是:越稳定、越长期不变的信息越靠前;越动态、越一次性的输入越靠后。
3.2 上下文预算
你可以把上下文窗口理解为一块有限屏幕,不同信息源在抢占可见区域。 建议先做预算分配,而不是等超长后再临时裁剪。
一个常见分配方式如下:
- 10%:系统指令和规则。
- 20%:任务说明和当前输入。
- 40%:检索证据或工具结果。
- 20%:历史对话摘要。
- 10%:输出 schema 与兜底说明。
这不是固定比例,但能帮助你形成“预算意识”。
3.3 证据优先级
不是所有检索结果都应平铺直叙地喂给模型。 应该先排序、去重、裁剪,再打包。
建议优先级规则:
- 与问题最直接相关的证据优先。
- 新版本制度优先于旧版本制度。
- 原文条款优先于二次解释。
- 来源明确的片段优先于来源不明的摘要。
3.4 输出契约
输出契约至少应包含:
- 返回字段名。
- 字段类型。
- 必填与可选字段。
- 失败时如何返回。
- 当证据不足时是否拒答。
示例:
json
{
"answer": "string",
"citations": [
{
"doc_id": "string",
"title": "string",
"quote": "string"
}
],
"confidence": "high|medium|low",
"need_human_review": true
}4. 一套可执行的设计方法
4.1 先定义任务,而不是先写 Prompt
先明确以下问题:
- 这个 Agent 到底要完成什么任务。
- 输出是给谁用:用户、前端组件还是另一个服务。
- 成功标准是什么:正确率、格式稳定率、引用准确率还是任务完成率。
如果这些问题不清晰,后面的 Prompt 和 schema 都会漂移。
4.2 拆分静态上下文与动态上下文
静态上下文指长期不变的信息,例如:
- 系统角色。
- 输出格式。
- 安全边界。
- 行为原则。
动态上下文指每轮请求会变化的信息,例如:
- 用户问题。
- 检索证据。
- 工具返回。
- 会话摘要。
拆开管理后,系统会更容易版本化和调试。
4.3 用“槽位”而不是“长段落”组织输入
推荐把 Prompt 设计成槽位拼装,而不是一整段长文:
system_roletask_goaluser_inputretrieved_contexttool_resultsmemory_summaryoutput_schema
这样做的好处是:
- 更容易追踪是哪一块输入导致问题。
- 更容易做 A/B 实验。
- 更容易给工作流系统复用。
4.4 先定义 schema,再约束生成
很多团队先让模型“自由回答”,再写正则或字符串切割去修补。 这在 Demo 阶段可行,但在工程化阶段成本很高。
更好的顺序是:
- 先定义字段结构。
- 再定义字段解释。
- 再定义字段缺失时的默认行为。
- 最后让模型按 schema 填充。
4.5 为失败设计恢复路径
结构化输出的关键,不只是“成功时长什么样”,还包括“失败时怎么降级”。 建议至少定义三类失败:
- 解析失败:返回保底文本与错误码。
- 证据不足:进入拒答模板。
- 高风险场景:标记
need_human_review=true。
5. 实操步骤
第一步:定义输入输出契约
至少写清楚:
- 输入字段有哪些。
- 哪些字段来自用户,哪些来自系统。
- 输出字段怎么消费。
- 哪些字段会被 UI 组件直接展示。
第二步:确定上下文槽位
先列出可能输入源,再删除冗余项:
- 用户问题。
- 历史摘要。
- 检索证据。
- 工具返回。
- 系统规则。
- 输出格式。
如果某个输入源不能提升正确率、稳定性或可解释性,就不要放进来。
第三步:控制上下文长度
对每一类输入设置上限:
- 最多保留多少轮历史摘要。
- 最多注入多少条证据。
- 每条证据最大长度多少。
- 是否需要先做重排或摘要压缩。
第四步:建立结构化输出检查
前端工程里会做类型校验,Agent 输出也要有类似机制。 建议做三层检查:
- 模型侧约束:Prompt 中声明 schema。
- 服务侧检查:运行时做 JSON 解析与字段校验。
- UI 侧兜底:对缺失字段做空态或警告提示。
第五步:沉淀调试样本
至少保留以下失败样本:
- 证据正确但回答错误。
- 证据不足但没拒答。
- 输出结构不完整。
- 引用错位。
- 历史消息污染当前回答。
6. 面向前端工程师的落地建议
6.1 把它当成“状态装配系统”来理解
前端常见问题是多个状态源彼此覆盖。 Agent 也一样:系统规则、历史对话、RAG 证据和工具返回都可能互相冲突。
你的任务不是写一段“聪明的 Prompt”,而是设计一套“输入优先级明确、输出格式稳定、失败可恢复”的状态装配系统。
6.2 前端要提前参与输出结构设计
不要等后端把自由文本丢给前端再做展示。 前端应该提前参与字段定义,例如:
- 回答正文。
- 引用来源。
- 风险提示。
- 后续推荐动作。
- 置信度等级。
6.3 把 UI 状态和模型状态区分开
例如:
isStreaming是界面状态。need_human_review是模型决策状态。citations是业务数据状态。
分层清楚后,产品体验会稳定很多。
7. 常见失败模式与排查方法
7.1 系统指令与业务规则冲突
现象:模型有时遵守格式,有时只顾回答自然语言。 排查:检查系统角色说明是否和任务说明冲突,是否在后文被覆盖。
7.2 检索证据过多导致注意力稀释
现象:明明召回了正确文档,最终还是答错。 排查:减少证据数量,优先做重排和压缩,而不是继续塞更多片段。
7.3 输出格式在边界场景漂移
现象:正常问题能输出 JSON,复杂问题就开始混入解释性文本。 排查:增加边界样本,对空结果、拒答、高风险结果单独定义模板。
7.4 历史消息污染当前任务
现象:上一轮讨论的内容影响了当前问题。 排查:对历史消息做摘要,而不是直接全量透传;必要时按任务切换新会话。
8. 验证方式
你可以用以下指标验证上下文工程是否成型:
- 结构化输出解析成功率 >= 95%。
- 相同输入多次运行,关键字段波动可控。
- 高风险场景下,系统能稳定进入人工复核或拒答。
- 检索片段减少后,总体正确率不下降或反而提升。
- 出现故障时,能明确定位是哪类上下文导致问题。
9. 可复用模板
9.1 槽位化 Prompt 模板
text
[System Role]
你是企业知识助手,只能基于给定证据回答。
[Task Goal]
回答用户问题,并输出结构化 JSON。
[User Input]
{{user_input}}
[Retrieved Context]
{{retrieved_context}}
[Memory Summary]
{{memory_summary}}
[Output Schema]
{{output_schema}}
[Fallback Rules]
如果证据不足,明确说明无法确认,并将 need_human_review 设为 true。9.2 输出校验清单
- 是否能被 JSON 解析。
- 必填字段是否齐全。
- 引用是否存在并与正文一致。
- 当证据不足时是否拒答。
- 当存在风险时是否显式标记人工复核。
10. 面试表达
你可以这样讲:
“我后来发现,Agent 质量不稳定的根因不只是模型本身,而是上下文组织方式不合理。于是我把输入拆成系统规则、任务目标、检索证据、历史摘要和输出 schema 五类槽位,再通过结构化输出和运行时校验保证结果可消费。这样做之后,系统不仅正确率更稳定,前端渲染和工作流编排也更可靠。”