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...

相关推荐
陈天伟教授2 分钟前
【30天学会机械制图 第4天】项目一 从平面图形开始 任务1 按标准来画图,秒懂!
人工智能·平面·ai编程·具身智能机器人技术·机械制图
PC2005-cloud9 分钟前
分享一个我发现的免费 AI 资讯 API:AI HOT,无需注册、无需 Token、开箱即用
人工智能
天涯明月19939 分钟前
SGLang深度研究报告
人工智能·后端·推理·sglang
liutao84120417 分钟前
TrainEye源码解读-02. 登录认证 · 后端篇
人工智能
AI导出鸭22 分钟前
怎么让文心做表格?AI导出鸭苹果版将文心输出的管道表格智能解析为二维结构,一键导出为Excel或Word标准表格
人工智能·chatgpt·word·excel·ai导出鸭
ZJU_统一阿萨姆26 分钟前
【算子开发】Reduction算子完全指南
人工智能·算法·语言模型
迪康coolmu28 分钟前
企业文件外发防泄漏实践:从通道封堵到三层全链路管控
大数据·运维·网络·人工智能·安全·阿里云
苦猿的大模型日记28 分钟前
Day49|投机解码:小模型帮大模型提速,为什么不一定更快?
人工智能
听你说3229 分钟前
三诺动态血糖仪i6搭载L5级小诺智能体,开启AI控糖新时代
人工智能
TMT星球32 分钟前
AI智融·场景共生,奥维云网2026数字AI生态大会在南京圆满举办
人工智能