Spring AI 写聊天 Agent:对话、记忆、工具
发布时间:2026-08-25 21:48 浏览量:1
Java 开发者想在 Spring 项目里接入大模型、做一个能对话又能调工具的 Agent,Spring AI 是最顺的一条路。它是 Spring 官方出品的 AI 框架,深度集成 Spring Boot,2.0 版本在 2026 年 6 月发布后,ChatClient 成了核心入口。
做这件事的理由也很充分:Gartner 预测到 2028 年,33% 的企业软件将内嵌 Agentic AI 能力。对 Java 后端来说,与其为了一个 Agent 换到 Python 全家桶,不如在已经熟悉的 Spring 生态里把它跑起来。而且国内模型接入也方便——用阿里官方的 starter,通义千问一行依赖就能接。
这篇文章从零走完一个聊天 Agent 的最小闭环,只讲三件事:
一次对话、多轮记忆、工具调用
。这三样拼起来,就是任何一个 Agent 的骨架。
为什么偏偏是这三步,而不是别的?因为一个 Agent 无论多复杂,拆到底都逃不出这三个能力:和用户对话(交互)、记得之前说了什么(状态)、动手调用外部能力(行动)。先把这个三角立起来,后面加 RAG、加多 Agent,都只是在这个三角上叠加,不会推翻重来。
环境要求很轻:Spring Boot 3.x,JDK 17 或更高。这两条几乎不用特意折腾,2026 年的新项目基本都满足。
先加依赖。走国内模型,用阿里官方的 Spring AI Alibaba starter(通义千问),坐标如下:
com.alibaba.cloud.aispring-ai-alibaba-starter-dashscope1.0.0.2
如果走 OpenAI,把坐标换成 spring-ai-starter-model-openai 即可,写法完全一致。
框架把不同模型厂商的差异封装在了 starter 后面,业务代码不用改。
再配置模型。API Key 建议放环境变量,别硬编码进代码——这既是安全习惯,也方便在测试和线上切换不同的 Key。在 application.yml 里写:
spring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY} chat: options: model: qwen-plus
qwen-plus 是通义千问里性价比比较均衡的一档,日常对话够用;追求更强推理可以换 qwen-max。启动前把 DASHSCOPE_API_KEY 环境变量设好,模型就接进来了——到这里,一行 Java 代码都还没写。
除了 api-key 和 model,Spring AI 还暴露了一堆可调参数,比如 temperature(控制回答的随机性,越低越稳定)、max-tokens(限制单次回复长度)。初学阶段这些都可以不碰,用默认值就能跑,等真觉得回答"太飘"或"太短",再回来调。
Spring AI 会自动配置好一个 ChatClient.Builder,直接注入就能用。最简的对话入口长这样:
@RestControllerpublic class ChatController { private final ChatClient chatClient; public ChatController(ChatClient.Builder builder) { this.chatClient = builder.build; } @GetMapping("/chat") public String chat(@RequestParam String message) { return chatClient.prompt .user(message) .call .content; }}
ChatClient 是 Spring AI 2.0 的核心入口,用法和 RestClient 几乎一样
,会 RestClient 的人看一遍就会。那行链式调用拆开看:prompt 构建请求、user 填入用户消息、call 发起调用、content 取出回复文本。
这里有一个容易被忽视的设计选择:
官方推荐用 ChatClient,而不是更底层的 ChatModel。
ChatClient 在 ChatModel 之上包了一层,把记忆、工具、结构化输出这些能力都做成了可插拔的 Advisor,后面加功能都是往这上面挂,不用改核心代码。
顺带一提,call 是同步调用,会阻塞到模型返回;如果想做打字机式的流式输出,换成 stream 即可,返回值变成一个个增量片段。对聊天场景来说,流式体验好得多,只是代码会多几行——初学先用同步把流程跑通,再换流式不迟。
启动后访问 /chat?message=你好,就能收到模型回复。但这一步的 Agent 是"失忆"的——每问一句,它都不记得上一句说了什么。
想让对话有上下文,得给它加记忆。Spring AI 里,记忆靠一个 Advisor(顾问)挂到 ChatClient 上:
ChatClient chatClient = builder .defaultAdvisors( new MessageChatMemoryAdvisor(new InMemoryChatMemory) ) .build;
加上这一行,Agent 就会把历史对话带进每一轮的上下文,问"我刚才说的城市是哪个",它能接得上。
这里藏着理解 Agent 记忆的关键:记忆不是模型自带的,而是框架在每次请求前,把历史消息拼进 prompt 再发给模型。
大模型本身是无状态的,它"记得"的每一句话,都是框架替它塞回去的。理解了这一点,就明白为什么记忆必须显式配置。
有两个坑值得提前知道:
内存记忆重启就丢
:示例里的 InMemoryChatMemory 只在进程内有效,重启全忘。生产环境要换成持久化实现。
记忆越长,成本越高
:每一轮都把完整历史发给模型,token 消耗是滚雪球的。生产上通常要限制记忆窗口,只保留最近几轮。
这是 Agent 和"普通聊天机器人"的本质区别——
不只是会答,还会动手做
。
先用 @Tool 注解定义一个工具,告诉模型"有这样一个能力可用":
public class WeatherTools { @Tool(description = "查询指定城市的天气") public String getWeather(String city) { // 实际场景里,这里调用真实的天气 API return city + " 今天晴,25 摄氏度"; }}
description 这一句很关键,模型就是靠它判断"什么情况下该调这个工具"。写清楚、写具体,模型才会在正确的时候调用。
return chatClient.prompt .user(message) .tools(new WeatherTools) .call .content;
现在问它"北京天气怎么样",它不会瞎编,而是
自己判断该调用 getWeather,把"北京"作为参数传进去,拿到结果再组织成回答
。
Spring AI 内置了完整的 ReAct 循环,几个要点:
推理与行动交替
:模型先想"该调哪个工具",调完拿到结果,再想"还要不要继续调"。
可连续调用
:一个任务可能需要多个工具接力,模型会自动串起来,直到信息够了才给最终回复。
全程对开发者透明
:开发者只负责"定义工具"和"注册工具",循环过程不用自己写。
这就是 Agent 的"边做边想"——不是一口答完,而是调工具、看结果、再决定下一步。
工具的参数可以不只是 String——整数、布尔、复杂对象都行,Spring AI 会自动生成参数描述,模型照着填。工具方法里抛异常时,异常信息也会回传给模型,让它知道"这个操作失败了",从而换一种方式重试,或坦白告诉用户。这套错误回传机制,是 Agent 稳健性的重要一环。
把对话、记忆、工具三件事串起来,就是一个最小可用的聊天 Agent:
@RestControllerpublic class AgentController { private final ChatClient chatClient; public AgentController(ChatClient.Builder builder) { this.chatClient = builder .defaultAdvisors( new MessageChatMemoryAdvisor(new InMemoryChatMemory) ) .build; } @GetMapping("/agent") public String agent(@RequestParam String message) { return chatClient.prompt .user(message) .tools(new WeatherTools) .call .content; }}
到这个节点,这个 Agent 已经能做到三件事:
正常对话、记住上下文、按需调用工具
。对比一下工作量——真正和业务相关的,只有"定义 WeatherTools 这个工具"和"写一个 Controller",其余全是框架代劳。
回看这一路,其实只有四步:加依赖、配模型、写 Controller、挂工具。Spring AI 把最繁琐的模型接入和 ReAct 循环都封装好了,留给开发者的,只剩"定义工具"和"组织业务"这两件真正有价值的事。
再往下走,方向也很清晰:
结构化输出
:用 BeanOutputConverter 让模型返回可解析的 Java 对象,而不是自由文本。
RAG
:接向量库,让 Agent 基于企业自己的知识回答,而不是只靠模型训练时的记忆。
多 Agent 编排
:把复杂任务拆给多个 Agent 协作,各自负责一块。
但无论往哪个方向走,
"对话 + 记忆 + 工具"这三块地基都不会变
。先把这套最小骨架跑通、吃透,后面的一切都是在这个骨架上添砖加瓦。
最后给一个建议:别一上来就研究框架源码,也别一上来就上生产级全家桶。就按这篇文章的三步,把"对话、记忆、工具"先在自己机器上跑通,亲手体验一次"模型自己决定调工具"的瞬间。那一下跑通之后,Agent 就不再是一个抽象概念,而是一件随时能动手做的事。
Spring AI 的价值也正在于此——它没有发明什么新概念,只是把大模型的能力,翻译成了 Java 开发者最熟悉的 Spring 写法。剩下的,就看你准备让它做什么了。