コンテンツにスキップ

ADK ツールの操作確認の取得

ADKでサポートPython v1.14.0TypeScript v0.2.0Go v0.3.0プレビュー

一部のエージェント ワークフローでは、意思決定、検証、セキュリティ、または一般的な監視のために確認が必要です。このような場合、ワークフローを続行する前に人間または監視システムから応答を取得する必要があります。Agent Development Kit (ADK) のツール確認 (Tool Confirmation) 機能を使用すると、ADK ツールはその実行を一時停止し、ユーザーまたは他のシステムと対話して確認を取得したり、構造化データを収集したりしてから続行できます。ADK ツールでツール確認を次の方法で使用できます。

  • ブール値の確認 (Boolean Confirmation): 確認フラグまたはプロバイダーを使用してツールを構成できます。このオプションは、はい/いいえの確認応答のためにツールを一時停止します。
  • 高度な確認 (Advanced Confirmation): 構造化データの応答が必要なシナリオでは、確認を説明するテキスト プロンプトと期待される応答を使用してツールを構成できます。

プレビュー

ツール確認機能はプレビュー段階であり、いくつかの既知の制限事項があります。 皆様からのフィードバックをお待ちしております。

リクエストがユーザーに伝達される方法を構成でき、システムは ADK サーバーの REST API を介して送信されたリモート応答を使用することもできます。ADK Web ユーザー インターフェースで確認機能を使用すると、図 1 に示すように、エージェント ワークフローに入力を求めるダイアログ ボックスが表示されます。

ツール確認のデフォルト ユーザー インターフェースのスクリーンショット

図 1. 高度なツール応答実装を使用した確認応答要求ダイアログ ボックスの例。

次のセクションでは、確認シナリオでこの機能を使用する方法について説明します。完全なコード サンプルについては、human_tool_confirmation の例を参照してください。エージェント ワークフローに人間の入力を組み込むその他の方法については、Human-in-the-loop エージェント パターンを参照してください。

ブール値の確認 (Boolean confirmation)

ツールでユーザーからの単純な yes または no のみが必要な場合は、確認ステップを追加できます。Python、Go、および Java では、ツールを FunctionTool クラスでラップし、require_confirmation パラメータ (または同等のパラメータ) を True に設定することでこれを有効にできます。TypeScript では、ToolContext を使用して execute 関数内でこのロジックを手動で実装します。

次の例は、ブール値の確認を有効にする方法を示しています。

root_agent = Agent(
    # ...
    tools = [
        # ツール呼び出しにユーザーの確認を要求するには、require_confirmation を True に設定します。
        FunctionTool(reimburse, require_confirmation=True),
    ],
    # ...
)

Note

現在、ADK for TypeScript では、ツールの execute 関数内で確認ロジックを手動で実装する必要があります。

/**
 * A reimbursement tool with dynamic confirmation logic.
 */
export const reimburseTool = new FunctionTool({
  name: 'reimburse',
  description: 'Reimburse an amount. Large amounts (>1000) require manager approval.',
  parameters: z.object({
    amount: z.coerce.number().describe('The amount to reimburse.'),
  }),
  execute: async ({amount}, toolContext) => {
    // 1. Check if we already have a confirmed response.
    if (toolContext?.toolConfirmation?.confirmed) {
      const isLarge = amount > 1000;
      return {
        status: 'SUCCESS',
        message: isLarge 
          ? `Large reimbursement of ${amount} approved by manager and processed.`
          : `Reimbursement of ${amount} has been successfully processed.`,
      };
    }

    // 2. Request a tool confirmation.
    const isLarge = amount > 1000;
    toolContext?.requestConfirmation({
      hint: isLarge 
        ? `The amount ${amount} exceeds the $1000 limit and requires manager approval.`
        : `Do you want to reimburse ${amount}?`,
      payload: {amount},
    });

    // 3. Return a status that tells the agent we are waiting.
    // Note: The model won't see this until the turn resumes after confirmation.
    return {
      status: isLarge ? 'AWAITING_MANAGER_APPROVAL' : 'AWAITING_CONFIRMATION',
      message: 'This request requires approval to proceed.',
    };
  },
});

export const rootAgent = new LlmAgent({
  name: 'Finance_Assistant',
  model: 'gemini-flash-latest',
  instruction: `You are a Finance Assistant. 
  - You MUST use the 'reimburse' tool for ALL reimbursement requests.
  - MANDATORY: Every tool call MUST be accompanied by a text response in the same message.
  - THRESHOLD LOGIC:
    - For amounts <= 1000: Say "I am initiating the reimbursement request for [amount]. Please confirm it to proceed."
    - For amounts > 1000: Say "I am initiating the reimbursement request for [amount]. Since this exceeds $1000, manager approval is required. Please confirm the request to submit it for review."
  - EXAMPLES:
    User: "Reimburse me $45"
    Model: "I am initiating the reimbursement request for 45. Please confirm it to proceed." [Tool Call: reimburse(amount=45)]

    User: "Reimburse me $2500"
    Model: "I am initiating the reimbursement request for 2500. Since this exceeds $1000, manager approval is required. Please confirm the request to submit it for review." [Tool Call: reimburse(amount=2500)]
  - If the user provides a currency symbol (like $), ignore it and pass only the number to the tool.
  - In the Web UI, the user will see a 'Confirm' button. In the terminal, the user should simulate a confirmation response.`,
  tools: [reimburseTool],
});
reimburseTool, _ := functiontool.New(functiontool.Config{
    Name:        "reimburse",
    Description: "Reimburse an amount",
    RequireConfirmation: true,
}, func(ctx tool.Context, args ReimburseArgs) (ReimburseResult, error) {
    return ReimburseResult{Status: "ok"}, nil
})

rootAgent, _ := llmagent.New(llmagent.Config{
    // ...
    Tools: []tool.Tool{reimburseTool},
})
LlmAgent rootAgent = LlmAgent.builder()
    // ...
    .tools(
        FunctionTool.create(myClassInstance, "reimburse", true)
    )
    // ...
    .build();

確認要件関数 (Require confirmation function)

ツールの入力に基づいてブール値の応答を返す関数を使用して、確認要件の動作を動的に変更できます。TypeScript では、execute 関数に条件付きロジックを追加することでこれを処理します。

async def confirmation_threshold(
    amount: int, tool_context: ToolContext
) -> bool:
  """金額が 1000 より大きい場合に True を返します。"""
  return amount > 1000

root_agent = Agent(
    # ...
    tools = [
        FunctionTool(reimburse, require_confirmation=confirmation_threshold),
    ],
    # ...
)
/* 
  Note: In TypeScript, dynamic threshold logic is implemented 
  directly within the tool's 'execute' function as shown above.
*/
reimburseTool, _ := functiontool.New(functiontool.Config{
    Name:        "reimburse",
    Description: "Reimburse an amount",
    RequireConfirmationProvider: func(args ReimburseArgs) bool {
        return args.Amount > 1000
    },
}, func(ctx tool.Context, args ReimburseArgs) (ReimburseResult, error) {
    return ReimburseResult{Status: "ok"}, nil
})
public Map<String, Object> reimburse(
    @Schema(name="amount") int amount, ToolContext toolContext) {

  if (amount > 1000) {
    Optional<ToolConfirmation> toolConfirmation = toolContext.toolConfirmation();
    if (toolConfirmation.isEmpty()) {
       toolContext.requestConfirmation("Amount > 1000 requires approval.");
       return Map.of("status", "Pending manager approval.");
    } else if (!toolConfirmation.get().confirmed()) {
       return Map.of("status", "Reimbursement rejected.");
    }
  }

  return Map.of("status", "ok", "reimbursedAmount", amount);
}

LlmAgent rootAgent = LlmAgent.builder()
    // ...
    .tools(
        FunctionTool.create(this, "reimburse")
    )
    // ...
    .build();

高度な確認 (Advanced confirmation)

ツールの確認でユーザーに対してより詳細な情報や、より複雑な応答が必要な場合は、tool_confirmation 実装を使用します。このアプローチは ToolContext オブジェクトを拡張してユーザー向けのリクエストのテキスト説明を追加し、より複雑な応答データを可能にします。

確認の定義

高度な確認を使用してツールを作成する場合は、hint パラメータと payload パラメータを指定して Tool Context Request Confirmation メソッドを使用します。

  • hint: ユーザーに何が必要かを説明する説明メッセージ。
  • payload: 返されると期待するデータの構造。これは JSON 形式の文字列にシリアル化可能である必要があります。
def request_time_off(days: int, tool_context: ToolContext):
    """従業員の休暇を申請します。"""
    tool_confirmation = tool_context.tool_confirmation
    if not tool_confirmation:
        tool_context.request_confirmation(
            hint=(
                'Please approve or reject the tool call request_time_off() by'
                ' responding with a FunctionResponse with an expected'
                ' ToolConfirmation payload.'
            ),
            payload={
                'approved_days': 0,
            },
        )
        return {'status': 'Manager approval is required.'}

    approved_days = tool_confirmation.payload['approved_days']
    approved_days = min(approved_days, days)
    if approved_days == 0:
        return {'status': 'The time off request is rejected.', 'approved_days': 0}
    return {
        'status': 'ok',
        'approved_days': approved_days,
    }
/**
 * A tool that requests time off for an employee.
 * It uses the Advanced Confirmation pattern to request manager approval.
 */
export const requestTimeOffTool = new FunctionTool({
  name: 'request_time_off',
  description: 'Request days off for the employee.',
  parameters: z.object({
    days: z.number().describe('The number of days requested.'),
  }),
  execute: async ({days}, toolContext) => {
    const confirmation = toolContext?.toolConfirmation;

    if (!confirmation) {
      // Step 1: Request confirmation with a payload
      toolContext?.requestConfirmation({
        hint:
          'Please approve or reject the tool call request_time_off() by ' +
          'responding with a FunctionResponse with an expected ' +
          'ToolConfirmation payload.',
        payload: {
          approved_days: 0,
        },
      });

      // Return a descriptive status to the agent
      return {
        status: 'PENDING_MANAGER_APPROVAL',
        message: `A request for ${days} days is pending manager approval.`,
      };
    }

    // Step 2: Process the confirmation response
    if (!confirmation.confirmed) {
      return {
        status: 'CANCELLED',
        message: 'The request was cancelled by the user.',
      };
    }

    let approvedDays = (confirmation.payload as any)['approved_days'] as number;
    approvedDays = Math.min(approvedDays, days);

    if (approvedDays === 0) {
      return {
        status: 'REJECTED',
        message: 'The time off request was rejected by the manager.',
        approved_days: 0,
      };
    }

    return {
      status: 'SUCCESS',
      message: `The request for ${days} days was approved (Total approved: ${approvedDays}).`,
      approved_days: approvedDays,
    };
  },
});

export const rootAgent = new LlmAgent({
  name: 'HR_Assistant',
  model: 'gemini-flash-latest',
  instruction: `You are an HR Assistant. 
  1. Use the 'request_time_off' tool to help employees with leave requests.
  2. MANDATORY: Every tool call MUST be accompanied by a text response in the same message.
  3. EXAMPLE:
     User: "I want 5 days off"
     Model: "I am initiating your leave request for 5 days. Management approval is required, so please confirm this request." [Tool Call: request_time_off(days=5)]
  4. In the terminal, if they want to 'confirm', tell them to simulate a confirmation response. 
  5. Once confirmed, the system will automatically provide the result of the approval.`,
  tools: [requestTimeOffTool],
});
func requestTimeOff(ctx tool.Context, args RequestTimeOffArgs) (map[string]any, error) {
    confirmation := ctx.ToolConfirmation()
    if confirmation == nil {
        ctx.RequestConfirmation(
            "Please approve or reject the tool call requestTimeOff() by "+
            "responding with a FunctionResponse with an expected "+
            "ToolConfirmation payload.",
            map[string]any{"approved_days": 0},
        )
        return map[string]any{"status": "Manager approval is required."}, nil
    }

    payload := confirmation.Payload.(map[string]any)
    approvedDays := int(payload["approved_days"].(float64))
    approvedDays = min(approvedDays, args.Days)

    if approvedDays == 0 {
        return map[string]any{"status": "The time off request is rejected.", "approved_days": 0}, nil
    }

    return map[string]any{
        "status": "ok",
        "approved_days": approvedDays,
    }, nil
}
public Map<String, Object> requestTimeOff(
    @Schema(name="days") int days,
    ToolContext toolContext) {
    Optional<ToolConfirmation> toolConfirmation = toolContext.toolConfirmation();
    if (toolConfirmation.isEmpty()) {
        toolContext.requestConfirmation(
            "Please approve or reject the tool call requestTimeOff() by " +
            "responding with a FunctionResponse with an expected " +
            "ToolConfirmation payload.",
            Map.of("approved_days", 0)
        );
        return Map.of("status", "Manager approval is required.");
    }

    Map<String, Object> payload = (Map<String, Object>) toolConfirmation.get().payload();
    int approvedDays = (int) payload.get("approved_days");
    approvedDays = Math.min(approvedDays, days);

    if (approvedDays == 0) {
        return Map.of("status", "The time off request is rejected.", "approved_days", 0);
    }

    return Map.of(
        "status", "ok",
        "approved_days", approvedDays
    );
}

REST API によるリモート確認

エージェント ワークフローの人による確認のためのアクティブなユーザー インターフェースがない場合は、コマンドライン インターフェースを使用するか、メールやチャット アプリケーションなどの別のチャネルを経由して確認を処理できます。ツール呼び出しを確認するには、ユーザーまたは呼び出し元のアプリケーションがツール確認データを含む FunctionResponse イベントを送信する必要があります。

 curl -X POST http://localhost:8000/run_sse \
 -H "Content-Type: application/json" \
 -d '{
    "app_name": "human_tool_confirmation",
    "user_id": "user",
    "session_id": "7828f575-2402-489f-8079-74ea95b6a300",
    "new_message": {
        "parts": [
            {
                "function_response": {
                    "id": "adk-13b84a8c-c95c-4d66-b006-d72b30447e35",
                    "name": "adk_request_confirmation",
                    "response": {
                        "confirmed": true,
                        "payload": {
                            "approved_days": 5
                        }
                    }
                }
            }
        ],
        "role": "user"
    }
}'

既知の制限事項

ツール確認機能には次の制限事項があります。

次のステップ

エージェント ワークフロー用の ADK ツールの構築の詳細については、関数ツールを参照してください。