用于 ADK 的 Model Consult 工具¶
只使用单一模型的智能体面临一个权衡。快速、低成本的模型能让常规步骤更快、更节省资源,但在对复杂任务进行深入分析和决策时可能不够胜任。相比之下,更强的模型能很好地处理复杂决策,但会增加每个智能体步骤的响应时间和资源成本。
Model Consult 让智能体兼得两者之长。智能体运行在快速的执行器模型上,当遇到一个它无法自信解决的决策时,它会调用 Model Consult 工具,从更强的顾问模型那里获取指导。随后智能体自行继续执行任务,使用它自己的工具。智能体只在需要的步骤上使用更强的模型,而且如果咨询失败或咨询预算已用尽,智能体会用已有的信息继续工作。
使用场景¶
- 成本优化:在低成本模型上运行智能体的常规编排和工具循环,只在需要的步骤上让智能体咨询更强的模型。
- 策略协调:让智能体把复杂的多条款策略决策升级给前沿模型,然后用自己的工具执行所得到的指导。
- 循环救援:当智能体反复发出相同的工具调用时,让它咨询更强的模型,从而帮助智能体跳出重复循环。
前置条件¶
- ADK Python v2.11.0 或更高版本。
- 可以访问两个模型:一个低成本的执行器模型和一个更强的顾问模型,例如托管在 Google Cloud 上的 Gemini Flash 和 Gemini Pro。
- 为 ADK 配置好模型凭据:要么是一个启用了 Vertex AI API 的 Google Cloud 项目,要么是一个 Gemini API key。
安装¶
Model Consult 是直接包含在 ADK Python 包中的原生工具。
在智能体中使用¶
把 ModelConsultTool 附加到 Agent 上,与你的领域工具并列,例如下面示例中的 lookup_order 函数。该工具会注册 model_consult 函数声明,并向执行器的系统指令追加一个默认的升级策略,从而给智能体明确的规则,说明何时以及如何咨询顾问。
from google.adk.agents import Agent
from google.adk.tools import ModelConsultTool
def lookup_order(order_id: str) -> dict[str, str]:
"""按标识符查询订单状态。"""
return {"order_id": order_id, "status": "held_for_fraud_review"}
root_agent = Agent(
model="gemini-flash-latest",
name="support_executor",
instruction=(
"你是一个订单支持助手。请使用你的工具解决客户问题。"
),
tools=[
lookup_order,
ModelConsultTool(
model="gemini-pro-latest", # 顾问模型
max_uses=2,
session_max_uses=5,
thinking_level="high",
),
],
)
在这个示例中:
support_executor智能体运行在快速模型(gemini-flash-latest)上,并尝试使用其lookup_order工具解决用户的问题。- 执行器模型决定何时调用
model_consult。在默认设置中,执行器被指示在确定一个决定之前、在卡住时,以及在宣布任务完成之前调用model_consult。 ModelConsultTool拦截该调用,校验 max_uses 预算,并把当前会话事件与lookup_order工具的描述打包成一次完整的顾问咨询。- 顾问模型评估上下文并返回结构化的文本指导,让
support_executor重新获得控制权,执行任何推荐的工具,并结束本轮交互。
可用工具¶
| 工具 | 说明 |
|---|---|
model_consult |
将会话历史和一个具体问题升级给更强的顾问模型,以获得结构化的指导。 |
工作原理¶
当执行器调用 model_consult 时,ModelConsultTool 会执行四个步骤,并向执行器返回一个结构化字典:
- 预算校验 —
ModelConsultTool会将本轮计数器与max_uses对比、将会话总计数器与session_max_uses对比。如果任一上限已达到,该工具会立即返回"status": "limit_reached",不再调用顾问模型,并指示执行器使用已收集到的信息继续处理。 - 上下文移交 —
ModelConsultTool把这次咨询打包成一条role='user'的types.Content消息。当include_agent_instruction和include_tool_inventory为True时,消息开头是解析后的执行器指令和同级工具清单。接着,ModelConsultTool会按照ModelConsultContextConfig转换Session.events中非 partial、非 rewound 的事件,按说话者给文本部分打标签,并把之前的工具调用和工具响应压平成可读的文本摘要,同时排除任何进行中的model_consult调用。最后,ModelConsultTool追加一个移交部分,其中包含当前活跃的智能体名称、执行器的问题,以及执行器传入的任何额外context字符串。 - 无工具的顾问调用 —
ModelConsultTool会以禁用工具调用的方式调用所配置的顾问BaseLlm,并使用默认的顾问系统指令,或在提供了advisor_instruction时使用自定义指令。由于顾问请求中排除了工具声明,顾问无法自行执行工具或产生副作用;它只能返回文本指导,说明执行器接下来应该调用哪些工具以及使用什么参数。 - 结构化的工具响应 —
ModelConsultTool永远不会把异常抛回智能体循环。取而代之的是,它返回一个带有status值的字典,详见响应状态值。
检查工具调用¶
默认情况下,人类可读模式的 adk run 只打印最终的文本回复([support_executor]: ...),并隐藏中间的工具调用。你可以通过三种方式检查 model_consult 调用并核对顾问的回答:
- ADK Web UI — 在
adk-python的克隆仓库中运行adk web contributing/samples/tools: 在聊天面板中,每次咨询都会显示为一个model_consult工具事件。点击model_consult事件,即可在左侧打开 Events / Trace 检查器: functionCall显示执行器发送给顾问的确切question(以及可选的context)。-
functionResponse显示ModelConsultTool返回的结构化字典,包括"status"、"guidance"、"advisor_model"、"thinking_level"、"consults"、"usage"和"latency_ms"。 -
ADK CLI: 使用
adk run命令,可以将每个会话事件(包括model_consult的functionCall和functionResponse)以 JSON 形式输出。选择你的模式: - 单次查询模式: 传入
--jsonl,将事件以 JSON 行形式流式输出到 stdout: -
交互模式: 传入
--save_session,在退出时保存完整的会话日志: -
通过
Runner.run_async事件以编程方式检查: 在 Python 中运行智能体时,检查event.get_function_calls()和event.get_function_responses()中name == "model_consult"的项:
async for event in runner.run_async(user_id="u1", session_id="s1", new_message=msg):
for resp in event.get_function_responses():
if resp.name == "model_consult":
print(resp.response["status"], resp.response.get("guidance"))
print("Consult budget:", resp.response.get("consults"))
print("Advisor token usage:", resp.response.get("usage"))
响应状态值¶
model_consult 返回的字典中,status 字段取以下值之一:
| 状态 | 返回时机 | 字段 | 咨询预算 |
|---|---|---|---|
ok |
顾问返回了指导。 | guidance, advisor_model, thinking_level, consults, usage, latency_ms |
递增本轮计数器和会话计数器。 |
limit_reached |
max_uses 或 session_max_uses 已耗尽。不会调用顾问模型。 |
message, consults |
不消耗。 |
error |
顾问调用超时、失败,或没有产生可见文本。 | error, message, advisor_model, consults |
不消耗。 |
invalid_request |
question 为空或只包含空白字符。 |
message |
不消耗。 |
一次成功的咨询会返回下面的字典结构。其中显示的 token 计数和延迟仅为示意,并非真实测量值:
{
"status": "ok",
"guidance": "1. 使用 order_id='ORD-42' 调用 lookup_order。",
"advisor_model": "gemini-3.1-pro-preview",
"thinking_level": "high",
"consults": {
"used_this_turn": 1,
"max_uses": 2,
"used_this_session": 1,
"session_max_uses": 5,
"remaining": 1
},
"usage": {
"prompt_tokens": 612,
"output_tokens": 184,
"thoughts_tokens": 320,
"total_tokens": 1116
},
"latency_ms": 842.5
}
最佳实践¶
Model Consult 无需额外配置即可工作。使用以下做法来改善效果:
- 在执行器模型上启用思考。
- 保留默认的升级策略,或在执行器提示词中为你的用例引导升级策略。
在执行器上启用思考¶
由执行器决定何时调用 model_consult,因此当它能够进行推理时会做出更好的决策。在执行器模型上启用思考。例如,使用一个支持动态思考的轻量模型。
自定义执行器何时咨询顾问¶
一个 ModelConsultTool 对象会向执行器的系统指令添加升级策略。默认情况下,该策略要求执行器在做出决定之前、在陷入困境时,以及在宣布任务完成之前调用 model_consult。这些覆盖了下表中的规划、诊断和复盘触发条件。
要替换默认策略,请在 executor_instruction 中传入你自己的文本。要移除该策略,请传入空字符串("")。
ModelConsultTool(
executor_instruction=(
"在你的第一次回复之前调用 model_consult,并且每当工具调用"
"因你无法解释的原因失败时也调用。"
),
)
常见的咨询触发条件¶
下表列出了咨询顾问的常见原因,以及你可以添加到 executor_instruction 中的触发条件。
| 原因 | 为何有帮助 | 触发条件示例 |
|---|---|---|
| 规划 | 任务早期的错误解读或方法会影响之后的每一步,浪费时间和 token。 | - 在第一次回复之前。 - 在执行器收集完事实、开始主要工作之前。 - 当请求提出一个方案时,询问如何验证它。 - 当存在多种可能的方法或解读、且没有证据倾向其中之一时。 - 对于你知道比较困难的请求类型。 |
| 诊断 | 失败或矛盾意味着执行器的某个假设是错误的。 | - 工具调用失败或返回了意外结果,而执行器无法解释原因。 - 执行器在没有新信息的情况下重复相同的工具调用或其近似变体。 - 执行器推翻了自己的工作。 - 两个来源或工具结果不一致。 - 执行器得出请求本身是错误的结论。 |
| 复盘 | 对照需求检查结果,可以在用户发现问题之前找出错误和遗漏。 | - 在给出最终答案之前。 - 在执行器完成复杂任务中相当一部分工作之后。 |
配置选项¶
ModelConsultTool 对象负责配置顾问模型选择、咨询预算和提示词覆盖,而 ModelConsultContextConfig 控制会话事件在移交前如何被格式化和限制。
ModelConsultTool 选项¶
ModelConsultTool 类接受以下构造函数参数:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
model |
str | BaseLlm |
'gemini-3.1-pro-preview' |
通过 ADK 模型注册表解析的顾问模型名称,或一个预配置的 BaseLlm 实例。默认是一个预览模型,可能会发生变化。 |
max_uses |
int |
None |
每个用户轮次中成功咨询的最大次数。None 表示没有每轮上限。 |
session_max_uses |
int |
None |
整个会话中成功咨询的最大次数。None 表示没有会话级上限。 |
thinking_level |
str | types.ThinkingLevel |
'high' |
顾问模型的推理力度:'minimal'、'low'、'medium'、'high'、一个 types.ThinkingLevel 枚举值,或 'off'、'none'、None(表示不设置思考)。 |
max_output_tokens |
int |
None |
顾问输出 token 的可选上限,涵盖推理模型上可见输出和思考 token。 |
timeout_seconds |
float |
None |
每次调用的挂钟超时时间(秒)。None 表示没有工具级超时。 |
context_config |
ModelConsultContextConfig |
None |
控制会话历史如何被打包并限定后提供给顾问。 |
executor_instruction |
str |
None |
覆盖自动追加到执行器 system_instruction 的默认升级策略。传入 "" 可禁用自动注入。 |
advisor_instruction |
str |
None |
覆盖发送给顾问模型的默认系统指令。 |
description |
str |
None |
覆盖展示给执行器模型的默认工具说明。 |
include_agent_instruction |
bool |
True |
将执行器智能体自身的指令转发给顾问,使指导遵循执行器的约束。 |
include_tool_inventory |
bool |
True |
在顾问咨询提示词中包含执行器其他工具的名称和说明。 |
generate_content_config |
types.GenerateContentConfig |
None |
每次顾问调用时克隆的基础生成配置,例如 temperature 或 safety_settings。 |
name |
str |
'model_consult' |
暴露给执行器模型的工具名称。 |
ModelConsultContextConfig 选项¶
ModelConsultContextConfig 控制 Session.events 如何被转换为顾问的输入内容:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
include_session |
bool |
True |
为 True 时发送转换后的 Session.events 历史;为 False 时省略之前的会话事件。 |
max_events |
int |
None |
在进行字符预算裁剪之前,最多保留这么多最近的非 partial 会话事件。None 表示保留所有事件。 |
max_chars |
int |
200000 |
所有移交的会话轮次的字符预算。None 表示禁用字符预算。 |
max_part_chars |
int |
4000 |
渲染后的工具调用、工具结果和代码块的单部分字符上限,纯文本部分允许该上限的八倍。 |
include_media |
bool |
True |
为 True 时将内联媒体和文件引用转发给顾问模型;为 False 时用文本占位符替换它们。如果不想将会话媒体发送给顾问模型,请设置为 False。 |
include_thoughts |
bool |
False |
为 True 时在顾问移交内容中包含执行器的内部思考部分。 |