RAG 在 Agent 中的作用从向量检索到 Coding Agent 的代码理解1. 前言前面几篇分别学习了Agent HarnessAgent 为什么需要外围控制机制Agent LoopAgent 如何不断执行任务Tool CallingLLM 如何选择 Tool 并调用外部能力Context EngineeringAgent 如何管理上下文MCPAgent 如何通过标准协议连接外部工具这一篇继续学习 Agent 开发中的重要技术RAGRetrieval-Augmented Generation检索增强生成很多人第一次接触 RAG 时会简单理解RAG 向量数据库 LLM但是在 Agent 系统中RAG 不只是一个搜索组件。它更像Agent 获取外部知识的一种能力。2. 为什么需要 RAG2.1 LLM 不知道私有数据假设用户问公司年假最多可以请多少天但是公司的制度存储在员工手册.pdfLLM 在训练阶段没有见过这个文件。如果直接询问用户问题 ↓ LLM ↓ 生成答案模型可能根据已有知识猜测生成错误信息产生幻觉所以需要用户问题 ↓ 检索企业知识库 ↓ 找到相关内容 ↓ 提供给 LLM ↓ 生成答案2.2 LLM 知识无法实时更新企业项目中的信息经常变化例如数据库结构 接口文档 业务规则 项目代码 配置文件这些信息可能每天变化。但是重新训练 LLM成本非常高。因此更合理的方法外部知识库 ↓ 实时检索 ↓ 辅助 LLM 回答这就是 RAG 的核心思想。3. RAG 的核心思想RAG 全称Retrieval-Augmented Generation中文检索增强生成核心流程用户问题 ↓ Retriever检索器 ↓ 找到相关知识 ↓ 加入 Context ↓ LLM ↓ 生成回答也就是说不让 LLM 凭空回答而是先提供相关资料再让 LLM 基于资料生成答案。4. 为什么不能把整个文档直接给 LLM假设公司有员工手册.pdf 500页一种方式500页文档 ↓ 全部发送给 LLM看起来简单但是存在问题。4.1 Context 太长500页文档可能包含大量 Token文档 ↓ Context ↓ LLM会导致Token 消耗增加成本增加响应速度下降可能超过 Context Window4.2 信息干扰例如用户年假怎么申请员工手册公司介绍 薪资制度 报销流程 年假制度 离职流程真正需要年假制度但是如果全部提供LLM 需要从大量无关信息中寻找答案。所以Context 越多不代表效果越好。这和 Context Engineering 的思想一致选择正确的信息 比 提供更多的信息 更加重要5. RAG 的完整流程一个简单 RAG用户问题 ↓ Query理解 ↓ Retriever ↓ 搜索知识库 ↓ 找到相关 Chunk ↓ 构建 Context ↓ LLM ↓ 生成回答完整过程用户问题 ↓ Embedding ↓ 向量检索 ↓ 找到相关文本 ↓ 加入 Context ↓ LLM生成答案6. 为什么需要 Chunk假设员工手册.pdf 500页不能直接整个PDF ↓ Embedding ↓ 向量数据库因为整个文档信息太复杂。通常需要Document ↓ Chunk切分 ↓ Embedding ↓ Vector Database例如原文员工年假规则 普通员工每年10天。 高级员工每年20天。 申请需要提前三天提交审批。切分Chunk1员工年假规则 普通员工每年10天。 高级员工每年20天。Chunk2申请流程 提前三天提交审批。然后每个 Chunk 单独进行向量化。7. Chunk 太大和太小的问题7.1 Chunk 太大例如整个500页PDF问题信息混杂一个向量代表公司介绍 薪资制度 年假制度 福利制度 ...语义不够准确。检索用户问题 ↓ 整个大文档很难精准匹配。7.2 Chunk 太小例如原文高级员工每年20天。 申请需要提前三天提交。如果切开Chunk1高级员工每年20天。Chunk2申请需要提前三天提交。可能导致用户问高级员工年假怎么申请检索只找到高级员工每年20天但是缺少申请流程导致信息不完整。所以 Chunking 的目标在保证语义完整的情况下控制文本长度。8. 常见 Chunk 策略8.1 固定长度切分例如每500 Tokens一个Chunk优点简单。缺点可能切断语义。8.2 按结构切分更适合代码。例如不要每500行代码切一次而是Class ↓ Method ↓ Function因为代码天然存在结构关系。8.3 Overlap重叠切分例如Chunk大小500 TokensOverlap100 Tokens作用避免重要信息刚好被切断。例如Chunk1员工年假规则 高级员工20天。Chunk2高级员工20天。 申请提前三天提交。这样上下文更加完整。9. Embedding文本如何变成向量Chunk 切分完成后还有一个核心问题计算机如何判断年假怎么申请和假期审批流程是相关的因为计算机无法像人一样理解语义。所以需要Embedding文本向量化Embedding 的作用将文本转换成计算机可以计算的向量表示。例如文本年假怎么申请经过 Embedding[0.23, 0.51, 0.82, ...]另一个文本假期审批流程转换[0.25, 0.50, 0.80, ...]因为两个文本语义接近所以两个向量距离更近10. Embedding 的核心思想Embedding 不是简单把文字转换成数字。它的目标让语义相近的内容在向量空间中的距离更近。例如文本 A苹果是一种水果。文本 B香蕉是一种水果。文本 CJava是一种编程语言。经过 Embedding距离(A,B) 小于 距离(A,C)因为苹果 香蕉 都有 水果 食物 植物语义更加接近。而Java 属于 代码 软件 编程所以距离更远。11. 为什么 RAG 不只使用关键词搜索传统搜索例如数据库查询 content LIKE %年假%它依赖字面匹配例如用户年假怎么申请文档假期审批流程虽然意思相近但是没有年假这个关键词。传统搜索可能无法找到。而 Embedding 可以理解年假申请 ≈ 假期审批流程因为它关注语义关系而不是文字是否完全相同12. Vector Database 保存什么很多人认为向量数据库只保存向量。实际上通常保存向量 原始文本 Metadata例如{text:员工年假申请需要提前三天提交,vector:[0.23,0.54,0.87],metadata:{file:员工手册.pdf,page:120}}为什么需要保存原文因为检索流程Query Vector ↓ 找到相似向量 ↓ 定位 Chunk ↓ 获取原始文本 ↓ 提供给 LLM最终 LLM 需要看到的是文本内容而不是[0.23,0.54,0.87]13. Similarity Search如何找到相关内容用户的问题也需要 Embedding。例如用户Spring Boot如何修改端口转换Query Vector然后和数据库里面所有 Chunk 的向量比较。流程用户问题 ↓ Embedding ↓ Query Vector ↓ Vector Database ↓ 计算相似度 ↓ 找到Top-K结果例如Chunk A: Spring Boot默认端口8080 相似度: 0.95 Chunk B: server.port配置方式 相似度: 0.87 Chunk C: Spring Boot介绍 相似度: 0.60选择Top-K进入下一步。14. 为什么需要 Reranker单纯依赖 Embedding 并不完美。例如用户Spring Boot如何修改端口知识库Chunk ASpring Boot默认启动端口是8080。Chunk Bapplication.properties: server.port9090Chunk CSpring Boot是一个快速开发框架。Embedding结果A: 0.95 C: 0.90 B: 0.85如果直接选择 Top2A C那么真正有用的B反而被丢弃。但是用户真正想知道如何修改端口不是默认端口是多少所以相关性高不代表一定能解决当前问题。这就是为什么需要Reranker重排序15. Retriever 和 Reranker 的区别Retriever作用尽可能找到可能相关的信息特点速度快。目标不要漏掉候选答案例如100万文档 ↓ Retriever ↓ 100个候选Reranker作用从候选里面选择真正有价值的信息例如100个候选 ↓ Reranker ↓ Top 5它会进一步判断这个内容是否真正回答用户问题完整流程用户问题 ↓ Retriever ↓ 候选Chunk ↓ Reranker ↓ 最佳Chunk ↓ LLM16. Hybrid Search为什么需要混合搜索Embedding 有一个问题它擅长语义理解但是对于订单编号 错误码 变量名 接口路径这种精确内容不一定效果最好。例如用户查询订单编号 202610101234数据库订单ID: 202610101234这种情况关键词搜索更有效。所以企业 RAG 常使用Hybrid Search即Vector Search Keyword Search流程用户问题 ↓ ---------------- 关键词搜索 向量搜索 ---------------- ↓ 结果合并 ↓ Reranker ↓ LLM这样既能处理自然语言问题也能处理精确字符串17. RAG 和 Agent 的关系很多人容易误解RAG Agent实际上不是。普通 RAG例如用户问题 ↓ 检索知识库 ↓ LLM回答本质搜索系统 LLMAgent例如用户帮我修复登录接口500错误。Agent可能分析问题 ↓ 搜索代码 ↓ 读取文件 ↓ 修改代码 ↓ 运行测试 ↓ 发现失败 ↓ 继续修改 ↓ 完成任务它包含规划 执行 观察 调整所以RAG 是 Agent 获取知识的一种能力而不是 Agent 本身。18. RAG 可以作为 Agent Tool在 Agent 中RAG 可以被封装成 Tool。例如{name:search_code,description:搜索项目代码}用户找到login相关代码LLM调用{name:search_code,arguments:{query:login}}执行LLM ↓ search_code Tool ↓ RAG系统 ↓ 返回代码片段 ↓ Context ↓ LLM继续推理这和前面学习的 Tool Calling 完全连接。19. 为什么 Coding Agent 的 RAG 更复杂普通知识库目标找到答案例如公司年假多少天找到员工手册即可。但是 Coding Agent目标完成软件工程任务例如修复login接口Bug它需要的不只是文本。19.1 代码位置例如UserService.java login方法 第85行19.2 代码调用关系例如Controller ↓ Service ↓ Repository ↓ Database19.3 当前任务状态例如已经修改代码 ↓ 下一步运行测试所以 Coding Agent 需要代码结构 调用关系 任务状态 而不是简单文本相似度搜索20. 为什么 Coding Agent 不直接读取整个项目假设项目 1000个文件 50万行代码直接整个项目 ↓ LLM存在问题20.1 Token成本大量代码Token增加 ↓ 成本增加20.2 注意力分散用户修复login问题但是 ContextOrderService PaymentService ReportService UserService Config Test真正重要UserService.login()可能被淹没。20.3 更新成本高代码不断变化。如果每次重新加载整个项目效率很低。所以 Coding Agent通常搜索 ↓ 定位 ↓ 读取 ↓ 分析 ↓ 修改21. RAG 与 Agent 可靠性的关系一个可靠 Agent不是依靠单一能力。例如如果RAG错误找到错误代码错误Context ↓ 错误分析Tool Calling错误调用错误工具错误执行 ↓ 任务失败Context错误保存错误状态错误判断下一步因此Agent可靠性需要多个机制共同保证LLM能力 Agent Harness Tool Calling Context Engineering RAG 权限控制 验证机制22. 总结RAG 并不是简单向量数据库 LLM在 Agent 系统中RAG负责帮助Agent找到需要的信息Context Engineering负责决定哪些信息应该提供给LLMTool Calling负责让Agent执行外部操作MCP负责标准化连接外部能力最终用户任务 ↓ Agent Loop ↓ 判断需要什么信息 ↓ RAG检索 ↓ Context构建 ↓ LLM推理 ↓ Tool Calling ↓ 执行任务 ↓ 验证结果 ↓ 完成目标一句话总结RAG 让 Agent 能够获取外部知识而 Coding Agent 的 RAG 更进一步需要理解代码结构、调用关系和任务状态帮助 Agent 完成真实的软件工程任务。