什么是AI Agent?大白话新手教学
Agent的诞生背景
如果只有LLM的话,那么LLM就相当于一个脑子,你问他一个问题,他会给你答案或者告诉你怎么做,但并不会帮你去解决这个问题,实际还是需要你自己动手去解决。
(比如我问大模型:“我要回福建,需要买河南到福建的机票”。那么大模型只会告诉你买机票的方法,并不会去帮你买机票)
这样非常的麻烦。
那么我们能不能让LLM返回答案的同时去把问题也给解决了呢?
为了能让LLM(脑)解决实际问题,我们先需要给大模型加上一个tools(手)。
再把脑子和手集成到一个东西里,让这个东西能够自由地调度手和脑子。这个东西就是agent。
大模型用于回答问题(脑子),agent是你的助理,他能够根据大模型回答的问题,并借助tools(手),去完成一系列指定的操作。


用LangChainGo集成Agent
Langchain是一个python框架,用于将大语言模型集成到各种应用中。
LangchainGo就是这个Langchain框架的Go语言版本,除此之外还有 langchain4j(用于java)、rust-langchain(用于rust)、langchain.js(用于javascript)
需求:
我们现在用LangChainGo集成一个Agent,让这个Agent可以根据我们的指令去打开电脑上的Wegame。
package mainimport ("context""fmt""log""os/exec""github.com/tmc/langchaingo/agents""github.com/tmc/langchaingo/chains""github.com/tmc/langchaingo/llms/openai""github.com/tmc/langchaingo/tools"
)// OpenWeGameTool 自定义一个 tool,用于打开 WeGame 应用
type OpenWeGameTool struct{}// Tool 的名称
func (t OpenWeGameTool) Name() string {return "OpenWeGame"
}// Tool 的功能描述
func (t OpenWeGameTool) Description() string {return "Opens the WeGame application on the user's computer."
}// Tool 的功能
func (t OpenWeGameTool) Call(ctx context.Context, input string) (string, error) {// Windows 命令:启动 WeGamecmd := exec.Command("cmd", "/c", "start", "", `D:\WeGame\WeGame.exe`)// 执行命令err := cmd.Run()if err != nil {return "", fmt.Errorf("failed to open WeGame: %v", err)}return "WeGame application opened successfully", nil
}func main() {// Step 1: 初始化LLMllm, err := openai.New(openai.WithModel("deepseek-reasoner"),openai.WithToken("你的api key"),openai.WithBaseURL("https://api.deepseek.com"),)if err != nil {log.Fatalf("Failed to initialize LLM: %v", err)}// Step 2: 初始化 toolsagentTools := []tools.Tool{OpenWeGameTool{}, // 打开wegame的tool}// Step 3: 初始化agentagent := agents.NewOneShotAgent(llm,agentTools,agents.WithMaxIterations(3), // 设置最大迭代次数为3)agentExecutor := agents.NewExecutor(agent)// Step 4: 运行agent,并输入promptprompt := "帮我打开vscode"answer, err := chains.Run(context.Background(), agentExecutor, prompt)if err != nil {log.Fatalf("Failed to run agent: %v", err)}// Step 5: 打印结果fmt.Println("Answer:", answer)
}
深入了解Agent

Agent 和 LLM 之间的通信方式:
Prompt
在初始化时,Agent 先将 Tools 的描述以及指定大模型返回的格式写在 System prompt 中。
在用户提问时,Agent 再将用户的提问写在 User prompt 中,连带着上面的 System prompt 一块发给LLM。
顺利的话,LLM会返回一个正确格式的信息。

但是,这里边儿 System Prompt 里的信息都是用自然语言写的,不够规范,不够严谨。
所以容易造成LLM返回一个错误格式信息,Agent 发现这个信息格式不对,会再次调用LLM,进行重试。这样会消耗很多无意义的 token。
为了避免LLM返回一个错误格式信息,我们需要对双方的 交互信息和 交互方式进行规范处理。
为此,各大厂商推出了一个新功能—— Function Calling。
Function Calling
主要通过两方面来进行改进的,分别是双方的交互信息和交互方式。
- 交互信息:
每个tool的描述都用一个统一格式的json对象来定义

LLM给的回复也需要用一个统一格式的json对象来定义

- 交互方式
这些 json 的定义不再通过prompt进行交互,而是是通过专门的 API 参数。
这样一来,所有工具描述和返回信息的格式都放在相同的地方,并且按照相同的格式。
所以LLM就更容易理解我们的诉求,生成的答案就更准确。人们也可以更加有针对性的训练LLM。
但是 function calling 也有缺点,例如各大厂商的标准不统一,部分大模型不支持 function calling 等,所以其并没有完全取代prompt。
目前 function calling 和 prompt 这两种方式使用都很流行。
Agent 和 Tools 之间的通信方式:

tools实际上是一个服务,Agent通过MCP通信协议去调用他。(MCP专门用来规范Agent和Tool服务之间是怎么交互的。)
运行Tools的服务叫作MCP Server,调用它的Agent叫作MCP Client。

MCP规定了MCP Server如何和MCP Cient交互,以及MCP Server要提供哪些接口,比如说用来查询MCP Server中有哪些Tool、Tool的功能、描述、需要的参数、格式等等的接口。
MCP server既可以和Agent跑在同一台服务器上,通过标准输入输出进行交互,也可以被部署在网络上通过http进行交互。
package mainimport ("context""fmt""github.com/i2y/langchaingo-mcp-adapter""github.com/tmc/langchaingo/agents""github.com/tmc/langchaingo/llms/openai"
)func main() {ctx := context.Background()// 初始化 OpenAI LLMllm, err := openai.New()if err != nil {panic(err)}// 连接到 MCP 服务器并加载工具mcpURL := "https://mcp.composio.dev/your-app-id"tools, err := mcpadapter.LoadTools(ctx, mcpURL)if err != nil {panic(err)}// 初始化 Agent Executorexecutor, err := agents.Initialize(llm,tools,agents.ZeroShotReactDescription,agents.WithMaxIterations(3),)if err != nil {panic(err)}// 提出问题prompt := "请发送一封邮件给张三,内容是会议安排。"answer, err := executor.Call(ctx, map[string]any{"input": prompt})if err != nil {panic(err)}fmt.Println(answer["output"])
}