Skip to content

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”
1. ADK Lifecycle Callbacks
Python functions attached to an ADK agent (before_model_callback, before_tool_callback, after_tool_callback) that execute deterministically in code before or after the LLM and tools run.
2. Callback Short-Circuiting
Returning None from a callback lets execution continue normally. Returning an LlmResponse (before model) or a dict (before tool) skips the LLM/tool call completely!
3. Tool-Level HITL
Intercepts a specific high-consequence tool call (via before_tool_callback or ADK tool confirmation) to pause execution until a human reviewer approves the exact tool parameters.
4. Conversation-Level HITL
Transfers the entire live customer chat or voice call in Customer Engagement Suite (CES) to a human contact-center rep (with an AI transcript summary) when sentiment drops or fallbacks repeat.

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:

Stage 1 / 4
1. User TurnHits ADK Runner2. Before-ModelInspects Request3. Return ValueNone vs. LlmResponse4. Token Savings$0 LLM Cost on Block
BEFORE_MODEL_CALLBACK (PRE-LLM GUARDRAIL)
1. Intercepting the Turn Before Calling Gemini
Callback Signature & Mechanism
before_model_callback(callback_context, llm_request) runs deterministically in Python right before the request is sent to the Gemini API.
Core Architecture Rule
Returning an LlmResponse object immediately short-circuits the turn—skipping the Gemini call completely and saving 100% of LLM tokens!

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”
  1. How Does ADK Pause a High-Value Tool Call Without Blocking a Container Thread for Hours? When before_tool_callback detects args['amount'] == 2500 (or when ADK’s built-in require_confirmation tool flag triggers), it does not hang the HTTP socket! Instead, it writes the pending tool call and arguments into persistent session.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.”

  2. 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 the issue_refund tool to execute with the verified parameters!

  3. 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 > $200 or terminate_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!