
企业知识助手这个方向我从去年开始陆续做了三四个版本从最早的纯 RAG 问答到后来加上 Function Calling再到引入 Memory 和任务编排踩的坑比写的代码还多。很多人一上来就想搞一个全能 Agent结果连最基础的检索准确率都保证不了用户问一句我们公司的报销标准是什么它给你返回三年前作废的旧制度这种体验直接劝退。所以这篇我想完整复盘一下一个真正能用的企业知识助手从 RAG 到 Agent 的演进路径到底该怎么走每一步解决什么问题哪些地方最容易翻车以及 Function Calling、Structured Output、Memory 这些能力应该在什么阶段引入才合理。如果你正在做企业内部的知识库问答、智能客服、文档助手或者单纯想搞清楚 RAG 和 Agent 的边界在哪里这篇内容应该能帮你少走不少弯路。我会尽量把每个设计决策背后的为什么讲清楚而不是只丢一堆代码让你抄。1. 先想清楚企业知识助手到底难在哪1.1 通用 RAG Demo 和企业级需求之间的鸿沟网上那些 RAG 教程基本套路都差不多把 PDF 切块、向量化、存进向量库、检索 Top-K、拼进 Prompt 让大模型回答。跑个 Demo 看起来效果还不错但一旦放到企业真实场景里问题立刻暴露。第一个问题是知识的时间性。企业文档是有生命周期的旧版本必须失效。通用 RAG 只做语义相似度检索它分不清2023 版报销制度和2024 版报销制度哪个是现行的甚至可能因为旧文档被引用得多、向量更典型而优先召回旧版本。这不是模型能力问题是检索策略问题。第二个问题是权限隔离。财务部的文档不能让销售部的人查到HR 的薪酬体系不能让普通员工随便问出来。通用 RAG 把所有文档塞进一个索引检索时一视同仁这在企业里是致命的。你必须在检索层就做权限过滤而不是指望模型自觉不回答。第三个问题是答案的可追溯性。企业用户问一个问题他要的不只是答案还要知道这个答案出自哪份文件的哪一段方便自己去核对。这就要求系统返回引用来源而且要精确到段落级别。第四个问题是多跳推理。很多企业问题不是单文档能回答的比如我们部门今年的差旅预算还剩多少按照现行标准还能出几次差这需要先查预算文档、再查差旅标准、再做计算。纯 RAG 的单轮检索搞不定这种。1.2 为什么不能一步到位做 Agent我见过太多团队第一个版本就想做能自己规划、自己调工具、自己反思的 Agent结果做出来的东西又慢又不稳用户问个简单问题它要转五圈才回答还经常跑偏。核心原因是Agent 的能力建立在可靠的基础能力之上。如果检索本身就不准Agent 拿着错误的检索结果去推理只会错得更离谱。如果工具调用的参数格式都不稳定Agent 编排再多步骤也是白搭。所以我的建议是分阶段演进先把 RAG 做扎实检索准、有引用、有权限再加上 Structured Output 让模型输出可控的结构化结果然后引入 Function Calling 让它能调工具最后才是 Memory 和任务编排把它变成一个真正的 Agent。每一步都建立在上一步稳定的基础上这样出问题也容易定位。2. 把 RAG 做扎实检索质量决定天花板2.1 文档切块策略别再无脑按字数切了切块Chunking是 RAG 里最被低估的环节。很多人直接按 500 字一刀切结果把一张表格切成两半把一段完整的流程说明拦腰截断检索出来的片段语义不完整模型自然答不好。我的做法是按文档结构切而不是按字数切。具体来说对于 Markdown、Word 这类有明确标题层级的文档优先按标题切分一个三级标题下的内容作为一个块如果太长再按段落二次切分。对于 PDF先用解析工具提取出段落和表格表格单独成块并保留表头因为表格脱离表头就完全失去意义。每个块要带上上下文元数据所属文档标题、章节路径、文档版本、生效日期、权限标签。这些元数据在后面检索过滤时会派上大用场。块的大小我一般控制在 300 到 800 字之间太短信息不足太长会稀释语义、影响检索精度。同时会做重叠切分相邻块之间保留 10% 到 15% 的重叠避免关键信息正好落在切分边界上被割裂。提示切块策略没有万能解一定要拿你真实的文档去试。我通常会准备 20 到 30 个真实问题用不同的切块参数跑一遍看召回率和答案质量再定最终参数。2.2 混合检索向量检索不是万能的纯向量检索有个明显短板它对精确匹配不敏感。用户问SM3267AB 这个型号的固件怎么升级向量检索可能召回一堆讲固件升级的通用文档但就是漏掉那个专门讲 SM3267AB 的。因为型号这种专有名词在向量空间里和固件升级的语义距离可能比另一篇泛泛而谈的文档还远。所以生产环境我基本都用混合检索向量检索 关键词检索BM25两路结果做融合排序。向量负责语义召回关键词负责精确命中两者互补。融合排序常用 RRFReciprocal Rank Fusion它对两路结果的排名做加权不需要归一化分数实现简单又稳定。公式大致是每个文档的得分等于它在各路结果中排名的倒数之和。这样既照顾了语义相关性又保证了关键词命中的文档不会被埋没。再进一步可以加一个重排序Rerank环节。先用混合检索召回 Top-50再用一个交叉编码器模型对这 50 个候选做精排选出 Top-5 送给大模型。交叉编码器把 query 和文档拼在一起打分精度比向量相似度高不少代价是慢所以只用在精排阶段。实测下来加了 Rerank 之后答案准确率能提升 15% 到 25%这个投入非常值。2.3 元数据过滤权限和时效的守门人前面提到的权限和时间性问题都要靠元数据过滤来解决。具体做法是在检索时把用户的身份信息和当前时间作为过滤条件先筛掉无权访问的文档和已失效的版本再在剩下的候选里做语义检索。这里有个工程细节过滤要尽量下推到向量库层面而不是检索完再在应用层过滤。因为如果你检索 Top-10 然后在应用层过滤掉 8 个实际只剩 2 个有效结果召回严重不足。主流向量库都支持带过滤条件的检索把权限标签、生效日期这些做成可过滤字段检索时直接带上条件保证返回的都是有效候选。时效性处理上我会给每个文档块打上effective_date和expire_date检索时默认只召回当前生效的。对于制度类文档还会维护一个现行版本标记确保同一主题只返回最新版。3. Structured Output让模型的输出变得可控3.1 为什么自由文本输出是个坑RAG 阶段如果直接让模型输出自然语言你会遇到一堆麻烦有时候它不返回引用来源有时候引用格式乱七八糟有时候该说我不知道的时候它硬编一个答案。下游系统想解析这些输出得写一堆正则还经常解析失败。Structured Output 的核心思路是让模型按照预定义的结构输出比如 JSON Schema。你告诉模型你必须返回一个包含 answer、sources、confidence 三个字段的 JSON它就会按这个格式来。这样下游系统可以直接解析不用猜。3.2 用 JSON Schema 约束输出结构一个典型的知识助手输出结构大概长这样{ answer: 根据现行差旅制度一线城市住宿标准为每晚 500 元。, sources: [ { doc_title: 2024 版差旅管理制度, section: 第三章 住宿标准, snippet: 一线城市住宿标准为每晚 500 元... } ], confidence: high, need_human: false }sources字段强制模型给出引用confidence让它自评把握程度need_human用于标记那些它不确定、需要转人工的问题。有了这个结构前端可以漂亮地渲染引用卡片后端可以根据 confidence 决定是否触发人工审核。实现上现在主流的大模型 API 都支持 JSON Schema 约束有的叫 Structured Output有的叫 JSON Mode能保证输出严格符合 schema。如果用的模型不支持可以用 Prompt 里明确给出 schema 加 few-shot 示例的方式再配合输出解析和重试。注意即使模型支持 schema 约束也要做好解析失败的兜底。我遇到过模型在极端情况下返回空字段或者字段类型不对的情况所以解析层一定要有 try-catch 和降级逻辑解析失败就返回一个默认的安全响应而不是直接报错给用户。3.3 引用溯源让每个答案都有据可查引用溯源不只是把来源贴出来还要做到答案和来源的对应。理想情况下答案里的每一句话都能对应到具体的来源片段。实现方式有两种一种是让模型在生成答案时对每个引用来源标注编号答案里用[1][2]这样的角标引用。另一种是生成完答案后再用一个模型做归因Attribution判断答案的每个部分来自哪个来源。前者实现简单但依赖模型自觉后者更准但多一次模型调用。我一般先用前者如果发现引用不准再上后者。对于合规要求高的场景比如法务、医疗归因这一步不能省。4. Function Calling从会回答到能办事4.1 什么时候该引入工具调用RAG 解决的是知识问答但企业用户的需求往往不止于问答。比如帮我查一下我上个月的报销进度这不是知识问题是要查数据库帮我预约明天下午三点的会议室这是要执行操作。这些都需要 Function Calling。引入时机上我的判断标准是当用户的问题里有 30% 以上是查询实时数据或执行操作类需求时就该上 Function Calling 了。如果大部分还是制度是什么流程怎么走这类知识问答那先把 RAG 做好更重要。4.2 工具设计少而精别贪多新手常犯的错误是一次性定义几十个工具觉得工具越多能力越强。实际上工具太多会带来两个问题一是模型选择困难容易选错工具二是每个工具的描述和参数都占用 Prompt 空间成本高还稀释注意力。我的原则是按场景收敛工具数量一个知识助手通常 5 到 10 个工具就够了。常见的工具类型包括工具类型作用示例知识检索查文档search_knowledge_base数据查询查实时数据query_expense_status操作执行触发动作create_meeting_booking计算工具做计算calculate_budget转人工兜底escalate_to_human每个工具的描述要写清楚什么时候用和什么时候不用这比写清楚参数更重要。模型选错工具往往是因为描述里没说清楚适用边界。4.3 参数校验与失败重试Function Calling 最容易出问题的地方是参数格式。模型可能给你传一个字符串类型的日期但你的函数要的是时间戳可能漏传必填参数可能传了一个不存在的枚举值。所以工具执行层必须做严格的参数校验校验失败时不要直接报错而是把错误信息返回给模型让它重新生成参数。这个失败-反馈-重试的循环通常一到两轮就能收敛。但一定要设重试上限我一般设 2 次避免模型陷入死循环。def execute_tool(tool_name, params, max_retry2): for attempt in range(max_retry 1): try: validated validate_params(tool_name, params) return call_tool(tool_name, validated) except ValidationError as e: if attempt max_retry: return {error: 参数校验失败, detail: str(e)} params ask_model_to_fix(tool_name, params, str(e))这段逻辑看着简单但它是 Agent 稳定性的关键。没有它一个参数错误就能让整个对话崩掉。5. Memory让助手记住上下文和用户5.1 短期记忆和长期记忆的分工Memory 分两层短期记忆是当前对话的上下文长期记忆是跨会话的用户偏好和历史。短期记忆相对简单就是把对话历史维护好注意控制长度别超上下文窗口。常见做法是保留最近 N 轮完整对话更早的做摘要压缩。摘要压缩要小心别把关键信息比如用户提到的订单号压没了我一般会把实体信息单独抽出来保留。长期记忆复杂得多它要解决这个用户是谁、他关心什么、他之前问过什么的问题。实现上通常是把用户的历史交互做向量化存储新对话开始时检索相关的历史记忆注入上下文。5.2 记忆的写入、检索与遗忘Memory 最难的不是存是什么时候存、存什么、什么时候忘。写入时机上不是每句话都值得记。我会在几个关键节点触发写入用户明确表达了偏好我习惯用邮件沟通、用户纠正了之前的错误理解、一次任务完成后的结果。这些信息对未来交互有价值。检索上用当前 query 去向量库里找相关的历史记忆取 Top-3 到 Top-5 注入。注意要控制注入量记忆太多反而干扰当前任务。遗忘机制经常被忽略但很重要。过期的偏好、已经完成的任务、被用户否定的信息都应该被清理或降权。我一般给每条记忆打一个时间戳和权重检索时按相关性 × 时间衰减排序老记忆自然沉底。提示Memory 做不好会适得其反。我见过一个助手记住了用户三个月前随口说的一句话然后在完全不相关的场景里引用它用户一脸懵。所以记忆的检索阈值要设高一点宁可少记不要乱记。5.3 多轮任务的状态管理当助手要执行多步任务时比如帮我订下周三去北京的机票要上午的经济舱它需要维护一个任务状态已经收集了哪些信息、还缺哪些、当前进行到哪一步。这个状态管理我建议用显式的状态机而不是全靠模型记忆。把任务拆成明确的槽位出发地、目的地、时间、舱位每轮对话检查哪些槽位已填、哪些还空缺什么就问什么。这样即使对话被打断、隔天继续状态也不会丢。6. 从 RAG 到 Agent 的编排与落地6.1 编排层决定什么时候用哪种能力到了 Agent 阶段系统要能自己判断这个问题该走 RAG、该调工具、还是该直接回答。这就是编排层的职责。我的做法是用一个路由Router做初步分类把用户输入分成几类知识问答、数据查询、操作执行、闲聊。分类可以用小模型做也可以用规则加模型混合。分类之后再走对应的处理链路。对于复杂问题路由之后还需要任务规划把一个大问题拆成若干子任务依次或并行执行。比如对比一下我们和竞品的定价策略需要先检索自家定价文档再检索竞品信息最后做对比分析。这种规划能力是 Agent 区别于 RAG 的核心。6.2 多 Agent 协作的取舍现在多 Agent 很火但我建议谨慎使用。多 Agent 的通信开销大、调试困难、容易出现踢皮球每个 Agent 都觉得该别人处理。对于大多数企业知识助手场景一个编排良好的单 Agent 加多个工具比一堆互相通信的 Agent 更稳、更快、更好维护。什么时候真的需要多 Agent当任务领域差异极大、需要完全不同的专业知识和工具集时。比如一个负责技术支持的 Agent 和一个负责财务的 Agent它们的知识库和工具完全不重叠这时候拆开是合理的。但如果只是任务步骤多用单 Agent 加规划就够了。6.3 评测怎么知道你的助手变好了没有评测的 Agent 优化就是瞎猜。我一般建三层评测第一层是检索评测用标注好的 query-文档对算召回率和准确率确保检索环节没问题。第二层是答案评测用一批标准问题人工或模型打分看答案的准确性、完整性、引用是否正确。第三层是端到端评测模拟真实用户的多轮对话看任务完成率和用户满意度。这三层评测要定期跑每次改动换模型、调参数、加工具都跑一遍用数据说话。我见过太多团队凭感觉调优改了半天其实是在退步。7. 那些文档里不会写的踩坑经验7.1 检索召回为空时的处理用户问了一个知识库里完全没有的问题检索返回空这时候千万别让模型硬答。我的处理是检索为空时直接返回抱歉我在知识库中没有找到相关信息建议您联系 XX 部门并触发转人工。硬答的代价是用户信任的崩塌一次胡编就能让用户再也不信这个系统。7.2 长文档的上下文超限有时候检索回来的片段加起来超过了模型的上下文窗口。这时候不要简单截断而是按相关性排序优先保留高分片段超出的部分做摘要。或者用分而治之先让模型分别读每个片段提取要点再基于要点综合回答。7.3 模型幻觉的抑制即使有 RAG模型还是可能幻觉。抑制手段有几个Prompt 里明确要求只基于提供的资料回答资料里没有的就说不知道降低 temperature在输出结构里加 confidence 字段让它自评对高风险问题医疗、法律、财务强制人工复核。7.4 成本与延迟的平衡Agent 每一步都要调模型成本很容易失控。我的优化手段简单问题走小模型复杂问题才用大模型能缓存的检索结果和答案就缓存并行执行没有依赖的子任务对工具调用做结果缓存相同参数短时间内不重复调用。实测下来一个设计良好的企业知识助手平均响应时间能控制在 2 到 4 秒单次对话成本能压到几分钱。这个水平在企业内部应用里是完全可以接受的。最后分享一个我自己的体会做企业知识助手技术只占一半另一半是对业务的理解。你得知道用户真正会问什么、他们的痛点在哪、哪些答案错了会造成严重后果。我每次上线新版本前都会找几个真实用户聊看他们怎么用、哪里卡壳这比看任何指标都管用。技术方案可以抄但对业务的理解只能自己一点点磨。