第 7 章 模型中立、开放生态与协议标准
第 7 章 模型中立、开放生态与协议标准
前六章我们一直在 ADK 这个"框架内部"工作。这一章,我们把镜头拉远,看 ADK 怎么和整个世界打交道。三个问题贯穿全章:ADK 能用哪些模型?ADK 怎么接入外部工具?ADK 怎么和别的 Agent 对话?答案分别是——模型中立、MCP、A2A。它们共同构成了 ADK 的开放生态。
7.1 模型中立:一个框架,所有模型
7.1.1 三种接入机制
ADK 的模型接入有三种机制,覆盖从"Google 深度集成"到"任意第三方"的全谱系:
机制一:直接字符串 / 注册表(Direct String / Registry)
针对与 Google Cloud 深度集成的模型——比如经 Google AI Studio 或 Agent Platform 访问的 Gemini、Claude。你只需要提供模型名(如 'gemini-flash-latest'),ADK 内部注册表会把它解析为对应的后端客户端。
from google.adk.agents import LlmAgent
# 直接用模型名字符串,注册表自动解析
agent_gemini = LlmAgent(
model="gemini-flash-latest",
name="gemini_flash_agent",
instruction="You are a fast and helpful Gemini assistant.",
)这是最省事的方式,适合 Gemini 用户。认证用 .env 里的 GOOGLE_API_KEY。
机制二:模型连接器(Model Connectors)
针对 Google 生态之外的模型,或需要特定客户端配置的模型。你实例化一个包装类(如 LiteLlm、ApigeeLlm),把它作为 model 参数传给 LlmAgent。这是本节的重点。
机制三:模型路由(Model Routing)
在运行时用路由函数在多个模型之间动态选择,出错时自动故障转移(failover)。见 7.1.4。
| 机制 | 适用模型 | 代码形态 |
|---|---|---|
| 注册表 | Gemini、Agent Platform 上的 Claude | model="gemini-flash-latest" |
| 连接器 | OpenAI、Anthropic、Ollama、vLLM、本地 | model=LiteLlm(model="openai/gpt-4o") |
| 路由 | 任意多个模型,按需动态选 | model=RoutedLlm(...) |
7.1.2 LiteLlm:接 OpenAI、Anthropic 和 100+ 模型
LiteLLM 是一个 Python 库,充当"模型与模型托管服务的翻译层",向 100+ 个大模型提供标准化、OpenAI 兼容的接口。ADK 通过 LiteLLM 集成,可以访问 OpenAI、Anthropic、Ollama、Mistral、DeepSeek、Cohere 等提供方的模型。
安装(注意版本要求):
pip install "litellm>=1.84"配置 API Key 作为环境变量:
export OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
export ANTHROPIC_API_KEY="YOUR_ANTHROPIC_API_KEY"准确 import 路径(这里容易写错,注意是 lite_llm 不是 litellm):
from google.adk.models.lite_llm import LiteLlm用 LiteLlm 接 OpenAI 的 GPT-4o:
from google.adk.agents import LlmAgent
from google.adk.models.lite_llm import LiteLlm
agent_openai = LlmAgent(
model=LiteLlm(model="openai/gpt-4o"),
name="openai_agent",
instruction="You are a helpful assistant powered by GPT-4o.",
)接 Anthropic 的 Claude:
agent_claude = LlmAgent(
model=LiteLlm(model="anthropic/claude-3-haiku-20240307"),
name="claude_direct_agent",
instruction="You are an assistant powered by Claude Haiku.",
)关键点:模型字符串采用 LiteLLM 的 provider/model 格式("openai/gpt-4o"、"anthropic/claude-3-haiku-20240307")。这个统一的字符串格式,就是"模型中立"的底层机制——换模型,只是换一个字符串。
补充一个细节:通过 LiteLlm 连接器使用 Anthropic Claude 时,ADK 自动支持其"思考块"(thinking blocks)特性——它会自动提取思考块及其签名,并在每次出站请求时重建,从而跨工具调用和多轮对话保留 Claude 的推理,无需你管理任何自定义状态。
安全提示:文档包含一则真实的安全公告——LiteLLM 1.82.7/1.82.8 曾在 PyPI 上被检出未经授权的代码(2026 年 3 月供应链事件)。使用 ADK Python 的用户应升级到最新版;此期间安装过 LiteLLM 的需轮换密钥。这提醒我们:第三方依赖也是供应链安全的一部分。
7.1.3 Ollama 本地模型:零成本跑起来
如果你没有云模型 API Key,或者想完全本地跑,Ollama 是最方便的选择。ADK 通过 LiteLLM 连接器接入 Ollama。
先装好 Ollama 并拉一个带工具能力的模型(比如 Gemma 3):
ollama pull gemma3然后配置环境变量指向本地 Ollama 服务:
export OLLAMA_API_BASE="http://localhost:11434"写 Agent:
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm
root_agent = Agent(
model=LiteLlm(model="ollama_chat/gemma3:latest"),
name="local_agent",
description="A local agent that can roll dice.",
instruction="You roll dice and answer questions about the outcome of the dice rolls.",
tools=[roll_die, check_prime],
)三个必须记住的坑(官方文档明确警告):
- 必须用
ollama_chat而不是ollama。用ollama可能导致无限工具调用循环和忽略之前上下文等意外行为。 - 务必设置
OLLAMA_API_BASE。虽然 LiteLLM 的api_base参数可用于生成,但自某版本起库依赖环境变量处理其他 API 调用。 - 选带工具支持的模型。依赖工具时,必须选 Ollama 上带工具能力的模型。用
ollama show mistral-small3.1检查Capabilities下是否列出tools。
如果 Ollama 模型没有原生工具支持,还有一个替代方案:用 openai provider 对接 Ollama 的 OpenAI 兼容端点:
export OPENAI_API_BASE=http://localhost:11434/v1
export OPENAI_API_KEY=anythingroot_agent = Agent(
model=LiteLlm(model="openai/mistral-small3.1"),
...
)7.1.4 模型路由:运行时动态选模型 + 故障转移
有些场景,一个 Agent 需要在运行时动态选择模型。ADK 的模型路由(Model Routing)正是为此设计,它支持:
- 故障转移:主模型挂了自动切到备选模型
- A/B 测试:按比例把请求分给不同模型
- 按复杂度路由:简单请求用便宜模型,复杂请求用强模型
RoutedLlm 是核心 API。路由函数在 errorContext(记录失败模型)的配合下决定下一个模型:
from google.adk.agents import LlmAgent
from google.adk.models import RoutedLlm, Gemini
primary_model = Gemini(model="gemini-flash-latest")
fallback_model = Gemini(model="gemini-pro-latest")
def router(models, request, error_context=None):
if not error_context:
return "primary" # 先试主模型
if "primary" in error_context.failed_keys:
return "fallback" # 主模型失败,切备选
return None # 没有更多选项,传播错误
routed_llm = RoutedLlm(
models={"primary": primary_model, "fallback": fallback_model},
router=router,
)
agent = LlmAgent(
name="my_agent",
model=routed_llm,
instruction="You are a helpful assistant.",
)路由的故障转移规则很清晰:
- 路由函数首次调用不带
errorContext,做初始选择 - 若所选模型在产出任何响应之前失败,则带着
errorContext(含failedKeys、lastError)再次调用 - 已尝试过的模型不能被重新选择;返回
undefined时停止重试并传播错误
注意:模型路由目前是实验性特性,官方文档以 TypeScript 呈现为主。如果你需要同时切换 instructions、tools 或子 Agent,用 Agent 级路由(
RoutedAgent)而不是RoutedLlm。
7.1.5 vLLM:自托管高吞吐模型
如果你的团队要自托管开源模型做高吞吐推理,vLLM 是常见选择。vLLM 把模型托管为 OpenAI 兼容的 API 端点,ADK 通过 LiteLlm 接入:
agent_vllm = LlmAgent(
model=LiteLlm(
model="your-model-name",
api_base="https://your-vllm-endpoint",
extra_headers=auth_headers,
),
name="vllm_agent",
instruction="You are a helpful assistant running on a self-hosted vLLM endpoint.",
)注意:部署 vLLM 时必须开启 OpenAI 兼容的工具/函数调用(如 --enable-auto-tool-choice),否则 ADK 的工具无法工作。
7.1.6 主线项目:把云销客服切到本地模型
验证一下"模型中立"。把第 2 章的云销客服从 Gemini 切到本地 Ollama,只需要改一行:
from google.adk.models.lite_llm import LiteLlm
yunxiao_agent = Agent(
model=LiteLlm(model="ollama_chat/gemma3:latest"), # 只改这一行
name="yunxiao_cs_agent",
...
)工具、指令、Session 全部不变。这就是"代码零改动换模型"——模型中立不是口号,是架构。
7.2 技能(Skills)深入:可复用的能力包
第 3 章我们入门了 Skills。这一节深入它的完整设计。
7.2.1 为什么 Skills 比 Tools 更高层
Skill 是 ADK agent 可用于执行特定任务的自包含功能单元,封装了任务所需的指令、资源和工具,基于 Agent Skill 规范(agentskills.io)。
它和 Tool 的区别在于:
- Tool:一个可执行函数,只有"做什么"
- Skill:指令 + 资源 + 工具 的打包,同时告诉 Agent"做什么"和"怎么做"
Skill 最大的卖点是增量加载——L1 只用于发现,L2 在触发时才加载,L3 资源按需读取。这最小化了对 Agent 上下文窗口的占用。
7.2.2 三层结构
my_agent/
agent.py
.env
skills/
example-skill/ # Skill
SKILL.md # main instructions (required)
references/ # 附加 Markdown 参考
REFERENCE.md
assets/ # 模板、图片、数据
scripts/ # 可执行脚本
*.py- L1 元数据:
SKILL.md的 frontmatter(name、description),用于技能发现。name≤64 字符、小写 kebab-case;description非空、≤1024 字符。 - L2 指令:
SKILL.md正文,Agent 触发技能时加载。 - L3 资源:
references/(附加文档)、assets/(素材)、scripts/(脚本),按需加载。
整个目录只有 SKILL.md 是必需文件。
7.2.3 加载与挂载
从文件系统加载:
import pathlib
from google.adk.skills import load_skill_from_dir
from google.adk.tools import skill_toolset
weather_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "weather_skill"
)
my_skill_toolset = skill_toolset.SkillToolset(
skills=[weather_skill],
additional_tools=[get_weather_tool], # 可附带额外工具
)
root_agent = Agent(
model="gemini-flash-latest",
name="skill_user_agent",
description="An agent that can use specialized skills.",
instruction="You are a helpful assistant that can leverage skills to perform tasks.",
tools=[my_skill_toolset],
)SkillToolset 会给 Agent 注入一套默认系统指令,规定它如何与 Skill 交互:
- 必须先用
load_skill工具读取技能的指令才能使用它 - 必须严格遵循技能定义中的指令
- 必须用
load_skill_resource查看技能目录内的文件 - 必须用
run_skill_script运行scripts/目录中的脚本
7.2.4 代码内联定义 Skill
除了从文件系统加载,还可以在代码里定义 Skill(内联 Skill):
from google.adk.skills import models
greeting_skill = models.Skill(
frontmatter=models.Frontmatter(
name="greeting-skill",
description="A friendly greeting skill that can say hello to a specific person.",
),
instructions=(
"Step 1: Read the 'references/hello_world.txt' file to understand how"
" to greet the user. Step 2: Return a greeting based on the reference."
),
resources=models.Resources(
references={
"hello_world.txt": "Hello! So glad to have you here!",
},
),
)内联定义的价值:Source 接口可被任意数据存储(如数据库)支撑,支持实时更新和个性化等动态用例——技能可以"动态生成",而不只是静态文件。
7.2.5 Skills 与 MCP 的对比
Skills 和 MCP 都是"能力打包",但有本质区别:
| 维度 | Skills | MCP 工具 |
|---|---|---|
| 粒度 | 指令 + 资源 + 工具 | 工具 |
| 加载方式 | 增量加载(省上下文) | 一次性工具清单 |
| 面向 | Agent 内部能力组织 | Agent 外部工具接入 |
| 规范 | agentskills.io | modelcontextprotocol.io |
Skills 管"内部组织",MCP 管"外部连接",两者互补。
7.3 协议标准:连接一切
7.3.1 协议全景图
ADK 的开放生态建立在几大协议之上。这一节我们逐个讲清楚:
| 协议 | 全称 | 解决什么问题 | 层 |
|---|---|---|---|
| MCP | Model Context Protocol | Agent 接入外部工具 | 工具层 |
| A2A | Agent2Agent | Agent 与 Agent 通信 | Agent 间 |
| Grounding | — | Agent 接入实时/私有知识 | 知识层 |
| AGENTS.md | — | 给编码 Agent 的项目说明 | 项目上下文 |
| AG-UI | Agent-User Interaction | Agent 与前端界面交互 | 人机界面 |
7.3.2 MCP:Agent 接入整个工具生态
MCP(Model Context Protocol) 是一个开放标准,用于标准化 LLM 与外部应用、数据源、工具之间的通信。它采用客户端-服务器架构,定义了数据(resources)、交互模板(prompts)、可执行函数(tools)如何被 MCP server 暴露、被 MCP client 消费。
ADK 在 MCP 生态里扮演双重角色:
角色一:作为 MCP 客户端,消费外部 MCP server 的工具。
这是最常见的模式。ADK agent 通过 McpToolset 使用外部 MCP server 提供的工具。第 3 章已经演示过 stdio 连接,这里再展示远程 HTTP 连接:
import os
from google.adk.agents.llm_agent import Agent
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
root_agent = Agent(
model='gemini-flash-latest',
name='travel_planner_agent',
description='A helpful assistant for planning travel routes.',
tools=[
McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://your-mcp-server.example.com/mcp",
headers={"Authorization": "Bearer YOUR_TOKEN"},
)
)
]
)McpToolset 初始化时自动完成:建立/管理连接、发现工具(list_tools)、把 MCP 工具的 schema 转成 ADK 兼容的 BaseTool 实例、代理调用。tool_filter 参数可以筛选只暴露部分工具——这是生产环境安全过滤的关键手段。
角色二:作为 MCP server,暴露 ADK 工具给其他客户端。
反过来,你可以把 ADK 工具包装成 MCP server,让任何 MCP 客户端(其他 Agent 框架、应用)都能调用。ADK 使用 FastMCP 处理 MCP 协议细节——"high-level and Pythonic,大多数情况下装饰一个函数就够了"。
7.3.3 A2A:让 Agent 与 Agent 对话
A2A(Agent2Agent) 是让不同 Agent 互相通信的标准协议。它和本地子 Agent 有本质区别:
| 维度 | 本地 sub-agent | 远程 Agent(A2A) |
|---|---|---|
| 进程 | 同一进程 | 独立服务 |
| 通信 | 内存中,极快 | 网络 |
| 维护 | 同一团队 | 可以是不同团队/组织 |
| 语言 | 同语言 | 可跨语言/跨框架 |
什么时候该用 A2A:对方是独立部署的服务、由不同团队维护、跨语言/框架、需要强形式化契约。什么时候不该用:纯内部代码组织、性能关键的高频操作、需要共享内存/上下文。
A2A 的三大核心能力:
- Reasoning:消息在 Agent 间传递时保留模型的推理痕迹
- Long-Running Tools:跟踪超过标准响应时长的工具调用
- Artifacts:在 Agent 间传递文件产物
暴露(Exposing):把已有 ADK agent 变成可在网络上接收请求的服务。最简方式:
from google.adk.a2a.utils.agent_to_a2a import to_a2a
a2a_app = to_a2a(root_agent, port=8001)to_a2a() 自动生成 agent card(描述这个 agent 能力/技能的元数据),经 uvicorn 服务后即可在 .well-known 端点提供。安装依赖 pip install google-adk[a2a]。
消费(Consuming):在另一个 agent 中使用 RemoteA2aAgent 调用远程 agent:
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent, AGENT_CARD_WELL_KNOWN_PATH
prime_agent = RemoteA2aAgent(
name="prime_agent",
description="Agent that handles checking if numbers are prime.",
agent_card=(
f"http://localhost:8001/a2a/check_prime_agent{AGENT_CARD_WELL_KNOWN_PATH}"
),
)然后把它作为 sub-agent 挂进根 agent,和本地子 Agent 一起编排:
root_agent = Agent(
model="gemini-flash-latest",
name="root_agent",
sub_agents=[local_roll_agent, prime_agent], # 本地 + 远程 混合编排
)调用远程 agent 就像调用本地工具一样——ADK 把网络通信、认证、数据格式化的全部复杂性都抽象掉了。
7.3.4 Grounding:接入实时与私有知识
Grounding(接地)是将 AI agent 连接到外部信息来源的过程,使响应更准确、最新、可验证,从而减少幻觉。ADK 支持多种 grounding 方式。
Google Search Grounding(实时网络信息):
from google.adk.agents import Agent
from google.adk.tools import google_search
root_agent = Agent(
name="google_search_agent",
model="gemini-flash-latest",
instruction="Answer questions using Google Search when needed. Always cite sources.",
description="Professional search assistant with Google Search capabilities",
tools=[google_search]
)它的数据流是:用户查询 → LLM 决定调用 google_search 工具 → grounding 服务向 Google Search 发查询 → 检索结果注入模型上下文 → 生成带引用的 grounded 响应。响应会带 groundingChunks(模型查阅的网页列表)和 groundingSupports(把回答的句子关联回 chunks)。
Grounding with Search(企业私有文档):
from google.adk.agents import Agent
from google.adk.tools import VertexAiSearchTool
DATASTORE_ID = "projects/YOUR_PROJECT_ID/locations/global/collections/default_collection/dataStores/YOUR_DATASTORE_ID"
root_agent = Agent(
name="vertex_search_agent",
model="gemini-flash-latest",
instruction="Answer questions using Agent Search to find information from internal documents. Always cite sources when available.",
tools=[VertexAiSearchTool(data_store_id=DATASTORE_ID)]
)这用于查询组织私有文档和企业数据。注意:这需要连接 Google Cloud 项目认证(GOOGLE_GENAI_USE_ENTERPRISE=TRUE 等),不能用 AI Studio 的 API Key。
7.3.5 AGENTS.md 与 AG-UI:生态的另外两块拼图
AGENTS.md:给编码 Agent 看的项目说明文件,跨工具通用的开放格式(由 Linux 基金会维护,已被 6 万+ 开源项目采用)。它相当于"给 Agent 的 README"——把构建步骤、测试命令、代码约定放在固定位置,让编码 Agent 自动读取。本书的 books/adk/AGENTS.md 就是它的应用。
AG-UI(Agent-User Interaction):由 CopilotKit 提出的协议,目标是"把 Agent 带进前端应用",标准化 Agent 与用户界面交互。
这些协议标准共同构成了 Agent 生态的"通用语言":MCP 让 Agent 用任何工具,A2A 让 Agent 连任何 Agent,AGENTS.md 让 Agent 理解任何项目,AG-UI 让 Agent 出现在任何界面。ADK 对这些协议的支持,就是"开放生态"的具体含义。
主线项目:给云销客服封装技能
这一节把 Skills 用到主线项目。给云销客服封装一个"退款处理技能":
skills/
refund-handling/
SKILL.md
references/
refund-policy.mdSKILL.md:
---
name: refund-handling
description: 处理售后退款咨询和退款申请,包括政策查询、资格判断、流程引导。
---
# 退款处理技能
1. 用户咨询退款时,先加载 references/refund-policy.md 了解当前政策
2. 按政策判断用户订单是否符合退款条件
3. 引导用户提供订单号和商品类别
4. 如需要人工审批(金额超阈值),转交人工挂载到云销客服:
import pathlib
from google.adk.skills import load_skill_from_dir
from google.adk.tools import skill_toolset
refund_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "refund-handling"
)
yunxiao_agent = Agent(
model="gemini-flash-latest",
name="yunxiao_cs_agent",
tools=[skill_toolset.SkillToolset(skills=[refund_skill])],
...
)退款处理的知识和流程被封装成了一个可复用的能力包——这正是 Skills 的价值:把 Agent 的专业知识从代码里解放出来,变成可管理、可复用、可跨 Agent 共享的资产。
「为什么 ADK 这样设计」:开放协议赢,封闭生态输
这一章讲了很多协议。为什么 ADK 要把自己押在"开放"上?
回顾第 1 章的框架版图:Agent 框架分"官方阵营"和"中立阵营"。官方阵营有个天然诱惑——把开发者绑在自己生态里(只用自己的模型、只用自己的云)。但 ADK 选择了反方向:
模型中立:不要求你用 Gemini。因为 Google 明白,开发者选框架的第一考量是"不被绑架"。ADK 赌的是"开放协议赢,不是自家模型赢"——只要你用 ADK,哪怕用 Claude,你也在 Google 的生态引力范围内。
工具中立(MCP):不要求你只用 Google 的工具。MCP 是 Anthropic 提出的协议,ADK 全力支持。因为"支持 MCP"不是支持 Anthropic,而是支持"工具互联"这个必然趋势。
Agent 中立(A2A):不要求你的 Agent 只和 ADK Agent 对话。A2A 让跨框架、跨组织的 Agent 能协作。这是"Agent 互联网"的雏形。
这一整套开放策略,本质是一个判断:Agent 生态的未来不属于任何单一公司,而属于开放的协议。谁先支持开放的协议,谁就在未来的 Agent 互联网里占据中心位置。ADK 的选择是——不做围墙,做连接器。
本章小结
- 三种模型接入机制:注册表(Gemini 直连)、连接器(LiteLlm 接 100+ 模型)、路由(运行时动态选)
- LiteLlm 是模型中立的钥匙:
from google.adk.models.lite_llm import LiteLlm,provider/model字符串格式,换模型只换字符串 - Ollama 本地跑:用
ollama_chat前缀、设OLLAMA_API_BASE、选带工具支持的模型(三个坑) - 模型路由:
RoutedLlm+ 路由函数,支持故障转移、A/B 测试、按复杂度路由 - Skills 是能力包:指令 + 资源 + 工具,三层结构(L1 元数据/L2 指令/L3 资源),增量加载省上下文
- MCP 双角色:作为客户端消费外部工具(McpToolset),作为 server 暴露工具(FastMCP)
- A2A 让 Agent 互联:
to_a2a暴露 +RemoteA2aAgent消费,本地/远程 Agent 混合编排 - Grounding 接地:Google Search(实时网络)+ VertexAiSearchTool(私有文档),减少幻觉
- 开放哲学:ADK 赌"开放协议赢",做连接器不做围墙
练习
- 换模型实战:把你的云销客服分别用 Gemini、OpenAI(如果有关键)、Ollama 本地跑一遍,对比响应质量和成本。
- 接一个 MCP server:找一个公开的 MCP server(比如 GitHub MCP),用
McpToolset接到你的 Agent,让 Agent 能用 GitHub 工具。 - 封装一个技能:给云销客服做一个"物流查询技能"(SKILL.md + references),验证增量加载和指令遵循。
- A2A 实验:如果你有第二个 Agent,用
to_a2a暴露它,再用RemoteA2aAgent从主 Agent 调用它,体验跨 Agent 通信。
下一章预告:第 8 章,我们把这些能力送上生产。从本地到云端——Cloud Run、GKE、自有服务器,ADK 的部署路径怎么选,怎么把云销客服真正跑在线上。