把 LLM 接到自己的数据上,听起来是最难的一步。但真正做过一遍后你会发现,这只是整条路上最先完成的一小段。我见过不少团队把文档灌进向量库,跑通一个问答 demo,然后宣布知识库助手已经完成。实际上,更准确的说法是:连接数据,只是那 21% 的解决方案。剩下的 79%,藏在数据质量、切分策略、检索效果、上下文组装、权限控制和评估迭代里。如果把这 79% 全部忽略,那么接完数据后的系统,通常会表现为答案不稳定、引错来源、超窗口、甚至产生看似合理但完全错误的回复。
你可以把这个“21%”当成一个经验判断,而不是精确统计。它想提醒的事情很简单:数据连接解决了“模型能不能看到数据”的问题,但没有解决“模型能不能正确使用数据”的问题。看到和用对之间,隔着好几个关键环节。就像给实习生发了一柜子资料,不等于他能做好分析;真正的价值,发生在检索、理解、判断、表达这些更靠后的步骤里。理解了这个前提,后面所有技术选型和调试优先级,都会变得清楚很多。
1. 为什么“接上数据”会让大部分团队产生 80% 的错觉
1.1 demo 跑通带来的虚假完成感
当你能上传 PDF,能从向量库检索到相关内容,能返回一段带引用的回答时,那种正反馈是非常强的。技术团队往往会在这个节点松懈,因为“已经看见了成果”。产品团队也会觉得核心功能已经搞定,剩下只是优化体验。这种虚假完成感,正是 21% 被误认为 80% 的心理机制。
从工程经验看,demo 用一条文档和一条 query 看起来正常,往往是因为问题边界太小。你的文档里只有一层意思,切分粒度不会明显影响结果;你的 query 和文档关键词高度重合,召回结果自然很准。一旦数据量增加到数万条,用户问题变成口语化、指代化、多跳式,问题就会集中暴露。
我通常建议团队在 demo 跑通后,立刻做两件事。第一,准备 20 到 30 条真实用户可能会问的问题,而不是自己设计的问题。第二,把检索到的中间结果全部打印出来,直接看召回片段到底相不相关。这两件事做完,虚假完成感通常就会消退。
1.2 “连接”和“可用”之间的距离
连接数据,在技术实现上通常是这样一条链路:加载文档 → 切分 → 做 embedding → 存入向量库 → 用户提问时检索相关片段 → 塞进 prompt → 交给 LLM 生成。在这个流程里,“连接”只完成了前几步和最后一步调用。中间的大量决策——切多长、用什么 embedding、检索多少条、怎么排序、上下文怎么组织、冲突怎么处理——都会直接影响最终结果。
如果把整个 RAG 流程看作一条链路,数据接入只占一个环节。更准确地说,连接数据只是把数据从“不可达”变成了“可见”。但“可见”不代表模型能正确理解,不代表模型能准确引用,也不代表模型在复杂场景下不产生幻觉。很多系统问题都发生在可见之后:数据被看到了,但看错了重点,或者不知道该怎么用。
所以我会把“连接”定义为第一步,而不是核心。它重要,但权重不该超过 21%。
1.3 21% 不是坏消息,而是定位
说“连接数据只是 21% 的解决方案”,不是为了否定数据连接的价值。恰恰相反,没有这 21%,后面所有环节都无法开始。它的意义在于:不要把起点当成终点,不要因为连接成功就停止投入。
把它当成项目的第一阶段,你会自然地分配精力:先跑通最小流程,再补数据治理,再调检索,再搭评估。如果把它当成项目的全部,你会陷入“为什么数据都接进去了,回答还是不对”的困惑。这个定位差异,决定了后续调试的方法论。
2. 数据切分与治理:21% 之外的第一块硬骨头
2.1 不是所有文档都适合直接进向量库
很多团队接数据时,把 Word、PDF、Markdown 一股脑切块 embedding,很快就会发现:表格被切碎,代码块被拆开,PDF 里的多栏文字错乱,同一主题被分散到多个 chunk。结果检索到的片段要么不完整,要么边界切在句子中间。这个问题不是 model 能力不行,而是输入数据本身就没准备好。
数据治理要做的,是把原始数据转换成适合模型检索的形态。这包括:清洗掉页眉页脚、目录、无效空格;统一文档格式;对表格、列表、代码块做结构化处理;对长文档保留标题层级。这一步不能省,因为它直接决定后续 embedding 和检索的质量。
在实操里,常见做法是先对文档类型做分类。规范类文档可以按章节切;问答类文档可以按条目切;表格类文档要转成 Markdown 表格或文本摘要;代码类文档要保留代码块边界。如果原始材料格式杂乱,宁可先用脚本清洗,也不要盲目喂进向量库。
| 文档类型 | 建议处理方式 | 常见问题 |
|---|---|---|
| 规范手册 | 按章节和标题层级切分 | 标题和正文脱节 |
| 常见问题 | 按问题条目切分 | 答案和问题被拆开 |
| 表格数据 | 转成 Markdown 表格或文本摘要 | 切块后行列错乱 |
| 代码示例 | 保留代码块边界 | 关键字被切断 |
| 网页抓取 | 去掉导航、广告、重复正文 | 大量无关文本进向量库 |
2.2 chunk 大小与重叠不是玄学,是检索质量的开关
chunk 的粒度影响两点:一是 embedding 的语义密度,二是上下文窗口的利用率。chunk 太小,单个片段信息量不足,模型缺少上下文;chunk 太大,向量表示容易被多个主题稀释,而且检索命中后可能把大量无关内容带进 prompt。
常见经验值是 300 到 800 token 左右,重叠 50 到 100 token。但这个值必须结合文档类型和实际检索效果调整。更通用的做法是先跑一批代表性 query,比较不同切分参数下的召回和回答质量,而不是直接套用某个社区的默认值。
我曾经遇到一个场景:技术文档里经常出现“这个变量”“上述函数”这类指代表达。如果 chunk 太小,模型只看到局部,完全不知道“这个”指的是什么。后来把切分窗口调大,同时保留章节路径,问题就明显缓解了。这说明切分策略必须服务于语义单位,而不是机械地按字数切。
2.3 版本更新与去重:数据是活的,不是一次性的
如果文档是静态的,一次接入就够了。但真实场景里,文档会更新、会被删除、会有多个版本同时存在。很多系统只做了导入,没有更新机制,导致模型总是引用旧版本。要长期使用,就需要给文档加元数据,例如来源、更新时间、版本号、权限范围。这样检索时才能按条件过滤,也可以在建索引时对已删除或过期文档做同步清理。
这里的思路和普通后端系统没有本质区别:先保证数据层可追溯,才能保证上层输出可解释。否则出现问题后,你甚至无法判断模型是从哪一个旧版本里找到的答案。更麻烦的是,用户问“为什么答案和最新规则不一致”时,你只能去翻数据源,而不是直接看检索日志。
我建议在数据库表结构设计时就预留几个字段:文档来源、上传时间、生效时间、版本号、权限组。这些字段在后续检索过滤和评估归因时非常有用。
3. 检索和上下文组装:从“查得到”到“答得对”
3.1 Top-K 只是把候选捞回来,排序才是真正的筛选
多数初版 RAG 实现只会做语义相似度检索,取 Top-K,然后直接塞进 prompt。但 embedding 的相似度不一定等于问题相关性。用户问的是“这个功能怎么配置”,候选片段可能包含大量同名但不同场景的段落,靠向量相似度很难区分。
常见的补强手段是加一层重排序。让一个专门的排序模型或更强的 LLM,对召回的候选片段再打分,再从结果里取最优几条。这样虽然多一次调用和更多耗时,但对回答准确率的提升非常明显。
如果不想引入额外模型,也可以用工程手段改善:给每个 chunk 加上标题、章节路径、摘要等元数据,检索时按元数据过滤候选范围;或者采用混合检索,把关键词匹配和向量召回的结果合并去重,再统一排序。每条路径都有成本,所以建议先用小样本评估再决定是否引入。
这里有一条很实用的经验:不要只看排序结果,还要看召回的候选里是否包含正确答案。如果正确答案根本没被召回,那无论重排序多强都无用。这个阶段要回到数据层和切分策略去解决问题。
3.2 上下文组装不是把片段拼起来,而是帮模型建立“信息秩序”
即使检索结果都正确,prompt 里片段之间的顺序、格式、引用方式也会影响回答。模型需要知道哪些片段是核心依据,哪些是补充说明,哪些可能与问题无关但被召回。
一种常见做法是给每个片段编号,并在 prompt 中明确要求模型“优先引用编号片段,如果片段没有足够信息,直接说不知道”。还可以在片段前标注来源、篇名、章节,让模型在回答时能引用出处。这些细节看着小,却能把“看似有个答案”提升到“答案有依据”。
我平时会用一个很简单的 prompt 结构:
你是一个知识库助手。请根据下面提供的资料回答问题。 资料片段: <doc id="1" source="产品手册-第3章">...</doc> <doc id="2" source="FAQ-常见问题#12">...</doc> 回答要求: 1. 优先引用编号片段作为依据。 2. 如果片段之间存在矛盾,请指出矛盾并列出各自来源。 3. 如果资料中没有足够信息,直接回答“当前资料不足”,不要编造。这样做的价值是:让模型在生成前就知道自己有哪些可用信息、信息边界在哪里。很多幻觉问题,其实能在上下文组装阶段就提前规避一部分。
3.3 冲突信息与幻觉:数据越多,越要处理“不确定”
当多个片段同时存在,而且彼此矛盾时,模型最容易犯错。很多情况下,模型不会主动告诉你数据冲突,而是选择其中一个片段的内容生成回答,或者把冲突信息融合成一个看似正确的答案。要处理这个问题,可以在 prompt 里加入“如果多个片段存在矛盾,请指出并列出各自来源”。也可以通过后处理规则,在模型回答后检查引用来源是否真的支持结论。
这些内容属于“如何用数据”的范畴,距离 21% 的数据连接已经有明显距离,但恰恰是决定用户是否信任系统的关键。用户不会因为你接入了数据就满意,他们只会因为每次回答都准确、可追溯、可验证而信任系统。
4. 评估体系才是那 79% 里的中枢
4.1 没有评估,就无法判断剩下 79% 到底做完没有
很多团队在数据接入和检索优化之后,面临一个尴尬:系统看起来能用,但不确定它“够好了”。要判断优化方向,就要建立评估集和评估指标。
建议先准备 50 到 100 条有代表性的真实问题,覆盖常规回答、边界情况、跨章节问题、找不到答案、有明显干扰信息等。然后定义几个维度:正确性、完整性、引用相关性、拒绝率(不知道答案时是否如实说)、超时率。不一定要做成多复杂的评分系统,哪怕先用人工标注打分,也能帮你定位问题出在哪一层。
| 评估维度 | 说明 | 可能的问题来源 |
|---|---|---|
| 正确性 | 回答的事实是否正确 | 检索、生成、数据源 |
| 完整性 | 是否漏掉了关键信息点 | 切分、检索 Top-K 不足 |
| 引用相关性 | 回答是否真的基于给出的片段 | Prompt 指令、生成层 |
| 拒绝率 | 不知道时是否如实回答 | Prompt、模型能力 |
| 超时率 | 响应是否在预期时间内 | 上下文长度、重排序、模型调用 |
4.2 从评估结果回溯到问题层
如果评估结果显示多数错误是“答案与检索到的内容不一致”,问题大概率在生成层,需要改 prompt 或后处理。如果错误是“检索到的内容本身不相关”,问题在检索层或 embedding 层。如果问题是“检索到的内容相关但缺失关键信息”,问题可能在切分策略或数据完整性。
这就是一个可复用的排查框架:先看输出,再判断归因到数据、切分、检索、上下文、生成哪一层。这个框架比盲目调参数更有效。
举个例子:某次评估里,系统对于“退款政策是什么”的回答总是只提到网页抓取到的摘要,没有提到原始 PDF 里的完整政策。后来检查发现,PDF 的表格被切碎了,退款比例和条件被分到不同 chunk。问题不在生成层,也不在检索层,而在数据切分。没有评估,这类问题可能要等用户投诉才会暴露。
4.3 把评估变成常规动作,而不是上线前的一次性检查
数据更新、embedding 模型升级、prompt 调整都会让系统行为发生变化。建议在每次调整后跑一遍评估集,保留对比记录。如果评估集足够稳定,还可以在 CI 流程中加入回归检查。这样系统在迭代过程中不会出现“改好一个 case,坏掉一片 case”的情况。
评估体系不会直接提升效果,但它让其他 79% 的优化工作有了方向,所以它是这套解决方案里的中枢。没有评估,你只能靠感觉判断“好像变好了”;有了评估,你才能说“这个参数提升了 3 个百分点的正确性”。
5. 从单点实验到工程化:编排框架、MCP 与 Agent 的定位
5.1 为什么单点跑通不等于能长期使用
单点实验通常是在脚本或 Notebook 里完成的。你写了加载、切分、检索、生成,输入一个 query,得到输出。但真实产品还需要服务化接口、日志、监控、重试、限流、权限控制、并发管理。这些都不属于“连接数据”本身,而是工程化的一部分。
从实践看,如果系统只是内部工具、数据量小、用户少,脚本方案也可以接受。但如果要面向团队或外部用户,就需要引入更完整的服务框架。这也是为什么现在很多项目会使用 LLM 编排框架:它们不只解决数据连接,还解决了多步流程、工具调用、记忆管理、权限校验和可观测性。
5.2 编排框架解决的是“流程控制”,不是“数据连接”
LangChain、LlamaIndex、Dify、FastGPT 这类工具的核心价值,是把“数据加载 → 切分 → 检索 → 生成 → 工具调用”这个过程变成可配置、可复用、可观测的流程。你不需要自己处理每个环节的细节,但必须理解每个环节的语义。
不过框架也带来新的问题:版本更新快、抽象层次高、调试时不容易看清底层发生了什么。所以更稳妥的方式是:先用最小代码量跑通,再渐进式引入框架。如果一开始就套大量高级抽象,遇到问题反而不好排查。
我自己的习惯是:第一版尽量少用框架,让数据链路清晰可见;当问题稳定后,再引入框架来统一管理流程。这样既能享受框架的工程能力,又不至于被框架的抽象挡住视线。
5.3 MCP 和 Agent:让数据成为可被主动调用的资源
MCP 的意义在于给模型和外部工具之间定了一个标准接口。模型不再需要针对每个数据源写独立适配器,而是通过统一协议访问工具、文件、数据库、API 等资源。这进一步降低了“连接”的技术成本,也再次带出那个判断:连接本身正在变得越来越便宜,真正值钱的是如何组织、选择和校验数据。
Agent 场景也一样。当模型可以主动调用工具时,数据不是预先塞进 prompt,而是在需要时通过工具获取。这一下把上下文长度、实时性、数据范围的问题都放大了。比如一个 Agent 需要先查订单,再查库存,再决定回复,每一步的中间结果都要可控、可追踪。没有权限校验和数据质量保障,Agent 越快,越容易把错误放大。
所以,把 LLM 连接到数据只是开始;当这个连接变成可被模型主动调用、动态选择的资源时,工程复杂度会更高,也更需要清晰的权限边界和评估反馈。
5.4 选型时先问三个问题
面对编排框架和 Agent 工具时,我建议先问三个问题:一是你的流程是否真的有多个步骤需要编排?二是每一步之间是否需要传递状态?三是你是否需要完整的日志和权限体系?如果答案都是“是”,那引入框架是合理的。如果只是简单问答,不一定要上重型框架。
这个判断逻辑,和 21% 的思路一脉相承:不要为了一个只占 21% 的问题,搭建一个覆盖 200% 的方案。先把核心痛点找准确,再决定投入多少工程成本。
6. 落地时的排查链路和适用边界
6.1 一套可复用的排查链路
如果系统已经上线,但回答质量不稳定,不要一上来就调 prompt。按下面的顺序排查:
- 看现象:错误是答案错误、引用错误、拒答错误,还是超时、无响应?
- 看输入:用户 query 是否被正确解析,是否有噪音或指代不清?
- 看数据:候选文档是否最新、是否完整、是否被错误切分?
- 看检索:召回的 Top-K 是否相关,相关片段是否排在前面?
- 看上下文:最终进入 prompt 的片段是否完整,是否发生了截断或冲突?
- 看生成:prompt 指令是否明确,模型是否有足够信息,有没有被要求输出没有依据的内容?
每个环节都有对应的中间产物:数据源列表、切分结果、embedding 向量、检索结果、prompt 内容、生成文本。把这些中间日志打出来,问题就很难滑走。我见过不少“模型回答错误”的 case,最后定位到是上游把日期字段格式弄错了,这种问题光调 prompt 永远解决不了。
6.2 什么情况下 21% 已经足够
也有一些场景,数据连接真的占了大头。比如问题非常结构化、文档非常简单、用户 query 与文档关键词高度重合、模型只做摘要或抽取、不要求实时更新。这种时候,一个简单的数据接入加上默认参数就可能够用。
判断依据可以总结成三个问题:数据是否稳定?用户问题是否规范?答案是否允许模糊?如果三个答案都偏向“稳定、规范、允许模糊”,就可以先交付,不必过度工程化。
例如,一个内部系统的操作手册,用户通常会问“某按钮在哪”“某参数怎么填”,这类问题关键词集中,检索相对容易。这时候把数据接好、切分合理,效果就可能已经接近可用。
6.3 不适用和需要注意的边界
相反,如果数据更新频繁、用户问题发散、答案必须可验证,那就必须把重心从连接挪到数据治理、检索优化、评估和权限上。只把数据连进去远远不够。
另外,也要注意成本和延迟。重排序、长上下文、多轮 Agent 调用都会增加成本和耗时。每个优化方案都要问一句:它带来的效果提升,是否值得增加的时间与费用?这个权衡没有统一答案,但应该在 79% 的投入过程中反复校验。
最后提醒一点:不要把“连接数据”这项工作做成了“为连接而连接”。如果你的数据根本不需要被模型访问,或者数据质量差到会误导模型,那还不如不接。连接之前,先确认数据值不值得接、能不能被理解、更新机制是否可持续。这比急着做大而全的知识库更重要。
回到开头那个被反复提到的 21%:它不是一个精确的数字,而是一个提醒。把 LLM 连接到数据,是进入这个系统的最短路径,也是最容易让人误判进度的地方。真正有价值的,是在连接之后,建立一套让数据变得可治理、可检索、可验证、可迭代的机制。如果你现在正准备做这类系统,我建议你先跑通一个最小流程,然后用 50 条真实问题去做一轮评估,看看错误到底集中在数据层、检索层还是生成层。从那里开始补齐,会比反复调 prompt 更有用。