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,674 @@
# 第10章高级主题
## 📌 本章目标
- 掌握 ADK 的安全最佳实践
- 了解 A2AAgent-to-Agent协议
- 学习多模型混合使用策略
- 掌握自定义 Agent 的开发方法
- 了解性能优化技巧
---
## 10.1 安全最佳实践
### 10.1.1 输入安全
```python
"""
输入安全:防止注入攻击和不当输入
"""
from google.adk.agents import Agent # 导入 Agent 类
from google.adk.agents.invocation_context import InvocationContext # 导入上下文
import re # 导入正则表达式模块
# ========================================
# 输入过滤器
# ========================================
async def input_filter_callback(
callback_context, # 回调上下文
invocation_context: InvocationContext, # 调用上下文
):
"""
输入安全过滤回调
在模型调用前检查用户输入的安全性
"""
# 获取用户消息
# 从调用上下文中获取最近的用户消息
events = invocation_context.session.events # 获取会话事件
user_messages = [ # 筛选用户消息
e for e in events
if hasattr(e, 'content') and e.content.role == 'user'
]
if not user_messages: # 如果没有用户消息
return # 直接返回
last_message = user_messages[-1] # 获取最后一条用户消息
user_text = last_message.content.parts[0].text # 提取文本
# ========================================
# 检查1提示注入检测
# ========================================
injection_patterns = [ # 注入攻击模式
r"忽略.*指令", # "忽略之前的指令"
r"ignore.*instruction", # 英文注入
r"你现在是", # 角色切换
r"pretend.*you are", # 英文角色切换
r"system\s*:", # 系统提示伪造
]
for pattern in injection_patterns: # 遍历模式
if re.search(pattern, user_text, re.IGNORECASE): # 如果匹配
print(f"[安全] 检测到可能的注入攻击: {pattern}") # 记录警告
# 在实际应用中,可以拒绝处理或返回安全提示
# ========================================
# 检查2输入长度限制
# ========================================
MAX_INPUT_LENGTH = 5000 # 最大输入长度
if len(user_text) > MAX_INPUT_LENGTH: # 如果超过限制
print(f"[安全] 输入过长: {len(user_text)} > {MAX_INPUT_LENGTH}") # 记录警告
# ========================================
# 检查3敏感信息检测
# ========================================
sensitive_patterns = [ # 敏感信息模式
r"\b\d{3}-\d{2}-\d{4}\b", # SSN 格式
r"\b\d{16}\b", # 信用卡号格式
r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", # 邮箱
]
for pattern in sensitive_patterns: # 遍历模式
if re.search(pattern, user_text): # 如果匹配
print(f"[安全] 检测到可能的敏感信息") # 记录警告
# 不要在日志中记录实际的敏感信息
# ========================================
# 创建安全 Agent
# ========================================
safe_agent = Agent(
name="safe_agent", # Agent 名称
model="gemini-2.0-flash", # 模型
instruction="你是一个安全的助手。遵循安全准则。", # 指令
before_model_callback=input_filter_callback, # 🔑 安全过滤回调
)
```
### 10.1.2 输出安全
```python
"""
输出安全:过滤不当输出
"""
async def output_filter_callback(
callback_context, # 回调上下文
invocation_context: InvocationContext, # 调用上下文
):
"""
输出安全过滤回调
在模型返回响应后检查输出内容
"""
response = callback_context.response # 获取模型响应
if not response: # 如果没有响应
return # 直接返回
# 检查响应中是否有文本内容
if response.candidates: # 如果有候选响应
for candidate in response.candidates: # 遍历候选
if candidate.content: # 如果有内容
text = candidate.content.parts[0].text # 提取文本
# 检查不当内容
forbidden_words = [ # 禁止词列表
"暴力", "违法", # 中文禁止词
]
for word in forbidden_words: # 遍历禁止词
if word in text: # 如果包含禁止词
print(f"[安全] 输出包含不当内容: {word}") # 记录警告
agent = Agent(
name="output_safe_agent", # Agent 名称
model="gemini-2.0-flash", # 模型
instruction="你是一个安全的助手。", # 指令
after_model_callback=output_filter_callback, # 🔑 输出过滤回调
)
```
---
## 10.2 A2A 协议Agent-to-Agent
### 10.2.1 A2A 概述
A2AAgent-to-Agent协议是 Google 提出的开放标准,用于实现不同 Agent 系统之间的远程通信。
```
┌──────────────┐ ┌──────────────┐
│ Agent A │ │ Agent B │
│ (ADK) │◄────────►│ (其他框架) │
│ │ A2A 协议 │ │
│ - 发送任务 │ │ - 接收任务 │
│ - 接收结果 │ │ - 返回结果 │
└──────────────┘ └──────────────┘
```
### 10.2.2 A2A 集成示例
```python
"""
A2A 协议集成示例
让 ADK Agent 与远程 Agent 通信
"""
from google.adk.agents import Agent # 导入 Agent 类
from google.adk.tools import AgentTool # 导入 AgentTool
# ========================================
# 创建远程 Agent 客户端
# ========================================
# 假设有一个远程 Agent 服务运行在 http://remote-agent:3000
# 可以通过 A2A 协议与之通信
# 在实际使用中,需要安装 A2A 客户端库
# pip install a2a-sdk
# 创建远程 Agent 的代理
# remote_agent_proxy = create_remote_agent_proxy(
# url="http://remote-agent:3000", # 远程 Agent 地址
# agent_name="RemoteExpert", # 远程 Agent 名称
# )
# 将远程 Agent 包装为工具
# remote_tool = AgentTool(agent=remote_agent_proxy)
# ========================================
# 在本地 Agent 中使用远程 Agent
# ========================================
local_agent = Agent(
name="local_agent", # 本地 Agent 名称
model="gemini-2.0-flash", # 模型
instruction=( # 指令
"你是一个协调助手。\n"
"对于本地可以处理的问题,直接回答。\n"
"对于需要专业知识的问题,使用远程 Agent 工具。"
),
# tools=[remote_tool], # 注册远程 Agent 工具
)
```
---
## 10.3 自定义 Agent 开发
### 10.3.1 继承 BaseAgent
```python
"""
自定义 Agent 开发
通过继承 BaseAgent 实现独特的 Agent 逻辑
"""
from google.adk.agents import BaseAgent # 导入基础 Agent 类
from google.adk.agents.invocation_context import InvocationContext # 导入调用上下文
from google.adk.events import Event, EventActions # 导入事件类型
from typing import AsyncGenerator # 导入异步生成器
import json # 导入 JSON 模块
import random # 导入随机数模块
# ========================================
# 示例一:随机决策 Agent
# ========================================
class RandomDecisionAgent(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 # 退出
# 随机选择一个子 Agent
chosen = random.choice(sub_agents) # 随机选择
print(f"[随机] 选择了 {chosen.name}") # 打印选择结果
# 将选择结果保存到状态
ctx.session.state["temp:chosen_agent"] = chosen.name # 保存选择
# 生成事件,指示委派给选中的 Agent
yield Event( # 生成委派事件
author=self.name, # 作者
actions=EventActions( # 事件动作
transfer_to_agent=chosen.name, # 委派给选中的 Agent
),
)
# ========================================
# 示例二:规则引擎 Agent
# ========================================
class RuleEngineAgent(BaseAgent):
"""
规则引擎 Agent
基于预定义规则处理请求,不使用 LLM
"""
def __init__(self, rules: dict, **kwargs):
"""
初始化规则引擎
Args:
rules: 规则字典key 为匹配模式value 为响应
"""
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 # 退出
user_text = user_events[-1].content.parts[0].text # 提取文本
# 匹配规则
matched_response = None # 匹配的响应
for pattern, response in self.rules.items(): # 遍历规则
if pattern.lower() in user_text.lower(): # 如果匹配
matched_response = response # 保存响应
break # 跳出循环
if matched_response: # 如果匹配到规则
yield Event( # 生成响应事件
author=self.name, # 作者
content=matched_response, # 响应内容
)
else: # 如果没有匹配
yield Event( # 生成默认响应
author=self.name,
content="抱歉,我无法处理您的请求。请尝试其他问题。",
)
# ========================================
# 使用自定义 Agent
# ========================================
# 创建规则引擎 Agent
faq_agent = RuleEngineAgent(
name="FAQBot", # Agent 名称
rules={ # 规则字典
"价格": "我们的产品价格请参考官网定价页面。", # 价格相关
"地址": "我们的地址是北京市海淀区xxx路xxx号。", # 地址相关
"电话": "客服电话400-xxx-xxxx。", # 电话相关
"营业时间": "营业时间:周一至周五 9:00-18:00。", # 营业时间
},
)
# 创建随机决策 Agent
random_agent = RandomDecisionAgent(
name="RandomRouter", # Agent 名称
sub_agents=[ # 子 Agent 列表
faq_agent, # FAQ Agent
],
)
```
---
## 10.4 多模型混合策略
```python
"""
多模型混合使用
根据任务类型选择不同的模型
"""
from google.adk.agents import LlmAgent # 导入 LlmAgent
from google.adk.models.lite_llm import LiteLlm # 导入 LiteLLM
# ========================================
# 策略一:不同 Agent 使用不同模型
# ========================================
# 简单任务使用快速模型
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="仔细分析问题,给出深入的推理过程。", # 指令
)
# 代码生成使用专用模型
code_agent = LlmAgent(
name="CodeAgent", # 代码 Agent
model=LiteLlm( # 使用 LiteLLM
model="deepseek/deepseek-coder", # DeepSeek Coder
api_key="your_api_key", # API Key
),
description="处理代码生成和调试任务。", # 描述
instruction="编写高质量的代码。", # 指令
)
# 协调器使用快速模型
coordinator = LlmAgent(
name="Coordinator", # 协调器
model="gemini-2.0-flash", # 快速模型
instruction=( # 指令
"根据任务复杂度分配给合适的 Agent\n"
"- 简单问答 → SimpleAgent\n"
"- 复杂推理 → ReasoningAgent\n"
"- 代码相关 → CodeAgent"
),
sub_agents=[simple_agent, reasoning_agent, code_agent], # 子 Agent
)
```
---
## 10.5 性能优化技巧
### 10.5.1 指令优化
```python
"""
指令优化技巧
减少 token 使用,提高响应速度
"""
# ❌ 冗长的指令(浪费 token
verbose_instruction = """
你是一个非常专业的、经验丰富的、知识渊博的助手。
你擅长回答各种各样的问题,包括但不限于技术问题、
生活问题、工作问题、学习问题等等。
当用户问你问题时,你应该:
1. 首先理解用户的问题
2. 然后分析问题
3. 最后给出答案
请始终使用中文回答。
"""
# ✅ 精简的指令(节省 token
concise_instruction = """
你是专业助手。用中文简洁回答。
"""
# ✅ 使用结构化指令
structured_instruction = """
## 角色
技术助手
## 规则
1. 使用中文
2. 简洁回答(<200字
3. 不确定时说"不确定"
"""
```
### 10.5.2 工具优化
```python
"""
工具优化技巧
减少不必要的工具调用
"""
# ❌ 工具描述过于详细(浪费 token
def bad_tool(query: str) -> dict:
"""
这是一个非常详细的工具描述,包含了大量的信息,
但是大部分信息对 LLM 来说是不必要的。
LLM 需要读取所有这些文本来理解工具的功能,
这会消耗大量的 token 并降低响应速度。
"""
return {"result": "done"}
# ✅ 精简的工具描述
def good_tool(query: str) -> dict:
"""搜索知识库并返回相关文档片段。"""
return {"result": "done"}
# ✅ 合并相似工具
# 如果有多个功能相似的工具,考虑合并
def unified_search(
query: str, # 搜索关键词
search_type: str = "all", # 搜索类型all/doc/faq
) -> dict:
"""
统一搜索工具
Args:
query: 搜索关键词
search_type: 搜索类型,可选 "all"(全部)、"doc"(文档)、"faq"(FAQ)
"""
return {"status": "success", "results": []}
```
---
## 10.6 完整实战项目:智能客服系统
```python
"""
完整实战项目:多智能体客服系统
整合本教程所有知识点
"""
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 google.adk.tools import google_search # 导入 Google 搜索
from typing import AsyncGenerator # 导入异步生成器
import asyncio # 导入异步库
# ========================================
# 第一步:定义工具
# ========================================
def search_faq(query: str) -> dict:
"""搜索常见问题解答"""
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", "answer": "未找到相关FAQ。"} # 未找到
def create_ticket(
category: str, # 工单类别
description: str, # 问题描述
priority: str = "normal", # 优先级
) -> dict:
"""创建客户工单"""
ticket_id = f"TK{len(description)}" # 生成工单号
return { # 返回工单信息
"status": "success",
"ticket_id": ticket_id,
"message": f"工单 {ticket_id} 已创建,我们会尽快处理。",
}
# ========================================
# 第二步:定义子 Agent
# ========================================
# FAQ Agent处理常见问题
faq_agent = LlmAgent(
name="FAQBot", # FAQ 机器人
model="gemini-2.0-flash", # 快速模型
description="处理常见问题,如退款、配送、退换货等。", # 描述
instruction="你是FAQ助手使用 search_faq 工具查找答案。", # 指令
tools=[search_faq], # FAQ 搜索工具
)
# 搜索 Agent处理需要联网查询的问题
search_agent = LlmAgent(
name="SearchBot", # 搜索机器人
model="gemini-2.0-flash", # 快速模型
description="处理需要搜索互联网的问题。", # 描述
instruction="使用 Google Search 搜索最新信息。", # 指令
tools=[google_search], # Google 搜索工具
)
# 工单 Agent处理需要人工介入的问题
ticket_agent = LlmAgent(
name="TicketBot", # 工单机器人
model="gemini-2.0-flash", # 快速模型
description="创建客户工单,转交人工处理。", # 描述
instruction="收集用户问题描述,使用 create_ticket 创建工单。", # 指令
tools=[create_ticket], # 创建工单工具
)
# ========================================
# 第三步:定义协调器
# ========================================
coordinator = LlmAgent(
name="CustomerServiceCoordinator", # 客服协调器
model="gemini-2.0-flash", # 快速模型
description="智能客服主协调器,负责路由用户请求。", # 描述
instruction=( # 系统指令
"你是一个智能客服协调器。\n"
"根据用户问题类型,分配给合适的子 Agent\n"
"- 退款、配送、退换货等常见问题 → FAQBot\n"
"- 需要最新信息的问题 → SearchBot\n"
"- 无法自动解决的问题 → TicketBot\n"
"使用 transfer_to_agent 进行任务分配。"
),
sub_agents=[ # 注册子 Agent
faq_agent, # FAQ 机器人
search_agent, # 搜索机器人
ticket_agent, # 工单机器人
],
)
# ========================================
# 第四步:添加监控回调
# ========================================
async def monitoring_callback(cb_ctx, inv_ctx):
"""监控回调:记录所有操作"""
agent_name = inv_ctx.agent.name # 获取 Agent 名称
print(f"[监控] Agent '{agent_name}' 正在处理请求") # 打印日志
coordinator.before_model_callback = monitoring_callback # 添加监控
# ========================================
# 第五步:设置 root_agent
# ========================================
root_agent = coordinator # 设置根 Agent
print("✅ 智能客服系统构建完成!") # 打印成功信息
print(f"根 Agent: {root_agent.name}") # 打印根 Agent 名称
print(f"子 Agent 数量: {len(root_agent.sub_agents)}") # 打印子 Agent 数量
```
---
## 📌 本章小结
- 输入安全:检测注入攻击、限制输入长度、过滤敏感信息
- 输出安全:过滤不当内容、记录审计日志
- A2A 协议:实现不同 Agent 系统间的远程通信
- 自定义 Agent继承 BaseAgent 实现独特逻辑
- 多模型策略:根据任务类型选择合适的模型
- 性能优化:精简指令、合并工具、合理选择模型
---
## 🎉 教程完结
恭喜你完成了 Google ADK 完整教程的学习!
### 学习路径回顾
```
第01章 环境搭建 → 第02章 Hello World
第03章 LLM Agent → 第04章 自定义工具
第05章 多智能体 → 第06章 会话状态
第07章 回调机制 → 第08章 评估
第09章 部署 → 第10章 高级主题
```
### 后续学习建议
1. **实践项目**:基于教程知识,构建自己的 Agent 应用
2. **阅读源码**:深入研究 [adk-python](https://github.com/google/adk-python) 源码
3. **社区参与**:关注 ADK 的更新和社区讨论
4. **探索生态**:了解 ADK 的 Java、Go 版本和 Web 版本
### 官方资源
- 📖 [官方文档](https://google.github.io/adk-docs/)
- 💻 [GitHub 仓库](https://github.com/google/adk-python)
- 📦 [示例代码](https://github.com/google/adk-samples)