Agent之Function Call

LLM只知道根据一段token预测下一个token,给它一段话,它能一个token一个token地猜出一个回答来。但是现在Agent做到的事可不仅仅是回答问题,它还能自己读代码改代码,自己设计方案写成文档,自己检查写的代码有没有问题等等。从知道到做到的关键,就是 function call(又被称为tool call,工具调用),LLM会告诉客户端,应该调用什么工具,客户端调用对应的工具,来真正做到一些事情。

一、回答日期相关问题

LLM是无状态的,更没有独立的时钟,问它时间的问题,它就完全不知道了:

(用的上一篇文的练习代码,只是调用了DeepSeek API,并没有调用工具:github.com/rengmo/ai-p...)

但是打开DeepSeek APP一问,回答得好好的:

可能是前端获取了会话时的时间信息,或者是后端调用了时间工具获取时间信息传给了模型。

这里并没有去看DeepSeek APP具体是怎么实现的。对于这次的练习来说,是在后端代码中加上了调用时间工具的逻辑,加上后就可以正常获得时间相关的答复了,这个工具是后端代码里实现的,不是LLM的能力。

  1. 首先定义工具的类型、名称和描述、工具的调用参数等信息:
jsx 复制代码
var toolDefs = []Tool{
	{
		Type: "function",
		Function: toolFunction{
			Name:        "get_current_time",
			Description: "获取当前日期、时间和星期。用户问「现在几点」「今天几号」时必须调用,不要编造。",
			Parameters: map[string]any{
				"type":       "object",
				"properties": map[string]any{},
			},
		},
	},
	...
  1. 然后在DeepSeek的API请求里面,作为Tools参数的值传递:
jsx 复制代码
body, _ := json.Marshal(apiChatRequest{Model: model, Messages: messages, Tools: toolDefs})
  1. 如果需要用到工具,模型会返回以下格式的数据(这个是DeepSeek API返回的,LLM本身可能只是返回某种格式的文本 ):
jsx 复制代码
tool_calls: [{ name: "get_current_time" }]
  1. 应用程序拿到数据之后,根据name信息,调用在应用程序代码里定义好的函数:
jsx 复制代码
result, _ := runTool(call.Function.Name, call.Function.Arguments)
jsx 复制代码
func runTool(name, argsJSON string) (ToolResult, error) {
	switch name {
	case "get_current_time":
		return ToolResult{Text: currentTimeText()}, nil
jsx 复制代码
func currentTimeText() string {
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	now := time.Now().In(loc)
	weekdays := []string{"日", "一", "二", "三", "四", "五", "六"}
	return fmt.Sprintf("%s 星期%s", now.Format("2006年1月2日 15:04:05"), weekdays[now.Weekday()])
}
  1. 拿到函数调用的结果后,把结果添加到message列表中,下一轮循环中,用包含tool调用结果的message列表,传给LLM,获取最终结果:
jsx 复制代码
			working = append(working, Message{
				Role:       "tool",
				ToolCallID: call.ID,
				Content:    result.Text,
			})
jsx 复制代码
	for step := 1; step <= 8; step++ {
		reply, u, err := chatOnce(working)
		
		...
		
		if len(reply.ToolCalls) == 0 {
			if reply.Content != "" {
				onEvent(map[string]string{"type": "delta", "content": reply.Content})
			}
			return working, total, nil
		}

这里比较关键的一点是ReAct,不是直接回答,而是推理(Reason)和 行动(Act)交替进行的多轮循环。

  • 观察(Observe)输入模型的内容。(观察 系统提示词 + 用户问题:"今天是几号,星期几?" )
  • 推理(Reason),LLM决定:先调用时间工具 get_current_time。
  • 行动(Act),应用执行对应的get_current_time函数。
  • 再观察(Observe),观察 系统提示词 + 用户问题 + get_current_time返回的时间数据。
  • 推理(Reason),LLM给到问题的答案。
  • 行动(Act),返回给用户答案。

上面这个是一个比较简单的例子,只循环了2次ReAct。

jsx 复制代码
func runAgent(messages []Message, onEvent SSEEventHandler) ([]Message, usageTotals, error) {
    working := append([]Message(nil), messages...)
    var total usageTotals

    for step := 1; step <= 8; step++ {                    // 上限 8 轮
        reply, u, err := chatOnce(working)                // 非流式,才能解析 tool_calls
        // ... 累加 token ...

        working = append(working, reply)

        if len(reply.ToolCalls) == 0 {                    // 模型不再调工具 → 正常结束
            if reply.Content != "" {
                onEvent(map[string]string{"type": "delta", "content": reply.Content})
            }
            return working, total, nil
        }

        for _, call := range reply.ToolCalls {
            onEvent(map[string]any{"type": "tool_start", "name": fn, "args": args})
            result, _ := runTool(call.Function.Name, call.Function.Arguments)
            onEvent(map[string]any{"type": "tool_done", "name": fn, "result": result.Text})
            if result.FileURL != "" {
                onEvent(map[string]any{"type": "file", "url": result.FileURL, "filename": result.FileName})
            }
            working = append(working, Message{Role: "tool", ToolCallID: call.ID, Content: result.Text})
        }
    }
    return working, total, fmt.Errorf("超过最大工具调用步数(8)")
}

这里设置的最大步骤为8次,目前这个循环是线性执行的非常简单的任务,如果是更复杂的任务,可以使用LangChain、LangGraph之类的实现加强版循环。

二、根据当前季节生成菜谱

根据当前季节,给到一个当季的菜谱PPT,用户可以直接下载。这个例子包含了文件处理能力,工具的实现要复杂一些,比上一个例子的ReAct循环次数会多一点,但主要思路还是一样的。

代码地址:github.com/rengmo/ai-p...

相关推荐
Easy_API7 小时前
2.8万亿参数,编程反超GPT-6 Astra:Kimi K3.1 Pro把开源模型推到了哪一步
大数据·人工智能·gpt·深度学习
GlobalInfo7 小时前
2026年机器人多指灵巧手市场分析报告——涵盖行业调查、趋势分析与发展前景
大数据·人工智能·microsoft·微服务·机器人
紧跟先前的步伐7 小时前
Go AI Agent 实战 24|工具系统工程化收尾与阶段验收
人工智能·ai·golang·1024程序员节
释厄6238 小时前
AI学习层更新与跨体转移律——人类社会同构·不缺理解缺 U
人工智能·学习
她说可以呀8 小时前
Vue插槽
前端·javascript·vue.js
qq_448011169 小时前
Vue + Jinja2两套模版与法冲突造成undefinedError
前端·javascript·vue.js
老金带你玩AI9 小时前
集万家所长,一键复制的Agent.md!
人工智能
ZhuoAIStage9 小时前
舞台工艺多专业审图提速:用 AI 智能体编排 A+B+C+G 四段读图流水线
人工智能·自动化·工作流编排·舞台工艺·审图智能体
小奶包他干奶奶9 小时前
AI学习——1、机器学习概念
人工智能·机器学习
展讯快报9 小时前
悬浮提词器免费App评估报告:说得AI的免费策略与可用性分析
人工智能