☰
Agent、LLM、RAG、GraphRAG、MCP工程实践与避坑指南
2026/10/8 9:51:48 网站建设 项目流程

1. 这期日报到底在聊什么

先把话说在前头,这不是一篇“行业综述”,也不是那种读完就忘的快讯合集。我做 Agent 和 LLM 方向的技术跟踪已经有一段时间了,每天刷的东西很杂——论文、开源仓库、社区讨论、踩坑记录,全都看。时间久了会发现一个规律:真正值得记下来的东西,往往不是某个模型又刷了多少分,而是工程实践中反复出现的那些卡点。这期日报的核心,就是围绕 Agent、LLM、RAG、GraphRAG、MCP 这几个关键词,把最近一段时间里最值得关注的动向和实操经验梳理一遍。

如果你正在做 AI Agent 相关的项目,或者正在搭建自己的 RAG 知识库,又或者只是对 MCP 到底是什么、GraphRAG 和普通 RAG 有什么区别感到困惑,那这篇内容应该能帮你省下不少翻文档的时间。我会尽量把每个技术点讲透,不光说“是什么”,还会说“为什么这么做”以及“实际做的时候会遇到什么问题”。

这期内容适合几类人看:一是刚入门 Agent 开发、想搞清楚整体架构和技术选型的新手;二是已经在做 RAG 项目、但遇到了检索效果瓶颈的开发者;三是对 MCP 协议感兴趣、想了解它到底解决了什么问题的工程师。不管你是哪一类,我都建议你从头看,因为这几个概念之间是有关联的,跳着看容易断片。

2. Agent 架构的核心思路与选型逻辑

2.1 为什么 Agent 架构没有标准答案

很多人一开始做 Agent 项目,第一反应是去找一个“标准架构”照着搭。我刚开始也是这个思路,后来发现根本行不通。Agent 架构的选型,本质上取决于你的任务类型、对延迟的要求、以及你能接受的成本上限。这三个因素一变,架构就得跟着变。

举个很实际的例子。如果你做的是一个单轮问答型 Agent,用户问一个问题,Agent 调用一两个工具就能给出答案,那你的架构可以非常简单:一个 LLM 做决策,几个工具函数做执行,中间加一个循环控制就够了。但如果你做的是一个多步骤任务型 Agent,比如让 Agent 自己去搜索资料、整理信息、生成报告,那你就需要考虑任务分解、中间状态管理、错误恢复这些问题,架构复杂度会直接上一个台阶。

我见过不少人一上来就搞多 Agent 协作,结果发现调试成本极高,每个 Agent 之间的通信协议、状态同步、优先级冲突都要处理,最后项目进度被拖得很难看。所以我的建议是:从最简单的架构开始,遇到瓶颈再升级。不要为了架构而架构。

2.2 单 Agent 与多 Agent 的取舍

单 Agent 架构的核心优势是链路短、调试简单。一个 LLM 负责所有决策,工具调用和结果处理都在一个循环里完成。这种架构适合任务边界清晰、步骤数可控的场景。比如一个代码生成 Agent,用户给需求,Agent 生成代码、运行测试、根据报错修改,这个流程用单 Agent 完全能搞定。

多 Agent 架构的优势在于职责分离。当你的任务需要不同领域的专业知识时,让一个 Agent 同时处理所有事情,效果往往不好。比如一个 Agent 既要懂数据库查询,又要懂前端渲染,还要懂业务逻辑,那它的 prompt 会变得极其臃肿,决策质量会下降。这时候拆成多个专职 Agent,每个 Agent 只关注自己的领域,整体效果反而更好。

但多 Agent 的代价也很明显。Agent 之间的通信需要定义协议,状态需要同步,错误需要传播和处理。我实测下来,多 Agent 系统的调试时间通常是单 Agent 的三到五倍。所以我的判断标准是:当单 Agent 的 prompt 超过 2000 字,或者工具数量超过 15 个,再考虑拆多 Agent。

2.3 Agent 安全与容错控制的工程实践

Agent 安全这个话题最近讨论得很多,但很多讨论停留在理论层面。我从工程角度说说实际怎么做。

第一层是输入过滤。用户输入进入 Agent 之前,需要做一轮清洗,把明显的注入攻击、越权指令过滤掉。这个用规则引擎就能做,不需要上模型。

第二层是工具调用权限控制。不是所有工具都对所有 Agent 开放。比如文件删除、数据库写入这类高危操作,应该单独授权,并且加上二次确认机制。我通常会在工具调用层加一个权限检查中间件,根据当前 Agent 的角色和任务上下文决定是否放行。

第三层是输出校验。Agent 生成的最终结果,尤其是涉及代码执行、文件操作的,需要经过一轮校验才能落地。校验规则可以很简单,比如检查文件路径是否在允许范围内、检查 SQL 语句是否包含危险操作。

容错控制这块,核心思路是让 Agent 具备自我修复能力。具体做法是在 Agent 循环里加入错误分类和处理逻辑。工具调用失败时,不是直接报错退出,而是把错误信息返回给 LLM,让它决定下一步怎么做。我试过在 prompt 里明确告诉 LLM:“如果工具调用失败,先分析失败原因,然后决定是重试、换工具、还是放弃当前步骤。”实测下来,这种方式的恢复成功率比硬编码重试逻辑高不少。

3. RAG 的瓶颈到底在哪里

3.1 从 RAG 到 GraphRAG 的演进逻辑

RAG 的核心思路很简单:把文档切块、向量化、存进向量数据库,用户提问时检索最相关的块,拼进 prompt 让 LLM 生成答案。这个思路在简单场景下很好用,但一旦文档量大、问题复杂,瓶颈就出来了。

最大的瓶颈是检索粒度和语义完整性的矛盾。切块太小,检索到的片段缺乏上下文,LLM 拼不出完整答案;切块太大,检索精度下降,噪音变多。我试过各种切块策略,固定长度、按段落、按语义,每种都有各自的适用场景,但没有一种能通吃。

GraphRAG 的思路不一样。它不依赖单纯的向量相似度,而是先构建一个知识图谱,把文档里的实体、关系、事件抽出来,形成结构化的知识网络。用户提问时,先在图谱上做推理和检索,找到相关的实体和关系,再把这些结构化信息喂给 LLM。这样做的好处是,检索结果自带上下文和逻辑关系,LLM 不需要自己去拼凑。

但 GraphRAG 的代价也很明显。构建知识图谱需要额外的抽取和清洗流程,成本比普通 RAG 高不少。而且图谱的质量直接决定检索效果,如果实体抽取不准、关系定义混乱,效果可能还不如普通 RAG。我的经验是:文档量在 1000 篇以下、问题类型以事实查询为主,普通 RAG 够用;文档量超过 5000 篇、问题涉及多跳推理和关系查询,再考虑上 GraphRAG。

3.2 KG 知识库、RAG 知识库和结构化知识库的区别

这三个概念经常被混在一起说,但它们的定位和适用场景完全不同。

KG 知识库的核心是实体和关系。它存储的是“A 是 B 的 C”这种三元组,适合做推理和关系查询。比如你问“张三和李四是什么关系”,KG 可以直接沿着关系边找到答案。但 KG 的构建和维护成本高,需要定义本体、抽取实体、消歧、对齐,每一步都有坑。

RAG 知识库的核心是文本块和向量。它存储的是文档片段和对应的向量表示,适合做语义检索和问答。你问“这份文档里关于 X 是怎么说的”,RAG 可以找到最相关的片段。但 RAG 不擅长处理关系型问题,因为它没有显式的结构信息。

结构化知识库的范围更广,包括关系型数据库、表格、JSON 文档等。它的优势是查询精确、更新方便,但灵活性差,不适合处理非结构化文本。

实际项目中,这三者往往是组合使用的。我的做法是:用 RAG 做第一层检索,找到相关文档片段;如果问题涉及关系推理,再查 KG 补充结构化信息;最后把两者拼在一起喂给 LLM。这样既能利用 RAG 的灵活性,又能借助 KG 的推理能力。

3.3 RAG 知识库能存图片吗

这个问题我被问过很多次。答案是:能,但不是直接存。

RAG 知识库的核心是向量检索,而向量检索的前提是把内容转成向量。图片本身不能直接转成文本向量,需要先经过处理。常见的做法有两种:

第一种是图片描述生成。用多模态模型给每张图片生成一段文字描述,然后把描述文本向量化存进知识库。检索时匹配的是描述文本,返回的是图片链接或路径。这种方式的优点是实现简单,缺点是描述质量依赖模型能力,细节容易丢失。

第二种是多模态向量化。直接用支持图文的多模态嵌入模型,把图片和文本映射到同一个向量空间。检索时可以用文本查图片,也可以用图片查图片。这种方式效果更好,但对模型和基础设施的要求更高。

我实测下来,如果图片是流程图、架构图这类信息密度高的图,第一种方式的效果往往不够好,因为文字描述很难完整表达图里的结构信息。这时候可以考虑把图片里的关键信息手动提取出来,做成结构化的文本描述,再存进知识库。虽然麻烦一点,但检索准确率会高很多。

4. MCP 协议到底解决了什么问题

4.1 MCP 是什么,为什么突然火了

MCP 的全称是 Model Context Protocol,翻译过来就是“模型上下文协议”。它的核心目标是标准化 LLM 与外部工具、数据源之间的交互方式。

在 MCP 出现之前,每个 LLM 应用要接入外部工具,都得自己定义一套接口。你接一个数据库是一个写法,接一个 API 是另一个写法,接一个文件系统又是另一个写法。代码重复度高,维护成本大,而且不同应用之间没法复用。

MCP 的思路是定义一个统一的协议,工具提供方按照协议实现服务端,LLM 应用按照协议实现客户端,双方通过标准化的消息格式通信。这样一来,工具提供方只需要实现一次,就能被所有支持 MCP 的应用使用;应用方也只需要实现一次客户端,就能接入所有支持 MCP 的工具。

这个思路其实不新鲜,类似 LSP(Language Server Protocol)在编辑器领域的做法。但 MCP 赶上了 LLM 应用爆发的时间点,所以关注度很高。我实测下来,MCP 确实能显著降低工具接入的成本,尤其是当你需要接入多个外部服务时,优势非常明显。

4.2 MCP 的典型应用场景

MCP 目前最常见的应用场景是开发工具集成。比如代码编辑器通过 MCP 接入代码分析工具、数据库客户端、API 调试工具,让 LLM 能够直接操作这些工具完成开发任务。我试过用 MCP 把数据库查询工具接入到 Agent 里,配置过程比之前自己写接口简单很多,基本上就是填几个参数的事。

另一个场景是知识库接入。通过 MCP 把向量数据库、文档管理系统、Wiki 接入到 LLM 应用里,让 LLM 能够直接检索和引用这些知识源。这种方式比传统的 RAG 管道更灵活,因为 MCP 支持动态发现工具和能力,不需要提前硬编码。

还有一个场景是多 Agent 协作。不同 Agent 之间通过 MCP 通信,共享工具和数据源。这种方式的好处是解耦彻底,每个 Agent 只需要关心自己的逻辑,工具接入的事情交给 MCP 处理。

4.3 MCP 接入的常见坑与排查

MCP 虽然好用,但实际接入过程中坑也不少。我整理了几个最常见的问题和排查思路。

第一个坑是授权配置错误。MCP 服务端通常需要授权才能访问,如果授权信息填错或者过期,客户端会直接报错。排查方法是先单独测试服务端是否正常,再检查客户端的授权配置。

第二个坑是工具描述不清晰。MCP 服务端注册工具时,需要提供工具的名称、描述、参数 schema。如果描述写得太模糊,LLM 可能不知道该什么时候调用这个工具。我的经验是,工具描述要写得像给新人看的文档,把使用场景、输入输出、注意事项都写清楚。

第三个坑是流式输出处理不当。MCP 支持流式输出,但很多客户端实现没有正确处理流式消息,导致内容丢失或顺序错乱。排查方法是先确认服务端是否正常发送流式消息,再检查客户端的消息处理逻辑。

第四个坑是版本兼容性问题。MCP 协议还在演进中,不同版本之间可能有差异。如果客户端和服务端版本不匹配,可能会出现各种奇怪的问题。建议在接入前先确认双方支持的协议版本。

5. LLM 工程实践中的关键细节

5.1 LLM as Judge 的使用边界

LLM as Judge 这个思路最近很火,核心是用 LLM 来评估另一个 LLM 的输出质量。这个思路在缺乏人工标注的场景下确实有用,但用不好也会出问题。

我踩过的坑是评估标准不一致。同一个输出,不同的 prompt 模板给出的评分可能差很多。后来我的做法是:把评估标准拆成多个维度,每个维度单独评分,最后加权汇总。比如评估一个问答结果,可以拆成“事实准确性”“完整性”“表达清晰度”三个维度,每个维度用独立的 prompt 来评。这样虽然麻烦一点,但结果稳定很多。

另一个坑是位置偏差。LLM 在对比两个输出时,往往倾向于选择第一个或最后一个。解决办法是交换顺序多次评估,取平均分。我通常会让 LLM 分别以 A-B 和 B-A 的顺序评估两次,如果两次结果不一致,就说明这两个输出质量接近,需要更细粒度的评估。

5.2 基于 LLM 的单元测试怎么做

用 LLM 生成单元测试,这个思路听起来很美,但实际做的时候要注意几点。

第一,测试用例的覆盖范围要明确。LLM 生成的测试往往集中在正常路径,对边界条件和异常路径覆盖不足。我的做法是:先让 LLM 生成一批测试,然后人工检查覆盖了哪些分支,再针对未覆盖的分支补充 prompt 让 LLM 重新生成。

第二,断言要具体。LLM 生成的测试有时候断言写得太宽松,比如只检查返回值不为空,不检查具体内容。这种测试跑起来全是绿的,但实际没什么用。我通常会在 prompt 里明确要求:“断言必须检查具体的返回值、异常类型、调用次数。”

第三,测试要能独立运行。LLM 生成的测试有时候会依赖外部状态,比如数据库连接、文件系统。这种测试在 CI 环境里很容易挂。解决办法是在 prompt 里要求使用 mock 和 stub,把外部依赖隔离掉。

5.3 LLM 请求失败的常见原因

“LLM request failed: provider rejected the request schema or tool payload”这个报错我见过很多次,原因通常有几个。

最常见的是工具参数 schema 不匹配。你定义的工具参数类型和实际传入的类型不一致,比如定义的是 integer,传的是 string。排查方法是打印出实际的请求 payload,和工具定义逐字段对比。

另一个原因是请求体过大。有些 provider 对请求体大小有限制,如果 prompt 太长或者工具定义太多,请求会被拒绝。解决办法是精简 prompt,或者把工具分组,按需加载。

还有一个原因是并发限制。有些 provider 对并发请求数有限制,超过限制会直接拒绝。这种情况需要加退避重试逻辑,我通常用指数退避,初始间隔 1 秒,最大重试 5 次。

6. 实操过程中的关键环节记录

6.1 在 Mac 上搭建 RAG 知识库的完整流程

我在 Mac 上搭过好几套 RAG 知识库,流程基本固定下来了。这里把关键步骤和参数选择记录一下。

第一步是环境准备。Python 环境用 conda 管理,创建一个独立环境,避免依赖冲突。向量数据库我常用 Chroma,轻量、易部署,本地开发够用。嵌入模型用 sentence-transformers 的 all-MiniLM-L6-v2,体积小、速度快,适合本地跑。

第二步是文档处理。把文档统一转成纯文本,PDF 用 pdfplumber 提取,Word 用 python-docx,Markdown 直接读。提取出来的文本要做清洗,去掉页眉页脚、多余空行、特殊字符。

第三步是切块策略。我试过固定长度切块和按语义切块,最后发现按段落切块 + 最大长度限制效果最稳。具体做法是:先按空行分段,如果某段超过 500 字,再按句子切分,保证每块在 200 到 500 字之间。这个范围是我实测下来检索效果和上下文完整性的平衡点。

第四步是向量化和存储。用嵌入模型把每个文本块转成向量,存进 Chroma。存储时把原文、元数据(来源、页码、时间)一起存进去,方便后续检索和引用。

第五步是检索和生成。用户提问时,先把问题向量化,在 Chroma 里检索最相似的 top-k 个块,k 一般取 3 到 5。然后把检索结果拼进 prompt,让 LLM 生成答案。prompt 里要明确要求 LLM 基于检索内容回答,不要自己编。

6.2 使用 MCP 工具流式输出内容到文件

这个场景我最近刚做过,需求是把 Agent 生成的内容实时写入文件,而不是等全部生成完再写。用 MCP 实现的话,核心是服务端支持流式输出,客户端正确处理流式消息。

服务端这边,工具的实现要支持分块返回。比如写文件工具,不要一次性写入全部内容,而是接收一个 chunk 参数,每次写入一部分。客户端这边,要监听流式消息,每收到一个 chunk 就调用一次写文件工具。

我踩过的坑是消息顺序问题。流式消息到达客户端的顺序不一定和发送顺序一致,如果直接按到达顺序写入,文件内容会乱。解决办法是在消息里加一个序号,客户端按序号排序后再写入。

另一个坑是错误处理。流式输出过程中如果某个 chunk 写入失败,需要能够回滚或者重试。我的做法是在服务端维护一个写入状态,客户端发现失败时发送重试请求,服务端从上次成功的 chunk 继续写。

6.3 Agent 项目的目录结构和配置管理

Agent 项目做多了,会发现目录结构对维护效率影响很大。我现在的习惯是分成几个固定目录:

  • agents/存放各个 Agent 的定义和 prompt 模板
  • tools/存放工具实现,每个工具一个文件
  • configs/存放配置文件,包括模型参数、工具权限、环境变量
  • tests/存放测试用例
  • logs/存放运行日志

配置管理这块,我强烈建议不要把配置硬编码在代码里。用 YAML 或 JSON 文件管理配置,代码里只读配置。这样切换环境、调整参数的时候不需要改代码,改配置文件就行。敏感信息比如 API key,用环境变量注入,不要写进配置文件。

7. 常见问题与排查技巧实录

7.1 Agent 开发中的典型问题速查

问题现象可能原因排查思路解决方案
Agent 循环不退出终止条件未触发打印每轮决策日志加最大轮次限制,超限强制退出
工具调用参数错误schema 定义不清晰对比实际参数和 schema完善工具描述,加参数校验
检索结果不相关切块策略或嵌入模型问题人工检查检索结果调整切块粒度,换嵌入模型
生成内容重复prompt 缺少去重指令检查 prompt 模板加“不要重复”指令,加后处理去重
响应延迟高工具调用串行执行分析各步骤耗时并行化独立工具调用

7.2 我踩过的几个印象深刻的坑

第一个坑是工具描述写得太简略。刚开始做 Agent 的时候,工具描述就写一句话,比如“查询数据库”。结果 LLM 经常在不该调用的时候调用,该调用的时候不调用。后来我把描述改成:“当用户询问具体数据、统计信息、或需要从数据库获取信息时调用此工具。输入为 SQL 查询语句,输出为查询结果。”改完之后,工具调用的准确率明显提升。

第二个坑是没有做超时控制。有一次 Agent 调用一个外部 API,那个 API 挂了,请求一直不返回,Agent 就卡在那里。后来我给所有工具调用都加了超时,默认 30 秒,超时后返回错误信息让 LLM 决定下一步。

第三个坑是日志记录不完整。出问题的时候想排查,发现日志里只有最终结果,没有中间过程。后来我在 Agent 循环的每个关键节点都加了日志,包括输入、决策、工具调用、返回结果。日志量大了很多,但排查效率提升非常明显。

7.3 性能优化的几个实用技巧

缓存是最有效的优化手段。LLM 调用结果、嵌入向量、检索结果,这些都可以缓存。我通常用 Redis 做缓存,设置合理的过期时间。实测下来,缓存能减少 30% 到 50% 的重复计算。

批处理也很重要。如果有多个独立的 LLM 调用,不要一个一个串行执行,打包成一批并行发送。很多 provider 支持批量请求,能显著降低总延迟。

模型分级是另一个思路。不是所有任务都需要用最大的模型。简单的分类、抽取任务用小模型,复杂的推理、生成任务用大模型。我通常会在 Agent 里配置多个模型,根据任务类型动态选择。

prompt 精简经常被忽视。prompt 越长,推理时间越长,成本越高。定期审查 prompt,删掉不必要的内容,合并重复的指令,能省不少资源。

8. 一些个人体会

做 Agent 和 LLM 相关的工作,最大的感受是变化太快。今天好用的方案,明天可能就有更好的替代。所以我的习惯是:保持关注,但不盲目追新。新技术出来先小范围试,验证有效再推广到项目里。

另一个体会是工程能力比模型能力更重要。同样的模型,不同的工程实现,效果可能差好几倍。工具调用的稳定性、错误处理、状态管理、日志记录,这些看起来不起眼的东西,往往决定了项目能不能真正落地。

最后说一个实际的小技巧:给 Agent 加一个“思考日志”。让 Agent 在每一步决策前,先输出一段简短的思考过程,记录为什么选择这个工具、为什么这样处理。这个日志不一定要展示给用户,但排查问题的时候非常有用。我试过之后,调试效率至少提升了一倍。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询