
我最近在整理一套 production agentic RAG 的实战课程笔记起因很直接团队里好几个项目都卡在同一个地方——本地 Demo 跑得飞快一进生产环境就各种翻车。检索结果乱飘、回答胡说八道、数据量稍微涨一点延迟就压不住最后所有人都在质疑 RAG 是不是根本不适合生产。我见过太多团队死磕 Prompt、换模型、调 Chunk 大小搞了一个月还是没进展为什么因为大家默认把 RAG 当成一个检索 生成的拼装玩具而不是一个需要端到端设计的数据系统。这篇文章就是我从零搭 production agentic RAG 系统的完整经验分享覆盖 Agent 工作流的构建、RAG 知识库与 KG 知识库、结构化知识库的选型边界、在 Mac 上的本地搭建调试、多模态图片如何处理以及生产环境最容易被忽略的评估和监控。适合所有正在做 RAG 落地、或者准备把 RAG 推向生产的工程师。1. 为什么你的 RAG 一上生产就卡住先拆解生产这个词先说一个反直觉的现象很多人本地写得津津有味的 RAG Demo放到生产环境之后第一周就开始被用户投诉。不是模型变笨了也不是服务器不够用而是 Demo 环境里那些没人明说的隐藏假设到了生产环境集体失效。1.1 教程类 Demo 的隐藏假设你看过的主流 RAG 教程基本都有一个共同套路拿几十页干净 PDF分割成 Chunk嵌入向量然后问你巴菲特是哪一年出生的这种单跳问题。这个流程跑通非常爽但它默认了几个事情语料量小几百到几千 Chunk向量检索随便召回都能撞到正确答案文档格式工整没有扫描件、表格、页眉页脚、代码片段混排用户问题措辞规范不会出现口语化表达、错别字、指代不明单个问题只依赖一段上下文不需要跨多个文档做推理。这些假设在生产环境几乎一个都不成立。生产环境的知识库可能是几百万个 Chunk文档是乱七八糟的 PDF、Word、HTML、Markdown、Excel 混着来用户问的问题一半带着错别字或者口语化缩略语。于是你会发现教程里的三板斧加载、分割、嵌入根本扛不住。1.2 Building for Production 卡住的真正卡点我观察下来团队真正卡住的地方通常不在模型而在三件事召回质量、数据管道、评估闭环。召回质量是最容易被低估的。很多人以为换个更好的 Embedding 模型就万事大吉实际上一半以上的召回失败是 chunking 策略导致的。生产文档里经常出现标题和正文分离表格被切开长段落语义断裂的情况这些都不是 Embedding 模型能解决的而是文档结构解析层面的事。我后面会专门讲 chunking 和混合检索的取舍这里先记住一个结论召回是 RAG 系统的地基地基不牢Agent 再聪明也没用。数据管道则是另一个隐蔽的卡点。生产环境的知识库是持续更新的不是一次索引完就结束。我见过一个项目文档更新后只跑了增量写入没做旧 Chunk 的删除和去重结果同一份内容在向量库里躺着好几个版本召回时重复结果占满 Top-K真正的答案反而排不进去。这个坑不是靠调参能填上的必须把采集-解析-切分-嵌入-入库-失效处理当成一条完整的数据工程链路来设计。至于评估闭环更是一言难尽。大多数团队在没想清楚什么算回答得好的情况下就开始调优结果就是今天换个 Embedding 觉得好一点明天改个 Prompt 又觉得回去了完全靠感觉迭代。生产级 RAG 必须把评估当成第一等公民我到最后一部分会给出可落地的评估方案。2. Agentic RAG从检索一次就生成到多轮决策工作流2.1 为什么单次检索注定不够用传统的 RAG 是Retrieve-Read两步走查一次向量库把 Top-K 拼进上下文让模型生成。但真实业务问题很少这么简单最常见的两种情况会直接击穿单次检索第一种是多跳问题。比如我们上季度卖得最好的产品它的供应商是哪家这种问题需要先从销售记录里找到产品名再去供应商数据库里查信息最后还可能要去产品文档里确认细节。一次向量检索只能覆盖其中一跳答案必然残缺。第二种是意图混杂的问题。比如用户问这个功能怎么收费另外帮我看看有没有 API 可以对接这是一个问题里同时包含价格问答和接口文档查询两种意图。单次检索只会把两种内容混在一起给模型结果两边都答不好。Agentic RAG 的核心思路就是把检索从一个动作变成一个过程模型或者一个编排层先理解问题再制定检索计划按计划调用不同的工具拿到中间结果后决定是继续检索、改写查询还是直接生成。本质上这是一个感知-决策-行动的循环。2.2 Agentic RAG 的核心循环与路由设计我用的循环结构并不复杂五个步骤反复迭代Query Understanding把用户原始问题做意图识别和查询改写拆出实体、时间范围、限定条件Routing根据意图决定走哪个检索通道向量库、关键词、SQL、知识图谱、外部 APITool Calling调用对应检索工具拿到结果后评估信息够不够Verification对检索结果做相关性验证过滤掉无关内容Generation信息充分后让 LLM 基于检索结果生成最终回答并给出引用来源。这里面最关键也最容易翻车的是 Routing 这一层。很多人一开始就把所有检索通道塞给 Agent 让它自己选结果 Agent 在几十个工具里选择困难延迟和错误率双双爆炸。我的经验是先做一层硬路由规则或轻量分类模型把明显的问题类型分流例如涉及数值聚合的直接走 SQL涉及关系推理的走知识图谱其余的才进入向量检索通道。Agent 的灵活性应该留给同一类问题内部的策略调整而不是在完全不同的检索范式之间乱跳。2.3 一个最小可运行的 Agentic RAG 闭环直接上代码。我自己常用的骨架逻辑是这样的基于 LangGraph 或者纯手写状态机都可以核心是把状态显式管理起来from dataclasses import dataclass, field from typing import Any, Callable dataclass class AgentState: query: str sub_queries: list field(default_factorylist) retrieved_docs: list field(default_factorylist) answer: str None done: bool False def query_understanding(state: AgentState) - AgentState: # 用LLM拆解子问题也可以在这里做实体识别和查询改写 state.sub_queries decompose_query(state.query) return state def route(state: AgentState) - AgentState: # 硬路由判断每个子问题该走哪个检索器 sub_queries_with_routes [] for q in state.sub_queries: route_name classifier(q) # vector / sql / kg / web sub_queries_with_routes.append((q, route_name)) state.sub_queries sub_queries_with_routes return state def retrieve(state: AgentState) - AgentState: for q, route_name in state.sub_queries: retriever: Callable RETRIEVERS[route_name] docs retriever(q) state.retrieved_docs.extend(docs) return state def verify(state: AgentState) - AgentState: # 相关性与去重决定是否继续检索 state.retrieved_docs filter_relevant(state.query, state.retrieved_docs) if not enough_info(state.retrieved_docs): state.sub_queries expand_query(state.query) # 重新改写继续 return route(state) return state def generate(state: AgentState) - AgentState: state.answer llm_generate(state.query, state.retrieved_docs) state.done True return state def run_agent(initial_query: str): state AgentState(queryinitial_query) while not state.done: state query_understanding(state) state retrieve(state) state verify(state) return generate(state)这套闭环的价值在于每个环节都留了状态钩子生产环境里可以做 tracing、做干预、做人工回退。不要迷信 Agent 框架的自动规划在当前模型能力下把规划逻辑显式写清楚远比让模型自由发挥稳定。2.4 实测中的几个坑Agentic RAG 跑起来之后最常踩的坑有三个。第一个是循环失控。Agent 在信息不足时会不断改写查询、反复检索开销成倍增长。我一般会加两个保险最大迭代次数3-5 轮足够和置信度阈值检索结果的相关性打分低于某个值就直接放弃转答我暂时无法回答。第二个是上下文污染。每轮检索回来的文档都堆进上下文最后的 prompt 又长又乱模型反而被噪音带偏。正确做法是每轮检索后都做一次压缩或者重排只保留真正相关的片段控制最终输入模型的上下文长度。第三个是成本失控。每个子问题都是一次 LLM 调用遇到复杂问题可能调十几轮账单飞涨。我的做法是分级处理简单问题直接走单次 RAG只有被识别为复杂问题的才进入 Agent 循环。生产系统不追求每个问题都用最聪明的路线而是用最经济的路线。3. 知识库选型KG 知识库、RAG 知识库、结构化知识库到底怎么分这个问题的搜索热度一直很高说明大家在选型时确实迷茫。我直接给结论这三种知识库解决的是不同层面的问题不是互相替代的关系而是互相补充的关系。3.1 三种知识库的本质区别RAG 知识库本质上是非结构化文本 向量索引。它的对象是自然语言文档优势是部署快、对语义相似性问题友好比如有没有可以离线运行的 OCR SDK这种问题靠向量相似度就能召回不错的候选。但它的弱点是没有全局一致性同一个实体在不同文档里可能有不同叫法也不擅长精确计算和聚合比如今年 5 月一共处理了多少工单向量检索根本答不上来。KG 知识库本质上是实体 关系 属性的图结构。它适合回答关系推理类问题比如A 公司的股东里有没有 B 公司的关联方这类问题需要沿着边一跳一跳地走。KG 的优势是精确、可解释、支持多跳推理劣势也一样明显构建成本高需要做实体抽取、关系抽取、对齐消歧而且知识覆盖率永远赶不上文档库——你不可能把每一段话都抽成三元组。结构化知识库本质上是表 SQL 维度模型。它适合做聚合统计、精确值查询比如各区域的销售额排名单价在 100 到 200 之间的商品列表。结构化知识库通常不直接面向用户而是作为 RAG 或 Agent 背后的一个工具通道通过 Text-to-SQL 暴露给模型使用。3.2 一个对比表格帮你快速选型维度RAG 知识库KG 知识库结构化知识库数据形态非结构化文档三元组/图表/视图查询方式向量相似度 关键词图遍历/SPARQLSQL擅长问题语义检索、开放性问答关联推理、路径查询聚合统计、精确值查询弱点无全局一致性、不擅计算构建成本高、覆盖有限无法处理模糊语义典型场景产品文档、客服知识库风控、供应链分析经营分析、报表问答我给团队定的选型逻辑是三步走先看用户问题里有多少比例是精确计算类和关系推理类如果超过三成就必须引入结构化通道或 KG 通道再看现有数据基础如果根本没有干净的关系型数据那就别硬上 KG先把 RAG 做好最后做融合把不同知识源挂到 Agent 的工具列表里让路由层决定怎么查。3.3 Ontology 在 RAG 里的真实角色热词里出现了 ontology rag值得单独说一下。很多人把 Ontology本体理解成知识图谱的增强版其实不够准确。Ontology 是 KG 的模式层——它定义了实体类型、关系类型、属性约束相当于给图数据画了一张类图。没有 Ontology 的 KG 是一堆松散的节点和边有了 Ontology语义才是完备的。在 RAG 场景里Ontology 的真正价值有两个。第一是约束 Text-to-Query 的生成质量。当我们要把自然语言问题翻译成图查询语言时如果 Ontology 给了明确的实体类型和关系类型LLM 就不会凭空捏造不存在的属性名而是严格从 Ontology 里选择。第二是给 RAG 召回做语义对齐。比如用户问谁负责这个模块Ontology 如果定义了人-负责-模块这个关系路由层就能直接知道该走 KG 而不是向量检索。实践上小规模团队不需要从零构建一套完整 Ontology。我的建议是先画一个极简版本覆盖 Top 20 的实体类型和 Top 50 的关系类型够用就行然后在使用过程中持续扩充。追求一步到位的 Ontology 反而会陷入建模地狱。4. 技术栈选型与 Mac 本地搭建别在这一步卡太久4.1 框架选择的真实经验RAG 框架这两年变化太快我直接给筛选标准第一看团队成员的熟悉度和社区活跃度第二看是否可以被拆掉——也就是说框架的各个组件能否独立替换。我自己在 LangChain、LlamaIndex、Haystack 里都写过生产代码结论是LangChain 生态最大但抽象层太厚适合快速原型LlamaIndex 对文档加载和索引管道的控制力更强Haystack 在生产管线方面更克制、更工程化。但说实话生产项目到后期基本都是半自研状态用框架做基础组件用自研代码做路由、评估和监控。框架的作用是让你不用重复造轮子而不是替你解决业务问题。如果你发现自己在框架里疯狂写 workaround那就说明框架选错了或者你的依赖太深了。4.2 在 Mac 上搭建 RAG 知识库M 系列芯片实战怎么在 Mac 上搭建 RAG 知识库这个热搜词背后其实有大量开发者在本地实验。我自己主力机是 M 系列芯片的 MacBook跑本地 RAG 的体验还算顺畅但有几个经验值得说。第一模型尽量选 MLX 格式。Apple Silicon 上用 MLX 框架跑量化后的模型推理速度和显存占用都比 PyTorch 原生好很多。以 7B-8B 规模的模型为例Q4 量化后在 32GB 内存的机器上基本能跑出可用速度如果内存只有 16GB建议用 3B-4B 模型或者干脆走 API。第二Embedding 模型不要贪大。很多人在本地跑 embedding 模型动辄上 billion 参数其实没必要。本地开发阶段用 100M-300M 参数的模型比如 bge-small、bge-base 系列完全够用召回效果和生产环境的差距主要靠后续的 rerank 和混合检索来弥补。第三向量数据库的选型。本地实验我推荐 Chroma 或 LanceDB零配置、文件即数据库需要接近生产环境的性能测试就上 Qdrant 或 Milvus 的 Docker 版。不建议一上来就搭分布式向量库那是自找麻烦。简单列一个我在 Mac 上的搭建路径供参考# 1. 安装 Python 环境和依赖 python3 -m venv rag-course source rag-course/bin/activate pip install llama-index chromadb sentence-transformers # 2. 用 Ollama 加载本地 LLMMLX 加速 brew install ollama ollama pull qwen2.5:7b-instruct-q4_K_M # 3. 最小 RAG 管道 python - EOF from llama_index.core import SimpleDirectoryReader, VectorStoreIndex from llama_index.vector_stores.chroma import ChromaVectorStore import chromadb docs SimpleDirectoryReader(./knowledge_base).load_data() client chromadb.PersistentClient(path./kb_db) vstore ChromaVectorStore(chroma_collectionclient.get_or_create_collection(kb)) index VectorStoreIndex.from_documents(docs, vector_storevstore) engine index.as_query_engine() print(engine.query(你们的退款政策是什么)) EOF这套路径能让你在半天内跑通本地实验。但我要强调一句本地跑通只是起点生产环境的差距在工程层面的数据管道、监控、评测和灰度策略这些才是你后面真正要花时间的地方。4.3 Mac 本地调试的几个常见坑第一个坑是依赖冲突。RAG 生态的 Python 包更新极快昨天能跑的版本今天装了新包就崩。我的习惯是用独立的 venv 加 requirements lock 文件管理不要图方便把包装进全局环境。第二个坑是 Metal 加速相关的兼容问题。有时候同样的代码在 Intel Mac 上能跑在 M 系列上反而报错多半是 PyTorch 版本和 MPS 后端的兼容问题。遇到这种情况先降级 PyTorch 版本或者直接用 CPU 推理做验证别在环境问题上耗时间。第三个坑是分块效果不可见。很多人用默认的 chunk_size 和 chunk_overlap 就完事结果检索效果差却不知道源头在哪。我强烈建议本地搭建阶段就用一个可视化工具打印 chunk 详情肉眼检查切分结果是否符合文档结构。这一步花的十分钟能省掉后面调优的三天。5. 多模态问题RAG 知识库到底能不能存图片rag 知识库能存储图片嘛这个问题问的人很多答案是有条件的能但要分清楚你存的是什么。5.1 图片在 RAG 里的三种处理方式第一种是存图片 存对应的文本说明。这是最务实也最稳定的方案。图片本身不进向量库但图片的文件路径、OCR 文本、图片标题、人工撰写的描述等作为文本元数据存入向量库。用户问那个流程图里第三步是什么检索系统把流程图第三步和 OCR 文本对应上再返回图片路径给前端展示。这个方案的优点是工程简单、召回可控缺点是依赖图片有足够好的文本描述。第二种是存图片的向量嵌入。用 CLIP 这类多模态模型把图片编码成向量和文本向量放在同一个向量空间里检索时文本向量直接和图片向量算相似度。这个方案支持用文字搜图片和用图片搜图片体验更自然但坑在于多模态嵌入模型的选择和召回阈值调优都需要经验而且图片向量没法直接回答文字问题还是要配合多模态 LLM 才能生成文本回答。第三种是让多模态 LLM 直接读图。像 GPT-4V、Qwen-VL 这类模型可以把图片作为输入的一部分在 Agent 循环里把图片路径直接传给模型。这个方案最灵活支持看图回答问题但成本最高、延迟最大。生产中通常只对少数关键图片走这条路不会把所有图片都塞进上下文。5.2 我的建议混合索引图片和文本分开管我的生产方案是二选一的混合索引两条线并行文本线负责语义检索图片线负责视觉检索最终由路由层决定哪条线介入。具体来说文本线里给每张图片建立一个图片卡片文本块包含图片标题、OCR 文本、关联文档上下文视觉线用 CLIP 把图片嵌入独立向量集。当用户问题里出现明确的视觉词汇截图里面流程图UI 界面路由层优先查视觉线再用多模态 LLM 做最终理解其他情况只走文本线。另外一个重要的点是图片入库前的清洗很关键。扫描件先 OCR带文字的截图先提字幕分辨率过低的需要预处理增强。跳过这些步骤直接入库检索回来的图片质量差后续怎么优化都没用。6. 生产级 Agentic RAG 的评估、监控与迭代路径最后这部分是很多人最想要的生产经验。别急着调 Prompt先搭好评估和监控否则你永远在暗箱里调优。6.1 离线评估先把好定义清楚离线评估分三层检索质量、生成质量、流程质量。检索质量用标准信息检索指标比如 RecallK、MRR、NDCG。我在实践中特别看重 RecallK 的一个变体答案片段是否出现在 Top-K 里。如果答案片段根本不在召回结果里那后面生成环节再使劲也没用。生成质量主打三个维度忠实度回答是否严格基于检索到的文档有没有编造、相关性是否回答了用户的问题有没有跑题、完整性是否覆盖了问题要求的全部要点。忠实度是目前 RAG 系统最大的短板大模型很容易在上下文里挑一段顺眼的就开编所以忠实度评估必须单独盯紧。流程质量针对 Agentic RAG 特殊设计路由准确率该走向量的时候有没有走错通道、工具调用成功率、循环轮数分布、超时率。这些指标直接反映 Agent 编排层的稳定性。6.2 评估集怎么建从生产日志里挖很多人问评估集怎么来。我的回答第一优先从生产日志里挖真实用户问题脱敏后人工标注标准答案和检索相关文档集合第二优先让业务专家构造困难问题集专门覆盖多跳、比较、边界情况实在没有积累的再考虑用 LLM 辅助生成候选问题但必须人工复核。一个可落地的操作是给评估集每个问题打标签标注问题类型单跳、多跳、比较、聚合、模糊这样迭代时能精确看到你的系统在哪种问题类型上表现差而不是笼统地看一个总分。6.3 线上监控不能只看用户点踩线上监控至少要覆盖三层。第一层是日志与追踪每个请求的完整链路都要能回溯查询改写了什么、路由走了哪条、检索了哪些文档、模型生成了什么、引用来源是哪些。没有链路追踪线上出了问题你根本无从排查。第二层是质量信号包括用户反馈点赞点踩、引用有效性引用的文档片段是否真的支撑了回答、超时和错误率。第三层是数据漂移监控知识库更新频率、Embedding 分布变化、用户查询词汇漂移这些能提前预警系统退化。我特别强调引用来源的监控生产 RAG 系统必须强制带引用没有引用的回答一律视为不合格。这既是合规要求也是质量抓手因为你可以自动化校验回答中的关键断言是否真的在引用文档里出现。6.4 一条务实的学习路径如果你想系统地把 production agentic RAG 搭起来我建议按这个次序走不要跳级先把单次 RAG 做扎实掌握文档解析、chunking、Embedding 选型、混合检索、rerank建立离线评估集和评估脚本从第一天就记录每次迭代的指标变化再上 Agentic 编排路由、查询改写、多轮循环每一步都用 Tracing 观察然后引入多知识源结构化通道、KG 通道逐步让路由层处理复杂问题最后做生产化加固数据管道自动化、监控告警、成本治理、灰度发布。这套路径我反复验证过相比一上来就铺 Agent 框架它能让你每一步都走得比较稳。很多项目翻车都是因为第 2 步没做就急着跳到了第 3 步结果系统烂在哪里都说不清楚。最后分享一点个人体会我在做这套课程的过程中最大的收获其实是把RAG 是一个检索系统这个认知彻底改成了RAG 是一个数据系统。检索、生成只是表象真正决定生产成败的是你对数据的理解、对评估的坚持、以及对工程细节的耐心。如果你现在正被某个 RAG 问题卡住别急着换模型先回过头看看你的数据管道和评估闭环是不是健全——十有八九答案就在那里。