第8节:理解Agent的设计思想
今天我们要来深入探讨一下Agent(智能体)的设计思想和实现原理。作为一个程序员,最好的学习方式就是通过代码来理解概念,所以我们直接从Go代码开始,深入剖析Agent的内部工作机制。
首先,让我们看看代码,这其实是一个非常典型的Agent应用:
func main() { ctx := context.Background() llm := DoubaoOpenai() //定义好工具 serpapiTool, err := serpapi.New(serpapi.WithAPIKey(Serpapi)) if err != nil { return } //calc calculator := new(tools.Calculator) tools := []tools.Tool{ serpapiTool, calculator, } //agent agent := agents.NewExecutor(agents.NewOneShotAgent(llm, tools)) res, err := chains.Run(ctx, agent, "你好,请问 it资源网的网站有哪些 ? ") if err != nil { log.Fatal(err) } fmt.Println(res) }
这段代码虽然简短,但已经完整地体现了Agent的核心设计思想。我们可以把它分解为几个关键部分:
- 语言模型(LLM) - Agent的大脑
- 工具集(Tools) - Agent的手脚
- Agent执行器(Executor) - Agent的决策中枢
- 任务执行 - Agent的工作流程
Agent的核心:语言模型(LLM)
首先初始化了一个llama3.2的大语言模型:
func DoubaoOpenai(t *testing.T) *ollama.LLM { llm, err := ollama.New( ollama.WithModel("llama3.2"), // 指定使用的模型 ) if err != nil { log.Fatal(err) } return llm }
这个LLM就是Agent的"大脑",负责理解自然语言、进行推理和生成回复。你可以把它想象成Agent的思维中枢,但它本身并不能直接执行具体任务。
Agent的"手脚":工具系统
Agent的强大之处在于它不仅能思考,还能通过工具来执行具体任务。在代码中,定义了两个工具:
// 搜索工具 serpapiTool, err := serpapi.New(serpapi.WithAPIKey(Serpapi)) // 计算器工具 calculator := new(tools.Calculator) tools := []tools.Tool{ serpapiTool, calculator, }
工具的本质:统一接口
在langchaingo中,所有工具都实现了统一的接口:
type Tool interface { Name() string Description() string Call(ctx context.Context, input string) (string, error) }
这个设计非常精妙,它意味着Agent可以使用任何实现了这个接口的工具。让我们看看两个具体工具的实现:
func (c Calculator) Description() string { return `Useful for getting the result of a math expression. The input to this tool should be a valid mathematical expression that could be executed by a starlark evaluator.` } func (c Calculator) Name() string { return "calculator" }
搜索引擎工具:
func (t Tool) Name() string { return "GoogleSearch" } func (t Tool) Description() string { return ` "A wrapper around Google Search. " "Useful for when you need to answer questions about current events. " "Always one of the first options when you need to find information on internet" "Input should be a search query."` }
这些描述信息非常重要,因为它们会被注入到Agent的提示词中,帮助LLM理解何时以及如何使用这些工具。
Agent的"灵魂":OneShotAgent
在你的代码中,最关键的一行是:
agent := agents.NewExecutor(agents.NewOneShotAgent(llm, tools))
这里创建了一个OneShotAgent,它是Agent的核心实现。OneShotAgent的职责是:
- 接收用户输入
- 根据输入和可用工具决定下一步行动
- 生成最终答案或工具调用指令
OneShotAgent内部使用了一个LLMChain,这是整个Agent的决策核心。它会将用户输入、工具描述、历史交互等信息组合成一个完整的提示词,然后让LLM进行推理。
Agent的"执行者":Executor
NewExecutor创建了一个执行器,负责管理Agent的整个执行流程:
NewExecutor创建了一个执行器,负责管理Agent的整个执行流程:
func (e *Executor) Call(ctx context.Context, inputValues map[string]any, _ ...chains.ChainCallOption) (map[string]any, error) { inputs, err := inputsToString(inputValues) if err != nil { return nil, err } nameToTool := getNameToTool(e.Agent.GetTools()) steps := make([]schema.AgentStep, 0) for i := 0; i < e.MaxIterations; i++ { var finish map[string]any steps, finish, err = e.doIteration(ctx, steps, nameToTool, inputs) if finish != nil || err != nil { return finish, err } } // ... }
Executor的工作流程是一个循环过程:
- 接收输入
- 调用Agent的Plan方法制定计划
- 如果需要使用工具,就执行工具调用
- 将工具执行结果作为观察(Observation)反馈给Agent
重复这个过程,直到Agent认为任务完成
Agent的工作流程:一个完整的例子
让我们通过你的示例来理解Agent的完整工作流程。当你执行:
res, err := chains.Run(ctx, agent, "你好,请问 it资源网的网站有哪些 ? ")
会发生以下步骤:
- 输入处理:Executor接收问题"你好,请问 it资源网的网站有哪些 ?"
- 计划制定:OneShotAgent使用LLM分析问题,由于这是关于网络资源的问题,它决定调用GoogleSearch工具。
- 工具调用:Agent生成类似这样的指令:
Action: GoogleSearch Action Input: it资源网的网站有哪些 - 执行搜索:Executor调用SerpAPI工具执行搜索。
- 结果反馈:搜索结果被作为Observation返回给Agent。
- 生成答案:Agent基于搜索结果生成最终回答
- 返回结果:通过chains.Run函数将最终答案返回。
Agent的智能之处:ReAct模式
Agent的智能来源于ReAct模式(Reasoning + Action)。它不是简单地回答问题,而是按照"思考-行动-观察-再思考"的循环来解决问题。这种模式让Agent能够处理复杂的、需要多步骤才能解决的任务。
在代码中,Agent面对"it资源网的网站有哪些"这个问题时,它会:
- 思考:这是一个需要网络搜索的问题
- 行动:调用GoogleSearch工具
- 观察:获取搜索结果
- 思考:基于搜索结果生成回答
- 行动:返回最终答案
总结
通过分析你的代码,我们可以看到Agent的设计思想非常优雅:
模块化设计:LLM、工具、执行器各司其职
统一接口:所有工具都遵循统一的接口规则
循环执行:通过迭代执行实现复杂任务处理
开放扩展:可以轻松添加新的工具
这种设计让Agent既保持了足够的智能,又具备了强大的可扩展性。它就像一个聪明的项目经理,知道什么时候该自己思考,什么时候该调用专家(工具)来解决问题。
Agent技术正在快速发展,而你已经在使用它了!随着你对这套系统的深入理解,相信你能构建出更加强大和智能的应用。

浙公网安备 33010602011771号