你是不是也遇到过这样的情况想用大模型做点实际的事结果它要么答非所问要么一本正经地编造数据库里根本不存在的订单记录要么明明说我可以帮你查天气却一步也动不了。这几年我在集成大模型时几乎所有问题都绕不开四个核心概念——Agent、RAG、Function Call、MCP。它们听起来像四个独立的黑话实际上配合起来就是一套完整的让模型真正干活的方案模型负责思考RAG负责喂知识Function Call负责动手操作MCP负责把各种工具统一接口接进来Agent则把前面的所有能力串成循环。这篇文章把我自己的理解、踩坑和落地经验一次讲清楚不绕概念只讲怎么理解、怎么选、怎么用。如果你正准备把大模型接进自己的产品、搞一个能干活的应用或者只是想知道这些技术名词到底解决什么问题这篇都适合你。下面按我个人的理解逻辑来展开。1. 先把四件事的边界画清楚谁在干什么活很多教程喜欢一上来就堆术语Agent是智能体RAG是检索增强生成Function Call是函数调用MCP是模型上下文协议。术语背完了仍然不知道什么时候用哪个。我个人的理解是这四个东西根本不在一个维度上它们解决的是不同层次的问题硬拉在一起比高低是比不出结果的。我习惯用一个类比来记。假设你要带一个刚入职的实习生做事RAG是给他配一个资料库。他的记忆不行不可能背下整个公司的文档但他可以随用随查查完再回答。对应到技术上就是让模型从外部知识库里检索信息再结合检索结果生成答案。Function Call是给他配一个行动清单。你不能让实习生凭空替你关单、退款、发邮件你只能告诉他如果你需要关单就调用关单系统如果需要退款就调用退款系统然后他自己决定要不要用、怎么调。Agent是给他配了一套工作流程加上复盘机制。实习生不会只回答你一个问题就结束他需要拆解任务、调用工具、看结果、再规划下一步直到任务完成。MCP是统一了接入外界工具的插头标准。实习生不可能为每一家公司的系统都学一套操作方式最好所有系统都长成同一个插座形状他按一个标准就能插上去用。顺着这个思路再看技术四个词的关系就清楚了。RAG管的是输入侧的补充Function Call管的是输出侧的落地MCP管的是工具的接入方式Agent管的是整个流程的组织与循环。前两者是能力后两者是架构。能力决定模型能做什么架构决定你接得多顺。技术解决问题你可以理解为主要处理阶段RAG模型不知道、记不住、会编造外挂知识库输入侧Function Call模型只能聊天不能动手方法的调用清单输出侧Agent单次调用不够需要多步闭环带循环的调度器全流程MCP每个工具一个接入方式维护成本高标准插头与插座工具接入理解了边界之后下文逐个展开并且会把我实际遇到的那些文档里绝不会写的问题一起说出来。2. RAG模型记不住的东西交给外置知识库RAG全称叫检索增强生成。名字很绕本质其实很朴素不要指望大模型背下你的私有资料你应该先从一个知识库检索出相关片段拼接成上下文再让模型基于这段上下文给出答案。我是在做一个企业内部文档问答系统时第一次正经用RAG的之前以为随便找个向量数据库就行真正做到好用才发现问题全在细节里。2.1 一条问答请求经历了什么一次完整的RAG请求大致分两段。第一段是离线的索引阶段把文档切分成块每块调用嵌入模型转成向量存进向量数据库里。第二段是在线的问答阶段用户问一句话先把这句话转成向量然后用相似度在数据库里召回最相关的若干块把这些块拼进提示词里告诉模型这是参考资料请基于参考回答不要编造。切片大小是第一个要决策的参数。我在做那套文档问答时一开始拿了整页文档当一块去嵌入结果检索回来的往往是一个巨大的文本块真正的答案只占其中一小部分生成的回复就会被无关内容带偏。后来把切片调小又发现上下文碎片化严重——一个问题需要跨多个块才能拼出完整的答案逻辑。到目前为止我习惯的做法是先观察文档的最小组织单位如果是规范文档按章节或条款切如果是问答型知识库按单条问答对切。块之间的重叠也值得加我一般设置80到150字符左右的重叠避免关键句刚好被拦腰切断。2.2 召回之后的上下文编排才是重头戏检索回来的块不能无脑塞进去。顺序很重要相关度最高的应该放在最靠近问题的地方来源标注也很重要让模型能区分几个不同来源之间的内容而不是把互斥的说法混在一起。我在实际项目里见到一个经典问题用户问退货政策是什么知识库里两条不同版本的规则都被召回了模型直接来了个根据制度A和制度B退货分为两种实际上B已经是过时版本。这个问题的解决方案需要一部分靠索引时给文档增加版本元数据在召回前先过滤另一部分靠提示词里明确如果多个来源冲突优先引用带更高优先级标记的来源。另一个经验是RAG的提示词里一定要写如果参考资料不足以回答直接说不知道。不写这句模型哪怕检索结果为空也会维持它的回答惯性编出一个很像那么回事的答案。我自己实测过同样的问答系统加上这句之后无依据回答的比例明显下降。这不是模型变聪明了只是你把它的行为边界划清楚了。2.3 做工程时的成本与性能取舍向量检索不是免费的。嵌入有成本数据库有成本但最容易忽略的成本是上下文膨胀——每次请求都多塞几千个token。我做在线问答服务时做过一轮优化核心思路是不是所有问题都需要召回。简单的、通用的、高频的问题完全可以让模型直接回答只有涉及内部制度、具体数字、操作流程时才走检索链路。为了做到这一点我在入口加了一道意图判断先让模型判断问题是否涉及需要查知识库的实体词汇比如某个系统名、某个制度名再决定是否触发召回。召回后的排序层也值得加。单纯靠向量相似度排前几名的结果往往语义接近但并非答案所需。我后面在召回结果上接了一个轻量的重排序模型把向量召回的前20条重新精排成前5条。这一步会多几十毫秒延迟但回答准确率提升非常明显。再配合一个简单的缓存完全相同的用户问题在24小时内直接走缓存结果不重新召回能省掉不少重复计算的费用。3. Function Call从会聊天到会办事的那一步大模型本身不会打开你的数据库不会调你的接口不会改你系统里的状态。想让模型办正事最直接的方式就是Function Call你先把系统里能做的事情列成一个清单给模型模型在回答时从清单里挑一个返回结构化的调用参数你的程序再真正去调用并拿到结果最后把结果塞回对话。我把这一步视为大模型从嘴强王者转变成行动派的分水岭。3.1 模型是怎么知道该调哪个函数的你告诉模型一个函数不是用自然语言讲你帮我查个订单而是要给它一份标准化的描述。我常用的做法是把工具清单写成JSON Schema格式。下面是一个简化的例子{ functions: [ { type: function, function: { name: query_order, description: 根据订单号查询订单详细信息包括状态、金额、物流进度。, parameters: { type: object, properties: { order_id: { type: string, description: 用户提供的订单编号格式为十位字母数字。 } }, required: [order_id] } } } ] }模型拿到这个清单后会在响应里返回一个特殊的函数调用消息告诉你我决定调用query_order参数是order_idxxx。注意模型本身不会真的去执行这个函数模型只是表态真正执行的是你的业务系统。这个边界一定要记清楚否则你会陷入为什么模型说查了单却查不到的困惑。最让我头疼的是如何写好description字段。模型做函数选择时很大程度上不是在理解函数逻辑而是在理解你的工具描述。有一次我写的描述是获取订单列表的接口参数里又没有限制必须带用户ID模型经常空着参数就调用导致返回全量订单线上直接慢查询。后来我把描述改成根据具体用户的ID获取该用户的订单列表必须先完成用户身份确认每次只能查询一个用户模型立刻收敛多了。这让我意识到描述就是另一种形式的提示词你不能指望模型看穿你的函数实现它只看你写在description里的话。3.2 多步调用里的结果回填Function Call看上去是一次模型提出调用→系统执行→返回结果但在真实对话里这个流程远不止一轮。用户问的往往是复合任务比如帮我查一下昨天的订单然后把地址改了。模型很可能需要先调查询接口拿到订单号再根据订单号调修改接口。这时候系统要维护一个循环模型提出调用 → 程序执行 → 把结果作为新消息追加进对话上下文 → 再次请求模型 → 模型根据结果决定是继续调下一个函数还是直接生成最终回答。我自己曾经在这种多步调用里犯过一个低级错误没有把上一步的函数执行结果拼进下一次请求导致模型第二次调用时拿不到必要的中间信息反复请求同一个函数把上下文刷得又长又乱。排查了半天才发现是上下文丢了。多轮Function Call最容易踩的坑不全在模型而在你自己的上下文管理。当函数执行结果很长——比如一张包含几十个字段的订单表——你要考虑把结果截断、汇总或转成简洁的文本摘要再拼回去否则多轮迭代会快速消耗上下文窗口。3.3 模型选错函数的那些诡异情况Function Call在实际使用中模型偶尔会做出完全离谱的选择。有一次我的工具集里既有查询快递轨迹又有生成退款标签用户问帮我看看快递到哪了模型居然选了退款标签。我后来排查发现问题的根源是工具描述里带了太多没有明确定界的词比如售后这个词同时出现在两个工具的description里模型就迷糊了。解决办法就是给每个工具加清晰的使用边界甚至可以在描述里写清楚仅当用户明确表达退款意愿时才调用本函数查询物流进度请使用另一个函数。这类问题不涉及模型层修改纯靠优化工具描述就能解决一大半。还有一类问题是参数类型不严格。模型返回的参数偶尔会类型错乱比如数字当成字符串返回日期格式来回变。我在业务系统里加了一层参数校验和清洗所有模型返回的参数都要过一次类型规范化不符合要求的主动让模型重新生成或提示用户补充绝不假设模型返回的一定是合法参数。4. 智能体Agent把单次调用变成闭环循环如果你把RAG当作让模型有知识把Function Call当作让模型能动手那么Agent就是在外面套了一层思考-行动-观察的循环机制。它解决的痛点是一个任务往往没法一次函数调用搞定模型需要像人一样先看任务、拆步骤、用工具、看结果、调整方案直到任务结束。很多人对Agent有误解以为它是一个什么特殊的模型实际上它是一个工程架构。底层模型可以是同一个模型只是你把它放进了一个带循环的调度框架里。4.1 核心循环结构规划、执行、观察、再规划我在搭建Agent时最常用的结构是经典的ReAct模式先把用户请求告诉模型模型给出下一步要调用的工具和参数程序去执行工具然后把执行结果作为观察喂回给模型模型再决定下一步动作。这个过程会一直循环到模型认为任务完成或者直到我们设定的终止条件。理解这个循环是理解Agent的关键因为它决定了Agent的成败不在某一轮的聪明与否而在你对循环的控制能力。一个完整的Agent请求链路大概是这样的用户提出帮我查所有未发货的订单并给每个订单生成催发货记录。Agent需要先调用一个查询工具获取未发货订单列表这个结果可能是一大串数据模型要能把这些数据处理成合适的输入再决定是否需要逐个调用另一个工具或直接批量生成记录。每一步都会消耗对话上下文如果中间结果太长还要压缩中间信息——我给自己的框架里加了上下文裁剪器当某轮观察结果超过一定长度时让模型先生成一个摘要再用摘要继续后续步骤。4.2 工程上真正的难点不要让它无限循环网上演示的Agent看起来很酷但真实的Agent跑起来最常见的问题是循环失控。我出现过最夸张的一次模型在一个工具上连续重试了十几次因为执行结果永远是鉴权失败模型不理解为啥失败一遍一遍用同样的参数重试白白烧掉大量token。从那以后我在Agent框架里加了几条硬性护栏。最大轮次限制。无论是单次Agent运行还是整个对话流程都要设一个最大循环步数我一般设为8到10步超过直接终止并转人工或自动给用户答复这件事我们需要进一步处理。工具调用失败要转化成可理解的反馈。不要把一串异常堆栈直接丢给模型它会越看越糊涂。要先清洗成参数校验不通过原因订单号格式错误模型才知道换一种方式处理。拒绝执行的红线也要写进系统提示词。比如不允许Agent调用某些危险操作不允许删除类工具在没有用户二次确认时执行。工程上不能只靠模型自觉要在工具层干脆不暴露这些能力。4.3 记忆把多轮对话变成连续工作Agent的另一个关键词是记忆。短期记忆就是上下文本身但如果你做一个客服Agent用户第一天问了一半第二天接着问短期记忆就失效了。我在实际项目里会单独维护一个状态缓存把对话过程中已经查到的重要信息订单号、用户ID、问题分类抽取出来存进结构化字段下次同一用户进来时直接拼接进系统提示词而不是依赖闲聊式记忆。这样既省上下文又稳定。更复杂一点的长期记忆方案可以将来做成向量召回但普通业务场景里先做结构化收益已经非常可观。从经验来看Agent的效果取决于你对流程的理解而不是模型能力。把一个大而模糊的目标拆成小步骤每一步做什么、返回什么、边界在哪都要在提示词和工具定义里预先铺好。模型只是在你铺好的轨道上跑轨道铺得越清晰Agent跑得越稳。5. MCP把工具接成一排标准插座说完了Agent和Function Call必须聊MCP。MCP全称是模型上下文协议。这个概念的出发点非常朴素工具接得越来越多每个工具都要做一套定制化的接入烦死了。今天你接一个订单系统明天接一个CRM后天接一个物流接口每个系统的鉴权方式、数据结构、参数格式都不一样每接一个就要写一堆胶水代码。MCP要做的事情就是把接入工具这个动作标准化工具方实现一个MCP服务端应用方用MCP客户端去连模型通过这个统一的协议拿到工具清单并调用。像什么像USB-C接口取代一堆乱七八糟的充电口。5.1 MCP的三个角色MCP架构里通常有三个角色MCP客户端跑在你的应用侧MCP服务器负责把真实工具封装成规范化接口远程服务是真正干活的业务系统。一个MCP服务器可以暴露三类能力给模型工具、资源和提示模板。工具就是可以调用的动作资源是外界可供读取的数据提示模板是预设好的常用问题或操作流程。大多数场景下你关注的第一类是工具就够了。我自己最直观的一次体验是把几个业务系统的工具全部封装进统一的MCP服务器之后客户端只需要一份配置声明连接哪个服务器、列出哪些服务、叫什么端口、鉴权用的密钥从哪个环境变量取。剩下的分布操作都像是把工具文件夹丢给模型自己挑。这极大降低了集成开发时的重复劳动。一个简单的MCP客户端配置概念看起来像这样{ mcpServers: { order_system: { type: sse, url: https://example-mcp.internal/service, headers: { Authorization: Bearer ${MCP_TOKEN} } } } }这是一个典型的配置即接插的场景。接入新工具时最繁重的工作不再是写胶水代码而是把工具的参数、返回值和语义写成协议要求的格式这比重新设计一套调用层清晰得多。5.2 它和其他三者的关系很多人学到这里会问MCP会不会取代Function Call我的答案是它们根本不在一个层面上。Function Call描述的是模型通过结构化声明决定调用哪个函数这个交互模式MCP描述的是工具如何被统一暴露给客户端的协议标准。实际运行时MCP的服务器照样会把工具列表翻译成模型能理解的函数声明也就是你仍然会在模型请求里看到类似Function Call的结构。可以说MCP是Function Call这种模式的一种工业化、平台化的落地方式它让不同工具都能进入同一个被模型调用的框架里。再往上看Agent我看过不少项目把MCP作为Agent的工具层Agent的调度循环负责决定下一步干什么MCP层负责把可用的工具清单展现给Agent并让Agent轻松完成调用。RAG则更多出现在数据库或知识库结构中知识库本身也可以暴露为一个MCP资源模型需要某份文档时直接通过MCP去读取。这样四者就形成一个正向配合RAG提供资料Function Call提供调用语义MCP提供统一接口Agent负责组织全过程。5.3 接MCP之前先想清楚成本MCP不是银弹它解决的是接入效率问题而不是调用质量问题。我在调研时见过一个反面案例某团队为了赶时髦把所有业务工具全部MCP化结果发现很多内部系统根本不适合暴露成标准接口强行封装反而带来了更复杂的鉴权设计和超时控制。在接MCP之前建议先问三个问题这个工具是否会被多个模型应用/多个客户端复用如果是值得MCP化这个工具的调用是否存在大量的一对一特殊逻辑如果不是先考虑简单的Function Call这个工具是否有标准化的输出结构如果没有先把它整理成标准结构否则MCP化之后也只是放大混乱。安全边界同样要注意MCP服务器一旦被Agent接入一个漏洞可能暴露的不只是单个函数而是整组工具。我对这个的态度是MCP服务器的工具列表实现显式注册只暴露当前任务必要的操作不把权限面放大到连接了就是全量可调。权限校验放服务端客户端只知道它可用不知道它不能用什么。6. 四者合体的落地顺序与选型建议讲完了单个技术说一个实际的组合。假设你要做一个售后客服助手用户说我要退一个订单帮我看看能不能退。如果你只用一个纯模型它大概率答出好的请提供订单号然后没了下文。接上RAG模型可以查询售后规则文档告诉你该订单是否在七天无理由时间内。再接上Function Call模型可以真正去订单系统查询订单状态然后按规则判断。再接上Agent整个对话可以变成自动循环查单→查规则→判断结果→如果符合条件继续走下一步流程。如果接入的是MCP化的工具集那订单系统、售后策略、客服留言系统都是统一插头接进来的模型挑工具就像插卡一样顺畅。在这种组合里我越来越习惯按一个固定顺序去推进产品第一步先上Function Call让模型具备基本行动力第二步上RAG让模型知道业务细节第三步把它们放进Agent循环第四步再考虑用MCP统一多个外部系统的接入。顺序不是随意拍的原因是我见过太多项目一上来就要搞Agent结果底层工具调用还没稳定Agent循环里每一步都在用蹩脚的接口问题被无限放大。展开说这个顺序背后的逻辑有三条。其一Function Call直接决定了模型的行动边界边界没定好后面全是白费。其二RAG决定了模型的知识边界边界越清晰模型在循环里做的判断越可靠。其三Agent只有在前面两者都达标以后才值得进入因为它会成倍地复用正确的行为也会成倍地放大错误。场景特征建议技术组合理由只做一个内部知识问答RAG输入侧补充就够不需要复杂行动已有稳定工具需要模型自主调用Function Call输出侧落地改动最小任务多步骤、跨系统Function Call Agent循环调度一个工具搞不定工具数量多、团队需要标准化接入Function Call MCP统一协议减少集成成本完整业务产品四者配合各管一段组合沉淀6.1 学习路径和参考资料布局如果你是从零开始摸索这四个概念我给的方向是先把Function Call的官方示例文档跑通理解一次模型声明调用→系统执行→结果回填的全过程。接着做一个带知识库的RAG小应用亲手感受切片大小和召回顺序带来的差异。然后尝试让它们合体做一个能回答怎么办的问题并能执行简易操作的Agent。最后你再审视自己的工具生态如果确实有大量接口要接再引入MCP。这样每一步的负担都不大却环环相扣。不要一上来就背MCP的各种配置不理解Function Call怎么工作MCP的配置就只是抄作业。不要一上来就追Agent的项目Demo那种演示往往隐藏了无数边界处理真正上线时你会为每一个边界条件付出代价。我也见过有经验的后端工程师直接跳过RAG自信地让Agent靠Function Call在数据库里现查结果大量的常识性业务问题每次都要靠多步检索猜出来效果和成本双双失控。知识外置这件事做要比晚做更好。6.2 实测过程中的坑和心态建议最后分享几条我在落地这四件事时的心态希望你有用。第一个是上下文开销要天天盯。任何能力接进来最终的代价都会体现成token消耗。RAG加长上下文、Agent循环多次往复、Function Call把中间结果反复塞回对话每一样都在烧钱。控制上下文的方法很简单能截断就截断能摘要就摘要能缓存就缓存。第二个是日志是所有问题排查的基础。Agent和Function Call这种多步流程没有完整的调用链日志出了问题你会完全懵掉。我每次开发时第一步就是加好结构化日志把每一次模型请求、函数调用、返回结果都记录下来后面调优全靠翻日志。第三个是先让一个流程跑通再追求智能。我看到太多项目一开始就野心巨大要做全自动客服、全自动运营结果卡死在某个验收场景里。把流程切成窗口窄、目标小、返回清晰的子任务一个节点一个节点地打通最后的效果反而是最稳定的。很多时候用户觉得智能恰恰是因为流程清晰、响应稳定而不一定是因为模型想得多么深。这也是我在这四个技术上一路踩坑下来最想让你带走的一句话大模型应用工程不是比谁的架构名词多而是比谁把每个环节的边界和成本控制得更清楚。先把一个小闭环跑稳再往外扩。