前言:为什么我会学这个问题

之前我写了个 AI 助手,让它帮我查天气、调接口,它时而正常时而发疯——有时候返回纯文本,有时候乱格式,有时候干脆不调用工具。后来我发现问题不在模型,在于我混淆了 Function CallAgent 工具调用 这两个完全不同机制。这篇就来把它们彻底讲清楚。

前文关联:这是《AI Agent 工程实践》系列的开篇,我们从最基础的概念区分开始。

一、问题背景

做 AI 项目时,大家都在说"让 AI 调用工具",但实现方式分两种:

  • Function Call(函数调用):模型原生能力,结构化输出,固定格式
  • Agent 工具调用(Tool Use by Agent):Agent 框架的能力,动态决策,可编排

大多数教程把它们混为一谈,导致代码写得四不像。

二、核心概念

Function Call 是什么?

Function Call 是 LLM 的内置能力。模型收到用户问题后,直接在响应中输出一个结构化的函数调用请求,格式类似:

{
  "name": "get_weather",
  "arguments": {"city": "北京"}
}

这个过程模型一次输出完成,不存在"思考要不要调用"的环节。

在这里插入图片描述

Agent 工具调用是什么?

Agent 工具调用是 Agent 框架(比如 LangChain、LangGraph)里的能力。Agent 会:

  1. 思考(Think):模型输出"我应该调用工具"
  2. 决定调用哪个(Action):从多个工具中选择
  3. 执行(Execute):调用工具
  4. 观察结果(Observation):把结果传回模型
  5. 再次思考:模型决定下一步

这是一个循环,不是一次性的。

在这里插入图片描述

核心区别

Function Call Agent 工具调用
本质 模型原生能力 Agent 框架编排
决策 一次性决策 循环决策
工具数量 通常单工具 多工具可选
灵活性 低,格式固定 高,可编排
适用场景 简单、结构化任务 复杂、多步骤任务

三、错误理解 / 常见误区

误区1:Function Call 就是 Agent

错。Function Call 只是让模型输出结构化 JSON,不包含执行逻辑。你还得自己解析 JSON、调用函数、把结果传回去。

误区2:Agent 必须用 Function Call

错。Agent 可以用 Function Call,也可以用 prompt engineering(比如在思维链里写"当你需要查天气时,直接在回答里插入 TOOL_CALL: get_weather")。Function Call 只是实现工具调用的一种方式。

误区3:Function Call 比 Agent 简单,所以功能也弱

不完全对。Function Call 的"简单"指的是调用方式简单,不代表能力弱。很多复杂任务可以用多工具的 Function Call 实现。

误区4:Agent 调用工具后模型就完成了

错。工具返回结果后,Agent 会把这个结果再传回模型,让模型继续决定下一步。这就是 Agent 的"循环"机制。

四、正确实现思路

Function Call 实现步骤

  1. 定义工具 schema(符合 OpenAI 格式)
  2. 把工具 schema 和用户问题一起发给模型
  3. 解析模型返回的函数调用
  4. 执行实际函数
  5. 把函数结果和原问题一起发回模型,让它组织最终回答
# 伪代码
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取城市天气",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}}
            }
        }
    }
]

response = openai.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "北京天气怎么样?"}],
    tools=tools
)

# 解析 Function Call
tool_calls = response.choices[0].message.tool_calls
if tool_calls:
    for call in tool_calls:
        if call.function.name == "get_weather":
            result = get_weather(call.function.arguments["city"])
            # 把结果发回模型,获取最终回答
            final = openai.chat.completions.create(
                model="gpt-4",
                messages=[
                    {"role": "user", "content": "北京天气怎么样?"},
                    response.choices[0].message,
                    {"role": "tool", "tool_call_id": call.id, "content": result}
                ]
            )

Agent 工具调用实现步骤

  1. 定义 Agent Prompt(包含工具描述、决策逻辑)
  2. Agent 接收用户问题,输出思考 + 工具调用
  3. 执行工具,把结果返回给 Agent
  4. Agent 继续思考,直到决定不再调用工具
  5. 返回最终答案
# LangChain Agent 伪代码
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain.tools import tool

@tool
def get_weather(city: str):
    """获取城市天气"""
    return f"{city}今天晴,25度"

tools = [get_weather]

prompt = """你是一个助手。
当你需要查天气时,调用 get_weather 工具。
其他情况直接回答。"""

agent = create_openai_functions_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)

result = executor.invoke({"input": "北京天气怎么样?"})
# Agent 会自动:思考 -> 调用工具 -> 拿到结果 -> 再思考 -> 返回答案

五、代码示例

Function Call 完整示例(Python)

import json
from openai import OpenAI

client = OpenAI(api_key="your-api-key")

# 定义工具
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的天气信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称,如:北京、上海"
                    }
                },
                "required": ["city"]
            }
        }
    }
]

def get_weather(city: str) -> str:
    """模拟天气查询"""
    weather_data = {"北京": "晴,25°C", "上海": "雨,18°C"}
    return weather_data.get(city, "未知")

def call_function(name: str, args: dict) -> str:
    """执行函数调用"""
    if name == "get_weather":
        return get_weather(**args)
    return "未知函数"

# 第一轮:用户提问,模型决定调用工具
messages = [{"role": "user", "content": "北京今天天气怎么样?"}]

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice="auto"
)

assistant_msg = response.choices[0].message
print("模型响应:", assistant_msg)

# 解析并执行函数调用
if assistant_msg.tool_calls:
    tool_call = assistant_msg.tool_calls[0]
    func_name = tool_call.function.name
    func_args = json.loads(tool_call.function.arguments)
    
    print(f"\n执行函数: {func_name}({func_args})")
    func_result = call_function(func_name, func_args)
    print(f"函数返回: {func_result}")
    
    # 第二轮:把函数结果发回模型,获取最终回答
    messages.append(assistant_msg)
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": func_result
    })
    
    final_response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages
    )
    
    print("\n最终回答:", final_response.choices[0].message.content)

六、运行结果 / 流程图

运行结果:

模型响应: ChatCompletionMessage(content=None, tool_calls=[ChatCompletionMessageToolCall(id='...', function=Function(arguments='{"city": "北京"}', name='get_weather'), type='function')])

执行函数: get_weather({'city': '北京'})
函数返回: 北京今天晴,25°C

最终回答: 北京今天天气晴朗,气温约25摄氏度,适合外出活动。

在这里插入图片描述

七、项目中怎么用

实际场景

  • 简单任务(查天气、算数学):用 Function Call 就够了,一次调用搞定
  • 复杂任务(多步骤分析、多工具组合):用 Agent 框架

最佳实践

  1. 不要过度设计:能 Function Call 解决就别上 Agent
  2. 工具描述要清晰:模型靠 description 决定调用哪个工具
  3. 错误处理:工具执行可能失败,要有重试和降级方案
  4. 避免循环调用:Agent 里设置 max_iterations 防止死循环

系列关联:本文介绍了 Agent 工具调用的基础。下一篇《LangGraph 中 State、Node、Edge 是怎么协作的?》将深入讲 Agent 的核心组件,理解这三个概念是理解 LangGraph 工作原理的基础。

八、总结 + 下篇预告

核心要点

  • Function Call 是模型原生能力,一次性输出结构化函数调用
  • Agent 工具调用是循环过程:思考→决策→执行→观察→再思考
  • Function Call 适合简单单步任务,Agent 适合复杂多步骤任务
  • 两者不是替代关系,是不同场景的选择

下篇预告:下一篇我们将探讨《LangGraph 中 State、Node、Edge 是怎么协作的?》,深入理解 LangGraph 的三大核心概念,理解它们如何配合实现复杂的 Agent 流程。也是我个人学习的记录。

延伸阅读

Logo

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

更多推荐