Chico Notes
LLM Wiki / RAG

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 作为前沿方向讨论;生产采用前仍需要在自己的数据、语言、模型和延迟预算上复现。

RAG Context Engineering 生产实战:候选召回、父子扩展、去重、MMR、Token Budget、冲突检测与引用锚定

图 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

它至少要保证:

  1. Required Evidence 不因扩展、去重、压缩或预算而丢失。
  2. Unauthorized、Stale、Invalid Evidence 在进入 Prompt 前被阻断。
  3. 同源重复内容不会挤占多来源证据。
  4. 冲突来源被明确标记,而不是静默选一个。
  5. 模型看到的每个 Context Block 都能回到稳定 Source Span。
  6. 同一个 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 流水线

Context Packing 生产流水线:候选归一化、扩展、去重、多样性、压缩、预算、排序与引用校验

图 2:Context Packing 应分阶段执行,每一步都输出结构化结果和移除原因,而不是在一个函数里完成不可解释的截断。

推荐把流水线拆成十个阶段:

阶段输入输出主要失败
Candidate Normalize多路召回结果统一候选结构ID 冲突、分数语义混乱
Scope ValidateCandidate + User Scope可访问候选越权、状态失效
HydrateChunk IDSource Span、Parent、版本数据缺失、Revision 不一致
Expand命中 ChildParent / Neighbor 候选无界扩展、重复
Dedup扩展候选去重候选错删互补证据
Conflict去重候选Conflict Set冲突未识别
Diversify候选 + Query多样候选相关性下降
Compress候选文本可引用精简证据事实或限定丢失
Budget / OrderToken 预算有序 Context BlocksRequired Evidence 被裁掉
ValidateContext Blocks可发布 PackAnchor、权限、覆盖失败

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_coherence

4.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

这类方法值得实验,但必须保持三个约束:

  1. 扩展不能跨 ACL 或 Revision。
  2. 需要记录为何扩展和为何停止。
  3. 评测必须同时看 Boundary Recall 与 Token Overhead。

5. 去重:Exact、Near、Version 与 Semantic Role

Context 去重与多样性选择:Exact、Near、Version Dedup 后进入 MMR 与来源配额

图 3:去重不是简单按文本相似度删候选,需要先区分完全重复、近重复、版本重复和同一 Parent 的结构重复。

5.1 Exact Dedup

优先使用稳定身份:

evidence_id
source_revision
source_span_id
content_hash

而不是只比较字符串。

相同 Source Span + 相同 Revision
→ 合并 Retrieval Channels

相同文本 + 不同来源
→ 不一定删除,可能是独立佐证

相同 Source + 不同 Revision
→ 进入 Version Conflict

5.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: true

6.4 Query-aware Diversity

不同问题需要不同多样性:

Query Type多样性需求
Exact ID低,优先精确证据
Definition低到中,权威来源优先
Comparison高,必须覆盖比较双方
Multi-hop高,但按 Hop 组织
Troubleshooting高,覆盖多个根因
Policy中,当前权威版本优先
Summarization高,覆盖不同章节和主题

7. 冲突检测:不要静默选择一个来源

Context 冲突治理与引用锚定:识别数值、版本、权威与状态冲突,再绑定可验证 Citation Anchor

图 4:冲突不是普通噪声。生产系统应保存 Conflict Set、选择规则和最终向用户展示的解释。

7.1 常见冲突类型

类型示例
Temporal2024 版与 2026 版政策不同
Numeric同一指标分别为 12.4% 和 13.1%
Definition“活跃用户”口径不同
Authority官方制度与个人笔记冲突
StatusDraft、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,000

8.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: 800

8.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 和 Citation

10.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 Context

11.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 Result

11.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_hash

12.2 Anchor 必须在 Packing 时生成

不要等模型回答后再通过相似度“猜引用”。

Packing 阶段应完成:

Context Block
→ Citation Key
→ Source Span
→ Revision
→ Rendered Text Hash

12.3 压缩后的 Anchor

如果使用 Extractive Compression:

compressed_span
→ 映射回一个或多个 original source spans

如果使用 Abstractive Compression:

summary block
→ 不能作为唯一 Citation
→ 必须附带支持它的原始 Evidence IDs

12.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 和 Prompt

17. 评测:不要只看最终答案

17.1 Packing 层指标

指标含义
Context RecallRequired Evidence 有多少进入 Context
Context PrecisionContext 中有多少是真正有用证据
Required Fact Coverage必需事实是否都有支持证据
Redundancy Ratio重复 Token 占比
Source Diversity独立来源覆盖
Parent Expansion Gain扩展后新增的有效事实
Boundary Recall边界问题是否被修复
Conflict Detection Recall冲突是否被识别
Anchor Resolution RateCitation 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 Cost

17.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: 0

Soft 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.10

Canary 期间

观察:

  • 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,就无法可靠地区分检索失败、组装失败与生成失败。

参考资料

讨论

继续讨论这篇笔记

有问题、补充案例或不同观点,可以通过 GitHub Discussions 继续交流。

On this page

一句话结论1. 为什么 Top-K 不能直接成为 Context1.1 长上下文不等于有效上下文1.2 Context 是证据产品,不是字符串2. 生产级 Context Packing 流水线3. 先统一 Candidate 与 Evidence 数据模型3.1 Candidate ID 与 Evidence ID 要分开3.2 Hydration 必须固定 Revision4. Parent–Child 与邻接扩展4.1 Small-to-Big 的基本原则4.2 Parent 扩展策略4.3 邻接窗口4.4 前沿方向:语义连续性扩展5. 去重:Exact、Near、Version 与 Semantic Role5.1 Exact Dedup5.2 Parent / Child Dedup5.3 Near Dedup5.4 Version Dedup5.5 Role-aware Dedup6. 多样性:MMR、来源配额与证据覆盖6.1 MMR 适合解决什么6.2 MMR 不能解决什么6.3 来源配额6.4 Query-aware Diversity7. 冲突检测:不要静默选择一个来源7.1 常见冲突类型7.2 Conflict Set7.3 冲突处理策略7.4 不要让压缩器“解决”冲突8. Token Budget:先分配,再选择8.1 总预算8.2 为什么要保留安全余量8.3 分区预算8.4 Required Evidence 优先8.5 价值密度9. 一个可解释的 Packing 算法9.1 数据结构9.2 分阶段选择9.3 稳定 Tie-break10. 上下文压缩:Extractive 优先,Abstractive 受控10.1 Extractive Compression10.2 Abstractive Compression10.3 Token-level Compression10.4 Emerging:自适应压缩11. 位置排序:避免把关键证据埋在中间11.1 Query-first Block11.2 按 Claim / Hop 分组11.3 冲突靠近展示11.4 Position Perturbation Test12. Citation Anchor:模型看到什么,就引用什么12.1 Citation Key 是响应内身份12.2 Anchor 必须在 Packing 时生成12.3 压缩后的 Anchor12.4 引用校验13. Context Pack Manifest14. MySQL 数据模型15. API 契约16. Trace:记录每一步为什么保留或删除16.1 不要把完整敏感 Context 放进 Span Attribute17. 评测:不要只看最终答案17.1 Packing 层指标17.2 端到端指标17.3 Ablation17.4 Cohort18. Release GateHard GateSoft GateCanary 期间19. 常见反模式反模式一:直接把 Top-K 拼接反模式二:Parent 无条件替换 Child反模式三:只按 Embedding 相似度去重反模式四:压缩后不保存 Source Map反模式五:冲突只保留高分项反模式六:所有问题使用相同 Token Budget反模式七:只计算 Context Precision反模式八:只保存最终 Prompt反模式九:Answer Cache 不绑定 Pack Hash反模式十:把长上下文窗口当作无界预算20. 分阶段落地路线P0:可追溯的确定性 PackingP1:多样性、冲突与压缩P2:自适应 Context Engineering21. 上线检查清单总结参考资料