RAG Context Engineering 生产实战:上下文打包、去重、冲突与引用锚定
从候选证据归一化、Parent/邻接扩展、Exact/Near 去重、MMR 多样性、冲突治理、Token Budget、压缩、排序到 Citation Anchor,构建可追溯、可评测、可回放的生产级 Context Pack。
检索系统返回 Top-K,只代表“这些候选值得继续处理”,不代表应该把它们原样塞进模型。
生产 RAG 的最后一公里是 Context Engineering:在固定 Token Budget 内,把候选证据整理成一个相关、充分、少冗余、可引用、能解释冲突、可以回放的 Context Pack。很多被归因于“模型幻觉”的问题,真实根因其实发生在这一层:
- 正确证据进入 Top-K,却在 Parent 回填时被错误替换;
- 同一段内容以多个版本重复出现,挤掉了必要证据;
- 多份政策互相冲突,系统没有标注生效时间和权威级别;
- 关键材料被排在长上下文中间,模型没有稳定利用;
- 压缩器删掉了数字、否定词或限定条件;
- Citation Key 指向了未实际进入 Prompt 的 Chunk;
- Token Budget 被对话历史、工具输出或重复元数据耗尽。
资料快照:本文核查截至 2026-08-06。理论与方法优先参考 Lost in the Middle、MMR、RECOMP、LongLLMLingua、LLMLingua-2,以及 LlamaIndex 的 Sentence Window、Hierarchical Node 与 Auto Merging Retriever 文档。2025–2026 年的 EXIT、AttnComp、SCAR 与 SARA 作为前沿方向讨论;生产采用前仍需要在自己的数据、语言、模型和延迟预算上复现。
图 1:基于 GPT-Image 主视觉草图重绘为可编辑 SVG:从候选召回到可回放 Context Pack 的完整心智模型。精确字段、算法与工程约束以本文正文、后续 SVG 和代码为准。
一句话结论
一个可发布的 Context Pack,不是一串按分数排序的 Chunk,而是一份版本化证据清单:
Retrieval Candidates
→ Scope / Revision Validation
→ Evidence Hydration
→ Parent / Neighbor Expansion
→ Exact / Near / Version Dedup
→ Conflict Detection
→ Diversity Selection
→ Compression
→ Token Budget Allocation
→ Position-aware Ordering
→ Citation Anchor Materialization
→ Final Validation
→ Context Pack Manifest它至少要保证:
- Required Evidence 不因扩展、去重、压缩或预算而丢失。
- Unauthorized、Stale、Invalid Evidence 在进入 Prompt 前被阻断。
- 同源重复内容不会挤占多来源证据。
- 冲突来源被明确标记,而不是静默选一个。
- 模型看到的每个 Context Block 都能回到稳定 Source Span。
- 同一个 Trace 可以重建当时真正发送给模型的上下文。
1. 为什么 Top-K 不能直接成为 Context
一个典型检索结果可能长这样:
[
{
"chunk_id": "policy_v3_101",
"score": 0.91,
"source": "bm25"
},
{
"chunk_id": "policy_v3_102",
"score": 0.89,
"source": "dense"
},
{
"chunk_id": "policy_v2_087",
"score": 0.86,
"source": "dense"
}
]这份列表没有回答:
- 第一、第二条是否来自同一个 Parent;
- 第三条是不是已经失效的旧版本;
- 每条证据是否属于当前 Tenant 和 ACL;
- Chunk 是否在句子中间截断;
- 是否需要补充上一段和下一段;
- 三条证据是否都支持同一个结论;
- 是否存在更权威但分数略低的来源;
- 每条内容实际占用多少 Token;
- 哪些内容最终进入了 Prompt;
[1]到底绑定哪一个 Source Span。
因此 Context Packing 不是格式化函数,而是一个证据决策系统。
1.1 长上下文不等于有效上下文
Lost in the Middle 的实验显示,模型对长上下文中相关信息的位置敏感:关键信息位于开头或结尾时往往表现更好,位于中间时可能明显退化。
工程结论不是简单把所有重要内容放在最前面,而是:
- 不要把大量重复或低价值内容堆进上下文;
- 对关键证据设置明确优先级;
- 记录位置和顺序;
- 在评测集中对位置进行扰动测试;
- 不把“模型支持更长窗口”误解为“所有位置都被同样可靠地利用”。
1.2 Context 是证据产品,不是字符串
推荐把最终上下文视为一个有 Schema 的产品:
Context Pack
├── Pack Identity
├── Query / Scope
├── Budget
├── Selected Evidence
├── Removed Evidence + Reason
├── Conflict Set
├── Citation Anchors
├── Rendered Prompt Blocks
├── Hashes / Versions
└── Validation Result只有这样,Context 才能被评测、缓存、回放和修复。
2. 生产级 Context Packing 流水线
图 2:Context Packing 应分阶段执行,每一步都输出结构化结果和移除原因,而不是在一个函数里完成不可解释的截断。
推荐把流水线拆成十个阶段:
| 阶段 | 输入 | 输出 | 主要失败 |
|---|---|---|---|
| Candidate Normalize | 多路召回结果 | 统一候选结构 | ID 冲突、分数语义混乱 |
| Scope Validate | Candidate + User Scope | 可访问候选 | 越权、状态失效 |
| Hydrate | Chunk ID | Source Span、Parent、版本 | 数据缺失、Revision 不一致 |
| Expand | 命中 Child | Parent / Neighbor 候选 | 无界扩展、重复 |
| Dedup | 扩展候选 | 去重候选 | 错删互补证据 |
| Conflict | 去重候选 | Conflict Set | 冲突未识别 |
| Diversify | 候选 + Query | 多样候选 | 相关性下降 |
| Compress | 候选文本 | 可引用精简证据 | 事实或限定丢失 |
| Budget / Order | Token 预算 | 有序 Context Blocks | Required Evidence 被裁掉 |
| Validate | Context Blocks | 可发布 Pack | Anchor、权限、覆盖失败 |
3. 先统一 Candidate 与 Evidence 数据模型
不同召回通道常返回不同结构:
BM25
→ `_score`、highlight、field matches
Dense kNN
→ similarity、vector store、embedding model
Graph
→ path、edge、entity
SQL / Metrics
→ query_run_id、row、column
Web
→ URL、title、snippet进入 Context Pipeline 前,应统一为 Candidate Manifest。
{
"candidate_id": "cand_001",
"evidence_id": "ev_20260806_001",
"knowledge_id": "doc_policy_2026",
"chunk_id": "chunk_101",
"parent_chunk_id": "parent_09",
"source_revision": 42,
"content_hash": "sha256:...",
"retrieval_channels": [
{
"channel": "bm25",
"rank": 2,
"raw_score": 12.81
},
{
"channel": "dense",
"rank": 5,
"raw_score": 0.84
}
],
"fused_rank": 3,
"rerank_rank": 1,
"rerank_score": 0.89,
"scope": {
"tenant_id": "tenant_001",
"acl_policy_version": "acl-v8"
},
"estimated_tokens": 186,
"required": false
}3.1 Candidate ID 与 Evidence ID 要分开
Candidate ID
→ 本次检索流水线中的临时身份
Evidence ID
→ 可以跨 Trace、评测和引用复用的证据身份同一 Evidence 可能被 BM25、Dense 和 Graph 同时找到,应该合并通道信号,而不是被当成三份上下文。
3.2 Hydration 必须固定 Revision
Hydration 不能只按 chunk_id 查询“当前内容”,还要绑定:
source_revision
content_hash
projection_schema_version
index_generation否则在用户请求完成前文档发生更新,Trace 中保存的 Candidate 与最终渲染文本可能来自不同版本。
4. Parent–Child 与邻接扩展
精确召回通常偏好较小的 Child Chunk;生成回答往往需要更完整的 Parent 或相邻上下文。
4.1 Small-to-Big 的基本原则
Child
→ 用于搜索和定位
Parent
→ 用于解释和生成
Source Span
→ 用于最终引用LlamaIndex 的 Hierarchical Node / Auto Merging Retriever 提供了一种典型实现:索引叶子节点,当多个叶子命中同一父节点且达到阈值时,使用父节点替换部分叶子,以获得更完整的上下文。
生产实现不应该简单地:
命中任意 Child
→ 无条件替换成完整 Parent而应考虑:
parent_selected =
child_coverage_ratio >= threshold
OR parent_is_required_for_coherence4.2 Parent 扩展策略
{
"parent_policy": {
"mode": "adaptive",
"child_coverage_threshold": 0.55,
"max_parent_tokens": 900,
"prefer_parent_when_children": 2,
"preserve_hit_spans": true
}
}必须保留:
- 哪些 Child 触发了 Parent;
- Child 的原始 Rank 和 Score;
- Parent 中真正相关的 Source Span;
- 替换前后 Token 差异;
- Parent 是否导致其他 Required Evidence 被挤出。
4.3 邻接窗口
Sentence Window Retrieval 的核心是:
用较小单元做精确 Embedding
→ 命中后替换为前后句窗口邻接扩展适合:
- 定义在上一句、结论在下一句;
- 表格标题与行内容分离;
- 代码声明与注释分离;
- 对话字幕被切在边界;
- 数字和单位落在相邻 Chunk。
建议使用自适应窗口:
K = 0
→ Chunk 自身已经完整
K = 1
→ 常规事实或定义
K = 2~3
→ 对话、叙事、长论证
结构边界
→ 不跨越权限、文档、章节或版本4.4 前沿方向:语义连续性扩展
SCAR 等近期工作尝试根据 Query–Neighbor 相关性与结构连续性决定是否扩展相邻 Chunk,而不是固定使用 prev/next = 2。
这类方法值得实验,但必须保持三个约束:
- 扩展不能跨 ACL 或 Revision。
- 需要记录为何扩展和为何停止。
- 评测必须同时看 Boundary Recall 与 Token Overhead。
5. 去重:Exact、Near、Version 与 Semantic Role
图 3:去重不是简单按文本相似度删候选,需要先区分完全重复、近重复、版本重复和同一 Parent 的结构重复。
5.1 Exact Dedup
优先使用稳定身份:
evidence_id
source_revision
source_span_id
content_hash而不是只比较字符串。
相同 Source Span + 相同 Revision
→ 合并 Retrieval Channels
相同文本 + 不同来源
→ 不一定删除,可能是独立佐证
相同 Source + 不同 Revision
→ 进入 Version Conflict5.2 Parent / Child Dedup
如果 Parent 已经完整包含 Child:
Context 中保留 Parent 文本
Citation 中保留命中 Child 的 Source Span不要同时把 Parent 和多个 Child 全部放入 Prompt。
5.3 Near Dedup
常用方法:
- MinHash / SimHash;
- Character N-gram;
- Embedding Cosine;
- 标题、Source ID 和段落位置联合判断;
- 业务模板指纹。
Near Dedup 不能只看相似度:
“退款率不超过 5%”
“退款率超过 5%”两句话高度相似,但语义相反。否定词、数值、比较符和时间必须作为不可丢失 Anchor。
5.4 Version Dedup
同一来源的多个版本应按业务规则处理:
问题询问当前政策
→ 优先 valid_at = now 的版本
问题询问历史状态
→ 使用 business_as_of 对应版本
用户要求比较版本
→ 两个版本都保留,并标注 Diff
无法判断时间
→ 追问或显式展示冲突5.5 Role-aware Dedup
同样的内容可能承担不同作用:
Direct Evidence
Background
Definition
Contradicting Evidence
Authority Evidence即使文本接近,也不能把“反例”当作重复项删除。
6. 多样性:MMR、来源配额与证据覆盖
MMR 将 Query 相关性和候选间新颖性组合:
MMR(d_i)
=
λ · sim(d_i, query)
-
(1 - λ) · max sim(d_i, selected)其中:
λ 接近 1
→ 更偏重相关性
λ 较低
→ 更偏重多样性6.1 MMR 适合解决什么
- 同一 Parent 的多个相似 Child;
- 多个渠道重复找到相同证据;
- 多文档比较问题;
- “原因有哪些”这类多角度问题;
- 多角色、多时间段、多来源分析。
6.2 MMR 不能解决什么
- 权限校验;
- 版本有效性;
- 数字和否定词冲突;
- Required Evidence 保证;
- Citation Anchor;
- 事实权威级别。
MMR 必须放在 Scope、Revision 和基础冲突校验之后。
6.3 来源配额
除了 MMR,还可以设置 Source Quota:
source_quota:
max_blocks_per_parent: 1
max_blocks_per_document: 3
min_distinct_documents: 2
min_distinct_authorities: 1
allow_override_for_required: true6.4 Query-aware Diversity
不同问题需要不同多样性:
| Query Type | 多样性需求 |
|---|---|
| Exact ID | 低,优先精确证据 |
| Definition | 低到中,权威来源优先 |
| Comparison | 高,必须覆盖比较双方 |
| Multi-hop | 高,但按 Hop 组织 |
| Troubleshooting | 高,覆盖多个根因 |
| Policy | 中,当前权威版本优先 |
| Summarization | 高,覆盖不同章节和主题 |
7. 冲突检测:不要静默选择一个来源
图 4:冲突不是普通噪声。生产系统应保存 Conflict Set、选择规则和最终向用户展示的解释。
7.1 常见冲突类型
| 类型 | 示例 |
|---|---|
| Temporal | 2024 版与 2026 版政策不同 |
| Numeric | 同一指标分别为 12.4% 和 13.1% |
| Definition | “活跃用户”口径不同 |
| Authority | 官方制度与个人笔记冲突 |
| Status | Draft、Deprecated 与 Active 并存 |
| Scope | 全球政策与地区政策冲突 |
| Language | 翻译版本与原文含义不一致 |
| Access | 高权限来源与用户可见来源冲突 |
7.2 Conflict Set
{
"conflict_id": "conf_20260806_001",
"type": "numeric_temporal",
"subject": "remote_employee_allowance",
"evidence": [
{
"evidence_id": "ev_policy_v3",
"value": 5000,
"currency": "CNY",
"valid_from": "2026-05-01",
"authority": 0.98
},
{
"evidence_id": "ev_faq_v2",
"value": 3000,
"currency": "CNY",
"valid_to": "2026-04-30",
"authority": 0.70
}
],
"resolution": {
"strategy": "business_as_of_then_authority",
"selected_evidence_id": "ev_policy_v3",
"must_explain": true
}
}7.3 冲突处理策略
可自动解决
→ 当前时间 + 明确有效期 + 权威来源
需要并列展示
→ 多个权威来源仍冲突
需要追问
→ 用户未说明地区、时间或业务口径
必须拒答
→ 证据严重冲突且无法确认
需要人工升级
→ 高风险财务、法律、医疗或安全问题7.4 不要让压缩器“解决”冲突
压缩器如果只保留其中一个版本,会把可见冲突变成隐藏错误。
在 Compression 前先标注 Conflict Role:
supporting
contradicting
superseded
authority_override压缩后仍必须保留足够信息让生成模型解释冲突。
8. Token Budget:先分配,再选择
8.1 总预算
model_context_window
-
system_and_policy_tokens
-
conversation_tokens
-
tool_schema_tokens
-
reserved_answer_tokens
-
safety_margin
=
available_context_tokens示例:
上下文窗口:16,000
系统与策略:1,400
会话历史:1,600
工具 Schema:800
回答预留:2,000
安全余量:1,200
可用 Evidence Budget:9,0008.2 为什么要保留安全余量
Token 估算可能因为:
- 模型 tokenizer 不同;
- JSON 转义;
- 多语言字符;
- 工具描述动态变化;
- Citation Metadata;
- 系统自动注入内容;
而发生偏差。
不要把预算使用率长期推到 100%。
8.3 分区预算
context_budget:
total_tokens: 9000
required_evidence: 3500
supporting_evidence: 2200
conflict_evidence: 1200
definitions: 800
citation_metadata: 500
reserve: 8008.4 Required Evidence 优先
多跳问题需要的证据不应该只依赖总分。
{
"required_evidence_groups": [
{
"group_id": "hop_1",
"requirement": "at_least_one",
"evidence_ids": ["ev_a", "ev_b"]
},
{
"group_id": "hop_2",
"requirement": "all_of",
"evidence_ids": ["ev_c", "ev_d"]
}
]
}只有 Required Groups 满足后,才把剩余预算分配给 Supporting Evidence。
8.5 价值密度
可以为候选计算:
utility =
relevance
× authority
× freshness
× coverage_gain
× citation_quality
× uniqueness
÷ token_cost但不要把所有决策压成单一分数。Hard Veto 和 Required Group 应先于 Utility。
9. 一个可解释的 Packing 算法
9.1 数据结构
type EvidenceCandidate struct {
ID string
SourceID string
SourceRevision int64
ParentID string
Content string
ContentHash string
EstimatedTokens int
Relevance float64
Authority float64
Freshness float64
CoverageGain float64
CitationQuality float64
RequiredGroupIDs []string
ConflictIDs []string
Accessible bool
Active bool
}
type PackDecision struct {
EvidenceID string
Selected bool
Order int
AllocatedToken int
Reason string
}
type ContextPack struct {
PackID string
BudgetTokens int
UsedTokens int
Decisions []PackDecision
RequiredSatisfied bool
ConflictIDs []string
ContentHash string
}9.2 分阶段选择
func BuildContextPack(
candidates []EvidenceCandidate,
budget int,
) (ContextPack, error) {
if budget <= 0 {
return ContextPack{}, fmt.Errorf("budget must be positive")
}
eligible := make([]EvidenceCandidate, 0, len(candidates))
for _, candidate := range candidates {
if !candidate.Accessible || !candidate.Active {
continue
}
eligible = append(eligible, candidate)
}
deduped := DeduplicateEvidence(eligible)
required, optional := PartitionRequiredEvidence(deduped)
selected := make([]EvidenceCandidate, 0, len(deduped))
used := 0
for _, candidate := range SortRequired(required) {
if used+candidate.EstimatedTokens > budget {
return ContextPack{}, fmt.Errorf(
"required evidence exceeds budget at %s",
candidate.ID,
)
}
selected = append(selected, candidate)
used += candidate.EstimatedTokens
}
for _, candidate := range SelectMMR(optional, selected) {
if used+candidate.EstimatedTokens > budget {
continue
}
selected = append(selected, candidate)
used += candidate.EstimatedTokens
}
ordered := OrderForGeneration(selected)
return MaterializeContextPack(ordered, budget), nil
}生产实现还必须加入:
- Scope 与 Revision 验证;
- Parent / Neighbor 扩展;
- Conflict Set;
- Compression;
- Citation Anchor;
- Stable Tie-break;
- Tokenizer 精确计算;
- Trace Events;
- Fallback。
9.3 稳定 Tie-break
相同分数时,建议使用:
required desc
authority desc
freshness desc
source_id asc
source_span_start asc
evidence_id asc这样同一版本、同一输入可以得到稳定顺序,便于缓存和回放。
10. 上下文压缩:Extractive 优先,Abstractive 受控
RECOMP 提出了 Extractive 与 Abstractive Compressor,并允许在检索内容无关或不能提供额外信息时返回空字符串,实现 Selective Augmentation。
10.1 Extractive Compression
保留原文中的句子或 Span:
优点
→ 可追溯、易引用、事实保真度较高
风险
→ 句间连接断裂、表格结构丢失、跨句关系不足适合:
- 数字;
- 政策;
- 法条;
- 接口字段;
- 代码;
- 高风险事实。
10.2 Abstractive Compression
生成摘要或融合多个来源:
优点
→ 压缩率高、跨文档整合强
风险
→ 可能改写限定、合并冲突、制造不存在的关系Abstractive 内容不能直接替代原始 Citation Evidence。推荐:
摘要
→ 帮助模型理解
原始 Span
→ 支持最终 Claim 和 Citation10.3 Token-level Compression
LongLLMLingua 与 LLMLingua-2 研究了长上下文和任务无关的 Token / Phrase 压缩。
生产使用时至少检查:
- 数字是否保留;
- 否定词是否保留;
- 单位是否保留;
- 实体和版本是否保留;
- Citation Span 是否仍可定位;
- 压缩后是否改变句法关系;
- 不同语言是否有不对称损失。
10.4 Emerging:自适应压缩
EXIT、AttnComp 等 2025 年工作尝试根据 Query 和上下文结构自适应选择句子或压缩比例;SARA 等 2026 年方向进一步探索在固定预算下混合保留原文片段与压缩表示。
这些方向值得关注,但生产落地要优先回答:
压缩输出是否可引用?
是否能保存稳定 Source Span?
是否能对冲突证据分别编码?
失败时如何回退到原文?11. 位置排序:避免把关键证据埋在中间
一种简单但不充分的策略是:
最重要证据放最前
第二重要证据放最后
其余放中间更稳妥的是根据任务结构组织 Context。
11.1 Query-first Block
每个 Context Block 包含:
Citation Key
Source Title
Revision / Valid Time
Evidence Role
Relevant Span
必要 Parent Context11.2 按 Claim / Hop 分组
Claim A
├── Direct Evidence
└── Supporting Evidence
Claim B
├── Direct Evidence
└── Contradicting Evidence多跳任务:
Hop 1 Evidence
→ Hop 1 Result
Hop 2 Evidence
→ Hop 2 Result11.3 冲突靠近展示
支持与反对同一 Claim 的证据应放在相邻位置:
[S1] 当前正式政策
[S2] 已失效旧政策
[Conflict Note] S1 supersedes S2不要把冲突来源分散在长上下文两端。
11.4 Position Perturbation Test
评测时对相同证据执行:
important_first
important_middle
important_last
random_seeded如果答案对位置非常敏感,应降低 Pack 长度、提高结构化程度或调整模型与 Prompt。
12. Citation Anchor:模型看到什么,就引用什么
最终 Context Block 可以采用:
[S1]
source_id: hr_policy
revision: 42
valid_from: 2026-05-01
section: §4.1
page: 12
source_span_id: span_p12_03
role: direct
text: 远程办公补贴上限为每年 5,000 元。12.1 Citation Key 是响应内身份
[S1]
→ 只在本次响应中有效持久身份来自:
source_id
source_revision
source_span_id
content_hash12.2 Anchor 必须在 Packing 时生成
不要等模型回答后再通过相似度“猜引用”。
Packing 阶段应完成:
Context Block
→ Citation Key
→ Source Span
→ Revision
→ Rendered Text Hash12.3 压缩后的 Anchor
如果使用 Extractive Compression:
compressed_span
→ 映射回一个或多个 original source spans如果使用 Abstractive Compression:
summary block
→ 不能作为唯一 Citation
→ 必须附带支持它的原始 Evidence IDs12.4 引用校验
最终验证至少包括:
Presence
→ Citation Key 是否存在于 Context
Membership
→ 被引用 Evidence 是否真的发送给模型
Permission
→ 用户是否有权查看
Revision
→ 是否绑定正确版本
Support
→ Evidence 是否支持 Claim
Coverage
→ Required Claim 是否都有 Citation
Resolution
→ Source Span 是否还能打开和高亮13. Context Pack Manifest
{
"pack_id": "ctx_20260806_000123",
"query_id": "q_20260806_000123",
"release_id": "rel_20260806_001",
"scope": {
"tenant_id": "tenant_001",
"acl_policy_version": "acl-v8"
},
"pipeline": {
"retrieval_version": "retrieval-v12",
"reranker_version": "rerank-v8",
"packing_version": "context-pack-v5",
"compression_version": "extractive-v3",
"tokenizer": "model-tokenizer-v2"
},
"budget": {
"total_tokens": 9000,
"used_tokens": 7420,
"reserved_tokens": 1580
},
"selected_blocks": [
{
"context_key": "S1",
"evidence_id": "ev_101",
"source_id": "hr_policy",
"source_revision": 42,
"source_span_id": "span_p12_03",
"rendered_hash": "sha256:...",
"tokens": 186,
"order": 1,
"role": "direct"
}
],
"removed_candidates": [
{
"evidence_id": "ev_087",
"reason": "superseded_revision"
},
{
"evidence_id": "ev_221",
"reason": "budget_exceeded"
}
],
"conflicts": [
"conf_20260806_001"
],
"validation": {
"required_groups_satisfied": true,
"unauthorized_count": 0,
"unresolved_anchor_count": 0,
"token_budget_ok": true
},
"pack_hash": "sha256:..."
}这份 Manifest 用于:
- Trace;
- Answer Cache;
- Bad Case Replay;
- Citation Validation;
- Offline Evaluation;
- Release Gate;
- 事故证据冻结。
14. MySQL 数据模型
CREATE TABLE rag_context_pack (
pack_id VARCHAR(64) PRIMARY KEY,
query_id VARCHAR(64) NOT NULL,
release_id VARCHAR(64) NOT NULL,
tenant_id VARCHAR(64) NOT NULL,
packing_version VARCHAR(64) NOT NULL,
tokenizer_version VARCHAR(64) NOT NULL,
budget_tokens INT NOT NULL,
used_tokens INT NOT NULL,
pack_hash CHAR(71) NOT NULL,
validation_status VARCHAR(32) NOT NULL,
created_at DATETIME(6) NOT NULL,
KEY idx_context_pack_query (query_id),
KEY idx_context_pack_release (release_id)
);
CREATE TABLE rag_context_block (
pack_id VARCHAR(64) NOT NULL,
context_key VARCHAR(32) NOT NULL,
evidence_id VARCHAR(64) NOT NULL,
source_id VARCHAR(64) NOT NULL,
source_revision BIGINT NOT NULL,
source_span_id VARCHAR(128) NOT NULL,
role VARCHAR(32) NOT NULL,
block_order INT NOT NULL,
token_count INT NOT NULL,
rendered_hash CHAR(71) NOT NULL,
selected_reason VARCHAR(64) NOT NULL,
PRIMARY KEY (pack_id, context_key),
KEY idx_context_block_evidence (evidence_id)
);
CREATE TABLE rag_context_decision (
pack_id VARCHAR(64) NOT NULL,
evidence_id VARCHAR(64) NOT NULL,
selected BOOLEAN NOT NULL,
decision_stage VARCHAR(32) NOT NULL,
reason VARCHAR(64) NOT NULL,
score_json JSON NOT NULL,
created_at DATETIME(6) NOT NULL,
PRIMARY KEY (pack_id, evidence_id, decision_stage)
);大文本和完整 Snapshot 可以进入加密 Artifact Store,MySQL 保存身份、Hash、版本和索引字段。
15. API 契约
POST /v1/context-packs
{
"query": "今年远程办公补贴是多少?",
"query_plan_id": "qp_001",
"candidate_manifest_id": "cand_manifest_001",
"scope": {
"tenant_id": "tenant_001",
"acl_groups": ["employee"]
},
"budget": {
"max_context_tokens": 9000,
"reserved_answer_tokens": 1800
},
"policy": {
"parent_expansion": "adaptive",
"neighbor_window": 1,
"dedup": "exact_near_version",
"diversity": "mmr",
"compression": "extractive",
"conflict": "explain"
}
}响应:
{
"pack_id": "ctx_20260806_000123",
"status": "ready",
"used_tokens": 7420,
"context_blocks": [
{
"context_key": "S1",
"text": "...",
"citation": {
"source_id": "hr_policy",
"source_revision": 42,
"source_span_id": "span_p12_03"
}
}
],
"conflicts": [
{
"conflict_id": "conf_20260806_001",
"resolution": "latest_valid_authoritative"
}
],
"validation": {
"required_groups_satisfied": true,
"safe_to_generate": true
}
}16. Trace:记录每一步为什么保留或删除
rag.context.pack
├── candidate.normalize
├── scope.validate
├── evidence.hydrate
├── parent.expand
├── neighbor.expand
├── dedup.exact
├── dedup.near
├── conflict.detect
├── diversity.select
├── context.compress
├── token.allocate
├── context.order
├── citation.materialize
└── context.validate阶段属性示例:
{
"pack_id": "ctx_20260806_000123",
"input_candidates": 80,
"hydrated_candidates": 76,
"parent_expanded": 9,
"neighbor_expanded": 12,
"exact_duplicates_removed": 14,
"near_duplicates_removed": 8,
"version_duplicates_removed": 5,
"conflict_sets": 2,
"compressed_blocks": 7,
"selected_blocks": 11,
"budget_tokens": 9000,
"used_tokens": 7420,
"required_groups_satisfied": true,
"degraded": false
}16.1 不要把完整敏感 Context 放进 Span Attribute
推荐:
Span
→ ID、数量、版本、Hash、分数、状态
Artifact Store
→ 受控保存完整 Candidate、Context 和 Prompt17. 评测:不要只看最终答案
17.1 Packing 层指标
| 指标 | 含义 |
|---|---|
| Context Recall | Required Evidence 有多少进入 Context |
| Context Precision | Context 中有多少是真正有用证据 |
| Required Fact Coverage | 必需事实是否都有支持证据 |
| Redundancy Ratio | 重复 Token 占比 |
| Source Diversity | 独立来源覆盖 |
| Parent Expansion Gain | 扩展后新增的有效事实 |
| Boundary Recall | 边界问题是否被修复 |
| Conflict Detection Recall | 冲突是否被识别 |
| Anchor Resolution Rate | Citation Anchor 是否可解析 |
| Token Efficiency | 有效 Evidence Token / 总 Token |
| Position Sensitivity | 证据顺序改变造成的质量波动 |
17.2 端到端指标
Answer Correctness
Faithfulness
Citation Precision
Citation Recall
Conflict Explanation Accuracy
Refusal / Clarification Accuracy
P95 / P99 Latency
Token Cost
Compression Cost17.3 Ablation
至少比较:
Top-K Direct
vs
Dedup Only
vs
Parent + Dedup
vs
Parent + Dedup + MMR
vs
Full Packing也应分别关闭:
- Neighbor Expansion;
- Compression;
- Conflict Detection;
- Position-aware Ordering;
- Source Quota。
17.4 Cohort
Exact Fact
Definition
Multi-document
Multi-hop
Temporal
Conflict
Table / Numeric
Code
Long Document
Multilingual
Permission-sensitive
No-answer平均分不能掩盖 Temporal、Permission 和 Conflict Cohort 的回归。
18. Release Gate
Hard Gate
hard_gates:
unauthorized_context_rate:
max: 0
invalid_revision_rate:
max: 0
unresolved_required_anchor_rate:
max: 0
required_group_failure_rate:
max: 0
critical_conflict_miss_rate:
max: 0
token_overflow_rate:
max: 0Soft Gate
soft_gates:
context_recall:
max_drop: 0.005
context_precision:
max_drop: 0.01
redundancy_ratio:
max_increase: 0.02
token_efficiency:
max_drop: 0.02
p95_packing_latency_ms:
max_increase_ratio: 0.20
context_tokens:
max_increase_ratio: 0.10Canary 期间
观察:
- Pack Size 分布;
- Conflict Rate;
- Required Group Failure;
- Compression Fallback;
- Citation Validation;
- Position Sensitivity Bad Case;
- P95 / P99;
- Context Token Cost;
- Answer False Positive / False Refusal。
19. 常见反模式
反模式一:直接把 Top-K 拼接
结果是重复、冲突、越权和 Token 浪费。
反模式二:Parent 无条件替换 Child
Parent 太长,真正命中 Span 反而被埋没。
反模式三:只按 Embedding 相似度去重
容易把数值、否定或时间不同的证据误删。
反模式四:压缩后不保存 Source Map
答案有引用 Key,却无法回到原文。
反模式五:冲突只保留高分项
分数不是版本、权威或法律效力。
反模式六:所有问题使用相同 Token Budget
Exact ID 与 Multi-hop 的证据需求不同。
反模式七:只计算 Context Precision
过度裁剪可能 Precision 上升、Recall 下降,最终无法回答。
反模式八:只保存最终 Prompt
无法判断证据在哪个阶段被删除。
反模式九:Answer Cache 不绑定 Pack Hash
文档、权限或 Packing Policy 更新后仍复用旧答案。
反模式十:把长上下文窗口当作无界预算
成本、位置偏差、延迟和噪声仍会增加。
20. 分阶段落地路线
P0:可追溯的确定性 Packing
- Candidate Manifest;
- Scope / Revision 校验;
- Parent / Neighbor 基础扩展;
- Exact / Version Dedup;
- 显式 Token Budget;
- Required Evidence Groups;
- Citation Key 与 Source Span;
- Context Pack Manifest;
- Context Recall / Precision;
- Trace 与 Replay;
- Hard Gate。
验收标准:
任意一条答案都能回答:
模型当时看到了哪些证据,
哪些候选被删除,
为什么删除,
每个引用回到哪个 Source Span。P1:多样性、冲突与压缩
- Near Dedup;
- MMR;
- Source Quota;
- Query-aware Budget;
- Conflict Set;
- Extractive Compression;
- Position-aware Ordering;
- Pack Cache;
- Position Perturbation Evaluation;
- Canary Dashboard。
P2:自适应 Context Engineering
- 语义连续性 Neighbor Expansion;
- Learned Utility Model;
- Adaptive Compression;
- Claim-aware Packing;
- 多模态 Context Pack;
- Online Risk–Coverage 优化;
- Agentic Re-retrieval;
- Pack Quality Model;
- 自动根因归类。
21. 上线检查清单
- Candidate 是否有统一 Schema?
- 多路召回是否按 Evidence ID 合并?
- Hydration 是否固定 Source Revision 和 Content Hash?
- ACL、Tenant、状态和有效期是否在 Packing 前校验?
- Parent 扩展是否有 Token 上限?
- Neighbor 扩展是否禁止跨权限、文档和 Revision?
- 是否分别处理 Exact、Near、Version 和 Parent/Child Dedup?
- 否定词、数字、单位、时间和实体是否作为 Anchor?
- MMR 是否在权限和版本校验之后执行?
- 是否有 Source Quota?
- Required Evidence Group 是否先于可选候选?
- Token Budget 是否预留回答和安全余量?
- Token 计数是否使用目标模型 Tokenizer?
- 是否记录预算内被删除的候选和原因?
- 冲突是否形成结构化 Conflict Set?
- 压缩是否保留 Source Map?
- Abstractive Summary 是否仍绑定原始 Evidence?
- 关键证据是否做 Position Perturbation 测试?
- Citation Key 是否在 Packing 阶段生成?
- Citation 是否绑定 Source Span、Revision 和 Hash?
- 最终 Context 是否通过 Permission、Revision、Coverage 和 Anchor 校验?
- 是否保存 Context Pack Manifest?
- Answer Cache 是否包含 Pack Hash?
- Trace 是否覆盖每个选择与删除阶段?
- 完整敏感 Context 是否进入受控 Artifact Store,而不是 Span Attribute?
- 是否计算 Context Recall、Precision、Redundancy 和 Token Efficiency?
- 是否按 Temporal、Conflict、Multi-hop 和 Permission Cohort 报告?
- Hard Gate 是否阻止越权、无锚点和 Required Evidence 丢失?
- 是否有压缩、扩展和冲突处理的降级路径?
- Packing Policy 是否版本化并可回滚?
总结
Context Engineering 的目标不是把更多文本塞进模型,而是在有限预算内构造一份可以被证明“足够好”的证据包:
相关
→ 能回答当前 Query
充分
→ Required Facts 有完整证据
少冗余
→ 重复内容不占据预算
有多样性
→ 不被单一来源垄断
可解释冲突
→ 不静默隐藏版本和口径差异
可引用
→ 每个关键 Claim 回到 Source Span
可回放
→ Pack、版本、顺序和 Hash 都可重建
可治理
→ 权限、评测、缓存和发布门禁完整最重要的工程原则是:
检索决定哪些证据有机会被看到,Context Engineering 决定模型真正看到了什么。没有版本化 Context Pack、选择原因和 Citation Anchor,就无法可靠地区分检索失败、组装失败与生成失败。
参考资料
- Lost in the Middle: How Language Models Use Long Contexts
- The Use of MMR, Diversity-Based Reranking for Reordering Documents and Producing Summaries
- RECOMP: Improving Retrieval-Augmented LMs with Compression and Selective Augmentation
- LongLLMLingua: Accelerating and Enhancing LLMs in Long Context Scenarios via Prompt Compression
- LLMLingua-2: Data Distillation for Efficient and Faithful Task-Agnostic Prompt Compression
- LlamaIndex Auto Merging Retriever
- LlamaIndex Sentence Window Retrieval
- EXIT: Context-Aware Extractive Compression for Enhancing RAG
- AttnComp: Attention-Guided Adaptive Context Compression for RAG
- SCAR: Semantic Continuity-Aware Retrieval for Efficient Context Expansion in RAG
- SARA: Selective and Adaptive RAG with Context Compression
- Hybrid Search 生产实战
- Reranker 生产实战
- Citation Engineering 生产实战
- RAG 答案置信度生产实战
- RAG 可观测性生产实战
- RAG 评测生产实战
讨论
继续讨论这篇笔记
有问题、补充案例或不同观点,可以通过 GitHub Discussions 继续交流。