init
This commit is contained in:
293
ADKLearning/google-adk-tutorial/code/advanced_demo.py
Normal file
293
ADKLearning/google-adk-tutorial/code/advanced_demo.py
Normal file
@@ -0,0 +1,293 @@
|
||||
"""
|
||||
Google ADK 高级主题完整示例
|
||||
展示安全、自定义 Agent、多模型等高级功能
|
||||
|
||||
对应教程:第10章 - 高级主题
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import ( # 导入所有 Agent 类型
|
||||
Agent, # LLM Agent
|
||||
LlmAgent, # LLM Agent(完整名)
|
||||
BaseAgent, # 基础 Agent
|
||||
)
|
||||
from google.adk.events import Event, EventActions # 导入事件类型
|
||||
from google.adk.agents.invocation_context import InvocationContext # 导入上下文
|
||||
from google.adk.models.lite_llm import LiteLlm # LiteLLM 适配器
|
||||
|
||||
# 导入辅助模块
|
||||
from typing import AsyncGenerator # 异步生成器
|
||||
import re # 正则表达式
|
||||
import random # 随机数
|
||||
import asyncio # 异步编程
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例一:输入安全过滤
|
||||
# ========================================
|
||||
|
||||
async def input_security_filter(cb_ctx, inv_ctx):
|
||||
"""
|
||||
输入安全过滤回调
|
||||
检测注入攻击和敏感信息
|
||||
|
||||
Args:
|
||||
cb_ctx: 回调上下文
|
||||
inv_ctx: 调用上下文
|
||||
"""
|
||||
# 获取用户消息
|
||||
events = inv_ctx.session.events # 获取会话事件
|
||||
user_msgs = [ # 筛选用户消息
|
||||
e for e in events
|
||||
if hasattr(e, 'content') and e.content.role == 'user'
|
||||
]
|
||||
|
||||
if not user_msgs: # 如果没有用户消息
|
||||
return # 直接返回
|
||||
|
||||
text = user_msgs[-1].content.parts[0].text # 提取文本
|
||||
|
||||
# 检测注入攻击
|
||||
injection_patterns = [ # 注入模式
|
||||
r"忽略.*指令", # 中文注入
|
||||
r"ignore.*instruction", # 英文注入
|
||||
r"你现在是", # 角色切换
|
||||
r"system\s*:", # 系统提示伪造
|
||||
]
|
||||
|
||||
for pattern in injection_patterns: # 遍历模式
|
||||
if re.search(pattern, text, re.IGNORECASE): # 如果匹配
|
||||
print(f"[安全] ⚠️ 检测到可能的注入攻击") # 记录警告
|
||||
break # 跳出循环
|
||||
|
||||
# 检测敏感信息
|
||||
sensitive_patterns = [ # 敏感信息模式
|
||||
r"\b\d{3}-\d{2}-\d{4}\b", # SSN
|
||||
r"\b\d{16}\b", # 信用卡号
|
||||
]
|
||||
|
||||
for pattern in sensitive_patterns: # 遍历模式
|
||||
if re.search(pattern, text): # 如果匹配
|
||||
print(f"[安全] ⚠️ 检测到可能的敏感信息") # 记录警告
|
||||
break # 跳出循环
|
||||
|
||||
# 检查输入长度
|
||||
if len(text) > 5000: # 如果过长
|
||||
print(f"[安全] ⚠️ 输入过长: {len(text)} 字符") # 记录警告
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例二:自定义 Agent — 规则引擎
|
||||
# ========================================
|
||||
|
||||
class RuleEngineAgent(BaseAgent):
|
||||
"""
|
||||
规则引擎 Agent
|
||||
基于预定义规则处理请求,不使用 LLM
|
||||
"""
|
||||
|
||||
def __init__(self, rules: dict, **kwargs):
|
||||
"""
|
||||
初始化规则引擎
|
||||
|
||||
Args:
|
||||
rules: 规则字典 {匹配模式: 响应}
|
||||
"""
|
||||
super().__init__(**kwargs) # 调用父类初始化
|
||||
self.rules = rules # 保存规则
|
||||
|
||||
async def _run_async_impl(
|
||||
self,
|
||||
ctx: InvocationContext, # 调用上下文
|
||||
) -> AsyncGenerator[Event, None]: # 返回事件生成器
|
||||
"""执行规则匹配"""
|
||||
|
||||
# 获取用户消息
|
||||
events = ctx.session.events # 获取事件
|
||||
user_events = [ # 筛选用户消息
|
||||
e for e in events
|
||||
if hasattr(e, 'content') and e.content.role == 'user'
|
||||
]
|
||||
|
||||
if not user_events: # 如果没有消息
|
||||
yield Event( # 生成提示
|
||||
author=self.name,
|
||||
content="请输入您的问题。",
|
||||
)
|
||||
return # 退出
|
||||
|
||||
text = user_events[-1].content.parts[0].text # 提取文本
|
||||
|
||||
# 匹配规则
|
||||
for pattern, response in self.rules.items(): # 遍历规则
|
||||
if pattern.lower() in text.lower(): # 如果匹配
|
||||
yield Event( # 生成响应
|
||||
author=self.name,
|
||||
content=response,
|
||||
)
|
||||
return # 退出
|
||||
|
||||
# 没有匹配的规则
|
||||
yield Event( # 生成默认响应
|
||||
author=self.name,
|
||||
content="抱歉,我无法处理您的请求。请尝试其他问题。",
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例三:自定义 Agent — 随机路由
|
||||
# ========================================
|
||||
|
||||
class RandomRouter(BaseAgent):
|
||||
"""
|
||||
随机路由 Agent
|
||||
随机选择一个子 Agent 处理请求
|
||||
"""
|
||||
|
||||
async def _run_async_impl(
|
||||
self,
|
||||
ctx: InvocationContext, # 调用上下文
|
||||
) -> AsyncGenerator[Event, None]: # 返回事件生成器
|
||||
"""随机选择子 Agent"""
|
||||
|
||||
sub_agents = self.sub_agents # 获取子 Agent
|
||||
|
||||
if not sub_agents: # 如果没有子 Agent
|
||||
yield Event( # 生成错误
|
||||
author=self.name,
|
||||
content="没有可用的子 Agent。",
|
||||
)
|
||||
return # 退出
|
||||
|
||||
chosen = random.choice(sub_agents) # 随机选择
|
||||
print(f"[随机路由] 选择了 {chosen.name}") # 打印选择
|
||||
|
||||
yield Event( # 生成委派事件
|
||||
author=self.name,
|
||||
actions=EventActions(
|
||||
transfer_to_agent=chosen.name, # 委派
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例四:多模型混合策略
|
||||
# ========================================
|
||||
|
||||
# 简单任务:使用快速模型
|
||||
simple_agent = LlmAgent(
|
||||
name="SimpleAgent", # 简单任务 Agent
|
||||
model="gemini-2.0-flash", # 快速模型
|
||||
description="处理简单的问答和翻译。", # 描述
|
||||
instruction="快速准确地回答简单问题。", # 指令
|
||||
)
|
||||
|
||||
# 复杂推理:使用强力模型
|
||||
reasoning_agent = LlmAgent(
|
||||
name="ReasoningAgent", # 推理 Agent
|
||||
model="gemini-2.5-pro-preview-05-06", # 强力模型
|
||||
description="处理需要深度推理的复杂任务。", # 描述
|
||||
instruction="仔细分析,给出深入的推理过程。", # 指令
|
||||
)
|
||||
|
||||
# 代码生成:使用 DeepSeek
|
||||
code_agent = LlmAgent(
|
||||
name="CodeAgent", # 代码 Agent
|
||||
model=LiteLlm( # 使用 LiteLLM
|
||||
model="deepseek/deepseek-coder", # DeepSeek Coder
|
||||
api_key="your_api_key", # API Key
|
||||
),
|
||||
description="处理代码生成和调试。", # 描述
|
||||
instruction="编写高质量的代码。", # 指令
|
||||
)
|
||||
|
||||
# 协调器:使用快速模型
|
||||
multi_model_coordinator = LlmAgent(
|
||||
name="MultiModelCoordinator", # 多模型协调器
|
||||
model="gemini-2.0-flash", # 快速模型
|
||||
instruction=( # 指令
|
||||
"根据任务类型分配给合适的 Agent:\n"
|
||||
"- 简单问答 → SimpleAgent\n"
|
||||
"- 复杂推理 → ReasoningAgent\n"
|
||||
"- 代码相关 → CodeAgent"
|
||||
),
|
||||
sub_agents=[simple_agent, reasoning_agent, code_agent], # 子 Agent
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例五:完整实战 — 智能客服系统
|
||||
# ========================================
|
||||
|
||||
def search_faq(query: str) -> dict:
|
||||
"""搜索 FAQ"""
|
||||
faq_db = { # FAQ 数据库
|
||||
"退款": "退款将在3-5个工作日内处理完成。",
|
||||
"配送": "标准配送3-5天,加急配送1-2天。",
|
||||
"退换货": "7天无理由退换货,请保持商品完好。",
|
||||
}
|
||||
for key, value in faq_db.items(): # 遍历 FAQ
|
||||
if key in query: # 如果匹配
|
||||
return {"status": "success", "answer": value}
|
||||
return {"status": "not_found"}
|
||||
|
||||
|
||||
def create_ticket(category: str, description: str) -> dict:
|
||||
"""创建工单"""
|
||||
ticket_id = f"TK{hash(description) % 10000:04d}" # 生成工单号
|
||||
return { # 返回结果
|
||||
"status": "success",
|
||||
"ticket_id": ticket_id,
|
||||
"message": f"工单 {ticket_id} 已创建。",
|
||||
}
|
||||
|
||||
|
||||
# FAQ Agent
|
||||
faq_agent = LlmAgent(
|
||||
name="FAQBot", # FAQ 机器人
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="处理常见问题。", # 描述
|
||||
instruction="使用 search_faq 工具查找答案。", # 指令
|
||||
tools=[search_faq], # FAQ 工具
|
||||
)
|
||||
|
||||
# 工单 Agent
|
||||
ticket_agent = LlmAgent(
|
||||
name="TicketBot", # 工单机器人
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="创建客户工单。", # 描述
|
||||
instruction="使用 create_ticket 创建工单。", # 指令
|
||||
tools=[create_ticket], # 工单工具
|
||||
)
|
||||
|
||||
# 客服协调器
|
||||
customer_service = LlmAgent(
|
||||
name="CustomerService", # 客服系统
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="智能客服主协调器。", # 描述
|
||||
instruction=( # 指令
|
||||
"你是智能客服协调器。\n"
|
||||
"常见问题 → FAQBot\n"
|
||||
"无法解决 → TicketBot\n"
|
||||
"使用 transfer_to_agent 委派任务。"
|
||||
),
|
||||
sub_agents=[faq_agent, ticket_agent], # 子 Agent
|
||||
before_model_callback=input_security_filter, # 安全过滤
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 打印信息
|
||||
# ========================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60) # 分隔线
|
||||
print("Google ADK 高级主题示例") # 标题
|
||||
print("=" * 60) # 分隔线
|
||||
|
||||
print("\n🔒 安全过滤回调: input_security_filter") # 安全
|
||||
print("🤖 自定义 Agent: RuleEngineAgent, RandomRouter") # 自定义
|
||||
print("🔀 多模型策略: SimpleAgent + ReasoningAgent + CodeAgent") # 多模型
|
||||
print("🏢 实战项目: 智能客服系统 (CustomerService)") # 实战
|
||||
|
||||
print("\n✅ 所有高级功能定义完成!") # 成功信息
|
||||
255
ADKLearning/google-adk-tutorial/code/callback_demo.py
Normal file
255
ADKLearning/google-adk-tutorial/code/callback_demo.py
Normal file
@@ -0,0 +1,255 @@
|
||||
"""
|
||||
Google ADK 回调机制完整示例
|
||||
展示四种回调函数的使用方法
|
||||
|
||||
对应教程:第07章 - 回调机制与事件系统
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import Agent # Agent 类
|
||||
from google.adk.agents.invocation_context import InvocationContext # 调用上下文
|
||||
from google.adk.runners import Runner # 运行器
|
||||
from google.adk.sessions import InMemorySessionService # 会话服务
|
||||
from google.genai import types # 类型定义
|
||||
|
||||
# 导入异步和时间模块
|
||||
import asyncio # 异步编程库
|
||||
import time # 时间模块
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例一:日志回调(记录所有操作)
|
||||
# ========================================
|
||||
|
||||
async def log_before_model(cb_ctx, inv_ctx):
|
||||
"""
|
||||
模型调用前回调
|
||||
|
||||
Args:
|
||||
cb_ctx: 回调上下文
|
||||
inv_ctx: 调用上下文
|
||||
"""
|
||||
# 记录开始时间
|
||||
inv_ctx.session.state["temp:model_start_time"] = time.time() # 保存时间戳
|
||||
|
||||
# 获取调用计数
|
||||
count = inv_ctx.session.state.get("model_call_count", 0) # 读取计数
|
||||
inv_ctx.session.state["model_call_count"] = count + 1 # 递增
|
||||
|
||||
print(f"🔍 [模型前] Agent '{inv_ctx.agent.name}' 即将调用 LLM (第{count+1}次)") # 打印日志
|
||||
|
||||
|
||||
async def log_after_model(cb_ctx, inv_ctx):
|
||||
"""
|
||||
模型调用后回调
|
||||
|
||||
Args:
|
||||
cb_ctx: 回调上下文
|
||||
inv_ctx: 调用上下文
|
||||
"""
|
||||
# 计算耗时
|
||||
start = inv_ctx.session.state.get("temp:model_start_time", time.time()) # 开始时间
|
||||
elapsed = time.time() - start # 计算耗时
|
||||
|
||||
response = cb_ctx.response # 获取模型响应
|
||||
|
||||
if response and response.function_calls: # 如果有工具调用
|
||||
tools = [fc.name for fc in response.function_calls] # 工具名列表
|
||||
print(f"✅ [模型后] LLM 调用完成 ({elapsed:.2f}s),决定调用工具: {tools}") # 打印
|
||||
else: # 如果直接响应
|
||||
print(f"✅ [模型后] LLM 调用完成 ({elapsed:.2f}s),直接响应") # 打印
|
||||
|
||||
|
||||
async def log_before_tool(cb_ctx, inv_ctx):
|
||||
"""
|
||||
工具调用前回调
|
||||
|
||||
Args:
|
||||
cb_ctx: 回调上下文
|
||||
inv_ctx: 调用上下文
|
||||
"""
|
||||
fc = cb_ctx.function_call # 获取函数调用
|
||||
print(f"🔧 [工具前] 调用工具: {fc.name}({fc.args})") # 打印工具信息
|
||||
|
||||
|
||||
async def log_after_tool(cb_ctx, inv_ctx):
|
||||
"""
|
||||
工具调用后回调
|
||||
|
||||
Args:
|
||||
cb_ctx: 回调上下文
|
||||
inv_ctx: 调用上下文
|
||||
"""
|
||||
fc = cb_ctx.function_call # 获取函数调用
|
||||
result = cb_ctx.tool_result # 获取工具结果
|
||||
|
||||
status = "成功" # 默认成功
|
||||
if result and result.get("status") == "error": # 如果错误
|
||||
status = "失败" # 标记失败
|
||||
|
||||
print(f"📊 [工具后] {fc.name} 执行{status}") # 打印结果
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例二:人工确认回调
|
||||
# ========================================
|
||||
|
||||
async def human_confirmation(cb_ctx, inv_ctx):
|
||||
"""
|
||||
人工确认回调
|
||||
在敏感操作前暂停
|
||||
|
||||
Args:
|
||||
cb_ctx: 回调上下文
|
||||
inv_ctx: 调用上下文
|
||||
"""
|
||||
tool_name = cb_ctx.function_call.name # 获取工具名
|
||||
tool_args = cb_ctx.function_call.args # 获取工具参数
|
||||
|
||||
# 定义敏感操作
|
||||
sensitive_ops = { # 敏感操作映射
|
||||
"delete_file": "删除文件", # 删除文件
|
||||
"send_email": "发送邮件", # 发送邮件
|
||||
"make_payment": "发起支付", # 发起支付
|
||||
}
|
||||
|
||||
if tool_name in sensitive_ops: # 如果是敏感操作
|
||||
op = sensitive_ops[tool_name] # 获取操作描述
|
||||
print(f"\n⚠️ [人工确认] 需要人工确认!") # 打印警告
|
||||
print(f" 操作: {op}") # 打印操作
|
||||
print(f" 参数: {tool_args}") # 打印参数
|
||||
print(f" 状态: 已记录(模拟自动通过)") # 模拟通过
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例三:参数验证回调
|
||||
# ========================================
|
||||
|
||||
async def validate_params(cb_ctx, inv_ctx):
|
||||
"""
|
||||
参数验证回调
|
||||
在工具调用前验证参数
|
||||
|
||||
Args:
|
||||
cb_ctx: 回调上下文
|
||||
inv_ctx: 调用上下文
|
||||
"""
|
||||
tool_name = cb_ctx.function_call.name # 工具名
|
||||
tool_args = cb_ctx.function_call.args # 工具参数
|
||||
|
||||
# 验证搜索查询长度
|
||||
if tool_name == "search": # 如果是搜索工具
|
||||
query = tool_args.get("query", "") # 获取查询
|
||||
if len(query) < 2: # 如果太短
|
||||
print(f"⚠️ [验证] 搜索查询过短: '{query}'") # 打印警告
|
||||
|
||||
# 验证数值范围
|
||||
if tool_name == "calculate": # 如果是计算工具
|
||||
value = tool_args.get("value", 0) # 获取数值
|
||||
if value < 0: # 如果为负数
|
||||
print(f"⚠️ [验证] 数值不能为负: {value}") # 打印警告
|
||||
|
||||
|
||||
# ========================================
|
||||
# 定义工具函数
|
||||
# ========================================
|
||||
|
||||
def get_weather(city: str) -> dict:
|
||||
"""获取天气信息"""
|
||||
weather_data = { # 天气数据
|
||||
"北京": {"temp": "25°C", "condition": "晴天"},
|
||||
"上海": {"temp": "28°C", "condition": "多云"},
|
||||
}
|
||||
data = weather_data.get(city) # 查找数据
|
||||
if not data: # 如果找不到
|
||||
return {"status": "error", "error_message": f"未找到'{city}'的天气信息"}
|
||||
return {"status": "success", "city": city, **data} # 返回天气
|
||||
|
||||
|
||||
def delete_file(filename: str) -> dict:
|
||||
"""删除文件(模拟)"""
|
||||
print(f"🗑️ 执行删除: {filename}") # 模拟删除
|
||||
return {"status": "success", "message": f"文件 '{filename}' 已删除"}
|
||||
|
||||
|
||||
# ========================================
|
||||
# 创建带回调的 Agent
|
||||
# ========================================
|
||||
|
||||
monitored_agent = Agent(
|
||||
name="monitored_agent", # Agent 名称
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction=( # 系统指令
|
||||
"你是一个天气助手。\n"
|
||||
"使用 get_weather 工具查询天气。\n"
|
||||
"使用 delete_file 工具删除文件(需要确认)。"
|
||||
),
|
||||
tools=[get_weather, delete_file], # 注册工具
|
||||
before_model_callback=log_before_model, # 模型前回调
|
||||
after_model_callback=log_after_model, # 模型后回调
|
||||
before_tool_callback=log_before_tool, # 工具前回调
|
||||
after_tool_callback=log_after_tool, # 工具后回调
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 运行演示
|
||||
# ========================================
|
||||
|
||||
APP_NAME = "callback_demo" # 应用名称
|
||||
USER_ID = "user_001" # 用户 ID
|
||||
SESSION_ID = "session_001" # 会话 ID
|
||||
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
|
||||
print("=" * 60) # 分隔线
|
||||
print("Google ADK 回调机制演示") # 标题
|
||||
print("=" * 60) # 分隔线
|
||||
|
||||
# 初始化
|
||||
session_service = InMemorySessionService() # 会话服务
|
||||
await session_service.create_session( # 创建会话
|
||||
app_name=APP_NAME, # 应用名称
|
||||
user_id=USER_ID, # 用户 ID
|
||||
session_id=SESSION_ID, # 会话 ID
|
||||
)
|
||||
|
||||
# 创建 Runner
|
||||
runner = Runner(
|
||||
agent=monitored_agent, # Agent
|
||||
app_name=APP_NAME, # 应用名称
|
||||
session_service=session_service, # 会话服务
|
||||
)
|
||||
|
||||
# 测试问题
|
||||
queries = [ # 测试列表
|
||||
"北京天气怎么样?", # 天气查询
|
||||
]
|
||||
|
||||
for query in queries: # 遍历测试
|
||||
print(f"\n{'='*60}") # 分隔线
|
||||
print(f"[用户]: {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()) # 执行主函数
|
||||
338
ADKLearning/google-adk-tutorial/code/custom_tools_demo.py
Normal file
338
ADKLearning/google-adk-tutorial/code/custom_tools_demo.py
Normal file
@@ -0,0 +1,338 @@
|
||||
"""
|
||||
Google ADK 自定义工具开发完整示例
|
||||
展示各种工具开发技巧和最佳实践
|
||||
|
||||
对应教程:第04章 - 自定义工具开发
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import Agent # Agent 类
|
||||
from google.adk.tools import AgentTool # AgentTool(Agent 作为工具)
|
||||
|
||||
# 导入类型提示
|
||||
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()) # 执行主函数
|
||||
201
ADKLearning/google-adk-tutorial/code/deploy_demo.py
Normal file
201
ADKLearning/google-adk-tutorial/code/deploy_demo.py
Normal file
@@ -0,0 +1,201 @@
|
||||
"""
|
||||
Google ADK 部署配置完整示例
|
||||
展示各种部署方式的配置
|
||||
|
||||
对应教程:第09章 - 部署指南
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import Agent # Agent 类
|
||||
from google.adk.tools import google_search # Google 搜索工具
|
||||
|
||||
|
||||
# ========================================
|
||||
# 定义 Agent(部署入口)
|
||||
# ========================================
|
||||
|
||||
def get_weather(city: str) -> dict:
|
||||
"""
|
||||
获取天气信息
|
||||
|
||||
Args:
|
||||
city (str): 城市名称
|
||||
|
||||
Returns:
|
||||
dict: 天气信息
|
||||
"""
|
||||
weather_data = { # 天气数据
|
||||
"北京": {"temp": "25°C", "condition": "晴天"},
|
||||
"上海": {"temp": "28°C", "condition": "多云"},
|
||||
}
|
||||
data = weather_data.get(city) # 查找数据
|
||||
if not data: # 如果找不到
|
||||
return {"status": "error", "error_message": f"未找到'{city}'的天气信息"}
|
||||
return {"status": "success", "city": city, **data} # 返回天气
|
||||
|
||||
|
||||
# root_agent 是 ADK 的入口点
|
||||
# 部署时 ADK 会自动查找这个变量
|
||||
root_agent = Agent(
|
||||
name="deploy_agent", # Agent 名称
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="部署演示 Agent。", # 描述
|
||||
instruction=( # 系统指令
|
||||
"你是一个多功能助手。\n"
|
||||
"可以查询天气和搜索信息。\n"
|
||||
"使用中文回答。"
|
||||
),
|
||||
tools=[get_weather, google_search], # 注册工具
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 以下为部署配置参考
|
||||
# ========================================
|
||||
|
||||
# ----------------------------------------
|
||||
# Dockerfile 内容(保存为 Dockerfile)
|
||||
# ----------------------------------------
|
||||
"""
|
||||
# 使用 Python 3.11 作为基础镜像
|
||||
FROM python:3.11-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 设置环境变量
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# 复制依赖文件
|
||||
COPY requirements.txt .
|
||||
|
||||
# 安装依赖
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# 复制 Agent 代码
|
||||
COPY deploy_demo.py .
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8080
|
||||
|
||||
# 启动 API Server
|
||||
CMD ["adk", "api_server", "--port", "8080", "--host", "0.0.0.0"]
|
||||
"""
|
||||
|
||||
# ----------------------------------------
|
||||
# requirements.txt 内容
|
||||
# ----------------------------------------
|
||||
"""
|
||||
google-adk>=1.0.0
|
||||
"""
|
||||
|
||||
# ----------------------------------------
|
||||
# start.sh 启动脚本
|
||||
# ----------------------------------------
|
||||
"""
|
||||
#!/bin/bash
|
||||
# ADK Agent 启动脚本
|
||||
|
||||
# 从环境变量读取 API Key
|
||||
export GOOGLE_API_KEY="${GOOGLE_API_KEY}"
|
||||
|
||||
# 启动 API Server
|
||||
adk api_server \\
|
||||
--port 8080 \\
|
||||
--host 0.0.0.0
|
||||
"""
|
||||
|
||||
# ----------------------------------------
|
||||
# docker-compose.yml 内容
|
||||
# ----------------------------------------
|
||||
"""
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
adk-agent:
|
||||
build: .
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
|
||||
restart: unless-stopped
|
||||
"""
|
||||
|
||||
# ----------------------------------------
|
||||
# 部署命令参考
|
||||
# ----------------------------------------
|
||||
"""
|
||||
# 构建镜像
|
||||
docker build -t my-adk-agent .
|
||||
|
||||
# 运行容器
|
||||
docker run -d \\
|
||||
--name my-agent \\
|
||||
-p 8080:8080 \\
|
||||
-e GOOGLE_API_KEY="your_api_key" \\
|
||||
my-adk-agent
|
||||
|
||||
# 使用 adk deploy 部署到 Cloud Run
|
||||
adk deploy . --platform cloud-run
|
||||
|
||||
# 使用 adk deploy 部署到 Vertex AI
|
||||
adk deploy . --platform vertex-ai
|
||||
"""
|
||||
|
||||
|
||||
# ========================================
|
||||
# API 调用示例
|
||||
# ========================================
|
||||
|
||||
def api_call_example():
|
||||
"""
|
||||
调用 ADK API Server 的示例代码
|
||||
需要先启动 API Server: adk api_server --port 8080
|
||||
"""
|
||||
|
||||
import requests # HTTP 请求库
|
||||
import json # JSON 处理
|
||||
|
||||
API_BASE = "http://localhost:8080" # API 地址
|
||||
APP_NAME = "deploy_agent" # 应用名称
|
||||
USER_ID = "user_001" # 用户 ID
|
||||
SESSION_ID = "session_001" # 会话 ID
|
||||
|
||||
# 创建会话
|
||||
session_url = f"{API_BASE}/apps/{APP_NAME}/users/{USER_ID}/sessions"
|
||||
response = requests.post( # 发送请求
|
||||
session_url, # URL
|
||||
json={"session_id": SESSION_ID}, # 请求体
|
||||
)
|
||||
print(f"会话创建: {response.json()}") # 打印结果
|
||||
|
||||
# 发送消息
|
||||
run_url = f"{session_url}/{SESSION_ID}:run"
|
||||
payload = { # 请求体
|
||||
"user_id": USER_ID, # 用户 ID
|
||||
"session_id": SESSION_ID, # 会话 ID
|
||||
"new_message": { # 新消息
|
||||
"role": "user", # 角色
|
||||
"parts": [{"text": "北京天气怎么样?"}], # 内容
|
||||
},
|
||||
}
|
||||
|
||||
response = requests.post( # 发送请求
|
||||
run_url, # URL
|
||||
json=payload, # 请求体
|
||||
stream=True, # 流式响应
|
||||
)
|
||||
|
||||
for line in response.iter_lines(): # 逐行读取
|
||||
if line: # 如果有内容
|
||||
data = json.loads(line) # 解析 JSON
|
||||
print(f"事件: {data}") # 打印事件
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("✅ 部署配置示例") # 打印信息
|
||||
print("请参考文件中的注释配置部署。") # 提示
|
||||
print("\n快速启动命令:") # 打印命令
|
||||
print(" adk api_server --port 8080 # 启动 API Server")
|
||||
print(" adk web --port 8000 # 启动 Web UI")
|
||||
print(" adk deploy . --platform cloud-run # 部署到 Cloud Run")
|
||||
272
ADKLearning/google-adk-tutorial/code/eval_demo.py
Normal file
272
ADKLearning/google-adk-tutorial/code/eval_demo.py
Normal file
@@ -0,0 +1,272 @@
|
||||
"""
|
||||
Google ADK 智能体评估完整示例
|
||||
展示评估集创建和评估运行方法
|
||||
|
||||
对应教程:第08章 - 智能体评估
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import Agent # Agent 类
|
||||
from google.adk.runners import Runner # 运行器
|
||||
from google.adk.sessions import InMemorySessionService # 会话服务
|
||||
from google.genai import types # 类型定义
|
||||
|
||||
# 导入辅助模块
|
||||
import asyncio # 异步编程库
|
||||
import json # JSON 处理
|
||||
|
||||
|
||||
# ========================================
|
||||
# 定义被评估的 Agent
|
||||
# ========================================
|
||||
|
||||
def get_weather(city: str) -> dict:
|
||||
"""
|
||||
获取天气信息
|
||||
|
||||
Args:
|
||||
city (str): 城市名称
|
||||
|
||||
Returns:
|
||||
dict: 天气信息
|
||||
"""
|
||||
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, **data} # 返回天气
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="weather_agent", # Agent 名称
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction="你是天气助手,使用 get_weather 工具查询天气。用中文回答。", # 指令
|
||||
tools=[get_weather], # 工具
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例一:创建评估集
|
||||
# ========================================
|
||||
|
||||
def create_eval_set():
|
||||
"""
|
||||
创建评估集文件
|
||||
生成 .evalset.json 文件供 adk eval 使用
|
||||
"""
|
||||
|
||||
# 定义评估用例
|
||||
eval_cases = [ # 用例列表
|
||||
{
|
||||
"case_id": "weather_beijing", # 用例 ID
|
||||
"description": "测试北京天气查询", # 描述
|
||||
"user_input": "北京今天天气怎么样?", # 用户输入
|
||||
"expected_keywords": ["北京", "天气"], # 期望关键词
|
||||
},
|
||||
{
|
||||
"case_id": "weather_shanghai", # 用例 ID
|
||||
"description": "测试上海天气查询", # 描述
|
||||
"user_input": "帮我查一下上海的天气", # 用户输入
|
||||
"expected_keywords": ["上海"], # 期望关键词
|
||||
},
|
||||
{
|
||||
"case_id": "greeting", # 用例 ID
|
||||
"description": "测试问候功能", # 描述
|
||||
"user_input": "你好!", # 用户输入
|
||||
"expected_keywords": ["你好"], # 期望关键词
|
||||
},
|
||||
{
|
||||
"case_id": "unknown_city", # 用例 ID
|
||||
"description": "测试未知城市处理", # 描述
|
||||
"user_input": "查询月球基地的天气", # 用户输入
|
||||
"expected_keywords": ["找不到", "无法", "不支持"], # 期望关键词
|
||||
},
|
||||
{
|
||||
"case_id": "multiple_cities", # 用例 ID
|
||||
"description": "测试多城市查询", # 描述
|
||||
"user_input": "北京和上海的天气对比", # 用户输入
|
||||
"expected_keywords": ["北京", "上海"], # 期望关键词
|
||||
},
|
||||
]
|
||||
|
||||
# 构建评估集
|
||||
eval_set = { # 评估集对象
|
||||
"eval_cases": eval_cases, # 用例列表
|
||||
}
|
||||
|
||||
# 写入文件
|
||||
filepath = "weather_agent_eval_set.evalset.json" # 文件路径
|
||||
with open(filepath, "w", encoding="utf-8") as f: # 打开文件
|
||||
json.dump( # 写入 JSON
|
||||
eval_set, # 数据
|
||||
f, # 文件对象
|
||||
ensure_ascii=False, # 允许中文
|
||||
indent=2, # 格式化
|
||||
)
|
||||
|
||||
print(f"✅ 评估集已创建: {filepath}") # 打印成功信息
|
||||
print(f" 用例数量: {len(eval_cases)}") # 打印用例数
|
||||
return filepath # 返回文件路径
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例二:代码方式运行评估
|
||||
# ========================================
|
||||
|
||||
async def evaluate_agent(test_cases: list) -> dict:
|
||||
"""
|
||||
评估 Agent
|
||||
|
||||
Args:
|
||||
test_cases: 测试用例列表
|
||||
|
||||
Returns:
|
||||
dict: 评估结果汇总
|
||||
"""
|
||||
# 初始化服务
|
||||
session_service = InMemorySessionService() # 会话服务
|
||||
runner = Runner( # 运行器
|
||||
agent=agent, # Agent
|
||||
app_name="eval_app", # 应用名称
|
||||
session_service=session_service, # 会话服务
|
||||
)
|
||||
|
||||
results = [] # 结果列表
|
||||
passed = 0 # 通过计数
|
||||
|
||||
for i, case in enumerate(test_cases): # 遍历用例
|
||||
case_id = case.get("case_id", f"case_{i}") # 用例 ID
|
||||
print(f"\n📋 测试用例: {case_id}") # 打印用例 ID
|
||||
print(f" 输入: {case['user_input']}") # 打印输入
|
||||
|
||||
# 创建独立会话
|
||||
session_id = f"eval_session_{i}" # 会话 ID
|
||||
await session_service.create_session( # 创建会话
|
||||
app_name="eval_app", # 应用名称
|
||||
user_id="eval_user", # 用户 ID
|
||||
session_id=session_id, # 会话 ID
|
||||
)
|
||||
|
||||
# 构造消息
|
||||
content = types.Content(
|
||||
role='user', # 角色
|
||||
parts=[types.Part(text=case["user_input"])], # 内容
|
||||
)
|
||||
|
||||
# 运行 Agent
|
||||
events = runner.run_async(
|
||||
user_id="eval_user", # 用户 ID
|
||||
session_id=session_id, # 会话 ID
|
||||
new_message=content, # 消息
|
||||
)
|
||||
|
||||
# 收集响应
|
||||
response_text = "" # 初始化响应
|
||||
async for event in events: # 遍历事件
|
||||
if event.is_final_response(): # 最终响应
|
||||
response_text = event.content.parts[0].text # 提取文本
|
||||
|
||||
# 检查期望关键词
|
||||
case_passed = True # 默认通过
|
||||
failure_reason = "" # 失败原因
|
||||
|
||||
if "expected_keywords" in case: # 如果有关键词要求
|
||||
missing = [] # 缺失的关键词
|
||||
for kw in case["expected_keywords"]: # 遍历关键词
|
||||
if kw not in response_text: # 如果缺失
|
||||
missing.append(kw) # 记录缺失
|
||||
if missing: # 如果有缺失
|
||||
case_passed = False # 标记失败
|
||||
failure_reason = f"缺少关键词: {missing}" # 失败原因
|
||||
|
||||
# 检查不应出现的关键词
|
||||
if "not_expected_keywords" in case: # 如果有排除关键词
|
||||
for kw in case["not_expected_keywords"]: # 遍历
|
||||
if kw in response_text: # 如果出现
|
||||
case_passed = False # 标记失败
|
||||
failure_reason = f"不应包含关键词: '{kw}'" # 失败原因
|
||||
|
||||
if case_passed: # 如果通过
|
||||
passed += 1 # 递增通过数
|
||||
print(f" ✅ 通过") # 打印通过
|
||||
else: # 如果失败
|
||||
print(f" ❌ 失败: {failure_reason}") # 打印失败原因
|
||||
|
||||
# 记录结果
|
||||
results.append({ # 添加结果
|
||||
"case_id": case_id, # 用例 ID
|
||||
"status": "passed" if case_passed else "failed", # 状态
|
||||
"response": response_text[:200], # 响应(截断)
|
||||
"reason": failure_reason, # 失败原因
|
||||
})
|
||||
|
||||
# 返回汇总
|
||||
return { # 返回结果
|
||||
"total": len(test_cases), # 总数
|
||||
"passed": passed, # 通过数
|
||||
"failed": len(test_cases) - passed, # 失败数
|
||||
"pass_rate": passed / len(test_cases) if test_cases else 0, # 通过率
|
||||
"results": results, # 详细结果
|
||||
}
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例三:打印评估报告
|
||||
# ========================================
|
||||
|
||||
def print_report(result: dict):
|
||||
"""
|
||||
打印评估报告
|
||||
|
||||
Args:
|
||||
result: 评估结果
|
||||
"""
|
||||
print("\n" + "=" * 60) # 分隔线
|
||||
print("📊 评估报告") # 标题
|
||||
print("=" * 60) # 分隔线
|
||||
print(f"总用例数: {result['total']}") # 总数
|
||||
print(f"通过: {result['passed']} ✅") # 通过数
|
||||
print(f"失败: {result['failed']} ❌") # 失败数
|
||||
print(f"通过率: {result['pass_rate']:.1%}") # 通过率
|
||||
print("-" * 60) # 分隔线
|
||||
|
||||
for r in result["results"]: # 遍历详细结果
|
||||
icon = "✅" if r["status"] == "passed" else "❌" # 状态图标
|
||||
print(f" {icon} {r['case_id']}: {r['status']}") # 打印结果
|
||||
if r["reason"]: # 如果有失败原因
|
||||
print(f" 原因: {r['reason']}") # 打印原因
|
||||
if r["status"] == "passed": # 如果通过
|
||||
print(f" 响应: {r['response'][:100]}...") # 打印响应片段
|
||||
|
||||
print("=" * 60) # 分隔线
|
||||
|
||||
|
||||
# ========================================
|
||||
# 主函数
|
||||
# ========================================
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
|
||||
# 第一步:创建评估集
|
||||
filepath = create_eval_set() # 创建评估集文件
|
||||
|
||||
# 第二步:加载评估用例
|
||||
with open(filepath, "r", encoding="utf-8") as f: # 读取文件
|
||||
eval_set = json.load(f) # 解析 JSON
|
||||
|
||||
test_cases = eval_set["eval_cases"] # 获取用例列表
|
||||
|
||||
# 第三步:运行评估
|
||||
result = await evaluate_agent(test_cases) # 执行评估
|
||||
|
||||
# 第四步:打印报告
|
||||
print_report(result) # 打印评估报告
|
||||
|
||||
|
||||
if __name__ == "__main__": # 直接运行
|
||||
asyncio.run(main()) # 执行主函数
|
||||
137
ADKLearning/google-adk-tutorial/code/hello_world.py
Normal file
137
ADKLearning/google-adk-tutorial/code/hello_world.py
Normal file
@@ -0,0 +1,137 @@
|
||||
"""
|
||||
Google ADK Hello World 示例
|
||||
一个带有自定义工具的完整 Agent 示例
|
||||
|
||||
对应教程:第02章 - 快速开始:Hello World
|
||||
运行方式:adk run hello_world(将此文件放在 hello_world/agent.py 中)
|
||||
"""
|
||||
|
||||
# 导入 ADK 的 Agent 类
|
||||
from google.adk.agents import Agent # Agent 是 LlmAgent 的别名
|
||||
|
||||
# 导入标准库:日期时间处理
|
||||
import datetime # 用于获取当前时间
|
||||
from zoneinfo import ZoneInfo # 用于处理时区信息
|
||||
|
||||
|
||||
# ========================================
|
||||
# 定义自定义工具函数
|
||||
# ========================================
|
||||
|
||||
def get_current_time(city: str) -> dict:
|
||||
"""
|
||||
获取指定城市的当前时间
|
||||
|
||||
这个函数会被 ADK 自动转换为工具(FunctionTool),
|
||||
Agent 可以在对话中调用这个工具来获取时间信息。
|
||||
|
||||
Args:
|
||||
city (str): 需要查询时间的城市名称,例如"北京"、"东京"、"纽约"
|
||||
|
||||
Returns:
|
||||
dict: 包含状态和结果的字典
|
||||
- status: "success" 或 "error"
|
||||
- report: 时间信息或错误消息
|
||||
"""
|
||||
# 定义城市到时区的映射字典
|
||||
city_timezone_map = { # 常见城市对应的时区
|
||||
"北京": "Asia/Shanghai", # 北京使用上海时区
|
||||
"上海": "Asia/Shanghai", # 上海使用上海时区
|
||||
"广州": "Asia/Shanghai", # 广州使用上海时区
|
||||
"深圳": "Asia/Shanghai", # 深圳使用上海时区
|
||||
"东京": "Asia/Tokyo", # 东京时区
|
||||
"首尔": "Asia/Seoul", # 首尔时区
|
||||
"纽约": "America/New_York", # 纽约时区
|
||||
"伦敦": "Europe/London", # 伦敦时区
|
||||
"巴黎": "Europe/Paris", # 巴黎时区
|
||||
"洛杉矶": "America/Los_Angeles", # 洛杉矶时区
|
||||
}
|
||||
|
||||
# 查找城市对应的时区标识符
|
||||
tz_identifier = city_timezone_map.get(city) # 从字典中获取时区
|
||||
|
||||
# 如果找不到该城市的时区信息
|
||||
if not tz_identifier: # 检查是否找到
|
||||
return { # 返回错误信息
|
||||
"status": "error", # 状态标记为错误
|
||||
"error_message": f"未找到'{city}'的时区信息,请尝试其他城市。" # 错误描述
|
||||
}
|
||||
|
||||
# 根据时区标识符创建时区对象
|
||||
tz = ZoneInfo(tz_identifier) # 创建 ZoneInfo 时区对象
|
||||
|
||||
# 获取该时区的当前时间
|
||||
now = datetime.datetime.now(tz) # 获取指定时区的当前时间
|
||||
|
||||
# 格式化时间字符串
|
||||
time_str = now.strftime( # 将时间格式化为字符串
|
||||
"%Y-%m-%d %H:%M:%S %Z%z" # 格式:年-月-日 时:分:秒 时区
|
||||
)
|
||||
|
||||
# 返回成功结果
|
||||
return { # 返回包含时间信息的字典
|
||||
"status": "success", # 状态标记为成功
|
||||
"city": city, # 城市名称
|
||||
"time": time_str # 格式化后的时间字符串
|
||||
}
|
||||
|
||||
|
||||
def get_weather(city: str) -> dict:
|
||||
"""
|
||||
获取指定城市的天气信息(模拟数据)
|
||||
|
||||
Args:
|
||||
city (str): 城市名称
|
||||
|
||||
Returns:
|
||||
dict: 包含天气信息的字典
|
||||
"""
|
||||
# 模拟天气数据(实际应用中应调用真实天气 API)
|
||||
weather_data = { # 模拟天气数据库
|
||||
"北京": {"temp": "25°C", "condition": "晴天", "humidity": "45%"}, # 北京
|
||||
"上海": {"temp": "28°C", "condition": "多云", "humidity": "65%"}, # 上海
|
||||
"广州": {"temp": "32°C", "condition": "雷阵雨", "humidity": "80%"}, # 广州
|
||||
}
|
||||
|
||||
# 查找城市天气数据
|
||||
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"], # 天气状况
|
||||
"humidity": data["humidity"], # 湿度
|
||||
}
|
||||
|
||||
|
||||
# ========================================
|
||||
# 定义 Agent(ADK 入口点)
|
||||
# ========================================
|
||||
|
||||
# root_agent 是 ADK 自动识别的入口变量
|
||||
# 变量名必须是 root_agent,不能修改
|
||||
root_agent = Agent(
|
||||
name="hello_agent", # Agent 的唯一标识名称
|
||||
model="gemini-2.0-flash", # 使用 Gemini 2.0 Flash 模型
|
||||
description="一个能查询城市时间和天气的友好助手。", # Agent 的描述
|
||||
instruction=( # 系统指令(多行字符串)
|
||||
"你是一个友好的助手,可以帮助用户查询世界各城市的当前时间和天气。\n"
|
||||
"当用户询问某个城市的时间时,使用 get_current_time 工具来获取。\n"
|
||||
"当用户询问某个城市的天气时,使用 get_weather 工具来获取。\n"
|
||||
"如果工具返回错误,请友好地告知用户并建议尝试其他城市。\n"
|
||||
"回复时请使用中文,语气亲切友好。"
|
||||
),
|
||||
tools=[ # 将自定义函数注册为 Agent 的工具
|
||||
get_current_time, # 时间查询工具
|
||||
get_weather, # 天气查询工具
|
||||
],
|
||||
)
|
||||
210
ADKLearning/google-adk-tutorial/code/llm_agent_demo.py
Normal file
210
ADKLearning/google-adk-tutorial/code/llm_agent_demo.py
Normal file
@@ -0,0 +1,210 @@
|
||||
"""
|
||||
Google ADK LLM 智能体完整示例
|
||||
展示 LlmAgent 的各种配置和用法
|
||||
|
||||
对应教程:第03章 - LLM 智能体详解
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import Agent, LlmAgent # Agent 和 LlmAgent
|
||||
from google.adk.agents import SequentialAgent # 顺序工作流
|
||||
from google.adk.models.lite_llm import LiteLlm # LiteLLM 适配器
|
||||
from google.adk.tools import google_search # Google 搜索工具
|
||||
from google.adk.tools import code_execution # 代码执行工具
|
||||
|
||||
# 导入运行相关模块
|
||||
from google.adk.runners import Runner # 运行器
|
||||
from google.adk.sessions import InMemorySessionService # 内存会话服务
|
||||
from google.genai import types # Google GenAI 类型定义
|
||||
|
||||
# 导入异步库
|
||||
import asyncio # 异步编程库
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例一:基础 LlmAgent 配置
|
||||
# ========================================
|
||||
|
||||
# 使用 Gemini 模型(默认)
|
||||
gemini_agent = Agent(
|
||||
name="gemini_agent", # Agent 名称
|
||||
model="gemini-2.0-flash", # 使用 Gemini 2.0 Flash
|
||||
instruction="你是一个专业的编程助手。", # 系统指令
|
||||
description="擅长编程和代码审查。", # 描述(用于多 Agent 路由)
|
||||
)
|
||||
|
||||
# 使用 LiteLLM 适配 DeepSeek 模型
|
||||
deepseek_agent = Agent(
|
||||
name="deepseek_agent", # Agent 名称
|
||||
model=LiteLlm( # 使用 LiteLLM 适配器
|
||||
model="deepseek/deepseek-chat", # 格式:provider/model_name
|
||||
api_key="你的_DEEPSEEK_API_KEY", # API Key
|
||||
),
|
||||
instruction="你是一个中文写作助手。", # 系统指令
|
||||
)
|
||||
|
||||
# 使用 LiteLLM 适配 OpenAI 模型
|
||||
openai_agent = Agent(
|
||||
name="openai_agent", # Agent 名称
|
||||
model=LiteLlm( # 使用 LiteLLM 适配器
|
||||
model="openai/gpt-4o", # OpenAI GPT-4o
|
||||
api_key="你的_OPENAI_API_KEY", # API Key
|
||||
),
|
||||
instruction="你是一个数据分析助手。", # 系统指令
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例二:使用 Google 内置工具
|
||||
# ========================================
|
||||
|
||||
# 带搜索能力的 Agent
|
||||
search_agent = Agent(
|
||||
name="search_agent", # Agent 名称
|
||||
model="gemini-2.0-flash", # 使用 Gemini 模型
|
||||
instruction=( # 系统指令
|
||||
"你是一个信息查询助手。\n"
|
||||
"使用 Google Search 工具搜索最新信息。\n"
|
||||
"根据搜索结果提供准确、全面的回答。"
|
||||
),
|
||||
tools=[google_search], # 注册 Google 搜索工具
|
||||
)
|
||||
|
||||
# 带代码执行能力的 Agent
|
||||
code_agent = Agent(
|
||||
name="code_agent", # Agent 名称
|
||||
model="gemini-2.0-flash", # 使用 Gemini 模型
|
||||
instruction=( # 系统指令
|
||||
"你是一个数据分析助手。\n"
|
||||
"使用 Code Execution 工具执行 Python 代码。\n"
|
||||
"确保代码正确且高效。"
|
||||
),
|
||||
tools=[code_execution], # 注册代码执行工具
|
||||
)
|
||||
|
||||
# 多功能 Agent(搜索 + 代码执行)
|
||||
super_agent = Agent(
|
||||
name="super_agent", # Agent 名称
|
||||
model="gemini-2.0-flash", # 使用 Gemini 模型
|
||||
instruction="你是一个全能助手,可以搜索信息和执行代码。", # 指令
|
||||
tools=[google_search, code_execution], # 注册多个工具
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例三:output_key 用法
|
||||
# ========================================
|
||||
|
||||
# 第一步:提取信息的 Agent
|
||||
extractor = Agent(
|
||||
name="Extractor", # 信息提取 Agent
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction="从用户输入中提取关键信息。只输出提取的信息。", # 指令
|
||||
output_key="extracted_info", # 将输出保存到 state['extracted_info']
|
||||
)
|
||||
|
||||
# 第二步:分析信息的 Agent(引用第一步的输出)
|
||||
analyzer = Agent(
|
||||
name="Analyzer", # 信息分析 Agent
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction=( # 指令:通过 {key} 引用 state 中的值
|
||||
"分析以下提取的信息,给出深度分析。\n"
|
||||
"提取的信息:{extracted_info}"
|
||||
),
|
||||
output_key="analysis_result", # 将分析结果保存到 state
|
||||
)
|
||||
|
||||
# 创建顺序流水线
|
||||
pipeline = SequentialAgent(
|
||||
name="InfoPipeline", # 流水线名称
|
||||
sub_agents=[extractor, analyzer], # 按顺序执行
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例四:Agent Transfer(动态委派)
|
||||
# ========================================
|
||||
|
||||
# 定义专门的子 Agent
|
||||
booking_agent = LlmAgent(
|
||||
name="BookingAgent", # 预订 Agent
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="负责处理航班和酒店的预订请求。", # 描述
|
||||
instruction="你是一个预订助手,帮助用户预订航班和酒店。", # 指令
|
||||
)
|
||||
|
||||
info_agent = LlmAgent(
|
||||
name="InfoAgent", # 信息查询 Agent
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="负责回答一般性问题和提供信息。", # 描述
|
||||
instruction="你是一个信息助手,回答用户的各种问题。", # 指令
|
||||
)
|
||||
|
||||
# 定义协调器 Agent
|
||||
coordinator = LlmAgent(
|
||||
name="Coordinator", # 协调器
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="主协调器,负责分配任务。", # 描述
|
||||
instruction=( # 指令
|
||||
"你是一个协调器。\n"
|
||||
"预订任务交给 BookingAgent。\n"
|
||||
"信息查询交给 InfoAgent。\n"
|
||||
"使用 transfer_to_agent 工具委派任务。"
|
||||
),
|
||||
sub_agents=[booking_agent, info_agent], # 注册子 Agent
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例五:通过代码运行 Agent
|
||||
# ========================================
|
||||
|
||||
# 定义应用信息
|
||||
APP_NAME = "llm_demo_app" # 应用名称
|
||||
USER_ID = "user_001" # 用户 ID
|
||||
SESSION_ID = "session_001" # 会话 ID
|
||||
|
||||
|
||||
async def run_demo():
|
||||
"""运行 LlmAgent 演示"""
|
||||
|
||||
# 创建会话服务
|
||||
session_service = InMemorySessionService() # 内存会话服务
|
||||
|
||||
# 创建会话
|
||||
session = await session_service.create_session(
|
||||
app_name=APP_NAME, # 应用名称
|
||||
user_id=USER_ID, # 用户 ID
|
||||
session_id=SESSION_ID, # 会话 ID
|
||||
)
|
||||
|
||||
# 创建运行器
|
||||
runner = Runner(
|
||||
agent=gemini_agent, # 使用 Gemini Agent
|
||||
app_name=APP_NAME, # 应用名称
|
||||
session_service=session_service, # 会话服务
|
||||
)
|
||||
|
||||
# 构造用户消息
|
||||
content = types.Content(
|
||||
role='user', # 角色:用户
|
||||
parts=[types.Part(text='用 Python 写一个冒泡排序算法')], # 消息
|
||||
)
|
||||
|
||||
# 运行 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(): # 如果是最终响应
|
||||
response = event.content.parts[0].text # 提取文本
|
||||
print(f"Agent 回复:\n{response}") # 打印回复
|
||||
|
||||
|
||||
# 运行演示
|
||||
if __name__ == "__main__": # 当脚本被直接运行时
|
||||
asyncio.run(run_demo()) # 执行异步函数
|
||||
275
ADKLearning/google-adk-tutorial/code/multi_agent_demo.py
Normal file
275
ADKLearning/google-adk-tutorial/code/multi_agent_demo.py
Normal file
@@ -0,0 +1,275 @@
|
||||
"""
|
||||
Google ADK 多智能体系统完整示例
|
||||
展示各种多 Agent 协作模式
|
||||
|
||||
对应教程:第05章 - 多智能体系统
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import ( # 导入所有 Agent 类型
|
||||
Agent, # LLM Agent(别名)
|
||||
LlmAgent, # LLM Agent(完整名)
|
||||
SequentialAgent, # 顺序工作流
|
||||
ParallelAgent, # 并行工作流
|
||||
LoopAgent, # 循环工作流
|
||||
BaseAgent, # 基础 Agent(自定义用)
|
||||
)
|
||||
from google.adk.events import Event, EventActions # 导入事件类型
|
||||
from google.adk.agents.invocation_context import InvocationContext # 导入上下文
|
||||
from typing import AsyncGenerator # 导入异步生成器
|
||||
|
||||
|
||||
# ========================================
|
||||
# 模式一:协调器/调度器模式
|
||||
# ========================================
|
||||
|
||||
# 定义专门的子 Agent
|
||||
math_agent = LlmAgent(
|
||||
name="MathExpert", # 数学专家
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="擅长数学计算和统计分析。", # 描述
|
||||
instruction="你是数学专家,解决数学问题。给出详细的计算过程。", # 指令
|
||||
)
|
||||
|
||||
writing_agent = LlmAgent(
|
||||
name="WritingExpert", # 写作专家
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="擅长文案撰写和内容创作。", # 描述
|
||||
instruction="你是写作专家,帮助用户撰写高质量的内容。", # 指令
|
||||
)
|
||||
|
||||
coding_agent = LlmAgent(
|
||||
name="CodingExpert", # 编程专家
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="擅长编程和代码调试。", # 描述
|
||||
instruction="你是编程专家,帮助用户解决编程问题。提供带注释的代码。", # 指令
|
||||
)
|
||||
|
||||
# 定义协调器
|
||||
coordinator = LlmAgent(
|
||||
name="Coordinator", # 协调器
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="根据问题类型分配给合适的专家。", # 描述
|
||||
instruction=( # 指令
|
||||
"你是一个任务协调器。\n"
|
||||
"根据用户的问题类型,将任务分配给合适的专家:\n"
|
||||
"- 数学相关 → MathExpert\n"
|
||||
"- 写作相关 → WritingExpert\n"
|
||||
"- 编程相关 → CodingExpert\n"
|
||||
"使用 transfer_to_agent 工具进行任务分配。"
|
||||
),
|
||||
sub_agents=[math_agent, writing_agent, coding_agent], # 注册子 Agent
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 模式二:顺序流水线模式
|
||||
# ========================================
|
||||
|
||||
# 步骤一:信息提取
|
||||
extractor = LlmAgent(
|
||||
name="Extractor", # 信息提取 Agent
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction="从用户输入中提取关键信息。只输出提取的关键信息。", # 指令
|
||||
output_key="extracted_info", # 输出保存到 state
|
||||
)
|
||||
|
||||
# 步骤二:信息分析
|
||||
analyzer = LlmAgent(
|
||||
name="Analyzer", # 信息分析 Agent
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction=( # 指令:引用上一步输出
|
||||
"分析以下提取的信息,给出深度分析报告。\n"
|
||||
"提取的信息:{extracted_info}"
|
||||
),
|
||||
output_key="analysis_result", # 输出保存到 state
|
||||
)
|
||||
|
||||
# 步骤三:报告生成
|
||||
reporter = LlmAgent(
|
||||
name="Reporter", # 报告生成 Agent
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction=( # 指令:引用前两步输出
|
||||
"根据分析结果生成一份简洁的报告。\n"
|
||||
"原始信息:{extracted_info}\n"
|
||||
"分析结果:{analysis_result}"
|
||||
),
|
||||
)
|
||||
|
||||
# 创建顺序流水线
|
||||
pipeline = SequentialAgent(
|
||||
name="InfoPipeline", # 流水线名称
|
||||
sub_agents=[extractor, analyzer, reporter], # 按顺序执行
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 模式三:并行扇出模式
|
||||
# ========================================
|
||||
|
||||
# 并行任务一:天气查询
|
||||
weather_agent = LlmAgent(
|
||||
name="WeatherFetcher", # 天气查询
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction="查询并返回天气信息。只返回天气数据。", # 指令
|
||||
output_key="weather_data", # 输出保存到 state
|
||||
)
|
||||
|
||||
# 并行任务二:新闻查询
|
||||
news_agent = LlmAgent(
|
||||
name="NewsFetcher", # 新闻查询
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction="查询并返回最新新闻。只返回新闻摘要。", # 指令
|
||||
output_key="news_data", # 输出保存到 state
|
||||
)
|
||||
|
||||
# 并行任务三:交通查询
|
||||
traffic_agent = LlmAgent(
|
||||
name="TrafficFetcher", # 交通查询
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction="查询并返回交通状况。只返回交通信息。", # 指令
|
||||
output_key="traffic_data", # 输出保存到 state
|
||||
)
|
||||
|
||||
# 创建并行执行器
|
||||
gatherer = ParallelAgent(
|
||||
name="InfoGatherer", # 并行执行器名称
|
||||
sub_agents=[weather_agent, news_agent, traffic_agent], # 并行执行
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 模式四:循环优化模式(Generator-Critic)
|
||||
# ========================================
|
||||
|
||||
# 生成器 Agent
|
||||
generator = LlmAgent(
|
||||
name="Generator", # 生成器
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction=( # 指令
|
||||
"你是一个创意写手。\n"
|
||||
"根据用户需求创作内容。\n"
|
||||
"将创作的内容保存到 state['draft']。"
|
||||
),
|
||||
output_key="draft", # 输出保存到 state
|
||||
)
|
||||
|
||||
# 评审器 Agent
|
||||
critic = LlmAgent(
|
||||
name="Critic", # 评审器
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction=( # 指令
|
||||
"你是一个严格的内容评审。\n"
|
||||
"评审以下内容,给出评分(1-10)和改进建议。\n"
|
||||
"当前草稿:{draft}\n"
|
||||
"如果评分 >= 8,将 state['approved'] 设为 True。\n"
|
||||
"否则,将改进建议保存到 state['feedback']。"
|
||||
),
|
||||
)
|
||||
|
||||
# 条件检查 Agent
|
||||
class ApprovalChecker(BaseAgent):
|
||||
"""检查内容是否通过审批"""
|
||||
|
||||
async def _run_async_impl(
|
||||
self,
|
||||
ctx: InvocationContext, # 调用上下文
|
||||
) -> AsyncGenerator[Event, None]: # 返回事件生成器
|
||||
"""执行检查"""
|
||||
|
||||
approved = ctx.session.state.get("approved", False) # 获取审批状态
|
||||
|
||||
yield Event( # 生成事件
|
||||
author=self.name, # 事件作者
|
||||
actions=EventActions(
|
||||
escalate=approved, # 通过则退出循环
|
||||
),
|
||||
)
|
||||
|
||||
# 创建迭代优化循环
|
||||
review_loop = LoopAgent(
|
||||
name="ReviewLoop", # 循环名称
|
||||
max_iterations=3, # 最多迭代3次
|
||||
sub_agents=[critic, ApprovalChecker(name="Checker"), generator], # 循环体
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 模式五:多层级嵌套
|
||||
# ========================================
|
||||
|
||||
# 第三层:具体执行 Agent
|
||||
code_reviewer = LlmAgent(
|
||||
name="CodeReviewer", # 代码审查
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="审查代码质量。", # 描述
|
||||
instruction="审查代码并给出改进建议。", # 指令
|
||||
)
|
||||
|
||||
test_writer = LlmAgent(
|
||||
name="TestWriter", # 测试编写
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="编写单元测试。", # 描述
|
||||
instruction="为代码编写单元测试。", # 指令
|
||||
)
|
||||
|
||||
# 第二层:开发流水线
|
||||
dev_pipeline = SequentialAgent(
|
||||
name="DevPipeline", # 流水线
|
||||
sub_agents=[code_reviewer, test_writer], # 顺序执行
|
||||
)
|
||||
|
||||
# 第二层:其他 Agent
|
||||
doc_writer = LlmAgent(
|
||||
name="DocWriter", # 文档编写
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="编写技术文档。", # 描述
|
||||
instruction="编写清晰的技术文档。", # 指令
|
||||
)
|
||||
|
||||
# 第一层:根协调器
|
||||
root_agent = LlmAgent(
|
||||
name="RootCoordinator", # 根协调器
|
||||
model="gemini-2.0-flash", # 模型
|
||||
description="开发团队协调器。", # 描述
|
||||
instruction=( # 指令
|
||||
"你是一个开发团队协调器。\n"
|
||||
"代码审查和测试交给 DevPipeline。\n"
|
||||
"文档编写交给 DocWriter。"
|
||||
),
|
||||
sub_agents=[dev_pipeline, doc_writer], # 子 Agent
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 打印结构信息
|
||||
# ========================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60) # 分隔线
|
||||
print("Google ADK 多智能体系统示例") # 标题
|
||||
print("=" * 60) # 分隔线
|
||||
|
||||
print("\n📦 模式一:协调器/调度器") # 模式一
|
||||
print(f" 根 Agent: {coordinator.name}") # 根 Agent
|
||||
print(f" 子 Agent: {[a.name for a in coordinator.sub_agents]}") # 子 Agent
|
||||
|
||||
print("\n📦 模式二:顺序流水线") # 模式二
|
||||
print(f" 流水线: {pipeline.name}") # 流水线
|
||||
print(f" 步骤: {[a.name for a in pipeline.sub_agents]}") # 步骤
|
||||
|
||||
print("\n📦 模式三:并行扇出") # 模式三
|
||||
print(f" 并行器: {gatherer.name}") # 并行器
|
||||
print(f" 任务: {[a.name for a in gatherer.sub_agents]}") # 任务
|
||||
|
||||
print("\n📦 模式四:循环优化") # 模式四
|
||||
print(f" 循环: {review_loop.name}") # 循环
|
||||
print(f" 最大迭代: {review_loop.max_iterations}") # 最大迭代
|
||||
|
||||
print("\n📦 模式五:多层级嵌套") # 模式五
|
||||
print(f" 根: {root_agent.name}") # 根
|
||||
print(f" 第二层: {[a.name for a in root_agent.sub_agents]}") # 第二层
|
||||
print(f" 第三层: {[a.name for a in dev_pipeline.sub_agents]}") # 第三层
|
||||
|
||||
print("\n✅ 所有模式定义完成!") # 成功信息
|
||||
print("使用 'adk web' 或 'adk run' 运行。") # 运行提示
|
||||
318
ADKLearning/google-adk-tutorial/code/session_state_demo.py
Normal file
318
ADKLearning/google-adk-tutorial/code/session_state_demo.py
Normal file
@@ -0,0 +1,318 @@
|
||||
"""
|
||||
Google ADK 会话与状态管理完整示例
|
||||
展示 Session、State、Memory 的使用方法
|
||||
|
||||
对应教程:第06章 - 会话与状态管理
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块
|
||||
from google.adk.agents import Agent # Agent 类
|
||||
from google.adk.runners import Runner # 运行器
|
||||
from google.adk.sessions import InMemorySessionService # 内存会话服务
|
||||
from google.adk.memory import InMemoryMemoryService # 内存记忆服务
|
||||
from google.genai import types # 类型定义
|
||||
|
||||
# 导入异步库
|
||||
import asyncio # 异步编程库
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例一:State 管理(购物车)
|
||||
# ========================================
|
||||
|
||||
def add_to_cart(item: str, price: float, ctx) -> dict:
|
||||
"""
|
||||
将商品添加到购物车
|
||||
|
||||
Args:
|
||||
item (str): 商品名称
|
||||
price (float): 商品价格
|
||||
ctx: 工具上下文(自动注入)
|
||||
|
||||
Returns:
|
||||
dict: 操作结果
|
||||
"""
|
||||
# 获取当前购物车
|
||||
cart = ctx.state.get("cart", []) # 从 state 读取购物车
|
||||
|
||||
# 添加新商品
|
||||
cart.append({ # 追加商品
|
||||
"item": item, # 商品名
|
||||
"price": price, # 价格
|
||||
})
|
||||
|
||||
# 更新 state
|
||||
ctx.state["cart"] = cart # 写回 state
|
||||
|
||||
# 计算总价
|
||||
total = sum(item["price"] for item in cart) # 求和
|
||||
|
||||
return { # 返回结果
|
||||
"status": "success",
|
||||
"message": f"已将 {item} 添加到购物车",
|
||||
"cart_items": len(cart),
|
||||
"total": total,
|
||||
}
|
||||
|
||||
|
||||
def get_cart(ctx) -> dict:
|
||||
"""
|
||||
获取购物车内容
|
||||
|
||||
Args:
|
||||
ctx: 工具上下文
|
||||
|
||||
Returns:
|
||||
dict: 购物车内容
|
||||
"""
|
||||
cart = ctx.state.get("cart", []) # 读取购物车
|
||||
|
||||
if not cart: # 如果为空
|
||||
return { # 返回空信息
|
||||
"status": "success",
|
||||
"message": "购物车是空的",
|
||||
"items": [],
|
||||
"total": 0,
|
||||
}
|
||||
|
||||
total = sum(item["price"] for item in cart) # 计算总价
|
||||
|
||||
return { # 返回购物车
|
||||
"status": "success",
|
||||
"items": cart,
|
||||
"total": total,
|
||||
}
|
||||
|
||||
|
||||
def clear_cart(ctx) -> dict:
|
||||
"""
|
||||
清空购物车
|
||||
|
||||
Args:
|
||||
ctx: 工具上下文
|
||||
|
||||
Returns:
|
||||
dict: 操作结果
|
||||
"""
|
||||
ctx.state["cart"] = [] # 清空购物车
|
||||
|
||||
return { # 返回结果
|
||||
"status": "success",
|
||||
"message": "购物车已清空",
|
||||
}
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例二:temp: 临时状态
|
||||
# ========================================
|
||||
|
||||
def step1_process(query: str, ctx) -> dict:
|
||||
"""
|
||||
处理步骤一:预处理数据
|
||||
|
||||
Args:
|
||||
query (str): 用户查询
|
||||
ctx: 工具上下文
|
||||
|
||||
Returns:
|
||||
dict: 预处理结果
|
||||
"""
|
||||
processed = query.strip().lower() # 预处理
|
||||
|
||||
# 保存到临时状态(当前调用结束后自动清除)
|
||||
ctx.state["temp:processed_query"] = processed # 临时存储
|
||||
|
||||
return { # 返回结果
|
||||
"status": "success",
|
||||
"processed_query": processed,
|
||||
}
|
||||
|
||||
|
||||
def step2_enhance(ctx) -> dict:
|
||||
"""
|
||||
处理步骤二:增强数据
|
||||
|
||||
Args:
|
||||
ctx: 工具上下文
|
||||
|
||||
Returns:
|
||||
dict: 增强结果
|
||||
"""
|
||||
# 从临时状态读取
|
||||
processed = ctx.state.get("temp:processed_query") # 读取临时状态
|
||||
|
||||
if not processed: # 如果没有数据
|
||||
return { # 返回错误
|
||||
"status": "error",
|
||||
"error_message": "请先执行预处理步骤。"
|
||||
}
|
||||
|
||||
enhanced = f"[增强] {processed}" # 增强处理
|
||||
|
||||
return { # 返回结果
|
||||
"status": "success",
|
||||
"enhanced_query": enhanced,
|
||||
}
|
||||
|
||||
|
||||
# ========================================
|
||||
# 创建 Agent
|
||||
# ========================================
|
||||
|
||||
shopping_agent = Agent(
|
||||
name="shopping_assistant", # Agent 名称
|
||||
model="gemini-2.0-flash", # 模型
|
||||
instruction=( # 指令
|
||||
"你是一个购物助手。\n"
|
||||
"帮助用户管理购物车:\n"
|
||||
"- 添加商品:使用 add_to_cart\n"
|
||||
"- 查看购物车:使用 get_cart\n"
|
||||
"- 清空购物车:使用 clear_cart"
|
||||
),
|
||||
tools=[add_to_cart, get_cart, clear_cart], # 注册工具
|
||||
)
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例三:Session 管理
|
||||
# ========================================
|
||||
|
||||
async def session_management_demo():
|
||||
"""演示 Session 管理功能"""
|
||||
|
||||
print("=" * 50) # 分隔线
|
||||
print("Session 管理演示") # 标题
|
||||
print("=" * 50) # 分隔线
|
||||
|
||||
# 创建会话服务
|
||||
session_service = InMemorySessionService() # 内存会话服务
|
||||
|
||||
# 创建会话
|
||||
session = await session_service.create_session(
|
||||
app_name="shopping_app", # 应用名称
|
||||
user_id="user_001", # 用户 ID
|
||||
session_id="session_001", # 会话 ID
|
||||
state={"cart": []}, # 初始化状态
|
||||
)
|
||||
|
||||
print(f"✅ 会话创建成功: {session.id}") # 打印会话 ID
|
||||
|
||||
# 获取会话
|
||||
existing = await session_service.get_session(
|
||||
app_name="shopping_app",
|
||||
user_id="user_001",
|
||||
session_id="session_001",
|
||||
)
|
||||
print(f"✅ 获取会话: {existing.id}") # 打印会话信息
|
||||
|
||||
# 删除会话
|
||||
await session_service.delete_session(
|
||||
app_name="shopping_app",
|
||||
user_id="user_001",
|
||||
session_id="session_001",
|
||||
)
|
||||
print("✅ 会话已删除") # 确认删除
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例四:多轮对话
|
||||
# ========================================
|
||||
|
||||
async def multi_turn_demo():
|
||||
"""演示多轮对话"""
|
||||
|
||||
print("\n" + "=" * 50) # 分隔线
|
||||
print("多轮对话演示") # 标题
|
||||
print("=" * 50) # 分隔线
|
||||
|
||||
# 初始化
|
||||
session_service = InMemorySessionService() # 会话服务
|
||||
await session_service.create_session( # 创建会话
|
||||
app_name="chat_app", # 应用名称
|
||||
user_id="user_001", # 用户 ID
|
||||
session_id="chat_001", # 会话 ID
|
||||
)
|
||||
|
||||
# 创建 Runner
|
||||
runner = Runner(
|
||||
agent=shopping_agent, # Agent
|
||||
app_name="chat_app", # 应用名称
|
||||
session_service=session_service, # 会话服务
|
||||
)
|
||||
|
||||
# 模拟多轮对话
|
||||
conversations = [ # 对话列表
|
||||
"帮我添加一个苹果,价格5元", # 第一轮
|
||||
"再添加一个香蕉,价格3元", # 第二轮
|
||||
"查看我的购物车", # 第三轮
|
||||
"清空购物车", # 第四轮
|
||||
]
|
||||
|
||||
for msg in conversations: # 遍历对话
|
||||
print(f"\n[用户]: {msg}") # 打印用户消息
|
||||
|
||||
# 构造消息
|
||||
content = types.Content(
|
||||
role='user', # 角色
|
||||
parts=[types.Part(text=msg)], # 内容
|
||||
)
|
||||
|
||||
# 运行 Agent
|
||||
events = runner.run_async(
|
||||
user_id="user_001", # 用户 ID
|
||||
session_id="chat_001", # 同一会话
|
||||
new_message=content, # 消息
|
||||
)
|
||||
|
||||
# 获取响应
|
||||
async for event in events: # 遍历事件
|
||||
if event.is_final_response(): # 最终响应
|
||||
print(f"[Agent]: {event.content.parts[0].text}") # 打印回复
|
||||
|
||||
|
||||
# ========================================
|
||||
# 示例五:Memory 管理
|
||||
# ========================================
|
||||
|
||||
async def memory_demo():
|
||||
"""演示 Memory 管理功能"""
|
||||
|
||||
print("\n" + "=" * 50) # 分隔线
|
||||
print("Memory 管理演示") # 标题
|
||||
print("=" * 50) # 分隔线
|
||||
|
||||
# 创建记忆服务
|
||||
memory_service = InMemoryMemoryService() # 内存记忆服务
|
||||
|
||||
# 添加记忆(从会话事件中提取)
|
||||
await memory_service.add_session_events_to_memory(
|
||||
app_name="my_app", # 应用名称
|
||||
user_id="user_001", # 用户 ID
|
||||
session_id="session_001", # 会话 ID
|
||||
)
|
||||
print("✅ 记忆已添加") # 确认添加
|
||||
|
||||
# 搜索记忆
|
||||
results = await memory_service.search(
|
||||
query="用户偏好", # 搜索查询
|
||||
app_name="my_app", # 应用名称
|
||||
user_id="user_001", # 用户 ID
|
||||
)
|
||||
print(f"✅ 搜索完成,结果数: {len(results)}") # 打印结果数
|
||||
|
||||
|
||||
# ========================================
|
||||
# 主函数
|
||||
# ========================================
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
|
||||
# 运行所有演示
|
||||
await session_management_demo() # Session 管理
|
||||
await multi_turn_demo() # 多轮对话
|
||||
await memory_demo() # Memory 管理
|
||||
|
||||
|
||||
if __name__ == "__main__": # 直接运行
|
||||
asyncio.run(main()) # 执行主函数
|
||||
69
ADKLearning/google-adk-tutorial/code/setup_demo.py
Normal file
69
ADKLearning/google-adk-tutorial/code/setup_demo.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
Google ADK 环境搭建验证脚本
|
||||
验证 ADK 是否正确安装,并打印版本信息
|
||||
|
||||
对应教程:第01章 - ADK 简介与环境搭建
|
||||
"""
|
||||
|
||||
# 导入 ADK 核心模块,验证安装是否成功
|
||||
from google.adk.agents import Agent # 智能体模块
|
||||
from google.adk.runners import Runner # 运行器模块
|
||||
from google.adk.sessions import InMemorySessionService # 内存会话服务
|
||||
|
||||
|
||||
def verify_installation():
|
||||
"""验证 ADK 安装是否成功"""
|
||||
|
||||
# 打印分隔线
|
||||
print("=" * 50) # 打印分隔线
|
||||
print("Google ADK 环境验证") # 打印标题
|
||||
print("=" * 50) # 打印分隔线
|
||||
|
||||
# 验证 Agent 类是否可用
|
||||
try: # 尝试导入
|
||||
agent = Agent( # 创建一个简单的测试 Agent
|
||||
name="test_agent", # 设置 Agent 名称
|
||||
model="gemini-2.0-flash", # 使用 Gemini 模型
|
||||
instruction="你是一个测试助手。", # 设置系统指令
|
||||
)
|
||||
print(f"✅ Agent 模块可用") # 确认 Agent 可用
|
||||
print(f" Agent 名称: {agent.name}") # 打印 Agent 名称
|
||||
except ImportError as e: # 如果导入失败
|
||||
print(f"❌ Agent 模块导入失败: {e}") # 打印错误信息
|
||||
return False # 返回失败
|
||||
|
||||
# 验证 Runner 类是否可用
|
||||
try: # 尝试导入
|
||||
print(f"✅ Runner 模块可用") # 确认 Runner 可用
|
||||
except ImportError as e: # 如果导入失败
|
||||
print(f"❌ Runner 模块导入失败: {e}") # 打印错误信息
|
||||
return False # 返回失败
|
||||
|
||||
# 验证 SessionService 是否可用
|
||||
try: # 尝试创建
|
||||
session_service = InMemorySessionService() # 创建内存会话服务
|
||||
print(f"✅ SessionService 可用") # 确认会话服务可用
|
||||
except Exception as e: # 如果创建失败
|
||||
print(f"❌ SessionService 创建失败: {e}") # 打印错误信息
|
||||
return False # 返回失败
|
||||
|
||||
# 验证 ADK 版本
|
||||
try: # 尝试获取版本
|
||||
import importlib.metadata # 导入元数据模块
|
||||
version = importlib.metadata.version("google-adk") # 获取版本号
|
||||
print(f"✅ ADK 版本: {version}") # 打印版本号
|
||||
except Exception: # 如果获取失败
|
||||
print("⚠️ 无法获取 ADK 版本") # 打印警告
|
||||
|
||||
# 打印成功信息
|
||||
print("=" * 50) # 打印分隔线
|
||||
print("🎉 所有模块验证通过!") # 打印成功信息
|
||||
print("可以开始使用 Google ADK 了!") # 提示用户
|
||||
print("=" * 50) # 打印分隔线
|
||||
|
||||
return True # 返回成功
|
||||
|
||||
|
||||
# 当脚本被直接运行时执行验证
|
||||
if __name__ == "__main__": # 判断是否直接运行
|
||||
verify_installation() # 执行验证函数
|
||||
Reference in New Issue
Block a user