5.3 Deterministic ADK Callbacks & Human-in-the-Loop (HITL) Patterns
1. Key Concept Definitions: Deterministic Runtime Guardrails & HITL
Section titled “1. Key Concept Definitions: Deterministic Runtime Guardrails & HITL”2. Interactive Explorer: ADK Callbacks, Short-Circuiting & HITL Patterns
Section titled “2. Interactive Explorer: ADK Callbacks, Short-Circuiting & HITL Patterns”Switch between the 3 Runtime Guardrail Modes below and click the 4 stages to see how before_model_callback, before_tool_callback (Tool-Level HITL), and Post-Tool Sanitization + Loop Caps protect Rosku Bank in production:
3. Visual Parameter Matrix: ADK Lifecycle Callbacks & Return Contracts
Section titled “3. Visual Parameter Matrix: ADK Lifecycle Callbacks & Return Contracts”Review the exact input parameters and return-value short-circuit contracts for every ADK callback:
| ADK Callback Hook | Input Parameters | Return None Behavior |
Short-Circuit Override Return Type | Primary Architectural Use Case |
|---|---|---|---|---|
before_model_callback |
callback_context: CallbackContext, llm_request: LlmRequest |
Proceeds to call the Gemini LLM normally. | Return LlmResponse (skips the Gemini API call completely and returns your response at $0 token cost!). |
Blocking banned topics/states with verbatim disclaimers before spending LLM tokens. |
after_model_callback |
callback_context: CallbackContext, llm_response: LlmResponse |
Keeps the model’s generated response as-is. | Return a modified LlmResponse to replace or sanitize the model’s output. |
Custom formatting checks or secondary output redaction before returning to the user. |
before_tool_callback |
tool: BaseTool, args: dict, tool_context: ToolContext |
Executes the target tool function with args. |
Return a Python dict (skips executing the actual tool function and passes your dict to the agent!). |
Validating tool argument math (amount <= 200), blocking unauthorized args, or triggering Tool-Level HITL. |
after_tool_callback |
tool: BaseTool, args: dict, tool_context: ToolContext, tool_response: dict |
Passes the original tool_response back to Gemini. |
Return a sanitized Python dict to replace the tool’s output before the next LLM turn. |
Scrubbing indirect prompt injections or sensitive fields from untrusted external tool results. |
4. Real-World Deep Dive: How Tool-Level HITL Pauses & Resumes Execution
Section titled “4. Real-World Deep Dive: How Tool-Level HITL Pauses & Resumes Execution”-
How Does ADK Pause a High-Value Tool Call Without Blocking a Container Thread for Hours? When
before_tool_callbackdetectsargs['amount'] == 2500(or when ADK’s built-inrequire_confirmationtool flag triggers), it does not hang the HTTP socket! Instead, it writes the pending tool call and arguments into persistentsession.state(or emits a confirmation request event) and returns a structured status dictionary ({'status': 'awaiting_approval', 'ticket_id': '991'}) so the agent can politely tell the customer: “Your $2,500 refund has been routed to a supervisor for approval.” -
How Does the Tool Execute Once the Human Supervisor Clicks “Approve”? When the supervisor approves Ticket #991 in the internal dashboard, the approval service updates the session state (or sends a confirmation event with the approved payload back to the ADK Runner for that
session_id), allowing theissue_refundtool to execute with the verified parameters! -
When to Pick Tool-Level HITL vs. Conversation-Level HITL (CES)
- Pick Tool-Level HITL (ADK Callbacks / Tool Confirmation) when the AI agent should keep handling the conversation, and a human supervisor/SRE only needs to approve 1 specific high-risk API mutation or parameter (like
refund > $200orterminate_production_node). - Pick Conversation-Level HITL (CES Live-Agent Warm Handoff) when the customer is frustrated (negative sentiment), hits repeated unmatched fallbacks, or asks to speak to a human representative who takes over the entire chat/call!
- Pick Tool-Level HITL (ADK Callbacks / Tool Confirmation) when the AI agent should keep handling the conversation, and a human supervisor/SRE only needs to approve 1 specific high-risk API mutation or parameter (like