资讯动态

大模型、RAG与智能体:三者关系与最小实现解析

发布时间:2026/10/20 18:04:56 来源:尧图企业网站定制
大模型、RAG、智能体这三个词最近几乎天天见。真要问一句这三者到底是什么关系能立刻说清的人其实不多——包括不少已经在写代码的开发者我自己也在这个问题上绕了很久。明明已经有大模型了为什么还要搞RAGAgent跟调API有什么区别三个概念是并列的还是上下层的关系这篇文章就围绕这三个问题展开把LLM、RAG、Agent的定位、分工、协作方式和落地选型拆开讲透最后还会给一套能直接跑通的最小实现。适合刚接触AI应用开发、或者已经在做知识库问答和自动化任务但概念还比较模糊的朋友。1. 三个概念各自的定位大脑、资料库与行动者先给结论LLM、RAG、Agent并不是同层级的概念它们分别扮演“大脑”“资料库”“行动者”的角色。把这三层关系理清了后面所有技术讨论都会变得很简单。1.1 LLM大模型能说不代表知道大模型Large Language Model本质上是基于海量文本训练出来的语言生成模型核心能力是理解和生成自然语言。它见过数万亿字符的语料能续写句子、总结文章、翻译、写代码甚至能做一点推理。它像是一个“博学但容易记混”的顾问——你问什么它都能接上话但它的知识有两个硬伤第一个硬伤是知识截止时间。训练数据只覆盖到某个时间点之后发生的事情它根本不知道。你问去年的行业数据它大概率只能靠猜。第二个硬伤是幻觉。因为它本质上是“预测下一个最合适的词”而不是“检索事实并告诉你”所以它经常一本正经地编造内容——给出看起来合理、实际是编的数字和结论。所以我说“能说不代表知道”。LLM像那种考场上不带教材、纯靠脑内记忆答题的学生平时成绩不错但遇到没背过的知识点就开始自由发挥。这就是为什么后面需要RAG。1.2 RAG给模型配一个随查随用的资料库RAG全称Retrieval-Augmented Generation翻译过来是“检索增强生成”。思路特别直白不要让模型凭记忆答题而是先从你自己的资料库里检索出相关内容把检索结果塞进提示词里再让模型根据这段材料作答。可以把它想象成“开卷考试”。你带着一本资料库进场遇到问题时先翻资料找到相关段落再结合这些段落组织答案。RAG要做的事情就是保证你在“开卷”的时候能快速翻到正确的那一页并且不会把资料上的内容记错。具体拆开看RAG有三个阶段索引阶段把文档切成小段chunk每一段做向量化存到一个向量库里。这里有个关键参数叫“分块大小”后面实操部分我会专门讲。检索阶段用户提问时把问题向量化去向量库里做相似度搜索返回最相关的Top N个片段。生成阶段把检索到的片段和用户问题一起拼进提示词里交给LLM生成回答。为什么最近RAG这么火有两个原因一是它能直接解决LLM“不知道近期信息”和“幻觉”的问题——你不知道的事我把资料查出来喂给你你照着说就行二是它比微调便宜太多——数据要更新只需要重新切片、重新构建索引完全不用训练模型。1.3 Agent智能体把“会说话”变成“会干活”Agent中文叫智能体本质是一个“感知-规划-行动-观察”的循环。它把LLM当成推理引擎不仅要回答问题还要完成多步骤任务理解目标、拆解步骤、调用工具、读取结果、再决定下一步做什么。最简单的Agent循环是五步接收任务比如“帮我调研一下这个行业近期的政策变化”用LLM做任务拆解第一步搜索信息第二步整理要点第三步输出报告调用工具搜索API、数据库查询、代码执行器、计算器等观察工具返回的结果判断是否已经完成目标没有完成就继续规划下一步完成了就输出最终结果举一个生活中的例子。你让助理去安排一次出差助理要查航班、比价格、看你的日程、预订酒店、最后发你一份确认单。如果助理只会“回答”那它只能说“你有出差需求”但“会行动的助理”会把这件事拆解成多个子任务并且一步步做掉。Agent就是那个“会行动的助理”LLM负责思考工具负责执行RAG负责提供参考材料。2. 三者如何组合从问答到自动化任务搞清楚各自定位后怎么把它们组合起来就是一个工程问题了。这一节我讲讲我实际搭建系统时用到的三层结构以及两个组合到底解决什么问题。2.1 一套通用的三层结构我在做实际项目时习惯把系统拆成三层从上往下看是执行层Agent、增强层RAG、基础层LLM。基础层是LLM所有语言理解和生成都走它。增强层是RAG负责把外部知识、私有文档接进来解决“LLM不知道的”问题。执行层是Agent负责拆解任务、调用工具、串起流程。这个分层不是随便拍的好处有三个每一层都能独立替换每一层都能单独测试出问题时能快速定位是哪一层出了毛病。比如回答不准确先查RAG的检索结果质量比如流程走不下去再查Agent的循环逻辑如果模型本身生成质量差最后才去评估LLM选型。2.2 “LLM RAG”就够了很多场景确实只需要这两层就够了。典型场景是知识库问答、文档审核、客服应答。这类任务的特点是单轮或者多轮对话需要引用外部资料但不需要频繁调用外部系统。我自己做过一个客服工单助手用户提问后系统先检索历史工单和知识库再让LLM基于检索结果生成回复。当时没有引入Agent因为用户的诉求是“快速得到标准回答”。这种情况下如果再套Agent循环只会增加响应延迟和成本并不会提升体验。所以“LLM RAG”组合的关键词是“回答得好”。它适合已经拥有文档内容、只要问与答就能解决问题的场景。通常一个API接口就能搞定全部逻辑。2.3 “LLM Agent”能干什么反过来有些场景不需要外部知识库但需要完成多步骤动作。典型的是数据分析助手用户说“帮我把销售数据按季度汇总并输出趋势”这时候你需要调用数据库查询工具可能还要执行一段Python代码来做计算最后生成图表描述。这些操作每一步都依赖前一步的结果光靠一次LLM调用是完不成的必须有一个Agent循环来控制节奏。再比如代码生成工具用户提需求Agent拆成“生成函数-运行测试-修复错误”三步每次调用LLM生成代码再在沙箱里执行执行失败就把报错信息反馈给LLM让它自己修。这类场景里知识库并不是核心矛盾核心矛盾是“多步决策和工具使用”。所以你看到差距了吗RAG回答“是什么、怎么做”Agent解决“谁来一步步做完”。两者解决的问题不同自然不是替代关系。2.4 一张表看完三者的区别我用一张表总结方便你对照查阅。维度LLM大模型RAGAgent智能体定位能力底座知识增强任务执行解决的核心问题语言理解与生成知识时效、幻觉、私有知识接入多步任务拆解与外部工具调用输入文本提示词文档库 用户问题目标任务 工具集合输出文本带引用来源的回答动作序列 最终结果是否需要训练需要预训练不需要训练不需要训练核心组件参数化模型向量库 检索器循环控制 工具注册表典型场景对话、翻译、写作知识库问答、文档总结自动化流程、数据分析助手这张表的核心是LLM是底层RAG是数据通路Agent是上层控制逻辑。现实里完整的系统通常三者都要用只是各自的权重不同。3. 落地选型拿到需求后先别急着上Agent我见过很多团队产品需求刚提出来就准备上Agent结果项目推进到一半发现大家都在调循环不到头的死逻辑而最初的业务问题用一个简单的RAG接口就能解决。这一节分享我踩过坑之后总结下来的选型思路。3.1 三个判断问题和一个决策表拿到需求后我通常先问三个问题这个问题是否依赖非公开资料如果答案是“是”那你很可能需要RAG。比如“根据内部年报回答毛利率变化”模型没见过这份年报不可能答对。这个问题是单次问答还是要分多步、调外部系统如果答案是“多步”需要Agent。比如“对比两个竞品文档并生成分析报告”要多次检索、多次生成、整理结构。这些资料是否会频繁更新如果经常更新RAG的优势就非常明显——你只需要换索引不需要动模型参数。根据你三个问题的答案组合就可以快速定位方案依赖外部资料多步骤/工具调用推荐方案否否LLM 好一点的提示词是否LLM RAG否是LLM Agent是是LLM RAG Agent最后一种最复杂但也是目前最能解决实际问题的架构。比如让一个智能体去完成“搜索最近三个月的文献-提炼核心观点-生成对比报告”这类任务它需要RAG提供资料更需要Agent来控制流程顺序。3.2 最小可用组合的成本对比很多初学者忽略成本我在这里提一句。假设同样的任务量单纯LLM调用是成本最低的因为只有一次请求。LLMRAG多了一次向量化检索的开销但响应准确性明显提升综合性价比通常最高。LLMAgent成本最高因为一次任务可能触发很多轮LLM调用每轮都有Token消耗还有工具调用耗费的时间。我做项目时的经验是先用LLMRAG快速跑通业务验证再逐步把流程中确实需要“判断下一步”的环节换成Agent。这样项目前期成本可控出成果快也容易给团队信心。3.3 数据流视角一次完整的AgentRAG任务会经过哪些环节从数据流看三者协作关系其实是一条清晰的链路用户输入任务后Agent先做任务解析把大目标拆成子任务。某个子任务需要知识支撑时Agent才会触发RAG检索拿到相关资料。资聊进入提示词交给LLM生成中间结果。Agent检查这个中间结果如果结果已经满足目标就输出如果不满足就再规划下一个动作——可能是再查一次资料也可能是调用一个计算工具。整个过程会循环多次直到出现明确的完成信号。这里的核心设计是“Agent把RAG当成自己可调用的一个工具”。RAG负责的是“信息输入”Agent负责的是“决策循环”。4. 最容易踩的坑和排查心得概念理解了代码写起来也会有各种想当然的坑。这一节我梳理了三类认知误区和四个高频翻车场景都是我自己实际调试时遇到的问题。4.1 三个高频认知误区误区一RAG就是Agent。这个错误最常见。RAG本质上是一种“检索生成”的技术模式它没有“循环决策”的概念也不调用工具。Agent是一种完整的任务执行系统它可能需要RAG来取资料但RAG本身并不代表Agent。误区二有了Agent就不需要写提示词了。反了。Agent的效果高度依赖提示词设计尤其需要写清楚系统指令什么时候调用工具、工具调用的输出格式是什么、什么情况下算任务完成。这部分如果没写好Agent循环很容易失控。误区三做RAG不如直接微调。两者解决的不是一个问题。微调改变的是模型的行为风格和特定能力像是让一个人“说话更专业”RAG改变的是模型的知识来源像是给他配了一套随时更新的笔记本。对大多数企业级应用来说RAG的投入产出比远高于微调。4.2 四个实战翻车场景场景一检索召回质量差。症状是LLM回答“找不到相关信息”。我排查后发现问题出在分块策略上——文档被切得太碎语义被切断向量检索自然抓不到重点。后来我根据文档结构按章节切块并且把chunk之间加了一段重叠文本召回率明显提升。场景二Agent死循环。症状是Agent反复调用同一个工具永不给出最终结果。原因是任务拆解时出现了重复的子目标。我用最大迭代次数兜底前几次先限制在3轮以内并且在系统提示词里强制要求“完成时输出[完成]标记”等流程稳定之后再逐步放开迭代上限。场景三上下文膨胀。有些实现会在每轮循环里把全部历史记录都塞进提示词导致Token消耗翻倍回答也变得啰嗦。后来我做了只保留最后两轮消息和检索摘要的优化效果立竿见影。场景四知识库更新没生效。症状是明明换了资料回答还是旧内容。排查后发现是缓存问题——向量库索引没有重建。后来我把“数据变更-触发重建索引-校验版本号”这一步写进了发布流程才彻底解决。4.3 问题排查速查表现象大概率原因优先排查动作回答不准确检索召回差/分块不合理检查Top K命中结果调整切片策略回答一本正经胡说相关资料没被检索到加大top_k或优化查询词Agent反复调用工具任务拆解出现循环加最大迭代数写明完成条件响应速度慢Agent循环次数太多精简子任务减少工具调用轮数知识更新不生效索引未重建检查向量库版本与索引更新时间成本飙升每轮历史消息过多裁掉冗余历史只保留关键上下文这张表我后来直接打印出来贴在工位上。排查问题的时候我先按表里的顺序找基本没有空转过。5. 手写一个最小可跑的Agent RAG系统说再多概念不如跑一段能动的代码。第五部分我手写一个最小实现不依赖任何重量级Agent框架只靠最基础的三样东西一个本地HTTP接口的大模型服务、一个用numpy实现的向量存储、一个自己写的Agent循环。看完你就能明白它们是怎么协作的。5.1 我的简化方案整体设计是本地启动一个兼容OpenAI接口格式的模型服务提供一个embedding接口和一个chat接口。代码部分负责三件事调用embedding接口给文档切片做向量化把向量存在一个简易的列表里查询时用余弦相似度排序写一个Agent循环在每一步先检索相关资料再让模型决定是输出最终答案还是调用工具。所有代码都是演示级别的不追求生产级性能但逻辑足够完整。你可以把“本地HTTP接口”替换成任何你常用的模型API向量存储换成任意开源向量数据库这样就能无缝迁移到真实项目里。5.2 关键代码检索、工具与Agent循环先看基础工具函数。下面是调用本地模型接口的代码import requests import numpy as np import re EMBEDDING_URL http://127.0.0.1:8080/v1/embeddings CHAT_URL http://127.0.0.1:8080/v1/chat/completions API_KEY local-key def get_embedding(text: str): resp requests.post( EMBEDDING_URL, json{model: local-embedding-model, input: text}, headers{Authorization: fBearer {API_KEY}}, ) return resp.json()[data][0][embedding] def chat(messages): resp requests.post( CHAT_URL, json{model: local-chat-model, messages: messages}, headers{Authorization: fBearer {API_KEY}}, ) return resp.json()[choices][0][message][content]然后是自己实现的简易向量存储。它能把文档切片存进去并在查询时返回最接近的Top K片段class SimpleVectorStore: def __init__(self): self.chunks [] self.vectors [] def add(self, chunk: str): self.chunks.append(chunk) self.vectors.append(get_embedding(chunk)) def search(self, query: str, top_k: int 3): qv np.array(get_embedding(query)) scores [] for i, vec in enumerate(self.vectors): sim np.dot(qv, vec) # 简化余弦相似度向量已归一化 scores.append((sim, i)) scores.sort(reverseTrue) return [self.chunks[i] for _, i in scores[:top_k]]接着是工具解析和执行部分。这里我用一个简单的计算器工具作为示例Agent在回复中如果带上了[工具]标记系统会解析并执行工具再把结果反馈给模型TOOL_PATTERN re.compile(r\[工具\]\s*(\w)\s*\|\s*(.*)) def parse_tool_call(text: str): match TOOL_PATTERN.search(text) if not match: return None return match.group(1).strip(), match.group(2).strip() def execute_tool(tool_name: str, param_text: str): if tool_name 计算器: allowed set(0123456789-*/.() ) if not all(c in allowed for c in param_text): return 不支持的表达式 try: return f计算结果为 {eval(param_text)} except Exception as exc: return f计算出错: {exc} return 未注册的工具这里要提醒一句eval直接执行表达式有安全风险上面的白名单和try-except只能抵御最基础的异常生产环境一定要使用安全的表达式解析方案或者把工具执行放到沙箱里。我这里只是为了演示工具调用的循环机制。最后是Agent主循环。它的设计逻辑是每轮先做RAG检索把检索结果拼到系统提示词里然后让模型回复。如果回复包含工具调用执行工具并回填结果如果回复包含完成标记则结束循环def run_agent(task: str, store: SimpleVectorStore, max_steps: int 5): messages [ { role: system, content: ( 你是智能助手。你需要根据资料回答问题也可以调用工具完成计算。 需要调用工具时使用格式: [工具] 工具名 | 参数。 完成最终回答后必须以[完成]结尾。 ), }, {role: user, content: task}, ] for step in range(max_steps): # 每一轮先做RAG检索 docs store.search(task, top_k3) context \n.join(docs) retrieved_messages [ { role: system, content: f以下是可参考的资料。如果资料与问题无关请忽略。\n{context}, } ] messages reply chat(retrieved_messages) print(f[第{step 1}步] 模型回复: {reply}) tool_call parse_tool_call(reply) if tool_call: name, param tool_call result execute_tool(name, param) print(f[工具] {name} 返回: {result}) messages.append({role: assistant, content: reply}) messages.append( { role: user, content: f工具返回结果: {result}\n请继续完成回答并以[完成]结尾。, } ) elif [完成] in reply: return reply else: messages.append({role: assistant, content: reply}) messages.append( {role: user, content: 请给出最终结论并以[完成]结尾。} ) return 达到最大步骤数任务未完成主流程里我把三份简短的“公司资料”放进向量库然后给Agent一个既要检索资料、又要调用计算器工具的任务if __name__ __main__: store SimpleVectorStore() store.add(公司2025年第三季度实现营收18.6亿元同比增长21%。) store.add(公司第四季度发布新一代智能客服产品。) store.add(2025年全年预期营收目标为70亿元目前完成率良好。) task 根据资料回答公司2025年第三季度营收是多少再把这个数字乘以2告诉我结果。 final run_agent(task, store) print(最终结果:, final)5.3 运行效果与调参观察这个任务跑起来后你会看到类似这样的输出[第1步] 模型回复: 根据资料2025年第三季度营收为18.6亿元。[工具] 计算器 | 18.6*2 [工具] 计算器 返回: 计算结果为 37.2 [第2步] 模型回复: 公司2025年第三季度营收为18.6亿元乘以2的结果是37.2亿元。[完成] 最终结果: 公司2025年第三季度营收为18.6亿元乘以2的结果是37.2亿元。第一次运行时我特意观察了它的“步骤感”你会发现两步之间模型做了一个决策先检索资料拿到原始数字再决定调用计算器工具执行运算。这就是Agent循环最核心的价值。调试时我建议你改三个参数观察差异把top_k改成1大概率会检索到不太相关的切片回答质量下降改成5虽然更全但上下文变长模型容易分心。3到4通常是比较稳的值。把max_steps改成1Agent就没机会调用工具只能回答“我不知道怎么乘”。这个实验能直观地让你感受到循环的重要性。在store.add里加入更多片段观察切片数量和内容对检索排序的影响。6. 一点个人体会我自己在这个问题上绕了不少路最后真正把我讲清楚的反而是亲手写了一遍这种几层结构。纸上谈概念很容易代码一跑模型的每一步输出都会提醒你“它到底缺了什么”没有RAG的时候它就瞎编没有Agent的时候它就停在一问一答拼起来之后才看得出系统怎么从“会被动说话”变成“能主动干活”。如果你正在做类似项目我的建议是别一上来就堆复杂的Agent框架。先拿一个提示词加一次RAG调用跑通业务闭环看看模型哪里还不够再决定要不要引入循环和工具。框架永远只是封装真正容易出问题的还是数据质量、检索效果和任务拆解方式——这些环节值得你把时间花在它们身上。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑