RAG、FunctionCall和MCP的简单介绍

使用大模型一段时间想总结点东西.

目前普通用户使用模型的最简单方法就是安装一个客户端与模型聊天.模型一般使用通用知识库进行反馈.模型提供的公司所能收集的数据或者当前网络公开的数据.

对于企业自身需要结合自有数据做垂直领域开发.有的企业训练自己的模型.使用自己的数据进行训练.这样模型的训练数据会越来越丰富.这个方式对于训练通用模型比较适用.大企业也可以不断推出新版模型.有些公司也可以通过现有发布的模型,结合自有数据进行训练.满足自己的业务模型.

这里有一个问题就是大模型的基础数据量太大了.企业自己的数据输入进行训练杯水车薪.目前的一个办法就是选择合适的算法.通过不断的调节参数.主要就是权重尽量满足需求.虽然本人使用开源工具调试过模型.但仅仅是学习如何调试.没有实际效果测试.不多说了.

那么除了训练模型还有什么方法可以将自己的数据发送给模型呢?让模型结合自己的业务数据完成任务呢?目前使用过的方案有RAG、function call(fc)、MCP.下面简单说一下这几个方法.

RAG

当我们使用同模型对话的时候就会发现.我们对模型提出问题.模型回答问题.我们是否可以给模型提供相关知识.让模型在我们提供的知识里面找答案呢?例如给模型的输入是:你是一位律师.明天要为一个经济纠纷案件做辩护.请提供一些辩护材料.通常模型会给出一个比较标准的答案.但是如果我们增加一些问题的内容会怎样呢?例如给模型输入:你是一位律师,今天是2025年6月6日.明天有一场经济纠纷的案件需要做辩护.原告是一位年轻小伙.出生年月日是:xxx.家庭背景xxx.被告是xxx.请提供辩护材料.模型返回的内容会根据提供的被告和原告的数据出一份辩护材料.这样答案就更加符合具体的使用场景了.我们简单分析一下两次提出问题的区别会发现.第二次比第一次多了我们已经掌握.但是模型没有掌握的知识.模型给出的答案更加切合实际场景了.

下面我就要想想如何更好的给模型输入我们已经掌握的知识呢?前面说了通过增加新的数据训练模型.但是数据总是有时效性的.训练无法满足时效性.我们如何时时的给模型提供数据呢?上面说的最单方法就是提问的同时将数据发送给模型.但是有些情况是数据在本地存储.提问人很难将大量的时时背景数据提供给模型.这里就要开发人员想办法读取本地数据,然后结合提问人的数据一起发送给模型.

在最简单的情况下.给模型的客户端包一层自己的处理逻辑.在收到提问人的问题之后.查询本地的和提问人相关的数据一起发送给模型.听起来很简单.就是收到提问人的消息之后查一次数据库然后整合一下提问人的内容一起发送给模型.实际开发过程中有一个难点.就是如何找到与问题相关的数据呢?

这里分两种情况来说.一种情况就是关键字匹配.这个对于大多数的开发人员来说很简单.使用过ES存储的人都知道倒排索引的原理.就是根据一段话或者关键词查找相关的内容.主要的实现方案就是对用户的输入进行分词,分词之后通过倒排索引找到匹配的内容然后返回.例如:用户输入我想去北京旅游.分词:我、想去、北京、旅游.倒排索引里面可能有:北京、旅游.这样含有北京、旅游关键字的数据就都查出来了.这个就像模糊匹配.这个方案一般在用户输入的同时,选择我们为用户提供的关键词标签或者直接对用户输入进行分词处理.但是这里有一个问题.就是我们很难限制用户的输入.例如:用户输入我想去北平溜达两天.我们的历史数据集没有北平和溜达这两个关键字,那要如何查到我们已经有的北京旅游的内容呢?

有一个方法.就是向量化数据.具体向量数据如何计算的这里不深入讲解.就说向量数据能做什么?大模型有一个能力.就是训练过程中能计算两个词的相似度.例如:北京和北平在地名场景中的相似度比北京和东京的相似度高.这样我们通过北平的向量可以近似的找到北京.原理不说了.说一下具体实现方案.

我们先有一个自己的向量数据库.我们对已经有的数据进行向量化.

向量化主要流程是:

  1. 遍历本地的数据.
  2. 选择合适的分词器进行分词处理.
  3. 对于分词之后的数据调用大模型的向量接口得到词的向量数据.
  4. 将词和向量写入向量数据库.
  5. 当接收到用户的输入之后.对用户的输入进行分词.
  6. 计算用户输入分词的向量数据.
  7. 根据向量数据查询向量数据库.得到近似词.
  8. 将用户的输入和近似词一起作为查询条件查找本地数据库内容得到本地数据集合.
  9. 将本地数据集合和用户的输入一起发送给大模型.

这里有一个成本问题.就是本地数据通过大模型向量化的过程.如果本地数据量很大完全调用大模型向量化成本太高,数据泄露风险很高.可以本地搭建一个开源模型.通过本地模型进行向量化操作.就是所有的向量化过程都由本地模型完成.

说一下本人实际测试环境使用的工具:本地数据存储使用ES.分词器使用java包装的jieba分词器.向量数据库使用milvus.向量化模型是ollama的embedding-text模型.以上都是开源免费的.外部对接的模型是openAI.本地环境搭建很容易.但是如果要实际提供服务还是要进行大量的数据验证.尤其是分词器、向量化存储和向量化模型的选择.由于本人仅仅测试验证简单说一下分词的优化:对分词器进行多次调整.尽量多的使用分词方法.不断的调整分词粒度.一句话分解的词的个数越少越能保证语义的正确.分词越多越能保证匹配范围的广泛,但是精度降低.

通过以上方法可以把本地数据和用户的输入数据一起发送给模型了.上面流程主要是增加大模型的输入词,增加模型返回数据的准确度.起个名就是检索增强生成RAG

Function Call

说了RAG,思考一下RAG有什么不足或者不容易实现的能力.有一个场景:我想出去旅游.想让模型帮我规划一下路线.其中有一个重要信息就是定酒店.大模型通常给出的方案是什么时候做什么交通工具,什么时候住酒店.但是无法提供时时的交通信息和酒店信息.如果采用RAG的方案把酒店火车信息都提供.数据量太大了.不现实.采用上面的语义识别能力就需要分析用户的输入.这个过程就叫意图识别.这个是一个很复杂的事情.但是大模型本身其实很适合做意图识别.大模型可以根据用户的输入分析出用户需要什么信息.

那么如何将本地的数据提供给模型呢?大模型提供了一个方法.就是定义一个查询本地数据的方法.大模型根据用户的输入进行意图识别.然后决定调用那个方法查询那些数据.例如:我们和大模型聊天.我明天想坐火车从上海去北京旅游2天.大模型会看看是否有查询火车时刻表的接口.是否有查询当地酒店的接口.如果有,大模型会从用户的输入信息里面分析出合适的入参.调用接口得到数据.大模型提供的调用本地接口的方法就是function call.我们在比较一下RAG和functioncall.二者都是将本地数据发送给大模型.如果我们自己有能力根据用户的输入分析出来用户可能需要数据的大致范围.那么可以直接通过RAG将数据发给大模型.如果不能可以让大模型帮我们分析出来需要数据的范围.我们提供查询接口.所以function call对比RAG的一个优势是对用户意图的分析.更加精确的知道用户想要什么数据.那么具体如何通过function call和大模型交互呢?可以查看各个大模型的接口文档.封装大模型接口,将本地接口的描述信息发送给大模型就可以了.如果完全使用代码开发工作量比较大.我是通过springbootAI进行测试(0.0.8版本之后不建议使用fc.建议使用MCP).实现很简单就是写一个接口.官方文档给的例子是查询天气.查询当前时间更简单(大模型无法识别当前时间,这个接口对所有大模型都很重要).这里具体代码就不说了.springboot官方文档都有.通常RAG和FC可以同时使用

MCP

有了RAG、function call.再分析一下function call有哪些不容易实现的地方呢?思考一个场景.我们需要面对不同的客户.提供个性化能力.使用一个模型可能无法满足.即使使用一个模型我们的提示词.系统角色设置、系统信息设置可能也不同.需要部署多个服务配合多个模型来做事情.但是function call属于本地调用.每一个服务都要写一个fc.是不是很麻烦.如果有一个通用的协议,大家都使用同样的调用方法.一个接口所有模型都能使用是不是更好.大家很早就想到了方法.但是总有一个最先公开提出.然后落地实现.起个名就是模型上下文协议MCP.其实本质上和fc一样都是让模型调用外部接口.MCP比fc的好处是有个通用协议.大家都认同.都按照协议办事.大家就通用了.

MCP具体架构就不说了.网上太多了.具体实现springbootAI里面有开源的代码.这里说一下具体实现时候可能遇到的一些问题.mcp架构是 服务端-客户端.使用过程中通常写一个服务端.然后写一个客户端.问题就在客户端.我在刚刚学习的时候springbootAI代码例子给出了服务端和客户端的例子.但是客户端如何配合大模型呢?其实我们使用springbootAI开发的时候不用关注客户端.客户端可以理解成将函数描述信息提供给大模型的作用和封装调用服务端的能力.MCP实现要求有一个查询接口描述信息的方法是listTools.springbootAI已经封装好了具体的方法.我们在使用过程中只需要开发服务端就可以了.在配置文件文件里面配置服务端的访问地址就可以了.但是文档没有给出具体配置文件的例子.需要我们去查看spring bootAI的源代码.里面有如何配置mcp的例子.所以在具体使用过程中不要纠结如何开发客户端.只要通过spring bootAI导入合适的jar包.写好配置文件就可以了.给一个配置mcp的配置参考:

js 复制代码
spring:
  ai:
    mcp:
      client:
        request-timeout: 60s
        request:
          timeout: 60s
          connect-timeout: 60s
          socket-timeout: 60s
        sse:
          connections:
            server1:
              url: 服务端访问地址的url
        enabled: true

注意超时时间.开始使用的时候总是失败.后来发现默认超时时间太短了.当然采用py开发也可以.py也提供了mcp实现方案.我是java背景,所以这里仅提供spirng bootAI的简单说明.如果真的想在本地搭建spring bootAI可以查看官方文档.

我在使用的时候发现一个有意思的地方.就是我在验证的时候deepseek文档还没有提供MCP的接入说明.但是使用springboot AI的openAI的接入客户端(chatClient)访问deepseek依然可以调用MCP接口.验证千问也没问题.不知道deepseek什么时候会增加mcp的接入文档说明.

说一下实际开发过程中遇到的问题.mcp服务端参数太多的时候模型也会犯错.例如调用高德的出行接口.有一个参数是出行方式.让模型提供北京到上海的建议.模型调用接口的时候出行方式是步行.接口直接报错了.大于100KM不支持步行查询.还有的模型参数传的不准确.所以在开发mcp服务端的时候接口入参要简单清晰.尽量明确标注用途.减少模型犯错.实际测试过程中接口错误的次数openAI比deepseek和千帆少.可能openAI做了更好的优化.也可能是我测试的数据太少.这里不做评价.

总结一下 RAG、fc、MCP都是将本地数据提供给大模型,让大模型在反馈的时候更精确的回答.相当于垂直领域的功能.fc可能会慢慢被mcp替代.当然有些本地功能的调用使用fc可能更简单.

最后说一下数据安全的问题.

大家对于将本地数据直接推给外部大模型直接训练比较敏感.至少目前不会有那个公司将自己的数据推给外部模型训练.毕竟数据是一个企业的宝贵财富.但是大多数公司都喜欢通过RAG或者MCP的方式将数据发送给模型.其实通过训练发送和RAG、MCP发送本质都一样.大模型企业最希望的就是所有企业都把数据发送到自己的模型.让模型越来越强大.但是企业要思考如何保护自己的数据.很多小公司自己训练模型不现实.只能依赖外部模型做业务.这个时候在提供RAG、MCP功能的时候一定要注意数据的过滤.对于敏感数据一定要警惕.因为发送给模型的所有数据在模型所有公司一定会留痕.大模型公司为什么高声疾呼推广MCP.一个原因是开源数据已经几乎处理完了.现在就是看谁能拿到各个企业垂直领域的专业数据了.如果谁拿到的多.那么谁的模型就越有竞争力.所以提供数据的同时也要做好数据脱敏.MCP服务提供端非常有必要增加一层数据过滤脱敏保护层.一个最简单方案就是关键词过滤.由于本人没有经验,不多说了.

好了.这就是我对RAG、FC和MCP的理解.主要是从使用层面的感性认知,没有深层原理的理性说明.也是能力所限.希望大家多交流.

相关推荐
亲爱的非洲野猪4 分钟前
Kafka消息积压的多维度解决方案:超越简单扩容的完整策略
java·分布式·中间件·kafka
陈随易6 分钟前
MoonBit助力前端开发,加密&性能两不误,斐波那契测试提高3-4倍
前端·后端·程序员
wfsm7 分钟前
spring事件使用
java·后端·spring
微风粼粼24 分钟前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
缘来是庄28 分钟前
设计模式之中介者模式
java·设计模式·中介者模式
搞笑的秀儿35 分钟前
信息新技术
大数据·人工智能·物联网·云计算·区块链
阿里云大数据AI技术1 小时前
OpenSearch 视频 RAG 实践
数据库·人工智能·llm
rebel1 小时前
若依框架整合 CXF 实现 WebService 改造流程(后端)
java·后端
XMAIPC_Robot1 小时前
基于ARM+FPGA的光栅尺精密位移加速度测试解决方案
arm开发·人工智能·fpga开发·自动化·边缘计算
极客悟道1 小时前
颠覆传统虚拟化:在Docker容器中运行Windows系统的开源黑科技
前端·后端