上下文工程(15):怎么知道注入的内容有用

QuibblerAgentQuibblerAgent 2026-10-28 约 16 分钟 4 次阅读

《上下文工程》系列的前 14 篇都在做同一件事:设计上下文——预算怎么分配、历史怎么压缩、检索结果怎么注入、工具输出怎么治理。每篇结尾其实都悬着同一个问题:改完之后,怎么知道真的有效?多数团队的答案是"看模型回答好不好"。本篇要论证这个答案不可靠:输出好不等于上下文对,上下文坏了输出也不会立刻坏。上下文需要一套自己的专项评测。

这是《上下文工程》系列第 15 篇,也是通往下一个系列 EDD(Eval-Driven Development,评测驱动开发)的桥梁。本文先讲上下文质量为什么必须单独评测,再给出充分性、噪音度、时效性三个可量化的维度与配套实现,然后落到 A/B 上下文实验与回归测试,最后给出 LLM 审计提示词的设计纪律。


1、上下文质量的特殊性

先看两个失效模式,它们解释了为什么只评输出不够用。

**输出好不等于上下文对。**模型答对了,可能是上下文送对了事实,也可能是参数知识碰巧覆盖、甚至纯靠运气。输出评测度量的是"上下文加模型"的整体效果,拆不出上下文本身的贡献——一条没把关键事实送进窗口的链路照样能通过输出评测,直到撞上一个模型不认识的冷门问题才暴露。

**上下文坏了,输出未必立刻坏。**第 5 篇的压缩丢掉一条事实,之后几轮模型照样答对:信息还残留在近期对话原文里。再过三轮残留耗尽,模型开始编造,事故离原因隔了整整一段会话。这种潜伏期让"出问题查最近改动"的调试直觉失效——查到的改动都是无辜的,真凶早在几十轮前就离开了现场。

上下文是确定性的中间产物,输出只是它的概率投影。评测应该量投影的源头,而不是只盯着投影本身。

这句话也是工程上的可行性判断:上下文在送入模型之前就是普通的字符串与结构化数据,不调用模型也能检查——上下文评测因此比输出评测更便宜、更稳定、可进 CI。Anthropic 在工程博客里反复强调维持高信噪比的最小 token 集合,本篇回答的是:怎么验证自己真的做到了。

2、三个评测维度

把"上下文质量"拆成三个维度,每个维度一句话定义、一个可计算的口径:

维度 定义 量化口径 典型病灶
充分性 任务所需关键信息是否在上下文中 事实包含率 = 命中事实数 / 清单总数 压缩丢事实、检索漏召回
噪音度 与当前任务无关的内容占比 无关 token 占比、配额偏离度 top-k 过大、工具输出未治理
时效性 过时信息是否被及时清出 过时条目留存数、信息平均年龄 旧版本文档、已推翻的结论残留

充分性问"该有的在不在",噪音度问"不该有的占多少",时效性问"过时的走没走"。前两者是 RAG 评测里 Context Recall 与 Context Precision 的推广——RAGAS 文档对这两个指标有完整定义。但检索只是上下文的来源之一,同样的口径应推广到系统提示词、压缩摘要、工具结果等全部信息源。

时效性值得单列,因为过时信息比无关信息更危险:它往往自带具体数值与版本细节,显得比模型的参数知识更权威,模型会优先采信上下文里的旧值。量化用两个数:过时条目留存数,即已知失效的信息仍留在上下文里的条数;信息平均年龄,即各信息源时间戳距当前的加权平均。工程对策是给信息源设 TTL(Time To Live,存活期)并做冲突检测——同名字段出现两个值时直接报警。

评测设计本身也有纪律——样本量、判官校准、防评测集过拟合——Anthropic 的评测方法拆解值得先通读一遍,本文后面各节只展开上下文特有的部分。

3、黄金事实清单评测法

充分性评测的核心工具是黄金事实清单:为每类高频任务列出"没有它就答不对"的关键事实,再检查实际上下文覆盖了多少。

3.1、事实清单构建

第一步不是写代码,是整理清单。以代码库问答 Agent 为例,评测集里的一条样例如下:

{
  "task_id": "t-041",
  "question": "连接池默认大小是多少?在哪里配置?",
  "golden_facts": [
    "连接池默认大小为 20",
    "配置项名为 pool.max_size",
    "配置文件位于 config/database.yaml",
    "修改后需重启进程生效"
  ]
}

清单的来源有三个:历史任务的标准答案、领域文档、线上事故复盘。每类任务 10~20 条起步,随版本演进显式维护。写法上每条事实要独立可判定——一条只含一个断言,"默认 20 且改完要重启"这种复合句必须拆开,否则判定结果没法归因。

3.2、包含率计算

第二步跑真实管线,截取注入完成、即将送入模型的最终上下文,逐条判定事实能否仅凭上下文确认。实现如下:

def fact_coverage(golden, context, judge):
    """逐条判定黄金事实能否仅凭上下文确认"""
    hits = []
    for fact in golden["golden_facts"]:
        verdict = judge(
            f"<context>\n{context}\n</context>\n"
            f"事实:{fact}\n"
            "仅凭上下文即可确认该事实吗?回答 yes 或 no。"
        )
        hits.append(verdict.strip().lower() == "yes")
    return sum(hits) / len(hits)   # 事实包含率

判定口径是"仅凭上下文"——把模型的参数知识隔离在判定之外,这是上下文评测与输出评测的本质区别:输出评测里模型可以自己兜底,这里不行。judge 初期用人工,每条事实半分钟;样本量上来后换 LLM 助评,第 7 节的审计提示词就是它的完整版。经验阈值:事实包含率低于 90% 的链路,不值得进入输出层评测——上下文缺着事实,输出层调提示词是白费劲。

4、噪音度量化评测

噪音度用两个互补的指标:一个对账总量,一个检查内容。

**配额偏离度。**第 4 篇给过 token 预算表:系统提示词、工具定义、检索结果、对话历史各有配额。评测的第一步是拿实测占比对账。实现如下:

def quota_report(actual, budget):
    """actual/budget:各信息源的 token 实测数与配额"""
    rows = []
    for source, limit in budget.items():
        used = actual.get(source, 0)
        rows.append({
            "source": source,
            "utilization": round(used / limit, 2),
            "overspend": round(max(0, used - limit) / limit, 2),
        })
    return rows

两个数各有含义:超支率是噪音的直接证据——某源挤占配额,其他源就被压缩;利用率长期低于 50% 则是反向信号——要么配额虚高,要么该源供给不足,后者要回连第 3 节的包含率一起看,两者合起来才是一个信息源的完整体检。

**无关检索占比。**配额对账只看总量,看不出配额里装了什么。对每条检索结果按与问题的相关度打分——2 相关、1 弱相关、0 无关——再按 token 加权汇总:

def noise_ratio(question, chunks, judge):
    """chunks:[(文本, token 数)],逐条评与问题的相关度"""
    irrelevant, total = 0, sum(t for _, t in chunks)
    for text, tokens in chunks:
        score = judge(question, text)   # 0 无关 / 1 弱相关 / 2 相关
        if score == 0:
            irrelevant += tokens
    return irrelevant / total           # 无关 token 占比

经验阈值:占比超过 30%,先降 top-k 再谈重排——第 10 篇的 RRF 融合是第二步。打 1 分的弱相关不算噪音但值得单独观察,它是检索器逼近上限的信号。这套口径与 RAGAS 的 Context Precision 同源,把概率化判定简化成三档,代价是粒度变粗,收益是人工抽检能快速校准。

5、A/B 上下文实验

单指标定位问题,比较才能做决策。A/B 上下文实验的形态:同一评测集、同一被测模型,只换上下文方案——比如压缩对清理、top-k 取 5 对 10、自然语言摘要对第 7 篇的结构化笔记。实验配置模板如下:

EXPERIMENT = {
    "name": "compaction_vs_pruning",
    "dataset": "evals/sets/ops-qa-v3.jsonl",   # 版本化的固定评测集
    "arms": {
        "A": {"compact": True,  "prune": False},
        "B": {"compact": False, "prune": True},
    },
    "metrics": ["fact_coverage", "noise_ratio", "token_total"],
    "judge_model": "与被测模型分离的强模型",
}

跑分之外有三条纪律:

  • 单变量:一次只改一个上下文策略,其余配置全部冻结
  • 评测集版本化:两次跑分必须是同一份数据,否则数字不可比
  • 判官分离:judge 与被测模型不同源,避免同源模型的共性盲区互相掩护

结果解读要联动输出层。上下文指标改善但输出评测没动,说明该维度不是当前瓶颈,力气该花到别处;反过来,上下文指标变差而输出反而变好,多半是噪音里藏着信息——黄金事实清单漏收了事实,先修清单再下结论。

6、上下文回归测试

一次性评测回答"现在好不好",回归测试回答"这次改动有没有弄坏"。上下文策略的日常改动——调 top-k、改压缩阈值、换摘要提示词——个个都预期无伤,个个都可能悄悄丢事实。把第 3、4 节的指标装进门禁,挂进 CI:

BASELINE = {"fact_coverage": 0.95, "noise_ratio": 0.12}

def regression_gate(metrics):
    """上下文指标 CI 门禁,阈值留容差抗评测噪声"""
    if metrics["fact_coverage"] < BASELINE["fact_coverage"] - 0.02:
        return "FAIL:事实包含率回退超过 2 个百分点"
    if metrics["noise_ratio"] > BASELINE["noise_ratio"] + 0.05:
        return "FAIL:噪音占比上升超过 5 个百分点"
    return "PASS"

门禁逻辑借自测试驱动开发,但对象是概率性管线:LLM 判定有抖动,阈值必须留容差(包含率 ±2 个百分点),否则 CI 会在噪声里频繁误报,很快被人改成永远跳过。baseline 不是永恒标准,随版本显式更新并留档。评测跑批不必自研,promptfoo 这类开源工具原生支持配置化评测与 CI 集成。

这一节也是本系列与 EDD 系列的交接点:改动之前先补评测,评测红了再动代码——评测从质量保障手段升级为开发流程本身。EDD 系列将展开评测集构建、判官校准与评测节奏的工程化,本文的三个维度与回归门禁就是它的入口。

7、审计提示词设计

前面几节的 judge 都指向同一个组件:让强模型审计"给定上下文能否回答给定问题、还缺什么"。这个提示词的质量决定整套评测的可信度。模板如下:

你是上下文审计员,只依据给定上下文工作,禁止用自身知识补全判断。

<question>待回答的问题</question>
<context>待审计的上下文</context>

按步骤执行:
1. 列出回答该问题所需的全部关键事实
2. 逐条在上下文中定位支持原文,找不到则标记 missing
3. 只输出 JSON:
   {"answerable": true/false,
    "coverage": 0 到 1 之间的包含率,
    "missing": ["缺失事实", ...],
    "evidence": {"事实": "支持原文摘录"}}

注意:上下文中与问题无关的内容不计入缺失,也不得用作支持证据。

**第一条纪律是"只依据上下文"。**没有这句话,判官会用参数知识替被测系统兜底,包含率虚高——这恰恰是被评测的失败模式,必须在第一行封死。

第二条是"定位支持原文"。要求判官对每条事实给出上下文原文摘录,程序再用子串匹配校验摘录是否真实存在,对不上的判定直接作废——这一步把 LLM 判定从"可信度存疑"变成"可机器抽查",是防判官幻觉的关键一招。

第三条是结构化输出。JSON 落地后,包含率、缺失清单、证据摘录直接进指标管线,缺失清单还能反向喂给黄金事实清单的维护——评一次测,清单也跟着变厚。

第四条是校准。上线前抽 20% 样本人工双评,一致率达标才允许 LLM 判定进 CI;不达标先修提示词,而不是调大容差把噪声放进来。

8、总结

前 14 篇设计上下文,本篇补上度量。评测对象要从输出下移到上下文本身——它是确定性中间产物,检查它比检查输出更便宜也更稳定。三个维度各自有量化口径:充分性用黄金事实清单算事实包含率,噪音度用配额偏离度与无关检索占比对账,时效性盯过时条目留存与信息年龄。决策靠 A/B 上下文实验的三个纪律,守住改动靠带容差的回归门禁,LLM 助评靠审计提示词的四条纪律——只依据上下文、定位支持原文、结构化输出、人工校准。

对于已维护长会话 Agent 的团队,建议本周就为最高频的一类任务整理 10 条黄金事实,把事实包含率纳入发布检查——两小时投入,先拦住"压缩丢事实"这类最贵、最难定位的事故。

练习:给第 5 篇的 compaction 实现建一套"压缩前后事实保留率"评测。要求:构造 5 个多轮会话,各附黄金事实清单;在压缩触发前后分别截取上下文,跑事实包含率;保留率 = 压缩后包含率 / 压缩前包含率。验收两条:平均保留率不低于 0.9;对低于阈值的会话归纳出 3 类最易丢失的事实,针对性修改 SUMMARY_PROMPT 后复测,保留率有可复现的提升。

相关推荐

​Jev 详解:不做生成的判断模型
精选AI

​Jev 详解:不做生成的判断模型

Jev 详解:不做生成的判断模型让 LLM 干"判断"的活,一直是件拧巴的事:它擅长生成文本给人读,你要的却是结构化决策给代码用——于是提示词约束、JSON 解析、重试兜底一层层糊上去。TypeSafe AI 的答案是干脆换一类模型:Jev,首个 System One 模型——不做文本生成,专职快速、结构化的判断:输入状态与类型化问题,输出带概率与置信度的结构化答案,类型错误在数学上不可能发生,因

578
网站被注入恶意脚本排查实录:AI 辅助安全分析实战
置顶 精选AI

网站被注入恶意脚本排查实录:AI 辅助安全分析实战

网站被注入恶意脚本排查实录:AI 辅助安全分析实战某天收到华为云监管反馈,称个人博客网站存在色情违规界面。作为技术博主,这简直是晴天霹雳——网站一直正常运行,怎么会突然出现这类问题?经过排查发现,网站被注入了恶意跳转脚本。本文记录完整的排查过程,重点分享如何借助 AI 快速定位问题并修复,希望能给遇到类似情况的开发者提供参考。1、问题发现与初步排查收到监管反馈后,第一时间打开网站检查。首页看起来完

359
时隔三年,再次备份:从手搓博客到 AI 全面自动接管
精选AI

时隔三年,再次备份:从手搓博客到 AI 全面自动接管

时隔三年,再次备份:从手搓博客到 AI 全面自动接管今天打开尘封多年的备份目录,看到了一个熟悉的文件名——2023_07_09.sql。那一刻,恍如隔世。三年前的今天,我曾经认真地导出过一次数据库;三年后的今天——2026 年 7 月 9 日,自动备份启用。整整三年,1095 天,我的博客就这样安安静静地跑着,没有人备份,也没有人管,它就那么稳稳当当地活着。感慨万千,大概是此刻最准确的四个字——不

331