logo

实战一:构建你的第一个工具调用 Agent

如果你第一次做 Agent,我不建议一上来就碰“自动改代码”或者“多 Agent 协作”。最合适的起点通常是一个非常小、但能完整跑通的工具调用闭环。

天气查询就是这种很适合练手的例子。它足够简单,不需要复杂业务背景,但又能把 Agent 最关键的几步都串起来:

  • 用户提出一个目标
  • 模型判断自己缺信息
  • 模型调用工具
  • 工具返回结果
  • 模型基于结果再组织最终回答

这就是 Agent 的最小骨架。

[PROMPT_LAB_BANNER]


1. 准备工作

这里用 Python 和 Gemini 只是为了把例子写得更直接,不代表你必须绑定某个模型厂商。核心思路在 OpenAI、Anthropic 或其他支持 tool calling 的模型里都类似。

我们先安装依赖:

pip install -q -U google-generativeai

2. 定义工具 (Define Tool)

Agent 不会凭空知道“现在墨尔本几度”。如果没有联网能力,它只能猜。

所以第一步是把“查询天气”暴露成一个工具。这里先用一个假的天气函数,把注意力放在调用机制本身,而不是第三方 API 细节。

import google.generativeai as genai
import os

# 模拟的天气 API(真实项目里可以接 OpenWeatherMap、WeatherAPI 等)
def get_current_weather(location: str):
    """获取指定地点的当前天气信息"""
    print(f"🔧 工具被调用: get_current_weather('{location}')")
    
    # 这里只是模拟返回
    weather_data = {
        "Beijing": "Sunny, 25°C",
        "Melbourne": "Rainy, 12°C",
        "New York": "Cloudy, 18°C"
    }
    return weather_data.get(location, "Unknown location")

# 将函数放入工具箱
tools = [get_current_weather]

这个示例里有两个刻意简化的地方,你要心里有数:

  1. 返回值只是纯文本,真实项目更建议返回结构化 JSON。
  2. 没做异常处理,真实环境里你至少要考虑超时、空结果和非法参数。

比如更稳一点的返回可以是:

{
  "location": "Melbourne",
  "temperature_c": 12,
  "condition": "Rainy",
  "source": "weather_api"
}

因为结构化数据更容易让模型稳定消费,也更方便后续程序处理。

3. 初始化模型

工具定义好以后,下一步是把它注册给模型,让模型知道“自己在什么情况下可以调用什么能力”。

genai.configure(api_key="YOUR_API_KEY")

# 使用支持 tool/function calling 的模型
model = genai.GenerativeModel(
    model_name='gemini-1.5-flash',
    tools=tools  # 注入工具
)

# 开启自动工具调用
# SDK 会帮你处理“模型提议调用 -> 执行函数 -> 把结果回传给模型”这段流程
chat = model.startChat(enable_automatic_function_calling=True)

自动模式很适合入门,因为它能让你先把最小闭环跑通。

但别太早依赖它。只要你开始做真实产品,很快就会遇到这些需求:

  • 想记录每次工具调用日志
  • 想限制某些工具只能调用一次
  • 想在敏感操作前插入人工确认
  • 想对异常做自定义重试

这时你最终还是会回到“手动控制循环”。

4. 运行 Agent

现在可以发一个真实一点的用户问题,让模型自己判断是否要调工具:

response = chat.send_message("墨尔本和北京现在的天气怎么样?适合穿什么?")
print(f"🤖 Agent 回答:\n{response.text}")

幕后发生了什么?

  1. User: "墨尔本和北京..."
  2. Model: 思考 -> 决定调用 get_current_weather(location='Melbourne')get_current_weather(location='Beijing')
  3. Execution (SDK自动处理): 运行函数,获取 "Rainy, 12°C" 和 "Sunny, 25°C"。
  4. Model: 接收到工具结果 -> 综合生成最终建议。
  5. Output: "墨尔本现在下雨,12度,建议穿雨衣和保暖衣物;北京..."

5. 进阶:手动控制循环

虽然 SDK 自动调用很省事,但复杂 Agent 系统通常不会把执行权完全交给 SDK。

原因很现实:

  • 你不知道模型为什么反复调用同一个工具
  • 你没法在关键节点插入审批
  • 工具调用失败时,不一定该直接把错误丢回给模型
  • 你可能还想对某些工具做限流、鉴权或审计

所以更常见的做法,是自己维护一个显式循环。

手动循环伪代码:

messages = [...] # ...

while True:
    # 1. 调用 LLM
    response = model.generate_content(messages)
    
    # 2. 检查是否有 Tool Call
    if not response.function_calls:
        break # 没工具调用,直接结束
        
    # 3. 执行工具
    for call in response.function_calls:
        tool_result = execute_tool(call.name, call.args)
        
        # 4. 将结果追加到对话历史
        messages.append({
            "role": "tool",
            "name": call.name,
            "content": tool_result
        })
        
    # 5. 循环继续,LLM 看到工具结果后会生成下一步

这段伪代码背后的重点其实只有一句:

模型负责决定“要不要用工具”,程序负责决定“工具到底怎么安全地被执行”。

这个边界一定要清楚。


6. 真实项目里最容易踩的坑

光把 demo 跑通还不够。工具调用 Agent 最容易翻车的点,通常在这些地方:

工具描述太弱

如果工具 description 写得太简略,模型可能根本不知道什么时候该调用它,或者乱调。

比如只写:

获取天气

就太弱了。更好的写法应该告诉模型:

  • 这个工具适用于什么问题
  • 输入参数是什么
  • 返回什么格式
  • 什么时候不该调用

把副作用工具和只读工具混在一起

查询天气这类工具是只读的,风险很低。

但一旦工具变成:

  • 发邮件
  • 改数据库
  • 删除文件
  • 提交 PR

风险就完全变了。真实系统里最好对工具做分级,至少分成:

  • 只读工具
  • 可写但低风险工具
  • 高风险工具,需要人审

工具失败时没有兜底

真实 API 经常会:

  • 超时
  • 429 限流
  • 返回空结果
  • 参数校验失败

如果你直接把原始报错扔给模型,它有时会继续“编”。更稳的方式通常是:

  • 把错误标准化
  • 明确告诉模型这是失败,不是数据
  • 决定让它重试、换方案,还是终止

7. 可以怎么继续升级这个实验

如果这个天气 Agent 你已经跑通,后面可以逐步加这几层能力:

  1. 把假数据换成真实天气 API。
  2. 把工具输出改成结构化 JSON。
  3. 加一个日志层,记录每次 tool call。
  4. 给工具调用加最大次数限制,防止死循环。
  5. 再加一个新工具,比如城市时区查询,观察模型如何选择工具。

做到这里,你就已经不是在玩“聊天增强”,而是在搭一个真正意义上的工具型 Agent。


小结

工具调用 Agent 的本质,真的可以压缩成一个 while loop

  1. Ask:问模型下一步想做什么。
  2. Act:由程序安全地执行动作。
  3. Observe:把结果回传给模型。
  4. Repeat:直到任务结束。

看起来很简单,但大多数复杂 Agent,最后其实都是从这个骨架慢慢长出来的。

AI Agent 开发实战手册
AI Engineer

AI Agent 开发实战手册

从 0 到 1 掌握 AI Agent 开发:涵盖自主计划、工具调用、MCP 协议与多智能体编排实战。

AI Agent 开发实战手册实战一:构建你的第一个工具调用 Agent

实战一:构建你的第一个工具调用 Agent

如果你第一次做 Agent,我不建议一上来就碰“自动改代码”或者“多 Agent 协作”。最合适的起点通常是一个非常小、但能完整跑通的工具调用闭环。

天气查询就是这种很适合练手的例子。它足够简单,不需要复杂业务背景,但又能把 Agent 最关键的几步都串起来:

  • 用户提出一个目标
  • 模型判断自己缺信息
  • 模型调用工具
  • 工具返回结果
  • 模型基于结果再组织最终回答

这就是 Agent 的最小骨架。

Prompt Lab

把这章的知识,直接变成实战能力

进入交互式实验室,用真实任务练 Prompt,10 分钟快速上手。

进入 Prompt Lab →

#1. 准备工作

这里用 Python 和 Gemini 只是为了把例子写得更直接,不代表你必须绑定某个模型厂商。核心思路在 OpenAI、Anthropic 或其他支持 tool calling 的模型里都类似。

我们先安装依赖:

bash
pip install -q -U google-generativeai

#2. 定义工具 (Define Tool)

Agent 不会凭空知道“现在墨尔本几度”。如果没有联网能力,它只能猜。

所以第一步是把“查询天气”暴露成一个工具。这里先用一个假的天气函数,把注意力放在调用机制本身,而不是第三方 API 细节。

python
import google.generativeai as genai import os # 模拟的天气 API(真实项目里可以接 OpenWeatherMap、WeatherAPI 等) def get_current_weather(location: str): """获取指定地点的当前天气信息""" print(f"🔧 工具被调用: get_current_weather('{location}')") # 这里只是模拟返回 weather_data = { "Beijing": "Sunny, 25°C", "Melbourne": "Rainy, 12°C", "New York": "Cloudy, 18°C" } return weather_data.get(location, "Unknown location") # 将函数放入工具箱 tools = [get_current_weather]

这个示例里有两个刻意简化的地方,你要心里有数:

  1. 返回值只是纯文本,真实项目更建议返回结构化 JSON。
  2. 没做异常处理,真实环境里你至少要考虑超时、空结果和非法参数。

比如更稳一点的返回可以是:

json
{ "location": "Melbourne", "temperature_c": 12, "condition": "Rainy", "source": "weather_api" }

因为结构化数据更容易让模型稳定消费,也更方便后续程序处理。

#3. 初始化模型

工具定义好以后,下一步是把它注册给模型,让模型知道“自己在什么情况下可以调用什么能力”。

python
genai.configure(api_key="YOUR_API_KEY") # 使用支持 tool/function calling 的模型 model = genai.GenerativeModel( model_name='gemini-1.5-flash', tools=tools # 注入工具 ) # 开启自动工具调用 # SDK 会帮你处理“模型提议调用 -> 执行函数 -> 把结果回传给模型”这段流程 chat = model.startChat(enable_automatic_function_calling=True)

自动模式很适合入门,因为它能让你先把最小闭环跑通。

但别太早依赖它。只要你开始做真实产品,很快就会遇到这些需求:

  • 想记录每次工具调用日志
  • 想限制某些工具只能调用一次
  • 想在敏感操作前插入人工确认
  • 想对异常做自定义重试

这时你最终还是会回到“手动控制循环”。

#4. 运行 Agent

现在可以发一个真实一点的用户问题,让模型自己判断是否要调工具:

python
response = chat.send_message("墨尔本和北京现在的天气怎么样?适合穿什么?") print(f"🤖 Agent 回答:\n{response.text}")

#幕后发生了什么?

  1. User: "墨尔本和北京..."
  2. Model: 思考 -> 决定调用 get_current_weather(location='Melbourne')get_current_weather(location='Beijing')
  3. Execution (SDK自动处理): 运行函数,获取 "Rainy, 12°C" 和 "Sunny, 25°C"。
  4. Model: 接收到工具结果 -> 综合生成最终建议。
  5. Output: "墨尔本现在下雨,12度,建议穿雨衣和保暖衣物;北京..."

#5. 进阶:手动控制循环

虽然 SDK 自动调用很省事,但复杂 Agent 系统通常不会把执行权完全交给 SDK。

原因很现实:

  • 你不知道模型为什么反复调用同一个工具
  • 你没法在关键节点插入审批
  • 工具调用失败时,不一定该直接把错误丢回给模型
  • 你可能还想对某些工具做限流、鉴权或审计

所以更常见的做法,是自己维护一个显式循环。

手动循环伪代码:

python
messages = [...] # ... while True: # 1. 调用 LLM response = model.generate_content(messages) # 2. 检查是否有 Tool Call if not response.function_calls: break # 没工具调用,直接结束 # 3. 执行工具 for call in response.function_calls: tool_result = execute_tool(call.name, call.args) # 4. 将结果追加到对话历史 messages.append({ "role": "tool", "name": call.name, "content": tool_result }) # 5. 循环继续,LLM 看到工具结果后会生成下一步

这段伪代码背后的重点其实只有一句:

模型负责决定“要不要用工具”,程序负责决定“工具到底怎么安全地被执行”。

这个边界一定要清楚。


#6. 真实项目里最容易踩的坑

光把 demo 跑通还不够。工具调用 Agent 最容易翻车的点,通常在这些地方:

#工具描述太弱

如果工具 description 写得太简略,模型可能根本不知道什么时候该调用它,或者乱调。

比如只写:

获取天气

就太弱了。更好的写法应该告诉模型:

  • 这个工具适用于什么问题
  • 输入参数是什么
  • 返回什么格式
  • 什么时候不该调用

#把副作用工具和只读工具混在一起

查询天气这类工具是只读的,风险很低。

但一旦工具变成:

  • 发邮件
  • 改数据库
  • 删除文件
  • 提交 PR

风险就完全变了。真实系统里最好对工具做分级,至少分成:

  • 只读工具
  • 可写但低风险工具
  • 高风险工具,需要人审

#工具失败时没有兜底

真实 API 经常会:

  • 超时
  • 429 限流
  • 返回空结果
  • 参数校验失败

如果你直接把原始报错扔给模型,它有时会继续“编”。更稳的方式通常是:

  • 把错误标准化
  • 明确告诉模型这是失败,不是数据
  • 决定让它重试、换方案,还是终止

#7. 可以怎么继续升级这个实验

如果这个天气 Agent 你已经跑通,后面可以逐步加这几层能力:

  1. 把假数据换成真实天气 API。
  2. 把工具输出改成结构化 JSON。
  3. 加一个日志层,记录每次 tool call。
  4. 给工具调用加最大次数限制,防止死循环。
  5. 再加一个新工具,比如城市时区查询,观察模型如何选择工具。

做到这里,你就已经不是在玩“聊天增强”,而是在搭一个真正意义上的工具型 Agent。


#小结

工具调用 Agent 的本质,真的可以压缩成一个 while loop

  1. Ask:问模型下一步想做什么。
  2. Act:由程序安全地执行动作。
  3. Observe:把结果回传给模型。
  4. Repeat:直到任务结束。

看起来很简单,但大多数复杂 Agent,最后其实都是从这个骨架慢慢长出来的。

常见问题

开发 AI Agent 需要掌握哪些编程语言?
首选 Python 或 TypeScript。Python 是 AI 生态的基石,而 TypeScript 在开发 MCP Server 和网页端交互时效率极高。借助 Cursor 等 AI 原生编辑器,编程门槛已大幅降低。
MCP 协议目前支持哪些模型?
MCP 是开放协议,目前对 Claude 3.5 系列支持最完美。通过 MCP Proxy,GPT-4o 和 Gemini 也可以间接访问 MCP Server 数据源。
AI Agent 会导致程序员失业吗?
不会,但会改变程序员的工作内容。未来的开发者将从“写代码”转向“管理 Agent 团队”,重点在于系统架构设计、复杂逻辑校验和 Agent 的提示词优化。