基于工具调用的智能体设计与实现(*)

15 阅读4分钟

基于工具调用的智能体设计与实现

一、这是什么?(概念解释)

基于工具调用的Agent(Tool Calling Agent) 是利用LLM原生函数调用能力实现的智能体。

与ReACT的区别

  • ReACT:依赖Prompt让LLM按特定格式输出(Thought/Action/Observation)
  • 工具调用Agent:利用模型原生的 tool_calls 功能,更稳定、更高效

核心优势

  • 原生支持:使用模型内置的函数调用能力
  • 结构化输出:自动返回结构化的工具调用指令
  • 多轮对话:支持聊天历史,可以实现对话式Agent
  • 更简洁:无需复杂的Prompt模板

二、有什么用?(应用场景)

场景说明
对话式助手支持多轮对话的智能助手
任务自动化自动调用工具完成复杂任务
信息检索结合搜索工具回答问题
内容生成调用图片/视频生成工具
数据分析调用数据分析工具生成报告
API集成 -调用外部API服务
多工具协同自动选择和组合多个工具

三、完整示例代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import dotenv
import os
import requests
from datetime import datetime
from langchain_classic.agents import create_tool_calling_agent, AgentExecutor
from langchain_community.tools import GoogleSerperRun
from langchain_community.utilities import GoogleSerperAPIWrapper
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()

# ============ 第一步:定义工具 ============

@tool
def generate_image(prompt: str) -> str:
    """
    使用通义万相生成图片

    Args:
        prompt: 图片描述提示词

    Returns:
        生成图片保存到当前目录
    """
    try:
        # 调用通义万相API生成图片
        response = ImageSynthesis.call(
            model='wanx-v1',
            prompt=prompt,
            n=1,
            size='1024*1024'
        )

        if response.status_code == 200:
            image_url = response.output.results[0].url

            # 下载图片并保存
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"generated_image_{timestamp}.png"

            img_response = requests.get(image_url)
            if img_response.status_code == 200:
                with open(filename, 'wb') as f:
                    f.write(img_response.content)
                return f"图片生成成功!已保存到: {filename}"
            else:
                return f"图片下载失败"
        else:
            return f"图片生成失败"

    except Exception as e:
        return f"图片生成异常: {str(e)}"

# 定义搜索工具
google_serper = GoogleSerperRun(
    name="google_serper",
    description="一个低成本的谷歌搜索API。当你需要回答有关时事的问题时,可以调用该工具。",
    args_schema=GoogleSerperArgsSchema,
    api_wrapper=GoogleSerperAPIWrapper(),
)

tools = [google_serper, generate_image]

# ============ 第二步:定义 Prompt ============

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个智能助手,善于帮助用户解决问题。"),
    ("placeholder", "{chat_history}"),  # 聊天历史
    ("human", "{input}"),  # 用户输入
    ("placeholder", "{agent_scratchpad}"),  # Agent执行历史
])

# ============ 第三步:创建工具调用 Agent ============

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

agent = create_tool_calling_agent(
    llm=llm,
    prompt=prompt,
    tools=tools,
)

# ============ 第四步:创建 Agent 执行器 ============

agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,  # 打印执行过程
    max_iterations=5,  # 最大迭代次数
    handle_parsing_errors=True,
)

# ============ 第五步:执行 Agent ============

result = agent_executor.invoke({
    "input": "帮我绘制一幅鲨鱼在天上游泳的场景"
})

print(result)

四、工具调用Agent vs ReACT Agent

┌─────────────────────────────────────────────────────────────────────────┐
│            工具调用Agent VS ReACT Agent 对比                              │
└─────────────────────────────────────────────────────────────────────────┘


  ================== ReACT Agent ==================

  Prompt 复杂度:高
  需要精心设计 Prompt 模板

  用户问题                  LLM                      工具执行
     │                       │                         │
     ▼                       ▼                         │
  "生成鲨鱼图片" ────────────▶│ Thought: 我需要生成图片  │
     │                       │                         │
     │                       │ Action: generate_image  │
     │                       │                         │
     │                       │ Action Input: "鲨鱼..."  │
     │◀──────────────────────│                         │
     ▼                       │                         │
  解析 Action Input         │                         │
     │                       │                         │
     ▼                       ▼                         ▼
  调用工具 ─────────────────────────────────────────────▶│
     │                                        生成图片
     │◀───────────────────────────────────────│
     ▼                       ▼                         ▼
  观察 (Observation)        "图片已保存"             返回结果
     │                       │                         │
     ▼                       ▼                         │
  Thought: 我知道答案了     Final Answer: "图片...     │
     │                       │                         │
     ▼                       ▼                         ▼
  返回结果                 完成                     完成


  ================== 工具调用 Agent ==================

  Prompt 复杂度:低
  只需简单的系统提示

  用户问题                  LLM                      工具执行
     │                       │                         │
     ▼                       ▼                         │
  "生成鲨鱼图片" ────────────▶│ 自动分析需求            │
     │                       │                         │
     │                       │ 返回 tool_calls:        │
     │◀──────────────────────│ [{name: "generate_image",│
     │                       │   args: {prompt: "..."]}}│
     ▼                       │                         │
  自动解析 tool_calls        │                         │
     │                       │                         │
     ▼                       ▼                         ▼
  自动调用工具 ──────────────────────────────────────────▶│
     │                                        生成图片
     │◀───────────────────────────────────────│
     ▼                       ▼                         ▼
  自动获取工具结果           "图片已保存"             返回结果
     │                       │                         │
     ▼                       ▼                         │
  自动生成最终回答           "图片已生成并保存..."      │
     │                       │                         │
     ▼                       ▼                         ▼
  返回结果                 完成                     完成


  ┌─────────────────────────────────────────────────────────────────────────┐
  │                         核心差异                                         │
  └─────────────────────────────────────────────────────────────────────────┘

  特性              ReACT Agent              工具调用 Agent
  ─────────────────────────────────────────────────────────────────────────
  Prompt 复杂度      高(需要严格格式)        低(简单提示)
  模型兼容性        广(几乎所有模型)        有限(需要支持函数调用)
  解析方式          手动解析文本              自动解析 tool_calls
  错误处理          容易出错                 更稳定
  Token消耗         高                       低
  多轮对话          需要手动管理             自动支持

五、执行流程示例

假设用户问:"帮我搜索一下深圳今天的天气,然后生成一张天气预报图片"

第1轮迭代

> Entering new AgentExecutor chain...

Invoking: google_serper
with: {'query': '深圳今天天气'}

Observation: 深圳今天晴天,温度25°C,湿度60%

第2轮迭代

Thought: 我需要根据天气信息生成一张天气预报图片

Invoking: generate_image
with: {'prompt': '深圳今天晴天,温度25度,湿度60%,天气预报插图'}

Observation: 图片生成成功!已保存到: generated_image_20260305.png

最终回答

> Finished chain.

根据搜索结果,深圳今天晴天,温度25°C,湿度60%。
我已经为您生成了一张天气预报插图,保存为:generated_image_20260305.png

参考资源


总结一句话:工具调用Agent利用模型原生函数调用能力,比ReACT更简洁、更稳定,是构建现代AI应用的首选方案!