Read OSS

工具系统与调度器:Gemini CLI 如何执行操作

高级

前置知识

  • 第 2 篇:智能体循环
  • 理解构建者模式与策略设计模式
  • MCP(Model Context Protocol)基础知识

工具系统与调度器:Gemini CLI 如何执行操作

当 Gemini 模型决定读取文件、执行 shell 命令或调用 MCP 工具时,这个决策会进入一套精密的处理流水线:工具调用被验证、经过策略检查、可能需要用户确认,执行完毕后将结果返回给模型,用于下一轮对话。本文将深入介绍 Gemini CLI 的工具系统与调度器是如何协同编排这整个流程的。

ToolInvocation 接口

Gemini CLI 中的每次工具调用都遵循由 ToolInvocation 接口 定义的统一生命周期:

flowchart LR
    V[validate params] --> D[getDescription]
    D --> C[shouldConfirmExecute]
    C --> E[execute]
    E --> P[getPolicyUpdateOptions]

该接口提供了清晰的契约:

  • params — 本次调用经过验证的参数
  • getDescription() — 以人类可读的方式描述工具将要执行的操作
  • toolLocations() — 工具将影响的文件路径(用于 UI 展示)
  • shouldConfirmExecute(abortSignal, forcedDecision?) — 若需要用户确认,返回确认详情;否则返回 false
  • execute(signal, updateOutput?, options?) — 执行工具并返回 ToolResult
  • getPolicyUpdateOptions(outcome) — 当用户选择"始终允许"时,提供工具特定的策略更新选项

shouldConfirmExecute 方法是策略决策转化为用户可见行为的关键所在。它接收可能来自 MessageBus 策略检查的 forcedDecision,返回 false(直接执行,无需确认)或一个包含特定 UI 数据的 ToolCallConfirmationDetails 对象。

BaseDeclarativeTool 与构建者模式

工具通过 BaseDeclarativeTool 以声明式方式定义,将 schema 定义与执行逻辑解耦。每个工具类需要指定:

  • 供模型 function declarations 使用的名称、显示名称和描述
  • 用于参数验证的 JSON parameter schema
  • Kind 枚举值(ReadOnly、Write、Execute、Other)
  • 输出是否为 markdown,以及是否支持实时更新

当模型请求工具调用时,BaseDeclarativeTool 会通过 SchemaValidator 对参数进行 schema 验证,然后调用 createInvocation() 生成一个 ToolInvocation 实例。这正是构建者模式的体现:工具定义是构建者,调用实例是最终产物。

classDiagram
    class BaseDeclarativeTool~TParams, TResult~ {
        +name: string
        +displayName: string
        +description: string
        +kind: Kind
        +parameterSchema: object
        #createInvocation(): ToolInvocation
        +validate(params): ToolInvocation
    }
    
    class ToolInvocation~TParams, TResult~ {
        <<interface>>
        +params: TParams
        +getDescription(): string
        +shouldConfirmExecute(): Promise
        +execute(): Promise~TResult~
        +toolLocations(): ToolLocation[]
    }
    
    class BaseToolInvocation~TParams, TResult~ {
        +messageBus: MessageBus
        +respectsAutoEdit: boolean
        +getApprovalMode: Function
        #getConfirmationDetails(): Promise
        #getMessageBusDecision(): Promise
    }
    
    BaseDeclarativeTool ..> ToolInvocation : creates
    BaseToolInvocation ..|> ToolInvocation

BaseToolInvocation 抽象类提供了默认的确认流程。其 shouldConfirmExecute 方法会检查工具是否遵守 AUTO_EDIT 模式,然后向 MessageBus 查询策略决策。若决策为 allow,则无需确认直接执行;若为 deny,则抛出异常;若为 ask_user,则委托给 getConfirmationDetails() 展示特定的 UI 界面。

提示: BaseToolInvocation 上的 respectsAutoEdit 标志控制工具是否可以在 AUTO_EDIT 模式下自动审批。只有写入类工具(WriteFile、Edit)会将其设为 true——shell 命令在默认模式下始终需要明确确认。

ToolRegistry 与模型感知的工具定义

ToolRegistry 是所有工具定义的中央存储,包括内置工具和动态发现的工具。它将工具名称映射到 AnyDeclarativeTool 实例,并为模型的 function-calling API 提供 getFunctionDeclarations(modelId?)

一个关键的设计特性是模型族感知的工具定义coreTools.ts 顶部的 getToolSet 函数根据模型类型路由到不同的 schema 集合:

export function getToolSet(modelId?: string): CoreToolSet {
  const family = getToolFamily(modelId);
  switch (family) {
    case 'gemini-3':
      return GEMINI_3_SET;
    case 'default-legacy':
    default:
      return DEFAULT_LEGACY_SET;
  }
}

Gemini 3 模型可能支持与旧版模型不同的参数 schema 或描述。每个工具定义(如 READ_FILE_DEFINITION)都有一个返回默认旧版 schema 的 base 属性,以及一个根据当前模型解析到对应集合的 overrides 函数。

内置工具覆盖文件操作、代码智能、网络访问和智能体控制等多个类别:

类别 工具
文件 I/O ReadFile、WriteFile、Edit、ReadManyFiles、Glob、LS
搜索 Grep(基于 ripgrep)
执行 Shell
网络 WebSearch、WebFetch
记忆 Memory(保存/检索事实)
智能体控制 ActivateSkill、AskUser、ExitPlanMode、UpdateTopic
任务跟踪 WriteTodos

调度器:事件驱动的工具编排

Scheduler 是模型工具调用请求与实际工具执行之间的桥梁。源码中将其描述为"工具执行的事件驱动编排器"。

flowchart TD
    A[Tool Call Requests from Turn] --> B[Scheduler.schedule]
    B --> C{Already processing?}
    C -- Yes --> D[Enqueue request]
    C -- No --> E[Start batch]
    E --> F[ToolModificationHandler<br/>validates & transforms]
    F --> G[Check Policy via PolicyEngine]
    G --> H{Policy Decision}
    H -- ALLOW --> I[Execute tool]
    H -- DENY --> J[Return error]
    H -- ASK_USER --> K[Evaluate BeforeTool hook]
    K --> L[Resolve confirmation via MessageBus]
    L --> M{User confirms?}
    M -- Yes --> N[Update policy if always-allow]
    N --> I
    M -- No --> O[Return cancelled]
    I --> P[ToolExecutor.execute]
    P --> Q[Track state via SchedulerStateManager]
    Q --> R[Return CompletedToolCall]

调度器协调以下五个组件:

  1. ToolModificationHandler — 在执行前对工具调用请求进行验证和转换
  2. PolicyEngine(通过 checkPolicy)— 评估规则,决定 allow/deny/ask_user
  3. evaluateBeforeToolHook — 触发执行前的钩子,可以修改或阻止执行
  4. resolveConfirmation — 通过 MessageBus 处理用户确认流程
  5. ToolExecutor — 实际执行工具并捕获结果

第 192 行schedule() 方法接受一个或多个 ToolCallRequestInfo 对象。当模型在单次响应中发出多个 function call(并行工具调用)时,它们会被批量处理。如果已有一批正在执行,新的请求会通过 _enqueueRequest() 进入队列等待。

每次工具调用的状态由 SchedulerStateManager 追踪,经历以下阶段:Scheduled → Validating → Executing → Completed(或 Errored)。状态管理器还负责处理 MCP 进度更新——当 MCP 工具上报增量进度时,调度器会将执行状态更新为对应的进度百分比和消息。

深入解析:ShellTool 与 EditTool

在所有内置工具中,ShellTool 是最复杂的一个。它需要:

  1. 解析命令以进行策略评估(使用 shell-quote 解析)
  2. 与沙箱管理器集成,用于命令包装
  3. 处理后台执行并跟踪 PID
  4. 通过 ShellExecutionService 支持平台特定的执行方式

Edit 工具采用了另一种思路——不是全量替换文件内容,而是使用基于 diff 的修改模型。模型提供 old_stringnew_string 参数,工具执行精准替换。这比发送整个文件内容更节省 token,同时也能为用户确认界面生成更清晰的 diff 视图。

这两个工具都很好地展示了确认流程的实际运作。ShellTool 生成 exec 类型的确认详情,包含解析后的命令和根命令;EditTool 生成 edit 类型的确认详情,包含文件 diff、原始内容和新内容——在终端 UI 中以可视化 diff 的形式呈现。

MCP 工具集成

MCP(Model Context Protocol)工具通过 DiscoveredMCPTool 类和 mcp_{serverName}_{toolName} 命名约定进行集成。配置 MCP 服务器后,McpClientManager 会发现可用工具,并以 mcp_ 前缀将其注册到 ToolRegistry 中。

sequenceDiagram
    participant Config as Config.initialize()
    participant MCM as McpClientManager
    participant MCP as MCP Server
    participant TR as ToolRegistry
    
    Config->>MCM: connectToServers()
    MCM->>MCP: listTools()
    MCP-->>MCM: tool schemas
    MCM->>TR: registerTool(DiscoveredMCPTool)
    Note over TR: Tool registered as<br/>mcp_serverName_toolName

MCP 工具与内置工具走相同的调度器流水线——经过验证、策略检查和用户确认后才会执行。mcp_ 前缀支持通配符策略规则,如 mcp_serverName_*,可以一次性允许或拒绝某个特定服务器的所有工具。这一点我们将在下一篇关于策略引擎的文章中详细介绍。

提示: 调试 MCP 工具问题时,可以查看 ToolRegistry 的 allKnownTools 映射。MCP 工具以带前缀的名称注册,并在 _serverName 注解中包含服务器名称,供策略匹配使用。

调度器与工具系统的构建者模式以及 MessageBus 确认流程相结合,构建出一套灵活且安全的执行流水线。下一篇文章中,我们将重点介绍管控这套流水线的安全层——策略引擎、沙箱机制和安全检查器。