Metadata设计
2009 字约 7 分钟
domain/aiai/rag
2026-07-24
Metadata 是 RAG 检索精度的"秘密武器"。它为每个 chunk 提供结构化的标签信息,让检索从"大海捞针"变成"精准定位"。好的 Metadata 设计能支持过滤、排序、溯源和权限控制,是生产级 RAG 与 Demo 级 RAG 的分水岭。
一句话解释
为每个 chunk 附加结构化的描述信息(来源、时间、层级、权限、分类),在检索时通过过滤和排序大幅提升检索精度,同时支持来源追溯和权限控制。
核心问题
为什么 Metadata 如此重要?
- 检索噪声:十万级知识库中,不加过滤的向量检索必然混入大量无关结果
- 权限安全:多租户、多角色场景下,用户不能看到不属于自己的知识
- 时效性:过期文档、废止版本的 chunk 不应该被检索到
- 可追溯性:答案必须能追溯到具体文档和段落,这在金融、医疗、法律场景是合规要求
六大 Metadata 类别
| 类别 | 核心字段 | 用途 |
|---|---|---|
| 文档标识类 | doc_id, source_url, file_name, content_hash | chunk 来源追溯、批量更新、错答回溯 |
| 结构信息类 | h1_title, h2_title, title_path, page_number, chunk_index | 生成精确引用路径、相邻 chunk 补全 |
| 时间版本类 | created_at, updated_at, effective_date, expiration_date, version | 过滤过期规则、版本治理、时效性保证 |
| 权限控制类 | access_roles, access_departments, tenant_id, sensitivity_level | 行级别权限过滤,防止越权访问 |
| 业务分类类 | category, subcategory, product_line, domain, language | 按业务线、产品、服务阶段缩小检索范围 |
| 技术追踪类 | chunk_id, status, doc_hash | 去重、运维定位、文档健康度监控 |
Metadata Schema 设计模板
完整示例
{
"content": "课程开始前 24 小时以上,学员可申请免费改期...",
"metadata": {
"source": {
"doc_id": "doc_edu_policy_20260401_001",
"file_name": "课程预约与改期规则.md",
"source_url": "/knowledge/course/reschedule-policy",
"doc_type": "markdown",
"content_hash": "sha256:abc123..."
},
"structure": {
"h1_title": "课程管理政策",
"h2_title": "改期规则",
"title_path": "课程管理政策 > 改期规则 > 免费改期条件",
"page_number": 2,
"chunk_index": 3,
"total_chunks": 12
},
"temporal": {
"created_at": "2026-04-01T09:00:00Z",
"updated_at": "2026-05-10T18:30:00Z",
"effective_date": "2026-04-01T00:00:00Z",
"expiration_date": null,
"version": "2.1"
},
"access_control": {
"tenant_id": "company_a",
"access_roles": ["student", "teaching_assistant", "academic_admin"],
"sensitivity_level": "public"
},
"business": {
"category": "课程管理",
"subcategory": "改期与退费",
"domain": "education",
"language": "zh",
"status": "active"
},
"search_enhancement": {
"keywords": ["改期", "免费", "24小时", "课程预约"],
"summary": "课程开始前24小时以上可免费改期"
}
}
}字段设计原则
- 时间字段统一使用 ISO 8601 格式,确保跨系统可解析
title_path应单独进入 sparse index,设置高权重——标题命中是强信号keywords可用于增强 sparse retrieval,弥补正文字数过少的 chunkstatus默认为 active,deprecated 只在用户明确询问历史版本时召回sensitivity_level分级为 public / internal / confidential / restricted
Metadata 过滤策略
三种核心过滤模式
| 过滤类型 | 触发条件 | 示例 |
|---|---|---|
| 硬过滤(Pre-filter) | 检索前收窄候选范围 | 权限过滤、租户隔离、status=active |
| 软过滤(Post-filter) | 检索后对结果再筛选 | 来源去重、时间排序、多样性过滤 |
| 动态过滤 | 根据查询意图动态选择 | 用户问"最新政策"→ 按 effective_date 降序 |
时间范围过滤
默认过滤条件:
status == "active"
AND effective_date <= NOW()
AND (expiration_date IS NULL OR expiration_date > NOW())用户明确询问历史版本时,可放宽为 status == "deprecated" AND effective_date <= 历史时间点。
权限过滤(多租户)
企业 RAG 中,权限过滤必须在检索层完成,而非召回后交给模型"自觉忽略"。
tenant_id作为第一道硬过滤,确保物理或逻辑隔离access_roles数组支持多角色叠加,使用array_contains(security_group, "sales")过滤- 权限更新通过 upsert 实现,Bitmap 索引保证查询效率
来源去重(Source Cap)
同一来源(doc_id)在最终结果中最多保留 2-3 条,避免同源 chunk 挤占上下文。这是最简单的多样性保障。
Metadata 在 Hybrid Search 中的角色
生产级 RAG 的检索层是一条排序流水线,而非简单的向量 top-k:
Query Understanding
→ Metadata Filter(先收紧可访问范围)
→ Sparse Retrieval + Dense Retrieval(并行召回)
→ Hybrid Fusion(RRF 融合)
→ Candidate Pool(构建候选集)
→ Reranker(精排)
→ Diversity & Policy Filters(去重、权限、版本)
→ Context Packing(组装上下文)三种检索方式的分工
| 检索方式 | 擅长 | 不擅长 |
|---|---|---|
| Sparse / BM25 | 错误码、SKU、条款号、专有名词、原文短语 | 同义改写、概念性问题 |
| Dense / 向量 | 同义表达、意图匹配、概念相关 | 精确符号、罕见名词、OOV |
| Metadata 过滤 | 权限、租户、版本、语言、时间、文档类型 | 判断内容是否真正回答问题 |
融合算法:RRF(Reciprocal Rank Fusion)
score(doc) = Σ (weight_i / (k + rank_i(doc)))同一 chunk 在 sparse 和 dense 中排名都靠前时,融合得分自然更高。k 为平滑常数,通常取 60。
权重按查询类型动态调整:
| 查询类型 | sparse 权重 | dense 权重 |
|---|---|---|
| 错误码 / SKU / 条款号 | 高 | 中 |
| FAQ 自然语言问题 | 中 | 高 |
| 概念解释 / 原理总结 | 中 | 高 |
| 多条件政策问题 | 中高 | 中高 |
元数据丰富度 vs 嵌入质量的平衡
这是一个关键的工程权衡。
核心原则:元数据一般不参与向量化
| 做法 | 风险 | 推荐方案 |
|---|---|---|
| 将标题、作者、时间等元数据拼接进 chunk 后统一 embedding | 向量表示被非语义信息污染,主题焦点模糊 | chunk 只保留正文;元数据作为结构化字段存储 |
| chunk 过长(>1024 tokens) | embedding 把多个主题混在一起,语义中心弱化 | 按语义边界切分,chunk 长度 256-512 tokens 起步 |
将 title_path 混入 dense vector | 结构信息在语义空间中无稳定意义 | title_path 单独进 sparse index,设置高权重 |
| 同一文档多版本同时入库 | 重复内容占据向量空间,检索时相互干扰 | 通过 status 和 version 硬过滤,旧版默认不召回 |
最佳实践
- 语义内聚:chunk 内容应围绕单一语义单元,避免跨主题
- 标题进 sparse,正文进 dense:利用各自检索器的优势,而非强行统一
- 上下文注入:在块文本前添加面包屑路径(如
[技术文档 > API 参考 > 认证接口]),使嵌入向量包含位置信息——这比把标题放进 metadata 然后忽略更有效 - 摘要增强:为 chunk 生成 LLM 摘要,单独建索引用于粗粒度召回
排序流水线成熟度模型
| 阶段 | 能力 | 产出 |
|---|---|---|
| 第 1 周 | 向量 top-k + 基础 metadata filter | 可用 demo |
| 第 2 周 | + sparse retrieval + RRF 融合 + source cap | 召回率提升 |
| 第 3 周 | + cross-encoder reranker + query rewrite | 精准率提升 |
| 第 4 周 | + query decomposition + diversity filter | 复杂问题覆盖 |
常见误区
- Metadata 只存不用:收集了丰富的 metadata 但检索时不做过滤,等于白费
- 将 metadata 文本混入 chunk 一起 embedding:稀释语义向量,降低检索精度
- 权限过滤放生成层:检索阶段不做权限过滤,靠 LLM "自觉"不泄露——这正是数据泄露的根源
- 不设计过期机制:过期文档即使不检索,也会占据向量空间和索引容量
- 忽视 source cap:同一文档的 10 个 chunk 挤占 top-10,让用户看不到其他来源的信息
进阶方向
- Hybrid Search:Metadata 过滤 + Sparse + Dense 三路协同
- Rerank重排序:在 Metadata 过滤后的候选池上做精排
- RAG评估与优化:评估 Metadata 过滤对检索和生成质量的提升
- 向量数据库:Bitmap 索引、Array 字段过滤等底层实现
- 动态 Metadata 生成:根据用户查询自动推断需要过滤的 metadata 维度