跳到主要内容

会话引导(Steering)

Steering 允许你在运行中的 Agent 循环中、工具调用之间注入消息。当你需要重新引导 Agent、提供新上下文或取消正在执行的计划时非常有用 —— 无需等待当前轮次完成。

工作原理

每个工具执行完毕后,PicoClaw 会检查当前会话的 Steering 队列。如果发现一条或多条消息:

  1. 剩余排队的工具将被跳过 —— 其结果被替换为占位符。
  2. Steering 消息被注入到对话中,作为用户消息。
  3. 模型被再次调用,使用更新后的上下文。

流程图

Agent 循环运行中


工具 N 执行完毕


检查 Steering 队列 ──── 为空 ──► 继续执行工具 N+1

│ (发现消息)

跳过剩余工具


将 Steering 消息注入对话


使用更新后的上下文调用 LLM


Agent 循环以新方向继续

作用域隔离的队列

Steering 队列按已解析的会话作用域隔离 —— 不是全局的。每个活跃会话维护自己的队列,因此发送到一个会话的 Steering 消息永远不会泄漏到另一个会话。

配置

Steering 模式通过 agents.defaults.steering_mode 进行配置:

行为
"one-at-a-time"(默认)每个轮询周期出队一条消息。
"all"一次性消费整个队列。

也可以通过环境变量设置:

export PICOCLAW_AGENTS_DEFAULTS_STEERING_MODE=all

轮询点

PicoClaw 在 Agent 循环的四个位置检查 Steering 队列:

  1. 循环开始时 —— 在执行任何工具之前。
  2. 每个工具执行后 —— 主要的拦截点。
  3. 直接 LLM 响应后 —— 当模型不调用工具直接响应时。
  4. 轮次结束前 —— 在返回轮次结果之前的最后机会。

为什么要跳过剩余工具

当 Steering 消息在轮次中途到达时,所有尚未开始的工具都会被跳过。这是有意为之,原因有三:

原因示例
防止不必要的副作用用户说"停下,别删那个" —— 但 file_delete 工具还在队列中。跳过可以防止不可逆的损害。
避免浪费时间Agent 计划了 5 个 API 调用,但用户的 Steering 消息使它们变得无关。跳过可以节省延迟和费用。
LLM 获得完整上下文模型看到 Steering 消息以及之前的结果,可以做出更明智的决定。

被跳过的工具结果格式

因 Steering 而被跳过的工具,其结果被设置为:

Skipped due to queued user message.

这会出现在对话历史中,让 LLM 理解这些工具未被执行。

完整流程示例

Agent 接收到:"搜索配置文件,然后删除所有临时文件。"


工具 1: search_files("*.conf") ──► 完成,返回结果


检查 Steering 队列 ──► 用户发送了:"算了,别删任何东西。"


工具 2: delete_files("*.tmp") ──► 已跳过("Skipped due to queued user message.")
工具 3: delete_files("*.bak") ──► 已跳过("Skipped due to queued user message.")


注入 Steering 消息:"算了,别删任何东西。"


LLM 看到:搜索结果 + 被跳过的工具 + 用户更正


LLM 回复:"明白了,我找到了 3 个配置文件,但不会删除任何内容。"

自动总线消费

当 Agent 正在处理一个轮次时,后台 goroutine 会自动从总线消费入站消息并放入 Steering 队列。这确保了 Agent 繁忙时发送的消息不会丢失。

关键细节:

  • 音频优先转录 —— 语音消息在入队前会被转换为文本。
  • 作用域感知 —— 消息根据其作用域被路由到正确会话的 Steering 队列。

携带媒体的 Steering

Steering 消息可以包含 media:// 引用。这些引用在队列中被保留,并在消息注入对话时通过正常的媒体管道进行解析。

注意事项

  • 队列最大容量为 10。 超过此限制的消息将被丢弃,并输出警告日志。
  • Steering 不会中断正在执行的工具。 工具必须完成(或超时)后,才会检查 Steering 队列。