从懵到通:LLM、RAG与Agent,它们到底在争什么
这段时间被问得最多的问题,不是某个模型又刷榜了,而是“我已经接了LLM的API,为什么还要搞RAG?”“Agent是不是以后会把RAG干掉?”“这三样东西放到项目里,到底该怎么选、怎么搭?”说实话,这些问题背后反映的不是工具焦虑,而是概念体系的混乱——LLM、RAG和Agent被包装成了三个互不相干的“产品”,但实际上它们是解决不同层级问题的技术方案,彼此之间不是替代关系,而是配合关系。
这篇文章我想把三者的本质差异、各自解决的核心问题、在真实项目中的选型边界,以及组合使用时的常见坑,一次性讲透。内容不追新、不追热,只讲那些放到两年后回头看依然成立的东西。适合正在做技术选型的开发者、刚接触大模型应用的产品经理,以及所有被“RAG已死”“Agent为王”这类论调搞糊涂的朋友。
1. 三者的本质差异:一个管记忆,一个管知识,一个管行动
1.1 大语言模型:不是“知识库”,是“模型”
很多人对LLM最大的误解,是把它当成一个可以随时检索的百科全书。实际上,大语言模型本质上是一个参数化的概率模型——它在训练阶段把海量文本中的统计规律压缩进几十亿、几百亿甚至上千亿的参数里,在推理阶段根据你给的上下文,逐字预测下一个token。
这个机制的优点是“什么都懂一点”,缺点是三个硬伤:
- 知识有截止日期:训练数据采集截止那天,就是它知识的“保质期”终点。之后的新闻、产品更新、内部制度,它一概不知道。
- 会一本正经地胡说八道:因为它生成的是“听起来合理的文本”,而不是“查证后的事实”,所以遇到没见过的内容,它更倾向于编造而不是承认不知道。
- 无法自主获取外部信息:它的所有输出都基于参数和上下文窗口内的内容,没有主动去读数据库、调接口、查文档的能力。
我用一个类比来理解:LLM像一个记忆力超强、读过很多书,但与社会脱节的“学者”。你问它理论问题,它能引经据典;你问它“公司最新的报销流程是什么”,它只能凭印象瞎编。
所以,如果你的应用场景只需要模型具备通用常识、文案生成、代码补全、逻辑推理能力,那直接用LLM就够了。但一旦牵涉到“最新信息”或“私有数据”,它必须借助外部机制。
1.2 RAG:给“学者”配一本随时可查的参考书
检索增强生成(Retrieval-Augmented Generation)解决的就是上面说的第二和第三个硬伤。它的核心思路非常朴素:模型不知道没关系,你先从外部数据库里把相关内容找出来,塞进上下文里,让它基于这些材料来回答。
所以RAG的本质不是修改模型本身,而是在“用户提问”和“模型生成”之间加了一个检索层。这个检索层负责把用户的问题转成向量,到文档库里找最相似的片段,再把片段作为上下文拼接进Prompt,最后交给LLM生成回答。
这里有个关键认知:RAG改变的不是模型的“大脑”,而是模型的“输入”。模型还是那个模型,但因为拿到了相关资料,它就能答出准确、可追溯的内容,并且可以随时更新外部文档库——换资料,就等于换知识,不需要重新训练模型。
如果继续用类比,RAG就是给学者配了一间资料室。学者本身没变,但他回答问题时可以先翻资料再开口,不再凭空瞎编。这也是为什么RAG成为目前企业落地大模型应用的最常用方案——它用最小的改造成本,解决了“私有知识注入”和“知识实时更新”这两个最痛的问题。
1.3 Agent:从“回答问题”到“完成任务”
如果说LLM是“能思考的大脑”,RAG是“资料室”,那Agent就是“能动手做事的人”。智能体的核心特征在于:它不只是根据输入生成一次输出,而是能够自主进行多步决策,调用外部工具,观察结果,调整策略,直到完成一个目标。
一个典型的Agent工作循环是这样的:
- 接收一个较为宏观的目标,比如“帮我订一张下周去上海的火车票,预算500以内,靠窗位置”。
- 模型先做任务拆解:查车次→筛选价格→看座位图→下单。
- 每拆出一个子步骤,就调用一次对应的工具(查票API、下单API)。
- 工具返回结果,模型判断这一步成没成、下一步怎么做,比如“没有靠窗票,那就换一个车次再查”。
- 直到所有子任务完成,汇总输出最终结果。
注意,这个过程不是预先写死的脚本,而是模型基于当前状态动态生成的决策序列。同一个目标,给不同模型或不同上下文,拆解出的步骤可能完全不一样。这种“自主规划+工具调用+结果反馈”的能力,才是Agent和普通API调用的本质区别。
继续用类比,Agent是一个既懂业务、又会使用工具、还能自己做判断的员工。他不只是问什么答什么,而是会主动规划、执行、纠错。
1.4 一句话总结三者的关系
| 维度 | LLM | RAG | Agent |
|---|---|---|---|
| 解决的问题 | 语言理解与生成 | 知识与信息的实时获取 | 任务规划与自主执行 |
| 核心机制 | 参数化概率生成 | 检索+上下文注入 | 决策循环+工具调用 |
| 输入 | 用户指令 | 用户指令+检索结果 | 用户目标+环境反馈 |
| 输出 | 文本 | 有依据的文本 | 行动结果(可能含文本) |
| 类比 | 专家大脑 | 参考书/资料室 | 动手干活的员工 |
| 典型难点 | 幻觉、知识过期 | 检索质量、切分策略 | 决策可靠性、错误恢复 |
LLM是底座,RAG是知识插件,Agent是行为框架。它们不会互相取代,因为解决的不是同一层的问题。理解了这一点,后面的选型和架构问题就都好谈了。
2. 拆开RAG看细节:从检索到注入,整条链路的每一环都可能掉链子
RAG听起来简单——查资料、拼上下文、让模型回答。但在真实项目里,把这三个词展开成工程实现,会牵出一大堆决定成败的细节。我做过的每个RAG项目,踩坑的地方基本都集中在下面几个环节。
2.1 文档切分:这一刀切不好,后面全白搭
RAG的第一步是把文档库“切”成可供检索的片段。切分策略直接决定了两件事:检索命中率,以及上下文的有效性。
切得太粗,比如把整个章节切成一个块,检索时相关片段会混入大量无关内容,既浪费上下文窗口,又稀释答案的准确性。切得太细,比如按单句话切,又会导致语义不完整,同一个知识点被腰斩成好几段,模型拿到的是信息的碎片。
我的经验是,先按文档原有结构粗切,再按语义边界细调。以一份技术手册为例:
- 第一步按标题或章节切,保证每块有相对完整的主题。
- 第二步检查每块的长度,超过1000字或低于200字的,再根据段落语义做合并或拆分。
- 第三步对表格、代码块这类特殊格式做单独处理,因为它们天然不适合按纯文本切分。
切分的本质是“保留语义完整性的同时,把检索粒度控制在合理范围”。现在有很多智能切分工具(按句子嵌入相似度动态切分),但我个人建议在项目初期,先用固定长度+标题层级就够了,先跑通流程,再优化切分策略。
2.2 向量化与检索:Embedding选型、相似度算法与重排
切好的文档块,接下来要被Embedding模型转换成向量。选Embedding模型时,最关键的指标不是它的名气,而是和你的中文语料的适配度。不同模型在通用文本、法律文书、代码片段上的表现差异很大,建议拿你们真实的业务文档做小范围评测后再定。
检索阶段,最常见的是余弦相似度或向量数据库自带的近似最近邻搜索。这里有个坑:TopK召回不等于模型能答对。比如技术FAQ场景里,一个问题往往涉及多个方面——“这个功能怎么开启?支持哪些平台?有什么限制?”——单靠最相似的1~2段内容,极容易漏掉信息。
所以在Retrieval之后,我强烈建议加重排序(Rerank)环节。初次召回可以取Top 20,再用重排序模型或基于规则的过滤精挑到Top 3~5作为上下文。这一步通常能让准确率上一个台阶,尤其是文档库规模上来之后,效果差异会非常明显。
# 示意:检索与重排的完整调用流程 from utils import get_embedding, vector_search, rerank query = "如何开通企业版?有哪些限制?" query_vector = get_embedding(query) # 第一步:向量检索,召回 Top 20 candidates = vector_search(query_vector, top_k=20) # 第二步:重排序,压缩到 Top 5 作为上下文 final_context = rerank(query, candidates, top_k=5) # 第三步:拼装 Prompt 并调用模型 prompt = f"请基于以下资料回答问题:\n{final_context}\n\n用户问题:{query}" response = call_llm(prompt)2.3 上下文注入的格式远比想象中重要
文档检索回来以后,怎么“喂”给模型是个看似简单、实则讲究的活。直接在Prompt开头堆资料和精心设计资料的组织格式,效果差距可能大到离谱。
我习惯的做法是:在Prompt里为每个文档块标注来源元数据,比如“以下内容来自《产品帮助文档》第2.3节《权限说明》”,然后明确告诉模型:优先参考资料内容,资料中未提及的部分要明确说明“资料中没有提到”,绝不允许自行补充或编造。
还有一个容易被忽略的细节是上下文顺序。把最相关的文档块放在离问题更近的位置,对答案质量有正向影响。很多模型对长上下文的“注意力分布”并不是均匀的,中间部分的信息容易被忽略,头部和尾部的信息留存率更高。基于这个特性,我会把最核心的检索结果放在Prompt的尾部,紧挨着用户问题那一段。
2.4 RAG落地时最容易忽视的三个评估指标
大多数RAG项目上线前只测“回答得对不对”,这远远不够。我至少会关注三个指标:
- 检索命中率(Recall):正确答案是否出现在召回的Top K里。如果答案根本不在上下文里,模型再强也巧妇难为无米之炊,所以这一步是RAG效果的天花板。
- 答案忠实度(Faithfulness):模型回答的内容是否都来源于资料,有没有“自由发挥”。这一项需要人工判断或另用模型打分。
- 回答完整率(Completeness):用户问题涉及的多个子问题是否都被回答到,不能漏点。
这三个指标分别对应RAG链条上的不同环节——命中率管检索,忠实度管注入和生成,完整率管整体流程设计。上线之前,至少拿50条真实问题跑这三项评估,再谈效果优化。否则上线之后,一堆“答非所问”和“看似正确实则编造”的翻车案例会让你怀疑人生。
3. Agent不是“写个Function Calling就行”:核心是决策循环和状态管理
3.1 重新理解“工具调用”:这只是一个起点
很多朋友一听说Agent,就说“不就是Function Calling嘛,我给模型注册几个函数,它能选着调用,就完事儿了”。这话只对了一半。
Function Calling确实是Agent的技术底座——它让模型具备了“发出工具调用指令”的能力。但这个能力本身只是一个“动作”,Agent真正难的是怎么决定在当前状态下该调用哪个工具、怎么解读返回结果、下一步该干什么。
举个很常见的例子:用户问“帮我查下订单号A10086的物流信息,如果已经签收了,就不用再提醒我了。”这个任务看似简单,但Agent需要判断:
- 先查物流信息,这是一个工具调用。
- 看返回结果是“已签收”,触发一个条件判断——既然不用提醒,那后续步骤就不要再执行了。
- 把“不提醒”这个决定以合适的语气回复给用户。
如果只是机械地调用工具、把原始结果吐给用户,那就不叫智能体,只是一个“接口封装器”。真正的决策能力体现在:根据上一轮结果动态规划下一轮动作,甚至在发现条件不满足时主动调整计划。
3.2 一个可运行的Agent核心循环:ReAct模式
目前业界最主流、也最适合作为起点的Agent模式是ReAct——Reasoning + Acting,即“思考+行动”的循环。它的流程可以简化为:
- 观察(Observation)当前的用户输入或工具返回结果;
- 思考(Thought)下一步该怎么办;
- 行动(Action)调用某个工具,或者直接给出最终答复;
- 循环,直到任务完成。
下面我用一个非常简化的Python示意来说明这个循环的结构,重点不在于完整实现,而在于理解它的组织方式:
# Agent核心循环(简化示意) import json def run_agent(user_request, tools, max_steps=10): messages = [{"role": "user", "content": user_request}] for step in range(max_steps): response = llm_with_functions(messages, tools=tools) # 如果模型直接给出最终答复,则结束 if response.get("finish_answer"): return response["finish_answer"] # 否则模型会请求调用某个工具 tool_name = response["tool_call"]["name"] tool_args = response["tool_call"]["arguments"] # 执行工具,拿到结果 tool_result = run_tool(tool_name, tool_args) # 把工具结果作为“观察”带回给模型 messages.append({"role": "tool", "content": json.dumps(tool_result)}) return "步骤超过上限,强制退出"这里有几个容易被忽略的工程细节:
- 每轮工具结果都要追加进messages,因为模型下一次决策必须基于上一轮的观察结果,不能丢掉状态。
- 必须设置最大步数,防止Agent陷入死循环,这在真实生产系统里是保命条款。
- 工具结果要结构化成精简文本,别把几十KB的原始JSON全部塞回上下文,那会把模型“淹死”。
3.3 工具怎么设计,决定了Agent的天花板
Agent的能力边界,很大程度取决于你给它配了哪些工具。一个只会写代码、但没法执行代码的Agent,和能编译运行并读取测试结果的Agent,是两种完全不同的生物。
我在设计工具集时有三个原则:
- 接口尽量原子化:一个工具只干一件事。比如“查天气”和“查空气质量”分开,“发送邮件”不做“同时抄送给多人”的复杂参数。粒度越细,Agent按需组装的空间越大。
- 返回结果带状态和错误码:工具不仅要返回数据,还要返回执行成功与否。Agent需要知道“这个动作有没有生效”,才能决定下一步。
- 工具描述必须写清楚适用场景:比如一个“根据产品ID查生产状态”的工具,描述里要写明“当用户询问生产进度或物流发货状态时使用”。描述写得模糊,模型就不知道该在什么时候选这个工具。
3.4 Agent的三个经典翻车场景与规避
- 规划幻觉:模型把任务拆成了能力之外的步骤,比如让它搜索实时信息,但根本没给搜索引擎工具。结果它编造了一个“搜索成功”的结果继续往下走。规避方法:所有子任务必须映射到实际存在的工具,模型输出计划时要做一次“工具可用性校验”。
- 状态丢失:Agent在第三步的时候忘了第一步的结论,导致重复提问或前后矛盾。规避方法:把关键约束在每一轮思考中都重复注入一次,或者用结构化记忆块保存中间结论。
- 错误恢复能力差:工具返回“权限不足”或“查无此单”,模型就愣住了。规避方法:在工具描述中,为常见错误结果提前写清楚后续建议动作。比如“权限不足时,应当向用户说明当前账号没有该操作权限,并询问是否需要更换账号”。
Agent的上限不是模型聪明与否,而是工程化程度有多高。工具设计、状态管理、错误恢复和强制终止条件,这四件事做扎实了,Agent才能真正进入生产环境。
4. 实战选型推演:同一个项目,三种架构的答案完全不同
理论讲得再多,不如推演一个落地的场景来得直观。我们用一个很典型的企业应用来做对比:某企业内部知识库问答助手,用于回答员工关于报销流程、IT支持、人事政策等问题。
4.1 方案A:只用LLM,不加RAG也不做Agent
你把员工的提问直接发给通用大模型,让它回答。
优点:搭建最快,一个小时就能出Demo,成本最低。适应于“公司规章制度变化不大、问题多为通用概念解释”的场景,比如“什么是年假”“报销单要填哪些字段”。
后果也很直接:问“2025年第一季度最新差旅标准”这类涉及具体时效性信息的问题时,模型大概率会给出过期或不准确的答案。更麻烦的是,它可能把A制度里的一条内容,套到B流程的提问上,员工照着做就出错。
结论:适合做演示和低风险场景,不能用于真实的企业制度查询。
4.2 方案B:LLM + RAG,注入制度文档
把公司全部制度、流程文档做好切分、向量化,员工提问时先检索再让模型回答。
这个方案能覆盖大部分真实问答场景,而且有几个看得见的好处:
- 答案可追溯到具体制度原文,员工如果不信,可以附上“来源:报销管理制度第3.2节”。
- 制度更新时,只需要重新索引新文档,不需要动模型。
- 回答“不知道”的时候可以明确说“资料中没有相关内容”,避免瞎编。
代价是你要维护一套文档切分、向量库、检索服务的链路,还要持续做评估优化。但对大多数知识库场景来说,这个复杂度是值得的。
结论:目前性价比最高的方案,是知识库问答类应用的最优起点。
4.3 方案C:LLM + RAG + Agent,加一层“会办事”的能力
在这个场景里,光答问题是不能满足所有需求的。员工除了“问政策”,还希望“办事情”:
- “我的报销单被退回了,帮我看看驳回原因,并起草一份补充说明。”
- “帮我查一下我去年还剩几天年假,如果今年安排了培训,我想约在3月的某个周五。”
这些诉求就不再是“查资料回答”,而是“查数据、写文档、走流程”的组合任务。这时候需要给系统接入公司内部系统,比如OA系统单据查询接口、假勤系统余额接口、日程管理接口。然后让Agent拆解任务、调用工具、逐步完成。
4.4 三个方案的效果对比表
| 维度 | 纯LLM | LLM + RAG | LLM + RAG + Agent |
|---|---|---|---|
| 问题类型 | 通用知识、常识 | 文档知识问答 | 多步骤业务办理 |
| 知识更新 | 需要重新训练 | 更新文档库即可 | 更新文档库即可 |
| 多步操作 | 不支持 | 不支持 | 支持 |
| 工程复杂度 | 极低 | 中 | 高 |
| 典型成本 | API调用费 | 向量库+检索服务 | 工具开发+流程编排 |
| 推荐场景 | 原型、泛聊 | 知识问答、客服辅助 | 业务联动、流程自动化 |
推演到这里你就明白了,选型不是“哪个更高级就选哪个”,而是“根据任务类型选架构”。80%以上的企业对话场景,其实用B方案就够了。为了显得“先进”硬上Agent,反而引入更多不确定性和维护成本。
5. 组合使用与避坑实录:把RAG和Agent真正放进一个系统里
最后聊一个我实践中反复使用、也反复踩坑的架构:Agent外部挂RAG,RAG内部养Agent。这句话听起来玄乎,拆开讲就很清楚了。
5.1 两种组合方式:外挂式与内嵌式
第一种组合是“Agent作为主控,RAG作为工具”。Agent负责理解用户目标、拆解任务,RAG作为其中一个子能力被调用。比如用户说“写一篇关于公司年度团建方案的提案”,Agent先规划,然后调用RAG检索公司往年的团建记录和预算制度,再结合LLM的文案能力生成完整提案。
第二种组合是“RAG作为主链路,Agent作为深度追问处理器”。先走RAG答一轮,如果模型判断“资料不足以回答”,就触发Agent去查关联系统、做多步检索、回来整合答案。这种设计适合文档库很大、且经常需要跨多个文档综合回答的场景。
两种组合不冲突,关键看谁当主控。我的经验是:对多数应用,让Agent当主控更自然,因为它能自主决定“什么时候该查、该查什么、查完以后怎么处理”。
5.2 上下文窗口的分配:这个坑我进过三次
把RAG和Agent组合起来后,最大的坑是上下文窗口不够用,而且不够用的方式和你想的不一样——不是“塞不下”,而是“塞进去但模型处理不过来”。
一个Agent流程可能有8到10轮工具调用,每轮的工具结果都要留在上下文里,加上RAG检索回来的文档块,Tokens消耗非常快。更麻烦的是,模型在大量历史信息中生成最终答案时,早先的观察结果的“记忆权重”会被稀释。
我采用的三个对策:
- 中间过程摘要化:每完成一个子任务,把详细执行结果压缩成一段摘要再放回上下文,原始结果存外部存储,不占据上下文空间。
- 上下文窗口预留配额:专门为RAG结果预留窗口空间,比如总窗口是32K tokens,最多只允许RAG部分占8K,超出则做摘要或分批处理。
- 分阶段对话:超长任务拆成多个短对话,每个对话重新建立上下文,关键信息通过结构化笔记跨阶段传递。
5.3 评测是组合架构的“逃生舱”
RAG和Agent组合起来后,链路变长,任何一个环节出错都会导致最终结果不对。这时候没有评测体系,排查问题无异于大海捞针。
我的做法是建立三层评测:
- 单环节评测:单独测检索命中率、工具调用正确率、任务拆解合理性,每个环节独立打分。
- 端到端评测:用一个包含200条真实业务问题的问题集,跑完整链路,人工或模型打分。
- 回归评测:每次更新文档、换模型、改Prompt后,跑一遍同样的测试集,对比分数变化。这一步能帮你及时发现“改了这个,影响了那个”的隐形连锁反应。
没有评测体系的RAG+Agent系统,就像一个没有仪表盘的飞行员——飞得起来,但永远不知道什么时候会出事。
5.4 另一个容易忽略的问题:多轮对话的记忆边界
很多人在组合架构里栽在“多轮对话”上:用户第一轮说“帮我查一下上海出差补贴标准”,第二轮说“那杭州的呢?”——如果系统没有把“出差补贴标准”这个主题跨轮保存下来,第二轮的“那杭州的呢”就变成了一个孤立的问题。
处理办法是给每个用户会话维护一个“对话记忆槽”,把用户的目标、关键实体、已经确认的条件以结构化字段存下来。每一轮处理时,把记忆槽内容和当前问题一起发给Agent。注意,这个记忆槽是一个离散的、结构化的信息块,不是把历史聊天记录整个拼进Prompt。
5.5 成本控制:组合架构烧钱烧得比你想象快
最后提醒一个务实的问题——成本。RAG+Agent的组合,单次用户请求的Token消耗量,往往是纯LLM方案的5到10倍。原因是:多轮工具调用会产生大量中间结果,检索到的文档块也占Token,最终的汇总输出反而只占一小部分。如果不做成本控制,一个To C产品上线后,光是模型调用费就能吃掉相当可观的利润空间。
我能给出的实操建议是:
- 对每个Agent任务设定工具调用次数上限,比如最多5次,超出则强制收敛到“基于已有信息回答”。
- 对不同的任务类型使用不同规模的模型——简单问答用轻量模型,复杂规划才用大模型。
- 建立Token消耗的按会话监控,出异常及时干预。
一些真正落地的体会
把LLM、RAG和Agent放到同一个工程体系里,我最大的感受是:概念边界越清晰,工程落地越从容。很多项目烂尾不是因为技术不够新,而是从一开始就把“知识检索”和“任务执行”混为一谈——该用RAG的地方非要上Agent,该用Agent的任务偏偏只接了个Prompt。选型之前,先问清楚自己的业务问题到底是“不知道”还是“不会做”,答案自然就浮出水面了。
最后分享一个我最近常挂在嘴边的小技巧:当团队为一个功能应该用RAG还是Agent争论不休时,让他们各自用一句话回答“这个功能的核心是获取信息,还是执行动作”——如果语气偏向获取信息,就规规矩矩走RAG;如果偏向执行动作,再谈Agent的规划链。大多数争论,到这一步就散了。