Google Agent Development Kit (ADK) 指南 第五章:工具集成与自定义

Google Agent Development Kit (ADK) 指南 第五章:工具集成与自定义

系列教程:这是《Google ADK 指南》系列的第五章。

前置知识:已完成第四章,掌握 Agent 开发。


目录

  1. 工具基础
  2. 内置工具
  3. 自定义工具开发
  4. [第三方 API 集成](#第三方 API 集成)
  5. [GCP 服务集成](#GCP 服务集成)
  6. 工具管理最佳实践

1. 工具基础

1.1 工具的作用

工具是 Agent 的"手和脚",让 AI 能够:

  • 🔍 获取信息:搜索、查询数据库
  • 📝 执行操作:创建订单、发送邮件
  • 🔗 集成系统:连接 CRM、ERP
  • 📊 处理数据:计算、分析、转换

1.2 工具类型

类型 说明 示例
函数工具 Python 函数 计算器、日期处理
HTTP 工具 REST API 天气、地图、支付
数据库工具 SQL 查询 订单、用户查询
GCP 工具 Google 服务 BigQuery、Storage
代码工具 执行代码 Python、JavaScript

1.3 工具签名

python 复制代码
from google.adk import Tool
from pydantic import BaseModel, Field

@Tool(
    # 基础信息
    name="calculate_shipping",
    description="计算运费,支持国内和国际",
    
    # 参数定义(Pydantic)
    parameters={
        "weight": {
            "type": "number",
            "description": "包裹重量(公斤)",
            "required": True
        },
        "destination": {
            "type": "string", 
            "description": "目的地城市",
            "required": True
        },
        "express": {
            "type": "boolean",
            "description": "是否选择快递",
            "default": False
        }
    },
    
    # 高级配置
    timeout=10,           # 超时(秒)
    cache_ttl=300,        # 缓存时间(秒)
    rate_limit=100,       # 每分钟限制
    requires_auth=True    # 需要认证
)
def calculate_shipping(weight: float, destination: str, express: bool = False) -> str:
    """计算运费并返回格式化结果"""
    # 实现...
    pass

2. 内置工具

2.1 搜索工具

python 复制代码
from google.adk.tools import GoogleSearchTool

# Google 搜索
search_tool = GoogleSearchTool(
    api_key="your_search_api_key",
    cse_id="your_cse_id",
    num_results=5
)

# 使用
@Agent(tools=[search_tool])
def search_agent(query: str):
    return agent.run(f"搜索:{query}")

2.2 计算工具

python 复制代码
from google.adk.tools import CalculatorTool

calculator = CalculatorTool(
    supported_operations=["+", "-", "*", "/", "^", "sqrt", "log"]
)

# 示例
response = agent.run("计算 (123 + 456) * 789")

2.3 日期时间工具

python 复制代码
from google.adk.tools import DateTimeTool

datetime_tool = DateTimeTool(
    timezone="Asia/Shanghai",
    locale="zh_CN"
)

# 可用功能
# - 获取当前时间
# - 日期计算
# - 时区转换
# - 格式化输出

2.4 文件工具

python 复制代码
from google.adk.tools import FileTool

file_tool = FileTool(
    base_dir="/data",
    allowed_extensions=[".txt", ".pdf", ".docx"],
    max_file_size=10 * 1024 * 1024  # 10MB
)

# 可用功能
# - 读取文件
# - 写入文件
# - 搜索文件
# - 文件转换

3. 自定义工具开发

3.1 简单函数工具

python 复制代码
from google.adk import Tool

@Tool(
    name="get_weather",
    description="获取城市天气信息",
    parameters={
        "city": {"type": "string", "description": "城市名称"},
        "date": {"type": "string", "description": "日期(YYYY-MM-DD),默认今天"}
    }
)
def get_weather(city: str, date: str = None) -> str:
    """获取天气信息"""
    import requests
    
    api_key = "your_weather_api_key"
    url = "http://api.weatherapi.com/v1/forecast.json"
    params = {"key": api_key, "q": city, "days": 1}
    
    response = requests.get(url, params=params)
    data = response.json()
    
    current = data["current"]
    return f"{city} 天气:{current['condition']['text']}, 温度:{current['temp_c']}°C"

3.2 类工具(复杂逻辑)

python 复制代码
from google.adk.tools import BaseTool
from pydantic import BaseModel, Field
from typing import Optional

class OrderManagementTool(BaseTool):
    """订单管理工具"""
    
    name = "order_management"
    description = "管理订单:查询、创建、取消"
    
    # 参数定义
    class Parameters(BaseModel):
        action: str = Field(..., description="操作类型:query/create/cancel")
        order_id: Optional[str] = Field(None, description="订单 ID")
        items: Optional[list] = Field(None, description="商品列表")
        user_id: str = Field(..., description="用户 ID")
    
    def __init__(self, db_connection):
        self.db = db_connection
    
    def execute(self, action: str, order_id: str = None, 
                items: list = None, user_id: str = None) -> dict:
        
        if action == "query":
            return self._query_order(order_id)
        elif action == "create":
            return self._create_order(items, user_id)
        elif action == "cancel":
            return self._cancel_order(order_id)
        else:
            raise ValueError(f"未知操作:{action}")
    
    def _query_order(self, order_id: str) -> dict:
        order = self.db.query("SELECT * FROM orders WHERE id=?", order_id)
        return {"status": "success", "order": order}
    
    def _create_order(self, items: list, user_id: str) -> dict:
        order_id = self.db.insert("orders", {"user_id": user_id, "items": items})
        return {"status": "success", "order_id": order_id}
    
    def _cancel_order(self, order_id: str) -> dict:
        self.db.update("orders", {"status": "cancelled"}, {"id": order_id})
        return {"status": "success", "message": "订单已取消"}

# 使用
order_tool = OrderManagementTool(db_connection)
agent = Agent(tools=[order_tool])

3.3 异步工具

python 复制代码
from google.adk import Tool
import aiohttp

@Tool(
    name="fetch_webpage",
    description="获取网页内容",
    parameters={
        "url": {"type": "string", "description": "网页 URL"}
    }
)
async def fetch_webpage(url: str) -> str:
    """异步获取网页内容"""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

3.4 带状态的工具

python 复制代码
from google.adk.tools import StatefulTool

class ShoppingCartTool(StatefulTool):
    """购物车工具(带状态)"""
    
    name = "shopping_cart"
    description = "管理购物车:添加、删除、结算"
    
    def __init__(self):
        self.carts = {}  # user_id -> cart_items
    
    def add_item(self, user_id: str, item: dict):
        if user_id not in self.carts:
            self.carts[user_id] = []
        self.carts[user_id].append(item)
        return {"status": "success", "cart": self.carts[user_id]}
    
    def remove_item(self, user_id: str, item_id: str):
        if user_id in self.carts:
            self.carts[user_id] = [
                i for i in self.carts[user_id] if i["id"] != item_id
            ]
        return {"status": "success", "cart": self.carts.get(user_id, [])}
    
    def checkout(self, user_id: str) -> dict:
        items = self.carts.get(user_id, [])
        total = sum(item["price"] * item["quantity"] for item in items)
        self.carts[user_id] = []  # 清空购物车
        return {"status": "success", "total": total, "items": len(items)}

4. 第三方 API 集成

4.1 REST API 工具

python 复制代码
from google.adk import Tool
import requests
from functools import wraps

def api_tool(base_url: str, api_key: str):
    """API 工具装饰器"""
    def decorator(func):
        @wraps(func)
        @Tool(
            name=func.__name__,
            description=func.__doc__,
            timeout=30
        )
        def wrapper(*args, **kwargs):
            headers = {"Authorization": f"Bearer {api_key}"}
            try:
                result = func(base_url=base_url, headers=headers, *args, **kwargs)
                return result
            except requests.exceptions.RequestException as e:
                return f"API 调用失败:{str(e)}"
        return wrapper
    return decorator

# 使用示例
@api_tool("https://api.stripe.com", "sk_test_xxx")
def create_charge(base_url: str, headers: dict, amount: int, currency: str) -> dict:
    """创建支付订单"""
    response = requests.post(
        f"{base_url}/v1/charges",
        headers=headers,
        data={"amount": amount, "currency": currency}
    )
    return response.json()

4.2 GraphQL API 工具

python 复制代码
from google.adk import Tool
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport

@Tool(
    name="github_query",
    description="查询 GitHub 数据",
    parameters={
        "query": {"type": "string", "description": "GraphQL 查询"}
    }
)
def github_query(query: str) -> dict:
    """执行 GitHub GraphQL 查询"""
    transport = RequestsHTTPTransport(
        url="https://api.github.com/graphql",
        headers={"Authorization": "Bearer YOUR_TOKEN"},
        verify=True,
        retries=3
    )
    
    client = Client(transport=transport, fetch_schema_from_transport=True)
    result = client.execute(gql(query))
    return result

4.3 WebSocket 工具

python 复制代码
from google.adk.tools import BaseTool
import websocket
import json

class StockPriceTool(BaseTool):
    """股票价格工具(WebSocket 实时)"""
    
    name = "stock_price"
    description = "获取实时股票价格"
    
    def __init__(self, ws_url: str):
        self.ws_url = ws_url
        self.ws = None
    
    def connect(self):
        self.ws = websocket.create_connection(self.ws_url)
    
    def execute(self, symbol: str) -> dict:
        if not self.ws:
            self.connect()
        
        # 订阅股票
        self.ws.send(json.dumps({"action": "subscribe", "symbol": symbol}))
        
        # 接收价格
        response = self.ws.recv()
        return json.loads(response)
    
    def close(self):
        if self.ws:
            self.ws.close()

5. GCP 服务集成

5.1 BigQuery 工具

python 复制代码
from google.adk import Tool
from google.cloud import bigquery

@Tool(
    name="bigquery_query",
    description="执行 BigQuery SQL 查询",
    parameters={
        "query": {"type": "string", "description": "SQL 查询语句"},
        "project_id": {"type": "string", "description": "GCP 项目 ID"}
    }
)
def bigquery_query(query: str, project_id: str) -> list:
    """执行 BigQuery 查询"""
    client = bigquery.Client(project=project_id)
    
    # 只读检查
    if not query.strip().upper().startswith("SELECT"):
        return {"error": "只允许 SELECT 查询"}
    
    query_job = client.query(query)
    results = query_job.result()
    
    return [dict(row) for row in results]

5.2 Cloud Storage 工具

python 复制代码
from google.adk import Tool
from google.cloud import storage

@Tool(
    name="gcs_upload",
    description="上传文件到 Cloud Storage",
    parameters={
        "bucket": {"type": "string", "description": "存储桶名称"},
        "source_path": {"type": "string", "description": "本地文件路径"},
        "destination": {"type": "string", "description": "目标路径"}
    }
)
def gcs_upload(bucket: str, source_path: str, destination: str) -> dict:
    """上传文件到 GCS"""
    client = storage.Client()
    bucket = client.bucket(bucket)
    blob = bucket.blob(destination)
    
    blob.upload_from_filename(source_path)
    
    return {
        "status": "success",
        "gs_uri": f"gs://{bucket}/{destination}",
        "public_url": f"https://storage.googleapis.com/{bucket}/{destination}"
    }

5.3 Vertex AI 工具

python 复制代码
from google.adk import Tool
from vertexai.preview.generative_models import GenerativeModel

@Tool(
    name="vertex_generate",
    description="使用 Vertex AI 生成内容",
    parameters={
        "prompt": {"type": "string", "description": "生成提示"},
        "model": {"type": "string", "description": "模型名称", "default": "gemini-pro"}
    }
)
def vertex_generate(prompt: str, model: str = "gemini-pro") -> str:
    """使用 Vertex AI 生成内容"""
    generative_model = GenerativeModel(model)
    response = generative_model.generate_content(prompt)
    return response.text

5.4 Secret Manager 工具

python 复制代码
from google.adk import Tool
from google.cloud import secretmanager

@Tool(
    name="get_secret",
    description="从 Secret Manager 获取密钥",
    parameters={
        "secret_id": {"type": "string", "description": "密钥 ID"},
        "project_id": {"type": "string", "description": "GCP 项目 ID"}
    },
    requires_auth=True
)
def get_secret(secret_id: str, project_id: str) -> str:
    """获取密钥"""
    client = secretmanager.SecretManagerServiceClient()
    name = f"projects/{project_id}/secrets/{secret_id}/versions/latest"
    
    response = client.access_secret_version(request={"name": name})
    return response.payload.data.decode("UTF-8")

6. 工具管理最佳实践

6.1 工具组织

python 复制代码
# 按功能分组
from google.adk.tools import ToolGroup

search_tools = ToolGroup([
    google_search_tool,
    internal_search_tool,
    vector_search_tool
])

data_tools = ToolGroup([
    bigquery_tool,
    sql_tool,
    analytics_tool
])

communication_tools = ToolGroup([
    email_tool,
    sms_tool,
    slack_tool
])

# Agent 使用
agent = Agent(tools=[search_tools, data_tools, communication_tools])

6.2 错误处理

python 复制代码
from google.adk.tools import ToolExecutionError

@Tool(name="reliable_tool")
def reliable_tool(param: str) -> dict:
    """可靠的工具实现"""
    try:
        # 主逻辑
        result = do_something(param)
        return {"status": "success", "data": result}
    
    except ValidationError as e:
        # 参数验证失败
        return {"status": "error", "code": "VALIDATION_ERROR", "message": str(e)}
    
    except APIError as e:
        # API 错误
        return {"status": "error", "code": "API_ERROR", "message": str(e)}
    
    except TimeoutError:
        # 超时
        return {"status": "error", "code": "TIMEOUT", "message": "请求超时"}
    
    except Exception as e:
        # 未知错误
        logger.exception("未知错误")
        return {"status": "error", "code": "UNKNOWN", "message": "内部错误"}

6.3 日志与监控

python 复制代码
from google.adk.tools import MonitoredTool

@Tool(
    name="monitored_tool",
    monitor=True,  # 启用监控
    log_level="INFO"
)
def monitored_tool(param: str) -> str:
    """带监控的工具"""
    # 自动记录:
    # - 输入参数
    # - 执行时间
    # - 输出结果
    # - 错误信息
    pass

6.4 测试工具

python 复制代码
import pytest
from google.adk.tools import ToolTester

def test_weather_tool():
    tool = get_weather
    
    # 测试正常情况
    result = tool.execute(city="北京")
    assert "天气" in result
    assert "°C" in result
    
    # 测试错误情况
    result = tool.execute(city="无效城市")
    assert "error" in result.lower() or "失败" in result

# 使用测试器
tester = ToolTester(get_weather)
tester.test_with_inputs([
    {"city": "北京"},
    {"city": "上海"},
    {"city": ""}  # 边界测试
])

系列教程导航

相关推荐
❀搜不到16 小时前
Ubuntu查看指定Python程序的CPU、GPU、内存占用情况
linux·python·ubuntu
imbackneverdie16 小时前
深耕医学科研智能化十年,MedPeer打造新一代AI生物医学科研操作系统
大数据·人工智能·ai·信息可视化·数据分析·aigc·科研
AI程序员16 小时前
Claude Code Dynamic workflows:AI 编程正在从“助手”走向“工程编排”
人工智能
赵我说的做_life16 小时前
OpenClaw Agent 改配置导致 assistant turn failed 故障排查与修复
人工智能
卷无止境16 小时前
用一个机器车间,研究SimPy核心概念
python
意图共鸣17 小时前
意图共鸣科技发布《认知智能白皮书》:AI认知架构(CA)与认知操作系统(COS)——为什么大模型之外还需要一层认知调度层,技术原理与架构设想
人工智能·科技·架构
Jmayday17 小时前
NLP第四章:Transformer架构
人工智能·自然语言处理·transformer
zhendianluli17 小时前
PyTorch 复杂模型转 ONNX 踩坑纪实:从 diff 到 nan_to_num 的三关突破
人工智能·pytorch·python
不爱吃糖の糖糖17 小时前
RAG 06:RAG 多路召回与检索优化策略详解
人工智能·embedding