400-100-5265

预约演示

让LLM自己翻文档

2026-06-20

RAG 这些年几乎成了企业知识库的默认答案。做文档问答、内部制度查询、客服知识库、技术手册检索,很多团队的第一反应都是:切片、向量化、入库、召回、重排、生成。

这条链路当然有价值。它把大模型从纯参数记忆里拉出来,让答案能够依赖外部知识。但真正落到企业文档场景里,很多问题也会很快暴露出来:明明文档里有答案,模型没找到;明明召回了相关片段,回答却漏掉关键条件;引用看起来像那么回事,用户点回去却很难验证上下文。

这些问题不完全是模型能力不够,也不完全是向量数据库不够好。更底层的矛盾在于:我们把原本完整的文档拆成了碎片,再指望模型从碎片里拼回语义。这个过程有点像把一本制度手册撕成纸条,再让一个同事根据几张纸条回答你完整规则。能答对一些问题,但稳定性很难让人放心。

一个更朴素的思路是:既然现在长上下文已经足够长,为什么不让 LLM 像人一样先看目录,再决定打开哪些文件精读?也就是把知识库做成一个可导航的文件系统,让模型从目录索引中选择文件路径,再基于完整原文生成答案。

这不是要在所有场景里替代 RAG,而是在一类很典型的企业知识库场景里,重新评估“碎片检索”是不是唯一合理的工程解。

一、RAG的问题藏在切片里

传统 RAG 的标准流程大致是这样:

流程图 - 让LLM自己翻文档

这条链路的问题,很多时候不是某一个组件坏了,而是整个范式有天然损耗。

语义被切断

文档切片看上去是一个工程实现细节,其实影响很大。

企业文档里的知识经常不是一句话能讲完的。比如:

  • 某项福利的适用对象在第一段;
  • 申请条件在第二段;
  • 特殊情况在附录;
  • 表格里的数字依赖前面的标题;
  • 某个例外条款引用了另一份制度。

一旦按固定 token 长度切片,文档原本的结构就会被破坏。哪怕加 overlap,也只是缓解,不是根治。

很多团队会反复调这些参数:

参数 常见做法 代价
chunk size 从 300 调到 800,再调到 1200 大切片召回更粗,小切片上下文更碎
overlap 50、100、200 token 重叠 增加存储与召回冗余
topK 多召回几个片段 Prompt 更长,噪声也更多
rerank 引入重排序模型 成本和延迟上升

这些优化有用,但它们都在同一个前提下工作:文档已经被切开了。

如果问题恰好落在一个完整片段里,效果会不错;如果答案依赖跨段落、跨表格、跨文件关系,质量就开始摇摆。生产环境里最麻烦的往往就是这种“看起来差一点”的错误,它不是完全胡说,却漏掉了最关键的限定条件。

溯源不够自然

RAG 通常也会给引用来源,但很多引用对应的是切片 ID、段落片段或某个向量库里的记录。

这对系统来说足够,对用户来说不一定够。

用户真正想验证的是:

  • 这句话来自哪份文件?
  • 文件路径是什么?
  • 原文上下文是什么?
  • 这个答案有没有漏掉前后限制条件?
  • 多个来源之间有没有被模型强行拼接?

如果引用只是“chunk_1278”,那溯源体验其实很弱。即便前端把它包装成一个引用卡片,用户点进去看到的也可能只是一个被截断的段落。

在制度、合规、财务、产品手册这些场景里,答案错一次的成本可能比系统慢一点高得多。可验证性不是锦上添花,而是基础能力。

GraphRAG不是免费午餐

为了解决碎片化和跨文档关系问题,GraphRAG、知识图谱、实体关系抽取这些方案被重新推到台前。

它们确实能解决一部分问题,尤其是多跳推理、实体关系密集、跨文档关联复杂的场景。但工程成本也很实在:

  • 要做实体抽取;
  • 要做关系建模;
  • 要处理同义词、别名、歧义;
  • 要维护图谱更新;
  • 要评估图上的召回质量;
  • 还要把图检索结果重新转成 LLM 能理解的上下文。

很多企业内部知识库的高频问题,其实没那么复杂。用户问的是“年假怎么算”“报销标准是什么”“某个 API 参数怎么填”“某个流程谁审批”。这类问题更依赖精准定位和完整原文理解,而不是复杂图推理。

所以这里有一个很现实的权衡:如果 80% 的问题是文件级定位和条款理解,用一套高成本图谱系统去覆盖 20% 甚至更低比例的复杂问题,未必划算。

二、让模型先看目录

换一个角度看,企业知识库并不一定要从“片段”开始建模。

更自然的方式是从文件系统开始:

流程图 - 让LLM自己翻文档

这里的核心变化是:索引只负责导航,答案必须来自完整文件。

也就是说,文件摘要不是答案来源,只是帮助模型判断“应该打开哪份文件”。真正生成答案时,系统读取对应的 Markdown 原文,让模型在完整上下文里作答。

这和传统 RAG 的差异很关键。

维度 传统 RAG 文件索引方案
检索单位 文本切片 文件路径与摘要
答案来源 召回片段 完整原文文件
模型角色 被动接收上下文 主动选择要读的文件
溯源方式 chunk、片段、段落 文件路径,可直接打开
基础设施 向量库、检索服务、重排模型 文件系统、索引文件、LLM
主要风险 语义断裂、召回噪声 文档治理质量、索引摘要质量

这套方案不是把检索取消了,而是把检索从“语义向量匹配”改成“目录导航 文件精读”。

人查文档也是这么干的。通常不会先把所有文档切成 500 字片段再找相似内容,而是先看目录、标题、摘要,判断哪几份文件可能相关,然后打开原文看细节。

现在的问题只是:LLM 有没有能力做这个动作?在长上下文模型越来越成熟之后,答案开始变得务实起来。

三、索引文件是关键资产

这个方案里最重要的中间产物,不是向量库,而是一份模型能读懂、人也能读懂的索引文件。

一种简单格式可以是:

# /制度/考勤

- 年假规定.md | 员工年假适用条件、年假天数计算、申请与审批流程
- 加班调休规定.md | 加班认定标准、调休申请方式、补偿规则

# /制度/报销

- 差旅报销标准.md | 交通、住宿、餐补标准及特殊城市规则
- 发票管理规范.md | 发票类型、开票要求、报销审核注意事项

# /产品/API

- 用户认证接口.md | 登录、刷新 token、权限校验及错误码说明
- 订单查询接口.md | 订单查询参数、返回字段、分页与状态码说明

这个格式很土,但工程上很舒服。

它有几个好处:

  1. 人类可读出问题时可以直接打开看,不需要进向量库查 embedding。
  2. 模型友好路径、文件名、摘要都有明确结构,LLM 很容易输出候选路径。
  3. 可增量更新新增或修改文件时,只需要重新生成对应文件摘要,再更新索引条目。
  4. 上下文开销可控 把公共路径提取成标题,比每行写完整路径更省 token。

如果使用 256K 上下文模型,把其中一部分空间用于加载索引,容纳几百到上千个文件的路径和摘要并不夸张。尤其是经过治理后的高价值文档集,通常不会无限大。

这里要克制一点:不要把所有历史文件、聊天记录、扫描件、废弃版本都塞进来。知识库不是垃圾桶。模型再强,也不能替组织做信息治理。

四、文件粒度怎么定

文件粒度是这个方案成败的分水岭。

如果一个文件太大,比如一份 300 页制度汇编,模型即使打开了,也会浪费大量上下文,还容易在文件内部迷路。

如果文件太小,比如每个小节都拆成一个文件,索引数量会膨胀,文件之间的上下文关系又会被人为打散,最后重新走回 RAG 的老路。

比较合理的原则是:一个文件承载一个可独立引用的知识单元。

例如:

  • 一份“年假规定”可以是一个文件;
  • 一份“差旅报销标准”可以是一个文件;
  • 一个“订单查询 API”可以是一个文件;
  • 一个“部署手册”如果包含安装、升级、回滚、故障处理,可能需要拆成多个文件。

可以粗略用这几个标准判断:

判断项 建议
文件是否能独立回答一类问题 能,适合保留为一个文件
文件内部是否包含多个明显主题 拆分
文件是否依赖大量前置上下文 合并或补充背景说明
文件是否超过模型可舒适阅读范围 拆分
文件是否只是一个孤立小段 合并到相邻主题

很多团队做到这里会卡住,因为文档治理看起来不像“AI 项目”,更像苦活。但这一步绕不过去。未治理的文档堆,不管接 RAG、GraphRAG 还是长上下文,最后都会把脏数据的问题暴露出来。

五、查询链路可以很轻

工程实现上,这套链路可以保持得很薄。

一次查询可以分成两个阶段。

第一阶段,让模型读索引,选择文件:

你是企业知识库助手。
下面是一份文档索引,每行包含文件路径和摘要。
请根据用户问题,选择最可能相关的 1-5 个文件路径。
只返回 JSON 数组,不要回答问题。

用户问题:
员工入职不满一年,年假怎么计算?

文档索引:
...

模型返回:

[
  "/制度/考勤/年假规定.md",
  "/制度/考勤/员工入离职假期规则.md"
]

第二阶段,系统读取这些文件原文,再让模型回答:

请只基于以下原文回答用户问题。
如果原文没有依据,请明确说明无法从文档确认。
回答中必须列出引用文件路径。

用户问题:
员工入职不满一年,年假怎么计算?

引用文档:
[文件路径] /制度/考勤/年假规定.md
[文件内容]
...

[文件路径] /制度/考勤/员工入离职假期规则.md
[文件内容]
...

这条链路里,应用层只需要做几件事:

  • 读取索引文件;
  • 调用 LLM 选择路径;
  • 校验路径是否合法;
  • 读取 Markdown 原文;
  • 再调用 LLM 生成答案;
  • 返回答案和文件路径引用。

一个最小示意代码大概是这样:

# 示意代码:省略具体 LLM SDK 初始化,只展示核心流程
from pathlib import Path
import json

DOC_ROOT = Path("./knowledge_base")
INDEX_FILE = Path("./index.md")

def read_index() -> str:
    return INDEX_FILE.read_text(encoding="utf-8")

def safe_read_doc(path: str) -> str:
    """
    防止模型返回越权路径,例如 ../../secret.env
    """
    normalized = (DOC_ROOT / path.lstrip("/")).resolve()
    root = DOC_ROOT.resolve()

    if not str(normalized).startswith(str(root)):
        raise ValueError(f"非法路径: {path}")

    if not normalized.exists():
        raise FileNotFoundError(f"文件不存在: {path}")

    return normalized.read_text(encoding="utf-8")

def llm_call(prompt: str) -> str:
    """
    这里替换为实际的大模型 API 调用
    """
    raise NotImplementedError

def select_files(question: str) -> list[str]:
    index = read_index()

    prompt = f"""
你是文档导航助手。
请根据用户问题,从索引中选择最相关的 1-5 个文件路径。
只返回 JSON 数组,不要解释。

用户问题:
{question}

文档索引:
{index}
"""
    result = llm_call(prompt)
    return json.loads(result)

def answer_question(question: str) -> str:
    paths = select_files(question)

    docs = []
    for p in paths:
        content = safe_read_doc(p)
        docs.append(f"[文件路径] {p}\n[文件内容]\n{content}")

    prompt = f"""
请只基于给定文档回答问题。
如果文档中没有依据,请说明无法确认。
回答末尾列出引用文件路径。

用户问题:
{question}

文档:
{chr(10).join(docs)}
"""
    return llm_call(prompt)

这里有两个细节很重要。

第一,必须做路径校验。模型输出的路径不能直接信任,否则很容易引入越权读取风险。

第二,回答阶段要约束模型“只基于原文”。这不能完全消灭幻觉,但可以把错误空间压小。再配合文件路径引用,用户至少能回到原文核验。

六、不同规模下的策略

这套方案不是只能用于几百份文件。随着知识库规模变大,可以分阶段扩展。

小规模:全量索引

如果文档在几十到几百份,直接把完整索引塞进上下文是最省心的。

适合:

  • 部门制度库;
  • 产品帮助中心;
  • 内部技术手册;
  • 项目交付文档。

优点是链路短、稳定、容易调试。缺点是索引规模继续增长后,上下文成本会上升。

中规模:分块索引

如果文档达到几千份,可以按主题拆成多个索引文件:

/index
  制度索引.md
  产品索引.md
  技术索引.md
  客服索引.md

查询时先让模型选择索引分区,再加载对应分区的详细索引。

流程图 - 让LLM自己翻文档

这相当于两级导航,仍然保持“索引用于导航,原文用于回答”的原则。

大规模:向量作为辅助定位

当文档规模很大,或者用户问题经常跨主题跳跃,可以引入向量检索。但这里的定位和传统 RAG 不一样。

向量检索只返回:

  • 文件路径;
  • 文件摘要;
  • 可选的命中片段位置。

它不直接把切片作为答案来源喂给模型。

更合理的做法是:

流程图 - 让LLM自己翻文档

这样向量库变成了“导航工具”,不是“答案材料仓库”。

这是一个很重要的工程取舍:保留向量检索的召回能力,但不让模型基于断裂片段直接下结论。成本比纯文件索引高一些,但在大规模知识库里更稳。

七、成本不是只看Token

有人会担心:每次加载索引,会不会很贵?

这个问题要算总账。

传统 RAG 的成本不只是推理 token,还包括:

  • 文档切片任务;
  • embedding 生成;
  • 向量数据库;
  • 检索服务;
  • rerank 模型;
  • 索引更新流程;
  • 召回质量评估;
  • 线上调参和问题排查。

文件索引方案的成本主要是:

  • 文档治理;
  • 文件摘要生成;
  • 索引加载 token;
  • 两次 LLM 调用;
  • 原文读取与回答 token。

如果知识库规模不大,文件索引方案的基础设施成本会低很多。纯文件系统加一个轻量服务就能跑起来。索引文件可能只有几百 KB,Markdown 原文几十 MB,这种量级完全没必要上来就引入数据库。

但它也不是免费方案。

它对长上下文模型依赖更强。模型如果在长索引里导航能力差,选错文件,后面回答也会错。它还依赖摘要质量,如果摘要过短或过泛,模型很难判断文件相关性。

这里的权衡可以说清楚:

方案 更适合的情况 主要代价
传统 RAG 海量内容、弱结构文本、召回优先 语义碎片化、链路复杂
文件索引 治理后文档、强溯源、文件级知识 依赖文档治理和长上下文
GraphRAG 多实体、多关系、多跳推理 建模成本高、维护复杂
混合方案 大规模企业知识库 架构复杂度上升

所以结论不是“彻底抛弃 RAG”。更准确的判断是:在经过治理的企业文档问答场景里,文件索引 原文精读可能比传统切片 RAG 更直接,也更容易解释。

八、文档治理是前置条件

这个方案有一个不太讨喜但很真实的前提:文档要先治理。

最低限度要做几件事:

  1. 筛选有效文档过期制度、重复版本、临时草稿,不要直接进入知识库。
  2. 统一格式尽量转换成 Markdown。PDF、Word、网页都可以保留原始副本,但检索层最好使用统一文本格式。
  3. 按知识单元拆分太大的文件拆开,太碎的内容合并。
  4. 补充标题和元信息文件名要能表达主题,路径要体现分类。
  5. 人工抽查摘要 摘要不必写得很长,但要覆盖文件的关键范围。

文档治理不是这个方案额外发明出来的负担。只要做严肃知识库,迟早都要面对这件事。区别只是传统 RAG 往往把这个问题藏在切片和 embedding 后面,等线上效果不稳定时才暴露出来。

比较务实的启动方式,是先拿几十份高频文档做试点。不要一开始就治理全公司文档。先验证这条链路是否能在核心问题上稳定回答,再决定是否扩展。

九、一个可落地的试点路径

如果要在团队里试一下,可以按三步走。

第一步,选一批高价值文档。

数量不用多,30 到 100 份就够。最好选择问题边界清晰、用户经常查询、对溯源有要求的文档,比如制度、手册、API 文档、运维 SOP。

第二步,生成索引文件。

把文档统一成 Markdown,按目录组织。用小模型或大模型为每个文件生成一句摘要,再合并成层级索引。

摘要建议控制在一行,不要写成小作文。索引是导航,不是全文压缩。

第三步,做双阶段问答。

先让模型从索引选文件,再读取完整原文回答。记录这些指标:

  • 文件选择是否准确;
  • 回答是否遗漏关键条件;
  • 引用路径是否可验证;
  • 与传统 RAG 的答案差异;
  • 用户是否能快速核验答案。

如果实验里发现模型经常选错文件,优先检查摘要和目录结构,而不是马上上复杂检索系统。很多时候问题出在文件命名含糊、摘要过泛、同类文档边界不清。

如果用户材料里确实有实验代码、评测数据或 GitHub 仓库,建议把它放在文末,读者会更容易复现。但没有链接时,不要硬写“见文末仓库”。技术文章里这种承诺一旦落空,很伤信任。

十、边界要讲清楚

文件索引方案适合这些场景:

  • 企业内部制度库;
  • 政策条款问答;
  • 产品手册和帮助中心;
  • 技术文档查询;
  • 运维 SOP;
  • 对引用可验证性要求高的知识库。

它不适合直接套到这些场景:

  • 未清洗的杂乱文件堆;
  • 百亿级公开网页搜索;
  • 实时流式数据分析;
  • 高度依赖复杂实体关系推理的领域;
  • 文件本身特别长且难以拆分的材料;
  • 用户问题需要综合大量弱相关证据的开放式研究场景。

还有一个容易被忽略的点:文件级原文并不等于绝对正确。文档过期、互相冲突、缺少版本控制,模型照样会给出有问题的答案。只不过这种方案更容易把问题暴露出来,因为用户可以直接看到引用文件。

这在工程上反而是好事。系统能不能稳定,不只取决于模型,也取决于知识资产本身有没有被管理起来。

十一、RAG会留下来,但位置会变化

RAG 不会消失。向量检索、重排、图谱、多路召回都有自己的适用场景。

但在长上下文越来越可用之后,企业知识库的默认设计可以更灵活一些。过去我们不得不把文档切碎,因为模型装不下、读不动。现在至少在中小规模治理文档里,可以让模型先看目录,再打开原文。

这带来的变化很直接:

  • 检索结果从片段变成文件;
  • 摘要从答案材料变成导航线索;
  • 引用从 chunk ID 变成文件路径;
  • 向量库从必选基础设施变成可选辅助能力;
  • 文档治理从后期补救变成前置资产建设。

如果手头正好有一批重要文档要做 AI 问答,不妨先别急着搭完整 RAG 流水线。挑几十份文档,整理成 Markdown,生成一份索引,让模型试着自己翻文件。

你可能会发现,很多答案并不需要复杂召回链路。它们一直在原文里,只是过去我们给模型看的东西太碎了。[DONE]

创作声明:本内容包含AI辅助创作,观点仅供参考。