Skip to content

TIP

本页内容由本地原稿 02-第一个ReactAgent.md 同步生成。 如果你要长期修改站点内容,优先回原稿修改,再执行 npm run docs:sync

第 2 章:先把第一个 ReactAgent 跑起来

这章要解决什么问题

光知道 ReactAgent 是个什么东西还不够。
你必须亲手写出一个最小版本,框架才会从“名词”变成“手感”。

这章我们不追求复杂,只做一件事:

写一个最小可运行的 ReactAgent,让它能接问题、返回答案。

1. 先明确我们今天要搭的东西

今天先不接工具、不接 RAG、不做花活。
我们只要一个最小闭环:

你可以把它理解成:

  • Controller 负责收请求
  • ReactAgent 负责思考和组织调用
  • ChatModel 负责真正去和模型通信

2. 依赖怎么加

如果你已经有 Spring Boot 工程,最核心的是两类依赖:

  • Agent Framework
  • 具体模型的 starter

下面以 DashScope 为例,版本号建议跟着你本地官方仓库或官网同步,不要手写死老版本。

xml
<properties>
    <java.version>17</java.version>
    <spring-ai-alibaba.version>1.1.2.0</spring-ai-alibaba.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-agent-framework</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>
</dependencies>

参考来源:

3. 配置怎么写

最小配置不要上来就抄一堆。
你现在只关心一件事:模型能不能连上。

yaml
spring:
  application:
    name: saa-study-demo
  ai:
    dashscope:
      api-key: ${AI_DASHSCOPE_API_KEY}
      chat:
        options:
          model: qwen3.6-plus

这里故意只保留最小字段。
像你们公司项目里的 application-dev.yml(源码路径:D:/idea_space/ai-center-server/ai-center-api-server/src/main/resources/application-dev.yml) 会复杂很多,因为它还要处理:

  • 多模型
  • embedding
  • 向量库
  • Nacos 配置导入
  • 多环境

但你现在先不要被这些吓到。

4. 项目结构建议长这样

text
src/main/java/com/example/saastudy
├─ StudyApplication.java
├─ config
│  └─ AgentConfig.java
├─ service
│  └─ AgentChatService.java
└─ controller
   └─ AgentChatController.java

这不是唯一写法,但非常适合学习。

5. 第一个可运行版本

5.1 启动类

java
package com.example.saastudy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StudyApplication {

    public static void main(String[] args) {
        SpringApplication.run(StudyApplication.class, args);
    }
}

5.2 Agent 配置

java
package com.example.saastudy.config;

import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AgentConfig {

    @Bean
    public MemorySaver memorySaver() {
        return new MemorySaver();
    }

    @Bean
    public ReactAgent studyAgent(ChatModel chatModel, MemorySaver memorySaver) {
        return ReactAgent.builder()
                .name("study_agent")
                .model(chatModel)
                .instruction("""
                        你是一个帮助 Java 开发者学习 Spring AI Alibaba 的助教。
                        回答请使用中文,解释尽量清楚,不要故作高深。
                        """)
                .saver(memorySaver)
                .build();
    }
}

5.3 Service 层

java
package com.example.saastudy.service;

import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.stereotype.Service;

@Service
public class AgentChatService {

    @Resource
    private ReactAgent studyAgent;

    public String chat(String message) throws Exception {
        AssistantMessage answer = studyAgent.call(message);
        return answer.getText();
    }

    public String chatWithThread(String message, String threadId) throws Exception {
        RunnableConfig config = RunnableConfig.builder()
                .threadId(threadId)
                .build();

        AssistantMessage answer = studyAgent.call(message, config);
        return answer.getText();
    }
}

5.4 Controller 层

java
package com.example.saastudy.controller;

import com.example.saastudy.service.AgentChatService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/study/agent")
public class AgentChatController {

    @Resource
    private AgentChatService agentChatService;

    @PostMapping("/chat")
    public String chat(@RequestBody ChatRequest request) throws Exception {
        if (request.threadId() == null || request.threadId().isBlank()) {
            return agentChatService.chat(request.message());
        }
        return agentChatService.chatWithThread(request.message(), request.threadId());
    }

    public record ChatRequest(String message, String threadId) {
    }
}

6. 这段代码到底做了什么

6.1 ChatModel

它是底层模型能力。
starter 帮你把它注入到 Spring 容器里,你在 studyAgent(...) 方法里直接拿来用。

所以 .model(chatModel) 的含义不是“指定一个普通参数”,而是:

这个 Agent 以后要靠哪个模型来推理。

6.2 name("study_agent")

它不是一个花哨名字。
在更复杂的运行时里,Agent 的名字会参与状态追踪、日志定位、工作流编排。

对初学阶段来说,你先把它当成“这个 Agent 的身份标识”就够了。

6.3 instruction(...)

这部分非常重要。
它相当于在告诉 Agent:

  • 你是谁
  • 你说话的风格是什么
  • 你做事时要遵循什么规则

很多人把 Agent 写不好,不是 API 不会用,而是这里写得太空、太假、太像套话。

6.4 saver(memorySaver)

先别把它看复杂。
你现在只要记住:

没有 saver,Agent 很难可靠地把运行状态接起来。

这一章我们只是先把它放上去。
下一章的下一章会专门讲记忆。

7. 跑起来以后,你该怎么验证

请求示例:

http
POST /study/agent/chat
Content-Type: application/json

{
  "message": "请用通俗的话解释一下 ReactAgent 是什么",
  "threadId": "demo-session-001"
}

如果你想看它是否真的“记住”上下文,可以连续发两次:

json
{
  "message": "我叫小李,请记住",
  "threadId": "demo-session-001"
}

然后再发:

json
{
  "message": "我刚刚叫什么?",
  "threadId": "demo-session-001"
}

这里先不深讲,只先让你感受到:
同一个 threadId,对话才有机会接上。

8. 这个最小例子为什么值得你亲手敲一遍

因为它把 Spring AI Alibaba 的第一层心智模型都凑齐了:

  • ChatModel:模型入口
  • ReactAgent:Agent 主体
  • instruction:行为约束
  • RunnableConfig:运行上下文
  • MemorySaver:状态保存能力

你后面学工具、记忆、RAG,其实都是在这个骨架上继续加东西。

9. 对照你本地源码,它们分别映射到哪

9.1 模型装配

AiModelConfiguration.java(源码路径:D:/idea_space/ai-center-server/ai-center-api-server/src/main/java/com/hy/bigdata/ai/config/model/AiModelConfiguration.java

你会看到公司项目不是只接一个模型,而是注册了多个命名 Bean。
这个动作和你在教程里写的 ChatModel chatModel 是同一件事,只不过工程化程度更高。

9.2 聊天编排

AiChatBizImpl.java(源码路径:D:/idea_space/ai-center-server/ai-center-api-server/src/main/java/com/hy/bigdata/ai/biz/impl/AiChatBizImpl.java

你会发现业务代码不是直接在 Controller 里 new Agent,而是:

  • 先拿到 Agent 上下文
  • 再选择 ChatClientReactAgent
  • 再挂工具、RAG、拦截器

这说明:

你在这里学的最小例子不是玩具,而是工程主链路的缩小版。

9.3 练手项目参考

你也可以对照 MinimalAgentService.java(源码路径:D:/idea_space/og_ai_test/chat-demo/src/main/java/com/hy/bigdata/chatdemo/concept/MinimalAgentService.java),它就是一个非常接近这章思路的最小 Agent 服务。

10. 初学者最容易踩的坑

10.1 以为 ReactAgent 会自己凭空拥有能力

不会。
没有 model,它不会思考;没有 tools,它不会干活;没有 threadIdsaver,它也不会稳定记忆。

10.2 一上来就把项目搞得很复杂

不要一开始就加:

  • 多模型切换
  • 多工具
  • RAG
  • 流式输出
  • Graph

先把一个最小 Agent 写顺。

10.3 把 instruction 写成空话

像“你是一个智能助手,请帮助用户解决问题”这种句子,通常信息量太低。
你要尽量写清角色、风格、边界。

11. 本章小结

这一章你最该带走的,不是某一行代码,而是一个感觉:

原来 ReactAgent 不是一个抽象概念,它就是一个 Spring Bean,只不过这个 Bean 背后连着模型、状态和能力。

下一章,我们不继续堆概念,而是给这个 Agent 装上第一只“手”。

Built with VitePress. Deployed on Cloudflare Pages.