最近在优化生产级知识库和 Agent 网关说实话知识库和 Agent 网关这两个词放在一起看起来像是两件事但在生产环境里它们是同一件事的两面知识库的质量决定了 Agent 的上限网关的稳定性决定了这个上限能不能真正交付到用户手里。我最近一个月基本都泡在这块从检索效果的反复调参到网关上的一次超时事故排查踩了不少坑也沉淀了一些能直接用的结论。这篇文章把这些经验整理出来适合正在做 RAG、Agent 应用、或者准备把 demo 级项目推向生产的团队参考。先说我要解决的问题。业务方给的原始需求很朴素内部的知识散落在 wiki、技术文档、过往工单里希望做一个知识库让同事和大模型 Agent 都能用。听着简单但一旦挂上“生产级”三个字事情就完全不一样了。检索不能随便抽风回答不能偶尔胡说Agent 调用知识库和外部工具时不能超时、不能泄漏、不能把上下文塞爆。我之前搭过不止一套 RAG 原型这次是第一次从架构层面把知识库和 Agent 网关当成一个整体来设计过程中最深的体会是原型拼的是模型效果生产拼的是工程细节。1. 这次优化的出发点知识库和 Agent 网关为什么要一起设计1.1 生产级知识库的痛点到底在哪很多人一提知识库就是“文档切一切、向量化、丢进向量库”原型环境跑起来确实很爽但上线之后问题一个接一个。我这次接手的是一个已经跑了两三个月的系统问题清单拉出来有三类。第一类是检索质量问题。文档格式五花八门有的是一两千字的长篇技术方案有的是一句话的工单结论。固定长度切分之后长文档被拦腰截断语义完整的段落被切成碎片用户问一个问题召回回来的 top5 里可能只有一条是真正相关的。第二类是性能和成本问题。每天几万次查询embedding 调用和 LLM 调用的费用直线上升而且高并发时段检索延迟经常飙到三秒以上。第三类是稳定性和安全问题。没有统一的网关层每个 Agent 任务直接裸调大模型接口限流、鉴权、超时控制各做各的出了问题根本没法追踪。这些痛点单独拎出来都能解决但放在一起就需要一个统一的设计思路。我的做法是把知识库和 Agent 网关看成一条完整链路的两端知识库负责“供给信息”网关负责“调度所有能力”。如果只在知识库内部调检索参数问题会在 Agent 层重新暴露如果只做网关层知识库的烂检索效果照样会把垃圾喂给大模型。所以这次优化是两条线并行推进的。1.2 网关在 Agent 体系里到底扮演什么角色先给网关一个明确定位。我们说的 Agent 网关不是网络设备里的那种网关而是介于“Agent 运行时”和“模型服务、知识库、外部工具”之间的统一代理层。所有 Agent 产生的请求包括 LLM 调用、知识库检索、工具执行都先经过网关再分发出去。这样设计有一个很实际的好处Agent 本身的业务逻辑可以保持简单复杂的基础设施问题全部下沉到网关。举个例子团队里两个 Agent 项目一个做文档问答一个做工单分析它们都要调用知识库和同一个大模型。如果没有网关每个项目都要自己实现限流、重试、API Key 管理有了网关这些东西变成配置项两个项目共用一套基础设施。我这次遇到的一个典型场景是某次大模型服务端抖动上游 Agent 的任务全部超时失败。以前这种情况要手工改代码加超时逻辑现在网关层统一配置了超时、熔断和降级策略抖动期间自动切换到备用模型通道整个故障对业务无感。网关另一个关键职责是数据边界控制。Agent 要调用知识库但知识库里有些内部文档是分权限级的。网关在请求路径上做权限校验确保 Agent 只能检索它被允许访问的内容这是生产环境的硬性要求。2. 知识库优化从分块到召回的完整调参实录2.1 分块策略决定知识库质量的第一道关卡原型阶段我用的是固定长度切分chunk_size 设 500、overlap 设 50简单粗暴。这次优化第一个动刀的就是这里。为什么分块这么重要因为大模型做回答的时候上下文里塞进去的内容决定了它能参考的信息质量。一个 chunk 如果包含太多不相关内容或者一个完整知识点被切成两半检索和回答都会受影响。我对现有文档做了系统的分析。内部文档大致分几类长文技术方案800 到 3000 字、带编号的运维手册条目式、对话记录类工单一问一答。三类文档的语义粒度完全不一样统一用固定长度切分是非常不合理的。最终我采用的是“策略分块 语义分块”的组合方案。策略分块针对结构化文档按章节标题、列表项、对话轮次做切分尽量保持语义完整。比如运维手册按编号条目切一个条目就是一个 chunk工单按“问题-解决”成对切避免把问答拆散。对于技术方案这种长文先用规则识别标题层级把文档按章节切到二级标题以下的段落再对超长段落做滑动窗口补充切分窗口大小 768、重叠 128。这块有一个很值得说的细节重叠大小不是随便设的。重叠太小跨 chunk 的语义会断裂重叠太大会引入大量重复内容浪费向量库容量和 token。128 是经过对比实验得到的折中值。如果文档章节边界清晰甚至可以不设重叠直接按语义块切。另一个被很多人忽略的点是 chunk 的元数据。每个 chunk 除了文本内容和向量我还挂了 doc_id、标题路径、文档类型、更新时间。这些元数据在后续做权限过滤、按来源去重、结果展示时都是必需品。没有元数据的知识库就像一个没有标签的仓库东西能找回来但你不知道它从哪来。2.2 Embedding 模型选型与向量索引优化分块切好了接下来是向量化。很多人会忽略 Embedding 模型对检索效果的巨大影响。我这次对比了三种选择国内开源的 bge-large-zh、通用多语言模型、以及一个轻量的 text-embedding 类小模型。先讲结论中文场景下bge-large-zh 这类专门优化的中文 embedding 模型检索效果明显优于通用多语言小模型。我做了个简单的评测集包含 100 个真实用户问题用召回率Recall10和平均倒数排名MRR两个指标对比。bge-large-zh 的 Recall10 在 85% 左右小模型只有 68%。差距在长尾问题、专业术语多的场景下尤其明显。模型选型后还要处理向量维度的问题。bge-large-zh 输出 1024 维另一个候选模型是 768 维。维度高意味着检索精度可能更高但也意味着向量库占用更大、检索计算量更高。最终我保留了 1024 维的模型同时开启了向量库的 PQ 量化Product Quantization把存储体积压缩了一半以上精度损失在可接受范围。这里有个经验如果向量库规模在百万以下其实没必要过度纠结维度检索速度瓶颈通常在 IO 和网络而不是向量计算。向量索引我用的是 HNSWHierarchical Navigable Small World参数调成了 M16、ef_construction200、ef_search128。M 控制每个节点的连接数越大召回越准但索引越大ef_search 控制检索时的搜索范围越大越准但越慢。我对比过几组参数M32 相比 M16 召回提升不到 2 个点但索引体积涨了 40%所以最终选了 M16。生产环境一定要根据数据量实测不要照抄别人参数。2.3 混合检索与重排别只信向量相似度只用向量检索会有个经典问题关键词精准匹配的场景反而召回不好。比如用户搜“服务器 502 报错排查”向量检索可能召回一堆讲“服务器运维”的宽泛内容而精确包含“502”的工单条目反而排到了后面。解决思路是混合检索向量检索负责语义BM25 关键词检索负责字面匹配两者结果做融合。融合策略我调试了几轮。初期用的是简单加权向量得分占 0.7、BM25 占 0.3效果一般因为两个检索的分数范围不一致直接加权不公平。后来改成基于排名位置的融合RRFReciprocal Rank Fusion思路是把每个文档在两个检索结果里的排名名次倒数和作为融合得分不再依赖原始分数。这个改动让“502 报错”这类精确查询的命中率明显提升。混合检索之后还要加一道重排。重排模型的作用是先用低成本的混合检索把候选从几万条缩小到 top 50再用更精细的交叉编码器模型对这 50 条逐条计算相关度打分重新排序取 top 5。为什么需要重排向量检索是“粗筛”它用 embedding 向量计算相似度粒度比较粗重排模型把 query 和 doc 一起输入模型做精细匹配精度高但速度慢所以只能放在最后一小步。跑过对比加了重排后最终回答质量的主观评价明显提升用户反馈“回答更贴题了”。到这里知识库的核心链路是文档接入 - 策略切分 - 向量化 BM25 索引 - 混合检索 - 重排 - 返回 top N。这个链路调稳了Agent 拿到的输入质量才有保证。3. Agent 网关核心工程化改造路由、容错与可观测性3.1 为什么 Agent 需要独立的网关层知识库优化到一定程度瓶颈会转移到 Agent 调用的环节。我之前见过一个项目Agent 代码里直接写死了模型 API 的地址和 Key限流逻辑散落在每个工具函数里日志打到各自的文件。这种架构在并发低的时候没感觉一旦流量涨起来就是灾难。独立网关层解决的就是这堆问题。我把网关定位成 Agent 与大模型、知识库、外部工具之间的统一出入口所有请求先经过它。网关内部至少要承担五个职责路由根据请求类型、模型要求、成本预算把请求分发到不同的模型通道或知识库实例。鉴权与限流校验调用方身份按用户、按 Agent、按接口维度做速率限制。容错超时控制、重试策略、熔断和降级防止单点故障扩散。协议转换统一 handle 不同模型服务的 API 格式差异对上层提供一致的接口。观测请求级别的 trace、指标、日志让每一次调用都可追溯。网关层还有一个容易被忽视的作用模型通道的灰度切换。新的模型版本或者新的 embedding 模型要上线时先在网关层配置流量的 10% 切过去观察指标稳定后再逐步放量。没有网关的情况下这种灰度要改代码风险高得多。3.2 路由、降级与熔断的落地配置路由是网关的入口逻辑。我用的方式是定义一组路由规则基于请求里的模型名、接口名和租户信息做匹配。例如默认问答类请求走主模型通道高性价比批量任务走轻量模型通道embedding 请求单独走向量模型通道。路由表用文本配置维护改完直接生效不需要重启服务。路由上比较关键的是一个细节备用通道。生产环境里单一模型供应商难免有抖动。我在网关里给每个模型配置了主备两条通道主通道超时 30 秒无响应或者返回连续错误超过阈值网关自动把流量切到备用通道。切换过程对业务透明。限流配置方面我按三层做应用层、用户层、模型层。应用层的限制防止单个恶意或异常应用拖垮系统用户层的限制保证公平使用模型层的限制是硬约束因为模型供应商本身有速率上限。用最简单的令牌桶算法每层配置速率和突发容量。实测下来同样的配置不需要很复杂的算法关键是阈值要根据生产流量数据慢慢调不要拍脑袋。熔断机制是我排查一次事故后加的。某天内部一个定时任务突然大量调用 Agent短时间内请求量是平日的 20 倍知识库检索服务直接被打挂。因为没有熔断所有请求持续打到故障服务恢复之后又被新请求再次压垮。后来加了熔断单位时间窗口内错误率超过 50%直接断开该服务的调用快速失败而不是排队等待。配合降级策略如果知识库不可用Agent 直接返回“知识库暂时不可用”不会让用户无限等待。注意熔断和重试要配合好。很多系统的重试风暴就是这么来的服务已经故障但网关还在不断地重试每秒 100 个失败请求的重试直接把服务的最后一点余量打没。正确做法是重试只在首次连接阶段做两次连接成功后的业务调用错误不盲目重试直接交给熔断和降级处理。3.3 可观测性没有 trace 就别谈生产可观测性是我这次优化投入最大的板块也是回报最明显的。知识库 Agent 网关这条链路有多长用户提问 - Agent 入口 - 网关路由 - 大模型调用 - 知识库检索 - 工具调用 - 结果汇聚 - 生成回答。中间任何一个环节慢 100 毫秒整体体验就是灾难。没有链路追踪排查这种问题基本靠猜。我做了三层观测。指标层网关用 Prometheus 采集请求数、延迟分位数P50/P95/P99、错误率、token 消耗。日志层结构化输出每个请求的关键信息包括路由目标、响应状态、耗时、token 数。链路层每个请求生成一个全局 trace_id从进入网关开始一直到知识库检索和工具调用所有环节的子 span 都带上这个 trace_id最终汇聚到链路追踪系统。有一次线上反馈某个 Agent 任务特别慢用户等待了 40 秒才出结果。我通过 trace 定位到问题Agent 在调用知识库时网关配置的重试策略对检索接口也生效了首次检索超时后自动重试了两次每次间隔 5 秒加上重排模型的耗时最后累加成了 40 秒。如果没有 trace这个 40 秒根本没法拆解。可观测性的实施有优先级不要一上来全量铺开。我建议的顺序是先有结构化日志trace_id 耗时 状态再有指标延迟、错误率、流量最后才做完整的链路追踪。链路追踪接入成本最高但对长链路排障的价值也最大值得投入。4. 常见问题与排查技巧实录4.1 召回稀碎先查分块再查检索知识库上线之后最常见的吐槽是“回答的引用内容不对题”。用户问“如何配置 Nginx 反向代理”回答里引用的知识库内容却是“Nginx 负载均衡概述”。我排查这类问题的顺序是先看召回列表本身。把用户原始 query 丢进知识库直接看 top10 召回结果如果召回就不相关说明问题在分块或检索策略而不是模型生成。如果召回相关但回答不行问题在提示词或者模型。这一步能快速定位责任环节。分块相关的典型症状是召回的内容只有半截上下文断裂。比如一个 chunk 是“配置步骤如下1. 修改配置文件...”后面的步骤在下一个 chunk模型看到了刚才那条还没看完自然回答不完整。解决办法就是重新设计分块规则保证语义块完整。检索相关的问题我会一个环节一个环节验证向量检索 top10 是否合理、BM25 top10 是否合理、两者融合后的 top10 和重排后的 top10 变化是否合理。用四个列表对比一眼就能看出是哪个环节拉低了效果。4.2 上下文爆炸token 消耗不受控Agent 应用的一大隐性成本是 token。系统上线后的一周账单比预估高了 40%一查发现是上下文溢出。原因有两个一是检索返回的 top5 全部塞进 prompt其中两条其实是重复内容一个文档的不同 chunk 被重复召回二是 Agent 与工具的多轮调用中每一轮都把完整的历史对话重新送给模型对话一长token 消耗指数级增长。解决思路是做两层压缩。第一层是召回去重用 RRF 融合结果之后再用一个快速的相似度检测把内容高度重叠的 chunk 去掉最多保留两条来自同一文档的 chunk。第二层是上下文管理设定对话历史的最大轮数超过的早期轮次做摘要压缩用一段几百字的摘要替代原始对话内容。这里有个取舍问题摘要会丢失细节但相比直接把上下文撑爆这是性价比最高的方案。实践效果平均每次 Agent 请求的 token 消耗降低了 35% 左右。4.3 网关超时与重试风暴网关的超时设置是个精细活设置不好就会出现连锁故障。我总结的一个有效经验是超时时间逐层递减重试次数逐层递减不要在所有层都设置同样的超时和重试。比如面向用户的接口层超时 30 秒内部大模型调用层超时 25 秒知识库检索层超时 10 秒。这样上层有充足时间处理下层超时不会出现上层 30 秒刚超时、下层还在 35 秒慢悠悠跑的情况。重试风暴我之前已经踩过一次。那次事故的复盘结论是重试必须带退避backoff而且要有最大重试次数上限。我现在的配置是连接失败重试最多 2 次退避间隔 1 秒和 2 秒业务错误不重试交给熔断器。这个配置在后续几次模型供应商服务波动中表现稳定成功避免了事故扩散。4.4 效果评估改了什么、改对没有生产级系统最怕的是“改了但不知道改没改对”。我给这次优化搭了一套轻量评估流程。首先是建立回归测试集从真实用户查询里每天抽取 50 条标注好每条查询对应的标准答案引用来源。每次调整分块参数、更换 embedding 模型、调整检索权重都先在这 50 条上跑一遍评估脚本记录召回率和回答质量评分。评估脚本的逻辑很简单从回答中提取引用的来源 doc_id与标注的标准来源做比对算命中率。主观回答质量再按 1 到 5 分人工抽评。这套流程虽然简单但保证了每次改动都有数据支撑而不是靠感觉调参。实际效果经过三轮迭代召回命中率从 60% 提升到了 82%用户反馈“答非所问”的情况大幅减少。5. 个人经验沉淀与后续扩展方向优化做到这个阶段最深的体会是知识库和 Agent 网关的优化不是一次性工程而是一个持续迭代的过程。知识库永远有新的文档形态要接入Agent 也永远有新的工具要集成网关则是这两者的稳定器。一套好用的生产系统一定是在日常使用中不断发现问题、改进评估、再调优的循环里打磨出来的。有一个经验值得单独说上线之前一定要先做评估基线。我见过太多项目是先上线再优化结果优化时连对比的基准都没有改完也不知道是好是坏。在建索引之前花一天时间整理 100 条真实查询和标准答案这个投入的回报是十倍级别的。后续有几个方向我准备继续做。一是知识库的自动更新机制现在的文档更新还需要半自动触发重建下一步要做到源文档变更后自动触发增量索引和向量更新。二是 Agent 网关的多租户隔离业务方现在开始提出按部门做资源配额和权限隔离这块需要在网关层做更细粒度的控制。三是评估自动化把人工抽评逐步替换成基于规则和评判模型的自动打分让每次迭代都能快速拿到质量信号。生产级这三个字说到底不是某一天上线的而是每天优化出来的。希望这篇记录的参数、思路和踩坑经验能让你在搭建自己系统时少走几步弯路。
阅读完成 · 觉得有帮助?