本文详细介绍了如何使用Go语言通过MCP+LLM+RAG构建Agent系统。文章展示了系统架构,包括使用OpenAI的ChatGPT作为LLM、mcp-go库实现MCP客户端,以及如何整合这两部分创建Agent。提供了具体的代码实现,展示了LLM初始化、MCP客户端设置、Agent调用工具等核心功能。强调大模型不会直接执行工具调用,需要开发者编写MCP Server实现具体功能。RAG部分将在后续文章讲解。


写在前面

agent 这个话题其实是近年来最火的话题之一,这篇文章就来讲讲如何用go语言通过 mcp+llm+rag 做一个agent demo。

代码都在github上 https://github.com/CocaineCong/llm-mcp-rag ,过段时间B站会出coding视频,感兴趣的同学可以关注同名的B站账号~

整体架构

how agent works

  1. PromptMCP Client 的所有 Tools 以及 RAG内容 给到 LLM
  2. LLM会根据 Prompt + Tools 给出使用步骤以及 tools 名字和对应的参数
  3. 如果有多个MCP Client,要先找到对应的 Tool 是哪个MCP Client
  4. 接着 MCP Client 会调用 Call Tool 使用工具
  5. 真正执行是在 MCP Server 中,大模型不会调用,而是需要我们写代码进行 ToolCall

举个例子:如果是想爬取一个网页的内容

agent example

LLM

新建一个LLM,我们就选用 OpenAI 的 ChatGPT 了

  • NewChatOpenAI:New一个LLM对象,必须要传一个model name
type ChatOpenAI struct {
 Ctx     context.Context
 Model   string// 模型名称
 Tools   []mcp.Tool                               // 所需要的工具
 Message []openai.ChatCompletionMessageParamUnion // 会话历史
 LLM     openai.Client                            // 具体的客户端
}

funcNewChatOpenAI(ctx context.Context, model string) *ChatOpenAI {
 options := []option.RequestOption{
  option.WithAPIKey(os.Getenv(ChatGPTOpenAPIKEY)),
  option.WithBaseURL(os.Getenv(ChatGPTBaseURL)),
 }
 cli := openai.NewClient(options...)
 llm := &ChatOpenAI{
  Ctx:     ctx,
  Model:   model,
  LLM:     cli,
  Message: make([]openai.ChatCompletionMessageParamUnion, 0),
 }
return llm
}
  • Chat:实现具体和LLM进行Chat,而这里我们 Stream 流式进行模型的通信。而这个Chat函数的返回值有两个,一个是模型的结果,另一个是模型让我们调用的工具。

stream

func(c *ChatOpenAI)Chat(prompt string)(result string, toolCall []openai.ToolCallUnion) {
// 将prompt保存到message中,作为模型的上下文通信的消息,相当于本次session的缓存动作
if prompt != "" {
  c.Message = append(c.Message, openai.UserMessage(prompt))
 }
// 将MCP Tool转为OpenAI所理解的Tool的格式
 toolsParam := MCPTool2OpenAITool(c.Tools)
 stream := c.LLM.Chat.Completions.NewStreaming(c.Ctx, openai.ChatCompletionNewParams{
  Messages: c.Message,
  Seed:     openai.Int(0),
  Model:    c.Model,
  Tools:    toolsParam,
 })
// 流式结果的累加器,用来将每个分片chunk拼接成完整的消息
 acc := openai.ChatCompletionAccumulator{}
var toolCalls []openai.ToolCallUnion // LLM 返回的Tool的结果
for stream.Next() {
  chunk := stream.Current() // 当前的stream流的chunk分片
  acc.AddChunk(chunk)       // 解析每一个chunk,将chunk进行结构化
// 模型完整生成的一个工具调用
if tool, ok := acc.JustFinishedToolCall(); ok {
   toolCalls = append(toolCalls, openai.ToolCallUnion{
    ID: tool.ID,
    Function: openai.FunctionToolCallFunction{
     Name:      tool.Name,
     Arguments: tool.Arguments,
    },
   })
  }
// 模型所吐出的结果,一点一点进行拼接结果
iflen(chunk.Choices) > 0 {
   result += chunk.Choices[0].Delta.Content
  }
 }
iflen(acc.Choices) > 0 { // 将本次模型的最终回复写入会话历史
  c.Message = append(c.Message, acc.Choices[0].Message.ToParam())
 }
return result, toolCalls
}

MCP

我们MCP用的是这个库 github.com/mark3labs/mcp-go,主要有三个组成部份

  1. MCP 的Start启动连接,这会拉起一个MCP Server进程并建立连接
  2. MCP 的初始化 Initialize,这会进行协议握手,双方进行确认。
  3. MCP 的 CallTool 将 ToolName 和 Args 发给MCP Server。

MCP

type MCPClient struct {
 Ctx    context.Context // 上下文
 Client *client.Client  // mcp的服务client
 Tools  []mcp.Tool      // mcp 工具
 Cmd    string// 命令
 Args   []string// 参数
 Env    []string
}

funcNewMCPClient(ctx context.Context, cmd string, env, args []string) *MCPClient {
 stdioTransport := transport.NewStdio(cmd, env, args...) // 使用stdio进行连接通信
 cli := client.NewClient(stdioTransport)
 m := &MCPClient{Ctx: ctx, Client: cli, Cmd: cmd, Args: args, Env: env}
return m
}
  • Start:MCP Client的初始化
func(m *MCPClient)Start()error {
// 负责把 MCP 服务端真正跑起来并连上
 err := m.Client.Start(m.Ctx)
if err != nil {
return err
 }
 mcpInitReq := mcp.InitializeRequest{}
 mcpInitReq.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION
 mcpInitReq.Params.ClientInfo = mcp.Implementation{
  Name:    "example-client",
  Version: "0.0.1",
 }
// 让服务端认可我们的客户端与协议版本,再进入“可工作”的状态。
if _, err = m.Client.Initialize(m.Ctx, mcpInitReq); err != nil {
  fmt.Println("mcp init error:", err)
return err
 }
return err
}
  • CallTool: MCP进行工具调用,也就是调用MCP Server,具体的实现是在MCP Server中实行。
func(m *MCPClient)CallTool(name string, args any)(string, error) {
 res, err := m.Client.CallTool(m.Ctx, mcp.CallToolRequest{
  Params: mcp.CallToolParams{
   Name:      name,
   Arguments: args,
  },
 })
if err != nil {
return"", err
 }
return mcp.GetTextFromContent(res.Content), nil
}

Agent

接下来到我们的agent,agent主要是整合了上面的LLM和MCP。

how agent works

  • NewAgent:新建一个Agent
  1. 激活所有的mcp client 拿到所有的tools
  2. 激活并告诉llm有哪些tools
type Agent struct {
 Ctx          context.Context
 MCPClient    []*MCPClient
 LLM          *ChatOpenAI
 Model        string
}

funcNewAgent(ctx context.Context, model string, mcpCli []*MCPClient) *Agent {
// 1. 激活所有的mcp client 拿到所有的tools
 tools := make([]mcp.Tool, 0)
for _, item := range mcpCli {
// 启动 stdio 传输
  err := item.Start()
if err != nil {
continue
  }
  err = item.SetTools()
if err != nil {
continue
  }
  tools = append(tools, item.GetTool()...)
 }
// 2. 激活并告诉llm有哪些tools
 llm := NewChatOpenAI(ctx, model, WithLLMTools(tools))
return &Agent{
  Ctx:       ctx,
  MCPClient: mcpCli,
  LLM:       llm,
  Model:     model,
 }
}
  • Invoke:具体和LLM通信
  1. 从上面我们知道 LLM 的 Chat 方法会返回响应和所需要用到的工具 ToolCalls,ToolCalls 里面有对应的ToolName 和所需要的 Args。
  2. 根据ToolName找到对应的MCP Client,并进行CallTool
  3. CallTool就是调用MCP Server去真正的干活

⚠️注意:大模型是不会帮我们执行的,大模型只会给出一个步骤(也就是 tool name 和 tool args),而这个执行步骤是需要我们去写的,也就是真正的MCP Server

核心代码逻辑如下:

func(a *Agent)Invoke(prompt string)string {
if a.LLM == nil {
return""
 }
 response, toolCalls := a.LLM.Chat(prompt)
forlen(toolCalls) > 0 {
// 省略了一些代码... 找到是哪个MCP Client,并进行CallTool
if mcpTool.Name == toolCall.Function.Name {
   toolText, err := mcpClient.CallTool(toolCall.Function.Name, toolCall.Function.Arguments)
if err != nil {
continue
   }
   a.LLM.Message = append(a.LLM.Message, openai.ToolMessage(toolText, toolCall.ID))
  }
 }
return response
}

运行结果:

result

oolCall.Function.Name, toolCall.Function.Arguments)
if err != nil {
continue
}
a.LLM.Message = append(a.LLM.Message, openai.ToolMessage(toolText, toolCall.ID))
}
}
return response
}

篇幅受限,RAG的内容我们下一篇文章再讲解。

在大模型时代,我们如何有效的去学习大模型?

现如今大模型岗位需求越来越大,但是相关岗位人才难求,薪资持续走高,AI运营薪资平均值约18457元,AI工程师薪资平均值约37336元,大模型算法薪资平均值约39607元。
在这里插入图片描述

掌握大模型技术你还能拥有更多可能性

• 成为一名全栈大模型工程师,包括Prompt,LangChain,LoRA等技术开发、运营、产品等方向全栈工程;

• 能够拥有模型二次训练和微调能力,带领大家完成智能对话、文生图等热门应用;

• 薪资上浮10%-20%,覆盖更多高薪岗位,这是一个高需求、高待遇的热门方向和领域;

• 更优质的项目可以为未来创新创业提供基石。

图片

图片

《AI大模型从0到精通全套学习包》

图片

图片

如果你想要提升自己的能力却又没有方向?

想学大模型技术去帮助就业和转行又不知道怎么开始?

那么这一套**《AI大模型零基础入门到实战全套学习大礼包》以及《大模型应用开发视频教程》**一定可以帮助到你!

限免0元!👇👇

在这里插入图片描述

1

全套AI大模型应用开发视频教程

(包含深度学习、提示工程、RAG、LangChain、Agent、模型微调与部署、DeepSeek等技术点)

img

2

大模型入门到实战全套学习大礼包

01

大模型系统化学习路线

作为学习AI大模型技术的新手,方向至关重要。 正确的学习路线可以为你节省时间,少走弯路;方向不对,努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划,带你从零基础入门到精通!

img

02

大模型学习书籍&文档

学习AI大模型离不开书籍文档,我精选了一系列大模型技术的书籍和学习文档(电子版),它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。

img

03

AI大模型最新行业报告

2025最新行业报告,针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

img

04

大模型项目实战&配套源码

学以致用,在项目实战中检验和巩固你所学到的知识,同时为你找工作就业和职业发展打下坚实的基础。

img

05

大模型大厂面试真题

面试不仅是技术的较量,更需要充分的准备。在你已经掌握了大模型技术之后,就需要开始准备面试,我精心整理了一份大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

img

*这些资料真的有用吗?*

这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。

资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。

img

img

06

以上全套大模型资料如何领取?

在这里插入图片描述

👆🏻用微信加上就会给你发

无偿分享

遇到扫码问题可以私信或评论区找我

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐