跳转到内容

使用 Agent Handoff

当你需要在同一个 run、同一条 thread 内切换到另一个已注册 agent ID,而不终止 run 或创建新 thread 时,使用本页。

  • 已添加 awaken
  • 了解 PluginStateKeyAgentRuntimeBuilder

handoff 会把请求的 active agent 写入状态。下一个 step 边界时,loop 读取 ActiveAgentIdKey,通过 AgentResolver 重新解析该 agent ID,停用旧插件、激活新插件,并在同一条 thread 历史上继续执行。

需要切换到的目标应注册为具体的 AgentSpecAgentOverlayHandoffPlugin 保存并可通过 overlay() 查询的可选元数据;内置 loop 不会把 overlay 字段合并进基础 AgentSpec

关键类型:

  • HandoffPlugin:把 handoff 状态同步到 active agent ID
  • AgentOverlay:供集成方查看的可选 variant 元数据
  • HandoffState:记录当前 active variant 和待处理请求
  • HandoffActionRequestActivateClear reducer action
  1. 把 variant 定义成已注册 agent spec:
use awaken::registry_spec::AgentSpec;
let mut base = AgentSpec::new("assistant")
.with_model_id("claude-sonnet")
.with_system_prompt("You are a helpful assistant.");
let mut researcher = AgentSpec::new("researcher")
.with_model_id("claude-sonnet")
.with_system_prompt("You are a research specialist. Find and cite sources.");
researcher.allowed_tools = Some(vec!["web_search".into(), "read_document".into()]);
let writer = AgentSpec::new("writer")
.with_model_id("claude-sonnet")
.with_system_prompt("You are a technical writer. Produce clear documentation.");

request_handoff() 传入的字符串必须匹配这些 agent ID。

  1. 构建 HandoffPlugin
use awaken::extensions::handoff::HandoffPlugin;
let handoff = HandoffPlugin::new(Default::default());
  1. 把插件注册进 runtime:
use std::sync::Arc;
use awaken::engine::GenaiExecutor;
use awaken::registry_spec::ModelSpec;
use awaken::AgentRuntimeBuilder;
let mut spec = spec;
spec.plugin_ids.push("agent_handoff".into());
let runtime = AgentRuntimeBuilder::new()
.with_plugin("agent_handoff", Arc::new(handoff))
.with_agent_spec(base)
.with_agent_spec(researcher)
.with_agent_spec(writer)
.with_provider("anthropic", Arc::new(GenaiExecutor::new()))
.with_model(ModelSpec::new("claude-sonnet", "anthropic", "claude-sonnet-4-20250514"))
.build()?;

插件 ID 必须是 "agent_handoff"(导出为 HANDOFF_PLUGIN_ID),并且必须列在 AgentSpec.plugin_ids 中。该插件会在 Phase::RunStartPhase::StepEnd 注册 hook,同步 handoff 状态。

  1. 在 tool 或 hook 中请求 handoff:
use awaken::extensions::handoff::{request_handoff, activate_handoff, clear_handoff, ActiveAgentKey};
use awaken::state::StateCommand;
let mut cmd = StateCommand::new();
cmd.update::<ActiveAgentKey>(request_handoff("researcher"));
let mut cmd = StateCommand::new();
cmd.update::<ActiveAgentKey>(activate_handoff("writer"));
let mut cmd = StateCommand::new();
cmd.update::<ActiveAgentKey>(clear_handoff());
  1. 可选:读取 overlay 元数据:
let overlay = handoff.overlay("researcher");

HandoffState 有两部分:

  • active_agent
  • requested_agent

内部同步 hook 会在 RunStartStepEnd 检测 requested_agent,并在安全边界上把它提升为 active_agent

HandoffDelegation
Thread同一 thread、同一 run通常会产生子 agent 执行上下文
状态同一 thread state;在 step 边界重新解析 active agent一般隔离
适用场景切换角色、人设或工具集拆分独立子任务
开销很低更高
错误原因修复
handoff resolve failedrequest_handoff 的名字不是已注册 agent ID注册同名 AgentSpec
StateError::KeyAlreadyRegistered其他插件也注册了 ActiveAgentKey每个 runtime 只保留一个 HandoffPlugin
hook 没有执行agent hook filter 排除了插件"agent_handoff" 加到 hook filter,或保持 filter 为空
  • crates/awaken-runtime/src/extensions/handoff/mod.rs
  • crates/awaken-runtime/src/extensions/handoff/plugin.rs
  • crates/awaken-runtime/src/extensions/handoff/types.rs
  • crates/awaken-runtime/src/extensions/handoff/state.rs
  • crates/awaken-runtime/src/extensions/handoff/action.rs