This commit is contained in:
Nelson
2026-04-06 12:36:04 +08:00
commit 514723dbe7
23 changed files with 7529 additions and 0 deletions

View File

@@ -0,0 +1,338 @@
"""
Google ADK 自定义工具开发完整示例
展示各种工具开发技巧和最佳实践
对应教程第04章 - 自定义工具开发
"""
# 导入 ADK 核心模块
from google.adk.agents import Agent # Agent 类
from google.adk.tools import AgentTool # AgentToolAgent 作为工具)
# 导入类型提示
from typing import Optional, List # 可选类型和列表类型
# 导入运行相关模块
from google.adk.runners import Runner # 运行器
from google.adk.sessions import InMemorySessionService # 会话服务
from google.genai import types # 类型定义
# 导入异步库
import asyncio # 异步编程库
# ========================================
# 示例一:基础函数工具
# ========================================
def get_weather(city: str) -> dict:
"""
获取指定城市的天气信息
Args:
city (str): 城市名称,例如"北京""上海"
Returns:
dict: 包含天气状态的字典
- status: "success""error"
- city: 城市名称
- temperature: 温度
- condition: 天气状况
"""
# 模拟天气数据
weather_data = { # 天气数据库
"北京": {"temp": "25°C", "condition": "晴天"}, # 北京
"上海": {"temp": "28°C", "condition": "多云"}, # 上海
"广州": {"temp": "32°C", "condition": "雷阵雨"}, # 广州
}
# 查找城市天气
data = weather_data.get(city) # 获取天气数据
if not data: # 如果找不到
return { # 返回错误
"status": "error",
"error_message": f"未找到'{city}'的天气信息"
}
return { # 返回成功结果
"status": "success",
"city": city,
"temperature": data["temp"],
"condition": data["condition"],
}
# ========================================
# 示例二:带可选参数的工具
# ========================================
def search_restaurant(
city: str, # 必选参数
cuisine: str = "中餐", # 可选参数,默认中餐
price_range: str = "中等", # 可选参数,默认中等
) -> dict:
"""
搜索指定城市的餐厅
Args:
city (str): 城市名称
cuisine (str, optional): 菜系类型,默认"中餐"
price_range (str, optional): 价格范围,默认"中等"
Returns:
dict: 搜索结果
"""
return { # 返回搜索结果
"status": "success",
"city": city,
"cuisine": cuisine,
"price_range": price_range,
"results": [ # 餐厅列表
{"name": "美味餐厅", "rating": 4.5, "price": "人均100元"},
{"name": "佳肴轩", "rating": 4.2, "price": "人均80元"},
],
}
# ========================================
# 示例三:使用 Optional 类型
# ========================================
def create_user_profile(
username: str, # 必选参数
bio: Optional[str] = None, # 可选参数
avatar_url: Optional[str] = None, # 可选参数
) -> dict:
"""
创建用户档案
Args:
username (str): 用户名
bio (str, optional): 个人简介
avatar_url (str, optional): 头像 URL
Returns:
dict: 创建结果
"""
profile = { # 创建档案
"username": username, # 用户名
"bio": bio or "这个人很懒,什么都没写。", # 简介
"avatar_url": avatar_url or "", # 头像
}
return { # 返回结果
"status": "success",
"profile": profile,
}
# ========================================
# 示例四List 类型参数
# ========================================
def compare_cities(cities: List[str]) -> dict:
"""
比较多个城市的信息
Args:
cities (List[str]): 城市名称列表
Returns:
dict: 比较结果
"""
city_info = { # 城市信息
"北京": {"population": "2189万", "area": "16410km²"},
"上海": {"population": "2487万", "area": "6341km²"},
"广州": {"population": "1881万", "area": "7434km²"},
}
results = [] # 结果列表
for city in cities: # 遍历城市
info = city_info.get(city) # 获取信息
if info: # 如果存在
results.append({"city": city, **info}) # 添加到结果
return { # 返回结果
"status": "success" if results else "error",
"results": results,
}
# ========================================
# 示例五:健壮的工具(完善的错误处理)
# ========================================
def calculate_loan(
principal: float, # 贷款本金
annual_rate: float, # 年利率
years: int, # 贷款年限
) -> dict:
"""
计算贷款月供和总利息
Args:
principal (float): 贷款本金(元)
annual_rate (float): 年利率(百分比,如 4.5
years (int): 贷款年限
Returns:
dict: 计算结果
"""
# 参数验证
if principal <= 0: # 本金必须大于0
return { # 返回错误
"status": "error",
"error_code": "INVALID_PRINCIPAL",
"error_message": "贷款本金必须大于0。"
}
if annual_rate <= 0 or annual_rate > 30: # 利率范围检查
return { # 返回错误
"status": "error",
"error_code": "INVALID_RATE",
"error_message": "年利率必须在 0-30% 之间。"
}
if years <= 0 or years > 30: # 年限范围检查
return { # 返回错误
"status": "error",
"error_code": "INVALID_YEARS",
"error_message": "贷款年限必须在 1-30 年之间。"
}
try: # 尝试计算
monthly_rate = annual_rate / 100 / 12 # 月利率
total_months = years * 12 # 总月数
# 等额本息月供公式
if monthly_rate == 0: # 如果利率为0
monthly_payment = principal / total_months # 直接除
else: # 正常计算
monthly_payment = ( # 月供计算
principal * monthly_rate * (1 + monthly_rate) ** total_months
/ ((1 + monthly_rate) ** total_months - 1)
)
total_amount = monthly_payment * total_months # 总还款额
total_interest = total_amount - principal # 总利息
return { # 返回计算结果
"status": "success",
"monthly_payment": round(monthly_payment, 2), # 月供
"total_interest": round(total_interest, 2), # 总利息
"total_amount": round(total_amount, 2), # 总还款额
}
except Exception as e: # 捕获计算异常
return { # 返回错误
"status": "error",
"error_code": "CALCULATION_ERROR",
"error_message": f"计算出错:{str(e)}"
}
# ========================================
# 示例六Agent-as-a-Tool
# ========================================
# 定义一个翻译 Agent
translator_agent = Agent(
name="translator", # 翻译 Agent
model="gemini-2.0-flash", # 模型
instruction="你是翻译专家,将文本翻译成目标语言。只输出翻译结果。", # 指令
)
# 将翻译 Agent 包装为工具
translation_tool = AgentTool(
agent=translator_agent, # 传入翻译 Agent
)
# ========================================
# 创建综合 Agent
# ========================================
comprehensive_agent = Agent(
name="comprehensive_agent", # Agent 名称
model="gemini-2.0-flash", # 模型
instruction=( # 系统指令
"你是一个多功能助手。\n"
"你可以:\n"
"1. 查询天气get_weather\n"
"2. 搜索餐厅search_restaurant\n"
"3. 创建用户档案create_user_profile\n"
"4. 比较城市compare_cities\n"
"5. 计算贷款calculate_loan\n"
"6. 翻译文本translation_tool\n"
"根据用户需求选择合适的工具。"
),
tools=[ # 注册所有工具
get_weather, # 天气查询
search_restaurant, # 餐厅搜索
create_user_profile, # 用户档案
compare_cities, # 城市比较
calculate_loan, # 贷款计算
translation_tool, # 翻译工具
],
)
# ========================================
# 运行示例
# ========================================
APP_NAME = "tools_demo" # 应用名称
USER_ID = "user_001" # 用户 ID
SESSION_ID = "session_001" # 会话 ID
async def main():
"""运行工具演示"""
# 创建会话服务
session_service = InMemorySessionService() # 会话服务
await session_service.create_session( # 创建会话
app_name=APP_NAME, # 应用名称
user_id=USER_ID, # 用户 ID
session_id=SESSION_ID, # 会话 ID
)
# 创建运行器
runner = Runner(
agent=comprehensive_agent, # Agent
app_name=APP_NAME, # 应用名称
session_service=session_service, # 会话服务
)
# 测试查询
queries = [ # 测试问题列表
"北京天气怎么样?", # 天气查询
"帮我搜索上海的意大利餐厅", # 餐厅搜索
"贷款100万利率4.5%30年月供多少", # 贷款计算
]
for query in queries: # 遍历测试问题
print(f"\n[用户]: {query}") # 打印用户输入
# 构造消息
content = types.Content(
role='user', # 角色
parts=[types.Part(text=query)], # 内容
)
# 运行 Agent
events = runner.run_async(
user_id=USER_ID, # 用户 ID
session_id=SESSION_ID, # 会话 ID
new_message=content, # 消息
)
# 获取响应
async for event in events: # 遍历事件
if event.is_final_response(): # 最终响应
print(f"[Agent]: {event.content.parts[0].text}") # 打印回复
if __name__ == "__main__": # 直接运行
asyncio.run(main()) # 执行主函数