LlmAgent is the base class most ADK Java agents extend. Understanding its lifecycle matters because that's where you inject configuration, add safety checks, and control cleanup.

This walks through every stage from construction to termination — with the exact hook points that let you customize behavior without forking Core.

Advertisement

Stage 1: Construction

When you instantiate a subclass of LlmAgent, Core resolves your model, instructions, and tool list — but does not perform any I/O. Construction is intentionally cheap. If you need to validate credentials or preload data, do it inside onStart(), not the constructor.

Stage 2: onStart

@Override
protected void onStart(AgentContext ctx) {
  // Load config from Secret Manager
  this.apiKey = SecretsClient.get("MY_API_KEY");
  // Warm any caches
  cache.preload();
}

Called once per agent instance. This is where I/O belongs.

Advertisement

Stage 3: Per-invocation onInvoke

Every user turn triggers onInvoke(userMessage, session). You typically don't override this — Core handles the LLM call + tool dispatch loop for you. If you do override, you're taking full responsibility for the interaction loop.

Stage 4: Tool call hooks

Core surfaces two hooks around every tool call:

  • beforeToolCall(toolName, args, ctx) — mutate args, block calls, log.
  • afterToolCall(toolName, result, ctx) — sanitize output, add metrics.

Use these for cross-cutting concerns like rate limiting, auth, redaction.

Stage 5: Error paths

Three failure modes have distinct hooks:

  • onLlmError — LLM call failed (timeout, auth, quota).
  • onToolError — a specific tool threw an exception.
  • onFatalError — unrecoverable — Core is about to terminate the agent.

Handle the first two with retries or graceful degradation. The third is where you emit an alert and clean up external state.

Stage 6: onStop

Called during graceful shutdown. Flush metrics, close pooled connections, persist any in-memory state you care about. Core allows up to 5 seconds by default — configurable via shutdownGraceMs.

Master the six lifecycle stages before overriding onInvoke — most customization belongs in hooks, not the main loop.