description:Build, review, or explain Spring AI Alibaba hook and interceptor customizations for ReactAgent and related agent workflows. Use when requests mention ReactAgent.builder().hooks(...), .interceptors(...), MessagesModelHook, ModelHook, AgentHook, ModelInterceptor, ToolInterceptor, HumanInTheLoopHook, SummarizationHook, ModelCallLimitHook, ToolRetryInterceptor, TodoListInterceptor, ToolSelectionInterceptor, ToolEmulatorInterceptor, ContextEditingInterceptor, or when Codex must decide whether a behavior belongs in a hook or an interceptor.
---
# Spring AI Alibaba Hooks And Interceptors
Use this skill to implement or explain how Spring AI Alibaba customizes agent execution around `ReactAgent`. Read [references/hooks-interceptors.md](./references/hooks-interceptors.md) when exact built-in options, execution order, or API shapes matter.
## Workflow
1. Start from the control goal.
Classify the request as one of: observe, transform, enforce, limit, pause for approval, or short-circuit execution. Pick the extension point from that goal instead of starting from class names.
2. Choose the narrowest extension point that can solve the problem.
- Use `MessagesModelHook` for simple message-list changes before or after model calls.
- Use `ModelHook` when logic depends on `OverAllState`, custom state keys, or cross-call coordination.
- Use `AgentHook` when behavior belongs to overall agent start or finish.
- Use `ModelInterceptor` when wrapping or rewriting the model request or response.
- Use `ToolInterceptor` when wrapping, retrying, caching, monitoring, or rewriting tool execution.
3. Prefer built-ins before custom code.
Reach for the official implementations first: `SummarizationHook`, `HumanInTheLoopHook`, `ModelCallLimitHook`, `PIIDetectionHook`, `ToolRetryInterceptor`, `TodoListInterceptor`, `ToolSelectionInterceptor`, `ToolEmulatorInterceptor`, and `ContextEditingInterceptor`.
4. Keep each hook or interceptor single-purpose.
Compose several small units instead of one large class that does logging, moderation, retries, and prompt rewriting together.
5. Respect ordering rules.
`before*` hooks run in registration order, `after*` hooks run in reverse order, and interceptors wrap each other like nested middleware. Put broad outer concerns first and narrow inner concerns later.
## Selection Rules
- Need pause/resume, approval, or agent lifecycle control: use a `Hook`.
- Need request/response interception without resumable control flow: use an `Interceptor`.
- Need only message trimming, message filtering, or system-message injection: prefer `MessagesModelHook`.
- Need full state access, counters, shared state, or custom state updates: use `ModelHook`.
- Need behavior only at agent start/end: use `AgentHook`.
- Need dynamic tools, moderation, model-side logging, or response rewriting: use `ModelInterceptor`.
- Need tool retry, caching, failure wrapping, or per-tool telemetry: use `ToolInterceptor`.
## Implementation Defaults
- Prefer `MessagesModelHook` over `ModelHook` for message-only work. It is the recommended and simpler API.
- Use `RunnableConfig.context()` for transient counters and metrics shared within one agent run.
- Namespace custom context keys defensively, for example with double underscores such as `__model_call_count__`.
- Add a saver or checkpointer when using `HumanInTheLoopHook`; the official guide calls out that interrupted execution needs persisted state.
- Keep `ReactAgent` assembly in the service layer, not controllers, to stay aligned with this repository's Spring Boot structure.
- Read [references/hooks-interceptors.md](./references/hooks-interceptors.md) before inventing a custom class; an official built-in often already covers the need.
- Read [references/hooks-interceptors.md](./references/hooks-interceptors.md) for the extracted tutorial guidance on built-ins, custom extension points, execution order, and example patterns.
# Spring AI Alibaba Hooks And Interceptors Reference
This reference is distilled from the official Spring AI Alibaba Hooks and Interceptors tutorial and its linked example source. Use it when implementing, reviewing, or explaining customization points around `ReactAgent`.
- Example code: https://github.com/alibaba/spring-ai-alibaba/blob/main/examples/documentation/src/main/java/com/alibaba/cloud/ai/examples/documentation/framework/tutorials/HooksExample.java
The tutorial page was last updated on January 19, 2026 according to the site footer.
## Mental Model
- Hooks expose agent lifecycle checkpoints around agent execution and model calls.
- Interceptors wrap model or tool calls like middleware.
- Use hooks when you need lifecycle awareness or interruptible control flow.
- Use interceptors when you need request/response wrapping, mutation, logging, retry, fallback, or caching.
## Built-In Implementations
### Built-in hooks
-`SummarizationHook`
Use for long-running conversations approaching token limits.
Use when selected tools require approval or editing before execution.
Important: pair it with a saver or checkpointer such as `RedisSaver` so paused execution can resume.
-`ModelCallLimitHook`
Use to cap model-call loops and enforce budget limits.
-`PIIDetectionHook`
Use to detect or redact sensitive user data in input or output.
Common settings include `piiType`, `strategy`, and `applyToInput`.
### Built-in interceptors
-`ToolRetryInterceptor`
Use to retry failed tool calls with configurable retry count and failure behavior.
-`TodoListInterceptor`
Use to force a planning step before tool execution for multi-step tasks.
-`ToolSelectionInterceptor`
Use when multiple tools overlap and an LLM should choose the best one for the current request.
-`ToolEmulatorInterceptor`
Use to simulate tool outputs with an LLM during demos, testing, or low-risk development.
-`ContextEditingInterceptor`
Use to trim, inject, or rewrite context before it reaches the model.
## Custom Extension Points
### `MessagesModelHook`
Use this first for message-only transformations. It works directly on `List<Message>` and returns `AgentCommand`, which is simpler than editing `OverAllState`.
Typical fit:
- message trimming
- system message injection
- message filtering
- lightweight summary or context shaping
Useful details:
-`UpdatePolicy.REPLACE` replaces the full message list
-`UpdatePolicy.APPEND` appends new messages
-`canJumpTo()` plus `JumpTo.end` can short-circuit execution before the model call
### `ModelHook`
Use when hook logic must read or update more than just messages.
Typical fit:
- stateful counters
- custom status flags
- global decision logic based on `OverAllState`
- coordinated before/after behavior around the model call
Useful details:
- methods typically return `CompletableFuture<Map<String, Object>>`
- use `ReplaceAllWith` when replacing message collections
- use `RemoveByHash` carefully when deleting messages while preserving message order
### `AgentHook`
Use for logic that belongs to the entire agent run rather than a single model call.
Typical fit:
- start and stop telemetry
- resource setup and cleanup
- total execution timing
- run-level initialization
Common hook positions:
-`HookPosition.BEFORE_AGENT`
-`HookPosition.AFTER_AGENT`
### `ModelInterceptor`
Use to wrap the model request/response path.
Typical fit:
- logging and performance timing
- moderation on input and output
- request rewriting
- dynamic tool injection or tool filtering
Useful details:
-`ModelRequest.builder(request)` can clone and mutate the incoming request
- the tutorial explicitly shows dynamic tool control through `dynamicToolCallbacks(...)` and `tools(...)`
### `ToolInterceptor`
Use to wrap actual tool execution.
Typical fit:
- retries
- failure translation
- caching
- per-tool performance metrics
- graceful fallback messages
Useful details:
- the call boundary is `handler.call(request)`
- interceptors can return a synthetic `ToolCallResponse` instead of propagating an exception
## Decision Guide
- Need resumable human approval: `HumanInTheLoopHook`
- Need automatic history compaction: `SummarizationHook`
- Need loop limits or stateful guards: `ModelCallLimitHook` or custom `ModelHook`
- Need request/response moderation: `ModelInterceptor`
- Need dynamic tool availability: `ModelInterceptor`
- Need tool retries or tool cache: `ToolInterceptor`
- Need to modify only messages: `MessagesModelHook`
- Need run-level timing or setup/teardown: `AgentHook`
## Execution Order
When several extensions are registered:
1.`beforeAgent` hooks run in registration order.
2.`beforeModel` hooks run in registration order.
3. model interceptors wrap the model call in registration order.
4.`afterModel` hooks run in reverse order.
5. tool interceptors wrap tool execution in registration order when tools are called.
6.`afterAgent` hooks run in reverse order.
Practical consequence:
- put broad, outer concerns first
- keep related before/after state in the same hook class
- avoid relying on accidental ordering between unrelated concerns
## RunnableConfig Context
`RunnableConfig.context()` is the shared per-run scratchpad shown in the tutorial for:
- counting model calls
- storing start timestamps
- accumulating total duration
- enforcing limits across several hook invocations
Guidelines:
- treat it as per-run transient state, not durable storage
- choose stable key names such as `__total_model_time__`
- manage types carefully because stored values are generic objects
## Example Patterns To Reuse
- content moderation with `ModelInterceptor`
- model and tool performance timing with interceptors
- tool result caching with `ToolInterceptor`
- early exit from `MessagesModelHook` with `JumpTo.end`
- call counting and limit enforcement with `ModelHook` plus `RunnableConfig.context()`