---
name: spring-ai-alibaba-react-agent
description: Build or update Java and Spring Boot agents with Spring AI Alibaba ReactAgent, including DashScope model setup, ToolCallback definitions, ToolContext usage, structured output, memory, hooks, and invoke-based state access. Use when requests mention Spring AI Alibaba, ReactAgent, DashScope, MemorySaver, RunnableConfig, outputType, outputSchema, or implementing an agent on the Spring stack.
---

# Spring AI Alibaba ReactAgent

Use this skill to implement or refactor Spring AI Alibaba agent code around `ReactAgent`. Keep the skill focused on the framework patterns from the Spring AI Alibaba quick-start, and read [references/quick-start.md](./references/quick-start.md) when exact dependency, API, or assembly details matter.

## Workflow

1. Confirm prerequisites before coding.
JDK 17+ and Maven 3.8+ are the documented baseline. Default to environment variables for API keys, especially `AI_DASHSCOPE_API_KEY`.

2. Pick the model starter before writing agent code.
The quick-start uses `spring-ai-alibaba-agent-framework` plus a model starter such as DashScope. Keep framework and model starter versions aligned to the same release family instead of mixing arbitrary versions.

3. Build the `ChatModel` first.
For DashScope, initialize `DashScopeApi`, then create `DashScopeChatModel`. If you configure `DashScopeChatOptions`, set the model name explicitly before adding temperature and token settings.

4. Define tools with strong metadata.
Prefer `FunctionToolCallback` and clear tool names, descriptions, and parameter descriptions. If the tool needs runtime metadata, implement `BiFunction<Input, ToolContext, Output>` and read values from the `RunnableConfig` stored in the context.

5. Assemble `ReactAgent` from small, explicit pieces.
Start with `.name(...)`, `.model(...)`, `.systemPrompt(...)`, `.tools(...)`, and `.saver(...)`. Add `.outputType(...)`, `.outputSchema(...)`, or `.hooks(...)` only when the behavior requires them.

6. Add memory deliberately.
Use `MemorySaver` for local or example flows. Reuse the same `threadId` in `RunnableConfig` to continue a conversation. For production, swap in a persistent checkpointer instead of in-memory state.

7. Choose response shaping explicitly.
Use `outputType` when you want a Java class to define the response contract. Use `outputSchema` when the output must follow a custom JSON schema-like text contract.

8. Reach for advanced hooks only when there is a concrete need.
Use `invoke(...)` when the caller needs the full state instead of only the last assistant message. Use `ModelCallLimitHook` to cap loops, and use human-in-the-loop hooks when tool execution needs approval.

## Implementation Defaults

- Keep API keys out of source code. Prefer environment variables and property placeholders.
- Keep tool interfaces boring and explicit. Tool names and descriptions become part of the model prompt, so avoid vague naming.
- Prefer a focused system prompt over a long one. State role, available tools, and decision rules.
- Pass request-scoped metadata through `RunnableConfig.addMetadata(...)` when tools need user or tenant context.
- Reuse `threadId` for multi-turn chat. Change `threadId` to start a fresh conversation.
- Treat the versions in the quick-start as documentation examples, not a license to mix incompatible artifacts. Verify the chosen release line before changing a real project.

## Minimal Assembly Pattern

```java
DashScopeApi api = DashScopeApi.builder()
    .apiKey(System.getenv("AI_DASHSCOPE_API_KEY"))
    .build();

ChatModel model = DashScopeChatModel.builder()
    .dashScopeApi(api)
    .defaultOptions(DashScopeChatOptions.builder()
        .withModel(DashScopeChatModel.DEFAULT_MODEL_NAME)
        .withTemperature(0.5)
        .withMaxToken(1000)
        .build())
    .build();

ToolCallback weatherTool = FunctionToolCallback.builder("getWeatherForLocation", new WeatherTool())
    .description("Get weather for a given city")
    .inputType(String.class)
    .build();

ReactAgent agent = ReactAgent.builder()
    .name("weather_agent")
    .model(model)
    .systemPrompt(SYSTEM_PROMPT)
    .tools(weatherTool)
    .saver(new MemorySaver())
    .build();
```

## Decision Rules

- If the user asks for deterministic JSON, prefer `outputType` first and use `outputSchema` only when a custom shape is easier than a Java type.
- If a tool needs request metadata, add it to `RunnableConfig` and read it via `ToolContext`; do not hide it in globals.
- If the user wants follow-up questions to retain context, keep the same `threadId`.
- If the user only needs the assistant text, call `agent.call(...)`; if they need message history or graph state, use `agent.invoke(...)`.
- If an agent may loop on tool or model calls, add `ModelCallLimitHook`.

## References

- Read [references/quick-start.md](./references/quick-start.md) for the extracted quick-start guidance, dependency examples, and advanced features summary.