1. 先交代背景知识库发生了什么为什么要动网关1.1 从能跑到能用生产环境的真实差距最近一个月我把大半精力压在两件事上生产级知识库的匹配度和 Agent 网关的稳定性。起因很朴素——线上 Agent 的回答开始出现翻书翻错页的情况知识库召回率肉眼可见地往下掉网关那边又时不时冒出一批 429 和超时告警。这两个模块听起来是独立的东西实际是一条链路上的两个瓶颈知识库检索质量决定了 Agent 的上限网关能不能把请求稳定地送到正确的模型和正确的知识库决定了这个上限能不能兑现。很多团队做知识库的路径是类似的先拿 Dify 或者 MaxKB 搭一个 Demo传几十个 PDF 进去问几个问题感觉效果不错就以为万事大吉。但一旦进入生产文档规模从几十个涨到几千个查询类型从随便聊聊变成客户问合同条款、运维查故障手册、销售找产品参数原来的切分桶、向量索引、检索配置立刻就不够用了。我第一次意识到问题严重是看到一个线上查询在日志里召回了 20 个片段但人工看下来只有 2 个跟问题相关其余全是看起来像但其实无关的噪声。这种情况你不去抓根源后面 Agent 怎么用提示词都是白搭。1.2 优化的前置条件先把可观测性补上动手优化之前我做了一个后来被证明最关键的决定先给知识库和 Agent 网关加全链路观测再谈任何参数调整。原因很简单RAG 链路是分段的——用户 Query 进来经过改写、召回、重排、上下文组装、LLM 生成任何一环出问题表现都是回答不对但你不拆开看就永远不知道是哪一环。我把 Langfuse 接进来同时把网关侧的关键节点用 OpenTelemetry 埋点完整记录query 原文 → 改写后的检索词 → 向量检索 Top N 列表 → 重排后 Top K → 最终送入 LLM 的上下文片段 → 生成结果。每个环节都带时间戳、token 数、命中的知识库版本号。这一步做完之后很多玄学问题立刻变成了数学问题。比如我发现大量回答错误其实发生在召回阶段真正被重排和 LLM 放大的噪声反而是少数。没有这些数据后面的优化很容易变成拍脑袋。1.3 这次优化的目标与边界我给自己定了三条硬指标一是离线评估集上的 Recall5 要从 72% 提升到 85% 以上二是线上人工抽样判断的答案可用率不低于 90%三是网关侧在同等压力下 P95 延迟不增长超过 10%错误率从 2% 压到 0.5% 以下。同时我明确了一个边界不做大版本架构重写不换核心数据库不引入一个新的重组件。理由也很现实——生产系统最怕的不是慢而是改完以后你无法向团队解释为什么和上周不一样了。所以整个优化过程我都保持小步改、可回滚、全记录的节奏。2. 知识库匹配度上不去问题往往不在 Embedding 模型2.1 切分策略被低估的第一道关卡很多人一提知识库优化就想着换 Embedding 模型实际上在绝大多数生产案例里切分策略的影响比模型换代的收益大得多。我之前用的是一种很粗暴的固定长度切分每段 500 token、重叠 50 token。这种切法对纯叙述性的文档还行但一碰到合同条款、操作手册、表格密集型内容就崩了——一个完整的违约条件可能被拦腰切成两段一段有前提一段有结论向量相似度算出来永远半死不活。后来我改成结构感知切分先按 Markdown 标题层级和段落边界做一次粗切再对超长段落执行滑动窗口并为每个切片注入元数据标签包括文档标题、章节路径、页码、更新日期、文档类型。这一步看似简单效果却非常直接切出来的每个块都是语义完整的最小可回答单元。关键指标 Recall5 直接提升了 6 个点。我强烈建议做知识库的朋友先检查自己的切分器——尤其注意表格、代码块、PDF 里那些栏位式的内容很多 RAG 项目就是死在切得碎但切得不准上。顺带提一个容易忽略的点父块-子块Parent-Child策略在生产环境很值得尝试。做法是小的子块用于向量检索定位命中后回溯到大的父块作为上下文送给重排或 LLM。这样既保证召回的精粒度又保证生成时拿到完整上下文。配合元数据过滤比如只要 2024 年之后更新的合同条款检索精度还能再上一个台阶。2.2 检索链路召回、重排的正确组合生产级知识库不能只靠纯向量检索。最典型的问题用户问订单编号 SO-2024-0081 的状态如果文档里确实有这个编号向量检索往往匹配不到精确字符串而关键词检索一下就能命中。反过来用户问报销流程里财务审批的时限要求这种语义模糊的问题布尔检索又毫无招架之力。所以我在线上用的是混合检索BM25 关键词召回 向量召回并行执行各自的 Top 结果合并去重后再进重排器。混合检索的权重一开始是用固定比例但我发现不同知识库、不同查询类型的最优比例差异很大。后来在网关上加了检索配置路由按查询特征分配不同权重包含编号、型号、人名、日期等强标识符的查询BM25 权重上调到 0.7语义型问题反过来向量权重 0.7。重排器我选的是 bge-reranker-large 这类 Cross-Encoder 模型它对Given a question, classify whether the passage is relevant这类任务的效果是双塔模型比不了的。实测下来重排能把命中片段位置平均提前 40%这是整个优化里性价比最高的一步。这里要特别强调重排的输入 Top N 不要太小。我一开始从 Top 10 里重排取 Top 5效果一般后来把粗召回扩大到 Top 30重排取 Top 5指标才明显变好。原因是向量召回的长尾里往往藏着正确答案只是相似度分数排序靠后必须依赖重排器做第二遍判断。2.3 匹配度的度量方法没有指标就没有优化我不太相信感觉回答变好了这种话因为 LLM 的生成能力会掩盖检索质量问题——模型经常能根据碎片信息自己脑补出看起来合理的答案。所以我花了差不多两天时间建了一套离线评估集从线上日志里挑出 200 个真实用户问题再为每个问题标注 2-4 个正确的知识片段和已知不可接受的错误片段。标注标准定得很细片段必须独立回答问题才算相关只包含背景不包含结论的不算。评估指标我用三个Recall5正确片段是否在粗召回的前 5 里、HitTop1重排后第一个答案片段是否正确、MRR正确片段的倒数排名均值。每改一版切分参数、检索策略或模型就跑一遍全量评估集记录所有指标变化。这个过程很枯燥但没有它你根本没法判断一次改动到底是进步还是幻觉。我还额外用 LLM 做了辅助判分但它只用来筛可疑样本最终以上述客观指标为准——我吃过 LLM 判分的亏它会把看着相关但事实张冠李戴的内容打高分这个后面踩坑部分细说。2.4 多知识库分库与查询路由别让文档互相干扰生产级知识库发展到一定规模一个问题就出现了不同领域文档混在一个库里互相污染。比如用户问服务器常见故障排查结果召回里混进了销售团队的报价说明因为语义上服务器相关。解决方案不是加关键词黑名单而是按业务域分库产品文档库、内部制度库、FAQ 库、合同条款库每个库有独立的切分策略和检索参数再由上层 Agent 或网关根据 Query 做路由。路由落地有两种做法一种是规则优先先匹配字段规则比如含合同进合同库、含报销进制度库命中不了再用一个轻量分类模型决定走哪个库。另一种是允许跨库多路召回最后在重排层统一打分哪个库的片段分数高就用哪个。我推荐大部分团队先做第二种因为分类模型的错误会直接导致召回失败而多路召回 统一重排的容错性更好。后面等数据积累够了再慢慢收窄成规则 分类双保险的精确路由。3. Agent 网关的改造从透传到治理3.1 网关职责的重新定义协议转换只是起点早期的 Agent 网关在我看来就是个高级反向代理接住用户的聊天请求转发给大模型 API把结果拿回来。生产环境跑了一段时间才发现这种透传模式根本撑不住。真正的企业级 Agent 场景里网关至少要扛起五件事统一鉴权与租户隔离、模型与知识库路由、上下文缓存、限流熔断、全链路可观测。任何一个环节缺失Agent 平台都只能停留在 Demo 状态。我在改造中最先做的是把模型调用和工具调用统一抽象。之前代码里散落着各种直接调用 LLM SDK、直接查知识库的硬编码逻辑Agent 一多起来就变成一团乱麻。现在网关对外暴露一套统一的 Agent API内部再分发到具体模型供应商或知识库检索服务。这带来的直接好处是换模型、换知识库后端时上游 Agent 完全无感。比如我们把一部分低延迟场景从大模型切换到中等规模的模型只改了网关的一个路由配置Agent 服务一行代码没动。3.2 路由策略模型、知识库、工具的三角关系网关路由是这次优化里最有意思的部分。因为 Agent 请求不是问一句答一句那么简单而是多次迭代理解 → 检索知识库 → 调工具 → 生成回答。每次迭代都可能命中不同的模型和不同的知识库。所以我把路由拆成三层请求级路由决定这个会话走哪个 Agent 流程模型级路由决定当前这一步用哪个模型分类问答用小模型、复杂推理用大模型检索级路由决定查询进入哪个知识库及使用什么检索配置。模型级路由我做了个简单的动态策略根据当前上下文的预估复杂度打分分数超过阈值走大模型否则走小模型。复杂度分数来自三个特征上下文长度、历史轮次、是否包含外部工具结果。这套机制上线后整体 API 成本降了大约 18%回答质量在人工抽检中没有明显回退。工具注册表也统一放到网关管理每个工具声明自己的名称、参数 schema、需要的权限、可用的知识库权限域Agent 只能调用网关允许的工具避免出现Agent 自己去查了下游生产库这种事故。3.3 上下文治理防止 Agent 把缓存当真理Agent 网关和普通 API 网关最大的不同在于它是有状态的。会话上下文、知识库检索结果、工具返回数据都在网关里流转这些数据一旦被错误地缓存或复用Agent 就会把旧当新、把局部当全局。我遇到过一个非常典型的事故某个 Agent 会复用上一个问题检索到的知识片段去回答新问题因为网关层的语义缓存把两个相似但不同的 Query 判定为同一问题命中了旧答案。解决办法分两步一是给缓存键加知识库版本号和鉴权上下文任何库更新或权限变化都会让旧缓存自动失效二是语义缓存的相似度阈值收紧宁可多查一次也不能给错答案。同时我规定任何知识库片段在送入 LLM 前网关必须附带来源引用和置信度分LLM 如果拿不到高置信度的片段允许并鼓励它明说当前知识库中没有找到可靠资料而不是硬凑一段出来。这个允许不知道的开关反而让用户满意度更高。3.4 限流与降级网关必须扛住生产压力Agent 网关在生产环境上的压力模型和普通 HTTP 网关不太一样单个用户的一个问题可能触发内部多次模型调用和多次知识库检索峰值放大系数经常是 5 到 10 倍。如果不对网关做限流一个营销活动的流量尖峰就可能把模型配额打爆然后整个平台一起超时。我采用的是两层限流外层按租户和用户维度做令牌桶限流内层按模型供应商和知识库检索服务维度做并发控制。降级策略也提前设计了当主用模型供应商连续出现错误或延迟超过阈值时网关自动切换备选模型同时降低上下文长度优先保证核心服务可用。这里用到了熔断器模式连续 5 秒错误率超过 50% 就打开断路器进入快速失败或降级模式等冷却时间过了再半开试探。熔断逻辑必须放在网关里而不是业务代码里否则每个 Agent 都要自己处理一遍模型厂商的故障那就乱套了。4. 选型与落地Dify、MaxKB、自研网关怎么搭4.1 现成平台 vs 自研组件按团队阶段选择很多朋友问我知识库和 Agent 网关到底用开源平台还是自研我的回答是看你团队的人效比和变更频率。如果你们是业务先行、需要在两周内上线一个可演示可用的企业级知识库助手那 Dify 这类带可视化编排、知识库流水线和 API 输出能力的平台是首选。它把文档切分、Embedding、检索、Agent 编排都串好了你只需要把精力放在业务文档清洗和评测上。MaxKB 则更聚焦知识库问答本身私有化部署方便权限模型做得比较完整适合对数据安全要求高的内部场景。但如果你们的 Agent 不是简单的问答助手而是一批复杂的、需要精细控制路由和上下文的业务 Agent那我会建议把网关层拿出来自研知识库可以继续用 Dify 或 MaxKB 作为后端。自研网关的周期不用很长做好鉴权、路由、缓存、限流、观测五件事就够了重点是它能把团队从平台限制里解放出来。我自己就是走这条路线知识库用现成平台做底座Agent 网关自己维护。还要提一句Obsidian 这类工具很适合做知识库的上游创作侧让业务专家用 Markdown 维护原始资料再通过同步管线进入生产知识库比直接投喂乱七八糟的 Word 和 PDF 干净得多。4.2 企业级知识库的权限与更新机制企业级知识库和公开文档库的核心差异是权限和版本。文档可能按部门、按密级、按业务线划分Agent 代表一个用户去检索时网关必须把用户标识透传给知识库检索服务在召回阶段就过滤掉无权访问的内容而不是结果回来以后再做后置裁剪。否则会出现两个问题一是权限绕过风险二是用户明明能看到部分内容却因为后置裁剪导致答案残缺。更新机制同样关键。生产知识库最怕改了一个数全是旧结果。我在知识库服务上做了三层更新文档级增量同步定时扫描源目录识别新增、修改、删除、片段级版本标记每次重新切分和 Embedding 后旧版本片段进入待淘汰队列、以及引用级失效广播网关收到更新事件后主动清掉相关缓存。这套机制上线后我再也没有碰到知识库明明更新了Agent 还在回答旧内容的投诉。4.3 网关与知识库的联动设计网关和知识库之间不是简单的网关调一次检索 API的关系好的联动应该包含三个动作。第一是 Query 改写原始用户问题往往口语化、有歧义网关在送入知识库检索前先用一个轻量模型把问题改写成适合检索的形态比如报销流程多久能到账改写成财务报销审批流程及到账时间规定。第二是检索参数注入把租户 ID、权限域、知识库版本要求作为检索请求的固定参数保证数据隔离。第三是结果结构化知识库返回的片段必须带元数据来源、更新时间、置信度网关再按置信度过滤掉低于阈值的片段避免把噪声喂给大模型。这三个动作里最容易忽视的是 Query 改写。很多团队以为向量检索能直接理解口语实际效果差得远。我对比过同一批 100 个真实问题做了改写之后召回正确率提升了 9%。改写模型不用大一个 7B 级别的开源模型就够用关键是提示词要把改写目标说清楚并明确禁止添加原文没有的信息。5. 实测结果、踩坑记录与个人判断5.1 优化前后的关键数据对比整个优化做了大约四周我把关键数据整理成一张表方便大家对照参考指标优化前优化后变化说明离线评估 Recall572%89%主要来自结构感知切分、混合检索、Query 改写重排后 HitTop141%68%Cross-Encoder 重排器是最大功臣线上人工抽样答案可用率74%91%抽样量为每天 50 条真实问答网关 P95 延迟6.2s5.6s缓存命中率提升抵消了重排带来的额外耗时网关错误率2.1%0.4%限流、熔断、备选模型降级生效单用户平均 API 成本0.038 元/次0.027 元/次模型路由让长上下文调用明显减少有几个数据我想特别解释一下。召回率提升如果把功劳全算给 Embedding 模型就错了我中间确实试过一个更强的模型但离线指标只涨了 2 个点而把切分从固定长度改成结构感知一下子涨了 6 个点后来叠加混合检索和 Query 改写又各自贡献了 3 个点左右。这说明在 RAG 里检索链路整体设计的重要性远超单点模型提升。5.2 三个在文档里查不到的坑坑一LLM 自动判分会在评估集里做出错误的正反馈。我一开始偷懒用 LLM 批量给召回片段打分发现某个改造方案指标涨得很漂亮结果人工复核时发现 LLM 把大量主题相关但事实上张冠李戴的片段打成了高相关。比如用户问 A 合同的有效期LLM 认为介绍 A 合同背景的片段相关却把 B 合同的有效期条款漏掉了。从那以后所有指标变更我都强制要求人工复核至少 50 条LLM 判分只作为初筛工具。坑二改了切分策略后忘记处理旧的向量索引。有一次改了切分参数重新跑了全量文档并写入新向量但旧的向量片段还留在库里结果线上检索变成了新旧两套片段混合召回同一份文档的回答前后矛盾。排查了很久才发现是旧数据没清理。现在我的规则是任何切分策略或 Embedding 模型的变更都必须走重建索引 版本切换 旧数据下线三步流程缺一不可。坑三语义缓存让知识库更新失效。这个前面提到过网关的语义缓存把相似查询打成了同一个键导致知识库明明已经更新用户还是命中旧缓存答案。我最后的解法是给缓存键加知识库版本号并把语义相似度阈值从 0.92 上调到 0.96宁可多回源检查一次也不要给出过时答案。这个坑在文档里几乎找不到标准答案属于生产环境才会逼出来的教训。5.3 下一阶段从优化到持续治理这次优化做完之后我给自己定了一个新的工作习惯每周固定跑一遍离线评估集并结合线上抽样数据做一次周报对比。原因很简单RAG 系统没有调完就一劳永逸这回事。文档在变、用户在变、模型在变今天 89% 的召回率可能三个月后就掉到 80%。只有把评估和观测变成例行机制才能第一时间发现劣化并定位原因。我个人对知识库和 Agent 网关的下一步规划是这样在知识库侧尝试用业务反馈数据对 Embedding 模型做领域微调目标是让专业术语和内部简称的召回更准在网关侧把工具调用的权限审计做得更细同时探索让网关根据对话历史自动调整检索策略而不是永远用同一套参数打天下。这些方向我都还在验证中但方向已经很明确把知识库当作一个持续演进的产品来运营把网关当作一个需要精细化治理的中间层而不是一次性搭建完就扔在那里。
