上下文工程:把“一段话”升级成“一套解决方案”(工程师友好的通俗讲解)

一句话定义 :上下文工程不是"写几句提示词",而是把指令、知识、工具、记忆、状态和用户请求 按规则拼装成可执行、可评测、可复用 的输入,像写"接口契约 + 运行时编排"。
关键词:结构化、预算、证据、Schema、回退策略。


这篇文章适合谁

  • 在做问答/RAG、智能客服、Copilot/Agent 的后端或全栈工程师。
  • 觉得"prompt 可用但不稳""一改场景就崩"的同学。
  • 想把 LLM 从 demo 推到生产,并且可观测、可回归的人。

你会收获:一套能落地的思路(白话解释)+ 可复制的最小示例(代码与模板)+ 小 Checklist(上线前自检)。


热身:为什么"只写 Prompt"不够

"把报销政策丢给模型,问:机票能报销吗? "------第一次看起来能答,第二次换个说法就开始"自信胡说"。根因通常有三点:

  1. 信息不全:没把制度原文、更新日期、边界条件一起给到。
  2. 无结构约束:输出自由度太高,长答案不稳定。
  3. 无证据与回退:答错时无法追溯,也没有"保底答复"。

上下文工程做的事 :把"要素与规则"装进一个有结构的输入,并且控成本、控风险


白话版:到底什么是"上下文"

把模型看作函数

ini 复制代码
answer = LLM(context)

这个 context 不是一段话,而是一个拼装好的信息包

ini 复制代码
context = assemble(
  instructions,  # 系统/任务指令与风格、安全边界
  knowledge,     # 可靠来源的证据(文档片段/检索结果)
  tools,         # 可调用函数(参数契约/权限/超时)
  memory,        # 对话摘要、用户画像/历史
  state,         # 时间/位置/渠道/会话状态
  query          # 本轮用户请求
)

上面每一项都要预算 token控制顺序设置约束。这就是上下文工程的基本功。


10 分钟最小例子:做一个"退款客服"上下文

目标:让模型先查订单 再回答,答案里带证据与决策原因 ,失败时给出可解释回退

技术选型:任何主流 LLM 均可;示例用伪代码 + JSON。

1)系统指令(摘录)

diff 复制代码
你是退款客服助手。必须遵守:
- 先决策"是否需要查订单",需要则调用工具,不得臆测。
- 回答使用简洁中文;给出"要点"和"证据来源"。
- 严禁超出政策权限的承诺;不确定时走回退模板。

2)输出 Schema(约束自由度)

json 复制代码
{
  "decision": "lookup|answer|fallback",
  "reason": "string",
  "tool_params": {"order_id":"string"},
  "answer": "string",
  "citations": [{"title":"string","section":"string"}]
}

3)工具定义(函数契约)

json 复制代码
{
  "name": "get_order_status",
  "description": "查询订单的支付与发货状态",
  "params": {"order_id": "string"},
  "timeout_ms": 1200
}

4)知识片段(证据)

diff 复制代码
《退款与退货政策 v3.2》 2024-11-01
- 已发货未签收:支持退款,需走退货流程;
- 已签收 > 7 天:仅质量问题;需凭证;
- 数码产品:拆封后非质量问题不支持无理由;

5)内存与状态(可选)

json 复制代码
{
  "user_profile": {"tier":"gold","history_refund_rate":0.0},
  "now": "2025-08-08T09:30:00Z",
  "channel": "web"
}

6)组装(伪代码)

scss 复制代码
def assemble(query, user_state):
    instructions = load("system_refund_cn")
    schema = load("schema_refund_v1")
    tool_spec = load("tool_get_order_status")
    evidence = retrieve(query, topk=4)        # 混合检索
    evidence = rerank_dedup(evidence)[:2]     # 去冗重排
    budget = plan_budget({
      "instructions":300, "schema":80, "tools":120,
      "evidence":800, "memory":120, "query":80
    })
    return format_context(instructions, schema, tool_spec,
                          evidence, user_state.memory, query)

7)一次交互(模拟示例

用户我的订单 8123 已发货,但想退款可以吗?
模型(第一步)

json 复制代码
{"decision":"lookup","reason":"需确认是否已签收","tool_params":{"order_id":"8123"}}

工具返回{ "order_id":"8123","paid":true,"shipped":true,"delivered":false }
模型(第二步)

json 复制代码
{
  "decision":"answer",
  "reason":"已发货未签收,可退款需退货流程;不涉及超过7天或质量条款",
  "answer":"可以办理退款。请在包裹签收前或签收后7天内发起退货,快递寄回后原路退款。",
  "citations":[{"title":"退款与退货政策 v3.2","section":"已发货未签收"}]
}

失败回退(示例)

json 复制代码
{
  "decision":"fallback",
  "reason":"工具超时",
  "answer":"我这边暂时查不到订单状态。请稍后再试,或在个人中心查看订单 8123 的物流与签收信息。"
}

对比"只写 Prompt"

  • 过去:一段话让模型"猜"。
  • 现在:先判断→再工具→有证据→结构化输出,稳定性显著提升。

如何把它落在你的项目里:四个阶段

S0:单轮可控输出(1 天)

  • 写清系统指令;给 JSON Schema;准备 2--3 个反例 few-shot。
  • 目标:答非所问显著下降;长输出结构完整

S1:加证据(2--3 天)

  • 用 BM25+向量混合检索;重排+去冗;把"片段原文+元数据"塞进上下文。
  • 目标:答案可溯源,幻觉明显减少

S2:加工具与状态(1 周)

  • 把核心查询、下单、审批做成"最小接口",设定超时、幂等、权限
  • 目标:从"会说"到"会做" ;错误有回退路径。

S3:加记忆与评测(持续)

  • 对话摘要→事件/实体库→长期画像;定期去重与过期。
  • 建离线评测集(100--300 条)+ 在线 A/B(解决率、延迟、成本)。
  • 目标:可回归、可观测、可持续优化

工程细节与小技巧(真正好用的那类)

1)切分与索引

  • 切分按"标题锚点+语义边界";保留"生效时间/版本号/条款号"。
  • 为规章/FAQ 建"结构化字段索引"(主题、适用人群、例外场景)。

2)查询与重排

  • 先"改写/扩展查询"(同义、上下位词、关键实体)再检索。
  • Cross-Encoder 重排 + 片段投票,极大降低"跑题证据"。

3)压缩与位置编排

  • "约束式摘要":保留数字、时间、名词;禁止改写结论。
  • 靠近原则:最关键的证据放在 Schema 前或紧挨问题处。

4)输出与校验

  • 让模型按 Schema 输出,再由程序二次校验(缺字段/类型不符→重试一次)。
  • 把"风险词/承诺词"列入黑名单,出现则强制回退。

5)成本与延迟

  • 预算每块 token,给出上限;过长则"先压缩后投喂"。
  • 并发调用工具;对慢工具设超时 + 降级答案

常见坑与修复

现象 根因 快速修复
同一问题答法不一 输出自由度高 加 JSON Schema + few-shot 示例
胡编硬造 无证据 强制引用片段;答案必须带 citations
文档很全但答错 检索错/重排弱 扩展查询;加 Cross-Encoder 重排;投票融合
工具乱调或死循环 无权限/幂等/超时 工具契约化;加超时与重试上限
老事实覆盖新规则 记忆缺失治理 记忆加 TTL;新规则置顶、老版本降权或过滤
长答案东拉西扯 无结构与位置编排 约束式摘要;证据靠近;分段投喂

可观测与评测(上线必备)

离线集query, expected, doc_ids
指标

  • 任务成功率(Exact/Soft)
  • 证据覆盖率(回答引用是否命中正确文档)
  • 延迟 P95、Token 成本
  • 工具成功率、重试次数
  • 结构完整度(Schema 缺字段率)

最小评测脚本(伪代码)

csharp 复制代码
def evaluate(cases):
    stats = []
    for q, expected in cases:
        ctx = assemble(q, user_state={})
        out = call_llm(ctx)
        ok = match(out["answer"], expected)
        stats.append({"ok": ok, "latency_ms": out["latency"], "cost": out["tokens"]})
    return aggregate(stats)

一个最小的上下文流水线

flowchart LR Q[用户Query] --> P[改写/意图识别] P --> R[混合检索] R --> RR[重排/去冗] RR --> C[约束式摘要] C --> A[拼装: 指令/Schema/工具/记忆/状态] A --> L[LLM 推理] L --> V[结构校验/重试/回退] V --> O[响应 + 引用]

模板合集(拿走即用)

系统指令模板

diff 复制代码
[角色] 你是{domain}助手,目标是{business_goal}。
[硬性要求]
- 先判断是否需要工具;需要则仅输出工具调用意图与参数;
- 回答必须符合 {style};禁止虚构;
- 不确定时走回退模板:"{fallback}"。

工具模板

json 复制代码
{
  "name": "{tool_name}",
  "description": "{what_it_does}",
  "params": { "id": "string" },
  "timeout_ms": 1500,
  "idempotent": true,
  "auth": "service_jwt"
}

输出 Schema 模板

json 复制代码
{
  "decision": "lookup|answer|fallback",
  "reason": "string",
  "tool_params": {},
  "answer": "string",
  "citations": [{"title":"string","section":"string"}]
}

回退模板

复制代码
我暂时无法获取必要信息(原因:{reason})。建议你:
1) {step1}
2) {step2}

FAQ(面试与评审常见问题)

  • RAG 就是上下文工程吗?
    不是。RAG 只覆盖"找知识"的一部分;上下文工程还包含指令、工具、记忆、状态、结构化输出、回退与评测
  • 要不要微调?
    先把上下文工程做好,能解决 80% 的稳定性问题;剩余再考虑小规模微调或校准。
  • 有了长上下文模型就不用管了?
    不。窗口大≠有效信息密度高。重排、压缩、位置编排仍关键。
  • 为什么强调 Schema?
    因为输出自由度越小,稳定性越高;Schema 还能让后续系统直接消费。

结语

上下文工程的本质是工程化的输入治理 。你不是在"写几句好听的话",而是在定义契约、管理证据、安排动作、约束输出并可观测地改进。做到了这些,LLM 从"能聊"变成"能用"。

相关推荐
九河云2 分钟前
华为云代理商的作用与价值解析
大数据·人工智能·华为云
科技云报道26 分钟前
科技云报到:热链路革命:阿卡 CRM 的 GTM 定位突围
人工智能
路人蛃28 分钟前
Scikit-learn - 机器学习库初步了解
人工智能·python·深度学习·机器学习·scikit-learn·交友
AI导航猿2 小时前
做PPT、改图、带团队,这个协作工具干掉了我常用的4个软件|AI导航猿
人工智能
失散132 小时前
机器学习——04 逻辑回归
人工智能·机器学习·逻辑回归
荼蘼2 小时前
OpenCV 入门教程:开启计算机视觉之旅
人工智能·opencv·计算机视觉
左右_Sats2 小时前
SpringAI(RAG+MCP)使用-未完结
人工智能
星马梦缘3 小时前
RNN梯度爆炸/消失的杀手锏——LSTM与GRU
人工智能·rnn·深度学习·gru·lstm·长短期记忆
算家计算3 小时前
GPT-5终于发布!网友评价分化,为什么AI升级越来越难让人惊艳?
人工智能·openai·资讯