侧边栏壁纸
博主头像
牧云

怀璧慎显,博识谨言。

  • 累计撰写 139 篇文章
  • 累计创建 13 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

ReactAgent 快速开始

秋之牧云
2026-04-03 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

前置条件

环境要求

  • JDK 17+

  • Maven 3.8+

  • 选择你的 LLM 提供商并获取 API-KEY(如阿里云百炼的 DashScope)

添加依赖

<dependencies>
  <!-- Spring AI Alibaba Agent Framework -->
  <dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-agent-framework</artifactId>
    <version>1.1.2.0</version>
  </dependency>

  <!-- DashScope ChatModel 支持(如果使用其他模型,请跳转 Spring AI 文档选择对应的 starter) -->
  <dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
    <version>1.1.2.0</version>
  </dependency>
</dependencies>

配置 API Key

export AI_DASHSCOPE_API_KEY=your_api_key_here
# application.yml
spring:
  ai:
    dashscope:
      api-key: ${AI_DASHSCOPE_API_KEY}

构建一个基础 Agent


// 初始化 ChatModel
DashScopeApi dashScopeApi = DashScopeApi.builder()
    .apiKey(System.getenv("AI_DASHSCOPE_API_KEY"))
    .build();

ChatModel chatModel = DashScopeChatModel.builder()
    .dashScopeApi(dashScopeApi)
    .build();

// 定义天气查询工具
public class WeatherTool implements BiFunction<String, ToolContext, String> {
    @Override
    public String apply(String city, ToolContext toolContext) {
        return "It's always sunny in " + city + "!";
    }
}

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

// 创建 agent
ReactAgent agent = ReactAgent.builder()
    .name("weather_agent")
    .model(chatModel)
    .tools(weatherTool)
    .systemPrompt("You are a helpful assistant")
    .saver(new MemorySaver())
    .build();

// 运行 agent
AssistantMessage response = agent.call("what is the weather in San Francisco");
System.out.println(response.getText());

构建一个真实的 Agent

接下来,构建一个实用的天气预报 agent,演示关键的生产概念:

  1. 详细的 System Prom - 获得更好的 agent 行为

  2. 创建工具 - 与外部数据集成

  3. 模型配置 - 获得一致的响应

  4. 结构化输出 - 获得可预测的结果

  5. 对话记忆 - 实现类似聊天的交互

  6. 创建和运行 agent - 创建一个功能完整的 agent

让我们逐步完成每个步骤:

定义系统提示

系统提示定义了 agent 的角色和行为。保持具体和可操作:

String SYSTEM_PROMPT = """
    You are an expert weather forecaster, who speaks in puns.

    You have access to two tools:

    - get_weather_for_location: use this to get the weather for a specific location
    - get_user_location: use this to get the user's location

    If a user asks you for the weather, make sure you know the location.
    If you can tell from the question that they mean wherever they are,
    use the get_user_location tool to find their location.
    """;

创建工具

工具让模型能够通过调用你定义的函数与外部系统交互。工具可以依赖运行时上下文,也可以与 agent 的记忆交互。

注意下面的 getUserLocation 工具如何使用运行时上下文(通过 ToolContext):

import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.ai.tool.function.FunctionToolCallback;

import java.util.function.BiFunction;

// 天气查询工具
public class WeatherForLocationTool implements BiFunction<String, ToolContext, String> {
    @Override
    public String apply(
        @ToolParam(description = "The city name") String city,
        ToolContext toolContext) {
        return "It's always sunny in " + city + "!";
    }
}

// 用户位置工具 - 使用上下文
public class UserLocationTool implements BiFunction<String, ToolContext, String> {
    @Override
    public String apply(
        @ToolParam(description = "User query") String query,
        ToolContext toolContext) {
        // 从上下文中获取用户信息
        String userId = "";
        if (toolContext != null && toolContext.getContext() != null) {
            RunnableConfig runnableConfig = (RunnableConfig) toolContext.getContext().get(AGENT_CONFIG_CONTEXT_KEY);
            Optional<Object> userIdObjOptional = runnableConfig.metadata("user_id");
            if (userIdObjOptional.isPresent()) {
                userId = (String) userIdObjOptional.get();
            }
        }
        if (userId == null) {
            userId = "1";
        }
        return "1".equals(userId) ? "Florida" : "San Francisco";
    }
}

// 创建工具回调
ToolCallback getWeatherTool = FunctionToolCallback
    .builder("getWeatherForLocation", new WeatherForLocationTool())
    .description("Get weather for a given city")
    .inputType(String.class)
    .build();

ToolCallback getUserLocationTool = FunctionToolCallback
    .builder("getUserLocation", new UserLocationTool())
    .description("Retrieve user location based on user ID")
    .inputType(String.class)
    .build();

提示: 工具应该有良好的文档:它们的名称、描述和参数名称都会成为模型提示的一部分。Spring AI 的 FunctionToolCallback 支持通过 @ToolParam 注解添加元数据,并支持通过 ToolContext 参数进行运行时注入。

配置模型

import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.model.ChatModel;

DashScopeApi dashScopeApi = DashScopeApi.builder()
    .apiKey(System.getenv("AI_DASHSCOPE_API_KEY"))
    .build();

ChatModel chatModel = DashScopeChatModel.builder()
    .dashScopeApi(dashScopeApi)
    .defaultOptions(DashScopeChatOptions.builder()
        // Note: model must be set when use options build.
        .withModel(DashScopeChatModel.DEFAULT_MODEL_NAME)
        .withTemperature(0.5)
        .withMaxToken(1000)
        .build())
    .build();

根据不同的模型选择,增加依赖

<!-- DashScope-->
<dependency>
 <groupId>com.alibaba.cloud.ai</groupId>
 <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
 <version>1.1.2.1</version>
</dependency>

<!-- OpenAI-->
<dependency>
 <groupId>org.springframework.ai</groupId>
 <artifactId>spring-ai-starter-model-openai</artifactId>
 <version>1.1.2</version>
</dependency>

定义响应格式

// 使用 Java 类定义响应格式
public class ResponseFormat {
    // 一个双关语响应(始终必需)
    private String punnyResponse;

    // 如果可用的话,关于天气的任何有趣信息
    private String weatherConditions;

    // Getters and Setters
    public String getPunnyResponse() {
        return punnyResponse;
    }

    public void setPunnyResponse(String punnyResponse) {
        this.punnyResponse = punnyResponse;
    }

    public String getWeatherConditions() {
        return weatherConditions;
    }

    public void setWeatherConditions(String weatherConditions) {
        this.weatherConditions = weatherConditions;
    }
}

添加记忆

为你的 agent 添加记忆以维持跨交互的状态。这允许 agent 记住之前的对话和上下文,在多次调用之间,使用同一个 threadId 即可加载之前的对话记录。

ReactAgent agent = ReactAgent.builder()
    .name("weather_agent")
    //...
    .saver(new MemorySaver())
    .build();

在调用的时候,

RunnableConfig runnableConfig = RunnableConfig.builder().threadId(threadId).build();

// 第一次调用
AssistantMessage response = agent.call("what is the weather in San Francisco today.", runnableConfig);

// 第二次调用
AssistantMessage response = agent.call("How about the weather tomorrow", runnableConfig);

注意: 在生产环境中,使用持久化的 CheckPointer 将数据保存到数据库。更多详情参见 内存管理 文档。

创建和运行 Agent

现在用所有组件组装你的 agent 并运行它!

import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import org.springframework.ai.chat.messages.AssistantMessage;

import java.util.HashMap;
import java.util.Map;

// 创建 agent
ReactAgent agent = ReactAgent.builder()
    .name("weather_pun_agent")
    .model(chatModel)
    .systemPrompt(SYSTEM_PROMPT)
    .tools(getUserLocationTool, getWeatherTool)
    .outputType(ResponseFormat.class)
    .saver(new MemorySaver())
    .build();

// threadId 是给定对话的唯一标识符
RunnableConfig runnableConfig = RunnableConfig.builder().threadId(threadId).addMetadata("user_id", "1").build();

// 第一次调用
AssistantMessage response = agent.call("what is the weather outside?", runnableConfig);
System.out.println(response.getText());
// 输出类似:
// Florida is still having a 'sun-derful' day! The sunshine is playing
// 'ray-dio' hits all day long! I'd say it's the perfect weather for
// some 'solar-bration'!

// 注意我们可以使用相同的 threadId 继续对话
response = agent.call("thank you!", runnableConfig);
System.out.println(response.getText());
// 输出类似:
// You're 'thund-erfully' welcome! It's always a 'breeze' to help you
// stay 'current' with the weather.

查看完整示例代码

完整示例代码请查看仓库:https://github.com/spring-ai-alibaba/examples

开启高级功能

使用 outputSchema 定义输出格式

除了使用 outputType,你还可以使用 outputSchema 来定义自定义的 JSON 格式:

String customSchema = """
    请按照以下JSON格式输出:
    {
        "title": "标题",
        "content": "内容",
        "style": "风格"
    }
    """;

ReactAgent agent = ReactAgent.builder()
    .name("schema_agent")
    .model(chatModel)
    .saver(new MemorySaver())
    .outputSchema(customSchema)
    .build();

AssistantMessage message = agent.call("帮我写一首关于春天的诗歌。");
System.out.println(message.getText());

使用 invoke 方法获取完整状态

如果需要访问完整的 agent 状态(不仅仅是最后的消息),可以使用 invoke 方法:

import com.alibaba.cloud.ai.graph.OverAllState;
import java.util.Optional;

Optional<OverAllState> result = agent.invoke("帮我写一首诗。");

if (result.isPresent()) {
    OverAllState state = result.get();
    // 访问消息历史
    List<Message> messages = state.value("messages", new ArrayList<>());
    // 访问其他状态信息
    System.out.println(state);
}

配置最大迭代次数

为防止无限循环,可以使用 ModelCallLimitHook 来限制模型调用次数:

import com.alibaba.cloud.ai.graph.agent.hook.modelcalllimit.ModelCallLimitHook;

ModelCallLimitHook hook = ModelCallLimitHook.builder()
    .runLimit(5)  // 限制最多调用 5 次
    .exitBehavior(ModelCallLimitHook.ExitBehavior.ERROR)  // 超出限制时抛出异常
    .build();

ReactAgent agent = ReactAgent.builder()
    .name("my_agent")
    .model(chatModel)
    .hooks(hook)
    .saver(new MemorySaver())
    .build();

使用 Hooks 扩展功能

ReactAgent 支持通过 Hooks 扩展功能,例如人机协同、工具注入等:

import com.alibaba.cloud.ai.graph.agent.hook.Hook;
import com.alibaba.cloud.ai.graph.agent.hook.hip.HumanInTheLoopHook;

// 创建 hook
Hook humanInTheLoopHook = HumanInTheLoopHook.builder()
 .approvalOn("getWeatherTool", ToolConfig.builder().description("Please confirm tool execution.")
    .build())
 .build();       

ReactAgent agent = ReactAgent.builder()
    .name("my_agent")
    .model(chatModel)
    .hooks(humanInTheLoopHook)
    .saver(new MemorySaver())
    .build();

0

评论区