先把基线描述清楚。项目的形态是一个企业文档管理 + 自动知识图谱生成系统:文档入库后,由 LLM 抽取实体和关系,构建三元组图谱;问答时先在图谱上做路径检索,再把相关上下文拼进 prompt 生成答案。这是 RAG 的一个增强分支——相比纯向量检索,图谱的优势是可以回答「多跳」问题(A 和 B 之间隔着哪几层关系)。
但它的成本结构一开始就是错的。最初的 pipeline 是这样的:任何文档有任何变动,就把全库所有文档重新喂给 LLM 跑一遍三元组抽取。一次全量更新跑 20 小时,token 消耗按全库规模线性放大;更糟的是全量重跑会重新生成大量本来没变过的实体——它们被写回图谱时还会覆盖人工修正过的结果。问答端的答案分数(人工评测的百分制口径)长期停在 40+ 水平:召回的上下文里混着大量噪声段落,LLM 拿到的材料就是脏的,生成质量自然上不去。
复盘下来,问题分布是:约七成浪费在「不该生成的地方生成」,约两成在「生成了没人审」,约一成在「检索时把没用的也捞回来」。这个分布决定了优化优先级——先砍生成量,再补质量关,最后修检索。
第一个诱惑是换模型:觉得分数低、token 贵,是模型不够好。实测下来这个判断是错的。我们把图谱生成框架的生成逻辑拆开重写,模型一个没换。
原来的逻辑是「一篇文档进来,让 LLM 自由抽取所有实体和关系」。这意味着每篇文档都要把自己内部的实体先命名一遍、再两两判断关系——prompt 里没有任何先验知识,LLM 只能从零开始。改写后的逻辑分三步:
效果:单篇文档的图谱生成 token 消耗降到原来的零头量级(实测口径:单文档平均输入 + 输出 token 下降约一个数量级),而且实体命名混乱的问题同步减少——因为大部分实体是从已有库里挂过来的,不是新造的。这条经验值得记下来:图谱类任务里,LLM 最贵的用法是「让它凭空创造」,最便宜的用法是「让它在给定选项里做判断」。
这是 20 小时 → 30 分钟的最大贡献项。
全量重建的问题在于成本与实际变化量完全脱钩:今天只改了一篇文档里的一段描述,系统却让全库所有文档重新过一遍 LLM。增量更新的核心是把更新动作拆成三类,并各自限定影响域:
| 更新类型 | 触发场景 | 影响域(需要重算的范围) |
|---|---|---|
| 新增 | 新文档入库 | 只跑这篇新文档的实体对齐 + 关系抽取 |
| 更新 | 文档内容被修改 | 这篇文档 + 它在图谱里关联的邻居节点(检查关系是否失效) |
| 删除 | 文档被移除 | 删掉它专属的实体/关系,共享实体保留,删除前先做引用检查 |
这里有两个坑。第一,「更新」不能只重跑被改的文档——文档 A 改了,它和 B 的某条关系可能失效,B 没变但出边可能变脏,所以影响域必须沿图谱边走一跳(A 的邻居)做关系校验。第二,「删除」必须区分专属实体和共享实体:一个实体被多篇文档引用时,删一篇不能删实体本身,只能删掉这篇贡献的那条关系。做错这两点,增量更新跑两周就会大面积断边。
实测口径:在文档库总量稳定、日常变动约为总量个位数百分比的节奏下,一次日常更新的 LLM 调用量从「全库规模」降到「变动文档规模的两三倍」(含邻居校验),这是更新时间从 20 小时压进 30 分钟、token 消耗同步下降超过 90% 的主体来源。实测案例口径:日常增量更新
前两个手段把成本砍下来之后,暴露出一个更根本的问题:自动生成的图谱有相当比例的边是错的——错误关系、张冠李戴的实体、过宽的描述。在全量重建时代,错误被埋在几万个节点里,几乎没法修;在增量时代,每次更新产生的变更集很小,小到人可以直接看。
于是我们加了一道人工预览环节:单文件图谱生成完成后,不直接入库,而是先进入一个待审队列,展示给审核人员。审核界面做了三件事:
这道环节看起来是「加了人、加了时间」,实际上是省钱的:在生成阶段拦住一条错边,省掉的是后续问答端的一次错误回答 + 一次人工排查。更重要的是,被人工修正过的实体和关系类型,会回流成下一轮生成的先验知识——手段一的实体对齐库越用越准,人工干预量随时间递减。这是典型的「质量关前置」投资:前期慢一点,后期整个系统在自我收敛。
讲一个反直觉的发现:图谱更新的成本降下来之后,问答分数并没有立刻上去。继续排查发现,瓶颈已经移到了检索端——LLM 生成的图谱是干净的,但问答时捞回来的上下文是脏的。我们在检索链路上做了三件事:
不是所有问题都需要图谱。先判断问题类型:事实性单点问题走向量直检即可,多跳关系问题才需要图谱路径检索。原来的 pipeline 是所有问题都先跑一遍图谱,成本高且噪声大;加了意图识别后,约一半的问题直接走轻量路径,回答速度和准确率双升。
纯向量检索擅长语义相似,纯图谱检索擅长关系精确,但企业语料里两种问题各占一半。我们改成向量召回 + 图谱召回双路并行,结果按分数融合——同一个问题,「意思相近的段落」和「关系链上的邻居」都会进来,再交给生成模型取舍。实测融合后的 top-k 命中率比单路高一个明显档次。
这是分数跳变的最后一脚。原来的做法是把召回的 top-k 段落整段塞进 prompt——一个段落 500 字里可能只有 80 字和问题相关,剩下 420 字全是噪声,LLM 很容易被带偏。裁剪后:每个召回段落只保留与问题最相关的句子片段(按相似度打分截断),prompt 里的有效信息密度翻倍。token 消耗降了,答案反而准了。
这三件事叠加,部分场景的实测答案分数从 40+ 提到 80+。实测案例口径:同一评测集,优化前后对比注意这个提升主要发生在检索端,不是换了个更聪明的生成模型——这再次印证了开头的判断:RAG 的分数问题,七成是材料问题,三成是模型问题。
最后一件事是把 prompt 从「每个问题重写一份」改成分层结构。这是工程化的收尾,但影响面其实很大。
最初的 prompt 维护方式是:每次发现某个场景答不好,就改一版 prompt 直接怼上去。改来改去的结果是:通用 prompt 越堆越长(里面塞进了各种场景的特例说明),token 越用越多,而且不同场景互相干扰——为医疗文档调的特例,把法律文档的输出格式带坏了。
分层之后的结构是三层:
收益有三个:通用层只维护一份,token 不再随特例增长;场景层互不干扰,调一个场景不会带坏另一个;新接入一类语料时,只需要写一份场景特化片段,通用层和动态层原样复用。prompt 工程的终态不是一个超长 prompt,而是一组可组合的片段。
把两种模式的成本结构放在一起定性地看(具体数字按实测案例口径匿名化):
| 维度 | 全量重建(优化前) | 增量更新(优化后) |
|---|---|---|
| 单次更新耗时 | 约 20 小时,按全库规模线性增长 | 30 分钟以内,按变动量增长 |
| token 消耗 | 全库规模 × 每次更新,月度账单高到不可持续 | 日常变动规模 × 少量邻居校验,总量降 90%+ |
| 对人工修正的影响 | 重跑会覆盖人工修正过的节点 | 增量不动未变更区域,人工修正得以保留 |
| 图谱新鲜度 | 更新间隔被迫拉长(太贵),图谱永远滞后 | 可以做到近实时更新(便宜),图谱接近新鲜 |
| 错误传播 | 错边被全量重跑反复放大 | 错边在单文件预览环节即被拦截 |
一句话总结这条成本曲线:全量重建的成本与「文档变动量」无关,只与「文档总量」挂钩;增量更新把成本挂钩到了真正变化的那一小部分上。文档库越大、日常变动比例越小,两者的差距就越悬殊——到了万级文档的量级,全量重建在经济上已经是不可运行的方案,而增量更新的成本几乎不变。
Q:这五个手段里,哪一个是最该先做的?
A:手段二(增量更新)。它单独就能解决 80% 的成本问题——只要你还在全量重建,其他优化都是在为一个错误的成本结构做修补。先把「按变动量计费」这个骨架搭起来,再谈生成逻辑和检索质量。
Q:换模型难道一点用都没有吗?
A:不是没用,是性价比最低。在生成逻辑没改之前换模型,等于给一个会浪费 token 的 pipeline 换了个更贵的发动机;逻辑改完之后如果还卡分数,再考虑换模型不迟——我们的经验是那时提升空间已经不大了。
Q:人工预览环节会不会成为瓶颈?
A:取决于文档增长速度。实测下来因为增量更新每次产生的变更集很小(日常更新的待审量是分钟级可处理的),人工不是瓶颈;而且人工修正回流先验知识后,需要人工介入的比例在持续下降。真正要警惕的是拿人工预览去兜「生成本身就很差」的底——那样人会被淹没。
Q:增量更新会不会让图谱越来越不准?
A:方向相反。全量重建才是图谱失准的温床(重复生成、覆盖人工修正、错边被放大)。增量模式每次只动一小块、有人审、有邻居校验,图谱是在持续收敛。唯一要补的是周期性的「全量校验」——不是重建,而是用成本很低的方式(不走 LLM 的规则检查)扫一遍断边和矛盾关系。待验证:万级文档下周期性全量校验的开销
Q:答案分数 80+ 是什么口径?
A:内部人工评测集,百分制打分,同一批评测问题在优化前后的对比值。不是公开基准,不能直接外推到其他项目——但「优化前后同一口径对比」这个相对值是有参考意义的。
作者:王亚博(Abel Wang)· 医疗行业 · AI 数字效能方向 · 转载请注明出处。本文为工程实战记录,不构成任何项目实施建议。