1. 从一次“配置全写死在代码里”的翻车说起如果你已经能用 Spring Boot 跑通一个 Hello World 级别的接口那接下来大概率会碰到这个场景项目里要接大模型第一版代码把 API Key、模型名、系统提示词全硬编码在Service里本地跑得挺欢一换环境就全崩。我试过最典型的一次测试环境 Key 和线上 Key 混用排查了半天才发现是配置文件没抽离。Spring AI 的ChatClient就是来解决这类问题的。它是什么一句话它是 Spring 生态里操作对话模型的统一门面把提示词、顾问链、记忆、参数配置都收敛到一套 Fluent API 上。能做什么你可以用它构建带默认系统提示词的对话服务、挂载 Advisor 做 RAG 检索增强、接入 ChatMemory 维护多轮上下文。适合谁有 Spring Boot 基础、想把 AI 能力嵌进现有 Java 工程的开发者而不是只想在网页上聊两句的人。这一篇聚焦“高级配置入门”也就是在本地工程里把ChatClient和 TaoToken 的统一 Key/API 通道接起来交付可复制的application.yml、ChatClient配置骨架、Advisor 与 ChatMemory 装配片段最后给出启动验证和对话连通性检查动作。全程按能跟做的步骤走不堆概念。2. 前置准备TaoToken 统一 Key 与 API 通道在写配置之前先把“通道”这件事说清楚。TaoToken 提供的是统一的 API 入口你拿一个 Key就能在 Spring AI 里通过 OpenAI 兼容协议访问多种模型不用为每个模型厂商单独维护一套 SDK 和鉴权逻辑。对 Java 工程来说这意味着application.yml里只需要维护一份 base-url 和 api-key。你需要先拿到两样东西一个是 API Key一个是确认要用的模型名。Key 在控制台的 API Keys 页面创建模型名在文档里能查到当前可用的列表。这两个信息后面会直接写进配置文件。注意Key 属于敏感凭证不要提交到 Git 仓库。建议用环境变量注入或者在本地用application-local.yml并加入.gitignore。相关入口我放在这里按需取用创建和管理 Key 走 API Keys 页面接入参数和协议细节看接入文档想先在网页上验证模型通不通可以用模型对话长期做编码或 Agent 类任务可以了解 Coding Plan。3. 可复制配置application.yml 与 ChatClient 骨架3.1 application.yml 里的通道配置Spring AI 的 OpenAI starter 支持自定义 base-url这正是接入统一通道的关键。下面这份配置可以直接复制把占位符替换成你自己的值即可。spring: ai: openai: # 统一 API 通道地址注意结尾不要带多余斜杠 base-url: https://taotoken.net/api # 从控制台创建的 Key建议用环境变量注入 api-key: ${TAOTOKEN_API_KEY} chat: options: # 按文档里当前可用的模型名填写 model: gpt-4o-mini temperature: 0.7 # 日志级别调试 Advisor 时非常有用 logging: level: org.springframework.ai.chat.client.advisor: DEBUG这里有几个容易踩的点。第一base-url不要写成带/v1的完整路径Spring AI 的 OpenAI 客户端会自己拼接写多了会 404。第二api-key用${}占位启动时通过环境变量传入避免明文落盘。第三temperature这类参数属于可移植选项不同模型支持程度不一样先按默认值跑通再调。3.2 ChatClient 配置骨架ChatClient的构建推荐用Builder注入的方式而不是每次 new 一个。这样默认系统提示词、默认 Advisor 都能在构建期一次性装配好。import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class ChatClientConfig { Bean public ChatClient chatClient(ChatClient.Builder builder) { return builder // 默认系统提示词后续每次对话都会带上 .defaultSystem(你是一个严谨的 Java 技术助手回答尽量给出可运行的代码示例。) // 默认挂载日志顾问方便观察请求与响应 .defaultAdvisors(new SimpleLoggerAdvisor()) .build(); } }defaultSystem的作用是简化重复输入。比如你希望这个 ChatClient 永远扮演“Java 技术助手”就不用每次在prompt()里再写一遍系统提示词。defaultAdvisors则是把顾问链固化下来后面所有通过这个 ChatClient 发起的调用都会经过它。3.3 带参数的默认系统提示词默认提示词还能带占位参数这在需要动态切换角色或注入业务变量时很有用。构建时写模板调用时传参。Service public class ActorInfoService { private final ChatClient chatClient; public ActorInfoService(ChatClient.Builder builder) { this.chatClient builder .defaultSystem(生成演员 {actor} 的相关信息只输出事实性内容。) .build(); } public String generate(String actor, String message) { return chatClient.prompt() // 通过 system 的 lambda 形式注入参数 .system(it - it.param(actor, actor)) .user(message) .call() .content(); } }对应的 Controller 很直白把两个参数透传进去就行。RestController public class ActorInfoController { private final ActorInfoService service; public ActorInfoController(ActorInfoService service) { this.service service; } GetMapping(/ai/actor) public String actor(RequestParam String actor, RequestParam String message) { return service.generate(actor, message); } }启动后访问http://localhost:8080/ai/actor?actor刘亦菲message介绍她的教育情况就能看到系统提示词里的{actor}被替换成了实际值模型回答也会围绕这个演员展开。这就是带参数默认提示词的价值模板固定变量运行时注入。4. Advisor 与 ChatMemory 装配让对话有上下文4.1 Advisor 是什么为什么像 AOPAdvisor 的核心思想是对模型交互的输入输出做拦截和增强和 Spring AOP 的拦截器非常像。它能在提示词发给模型前动态添加上下文也能在结果返回后做过滤或结构化解析。常见用途有四类动态修改提示词、结果后处理、跨轮次上下文管理、业务规则注入。在ChatClient的 Fluent API 里通过advisors()方法挂载。这里有个关键规则添加顺序决定执行顺序每个 Advisor 依次修改提示或上下文再把变更传给下一个。ChatClient.create(chatModel).prompt() .advisors( new MessageChatMemoryAdvisor(chatMemory), new QuestionAnswerAdvisor(vectorStore) ) .user(userText) .call() .content();上面这段里MessageChatMemoryAdvisor先执行把对话历史作为消息集合加进提示然后QuestionAnswerAdvisor基于用户问题和刚加入的历史去向量库检索返回更相关的上下文。顺序反了检索质量会明显下降。4.2 ChatMemory 的几种实现与选择ChatMemory接口负责会话历史的存储提供添加消息、检索消息、清除历史三类方法。目前有四种实现选哪种取决于你的持久化需求。实现存储位置特点InMemoryChatMemory内存最简单重启即丢适合本地调试CassandraChatMemoryCassandra支持 TTL可设置记忆有效期Neo4jChatMemoryNeo4j图结构存储适合关系型上下文JdbcChatMemory关系库目前自动配置支持 PostgreSQL 和 MariaDB本地开发阶段我建议先用InMemoryChatMemory把链路跑通确认 Advisor 顺序和记忆注入都正常再换成持久化实现。下面是一个内存记忆加消息顾问的装配片段。Configuration public class MemoryConfig { Bean public ChatMemory chatMemory() { return new InMemoryChatMemory(); } Bean public ChatClient memoryChatClient(ChatClient.Builder builder, ChatMemory chatMemory) { return builder .defaultSystem(你是一个有记忆的助手请结合历史对话回答。) .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) .build(); } }如果你需要持久化JdbcChatMemory 的自动配置最省事引入对应 starter 后它会基于 JDBC 驱动自动建ai_chat_memory表。想手动控制就自己 create把JdbcTemplate传进去。JdbcChatMemory.create( JdbcChatMemoryConfig.builder() .jdbcTemplate(jdbcTemplate) .build() );4.3 RAG 与日志顾问RAG检索增强生成解决的是大模型在长篇内容、事实准确性和上下文感知上的局限。Spring AI 提供模块化架构你可以自己搭 RAG 流也可以用开箱即用的QuestionAnswerAdvisor。知识库体系后面会单独用一章展开这里先知道它挂在 Advisor 链上即可。调试阶段最实用的是SimpleLoggerAdvisor它记录 ChatClient 的请求和响应。建议加到链的末尾这样能看到前面所有 Advisor 处理完之后的最终提示词。ChatResponse response ChatClient.create(chatModel).prompt() .advisors(new SimpleLoggerAdvisor()) .user(你是谁) .call() .chatResponse();配合application.yml里把org.springframework.ai.chat.client.advisor的日志级别设为 DEBUG控制台就能看到完整的请求体。如果默认日志不够用还能自定义序列化函数只打印你关心的字段。SimpleLoggerAdvisor customLogger new SimpleLoggerAdvisor( request - Custom request: request.userText, response - Custom response: response.getResult() );5. 启动验证与对话连通性检查配置写完后别急着写业务先做三步验证。第一步启动应用观察日志里有没有base-url和模型名的加载信息。如果启动就报鉴权错误多半是 Key 没注入成功检查环境变量名和application.yml里的占位符是否一致。第二步用 curl 直接打你的接口确认返回不是空字符串。curl http://localhost:8080/ai/actor?actor刘亦菲message介绍她的教育情况正常返回应该是一段围绕该演员的文本。如果返回 401检查 Key返回 404检查base-url是否多写了路径返回超时检查网络出口和模型名是否拼错。第三步验证记忆是否生效。连续调两次同一个会话接口第二次问“我刚才问了什么”如果模型能答出上一轮内容说明MessageChatMemoryAdvisor装配正确。这一步是很多人容易忽略的记忆没生效往往是因为 Advisor 没挂上或者每次调用都新建了 ChatClient。6. 本篇常见错误排查错误一defaultSystem不生效。检查是不是在prompt()里又调用了.system()覆盖了默认值。默认系统提示词和运行时系统提示词是叠加关系但如果你在运行时传了新的 system行为会以运行时为准。错误二Advisor 顺序导致检索结果差。记住记忆顾问要在检索顾问之前。顺序错了检索时拿不到历史上下文RAG 效果会打折。错误三JdbcChatMemory 自动建表失败。目前自动配置只支持 PostgreSQL 和 MariaDB用 MySQL 需要手动建表或自己 create。另外确认spring.ai.chat.memory.jdbc.initialize-schema没有被设成 false。错误四日志顾问看不到输出。检查日志级别是否设成了 DEBUG以及SimpleLoggerAdvisor是否真的加进了链里。加在链末尾能看到最完整的提示词。错误五Key 泄露风险。不要把 Key 写进application.yml提交到仓库。用环境变量或本地 profile并在.gitignore里排除。排障和接入相关的细节可以对照 API Keys 页面和接入文档逐项核对想先确认模型本身通不通用模型对话页面发一条消息最快如果是要长期做编码或 Agent 类任务Coding Plan 的通道配置和这里略有不同可以单独看。把上面这套配置跑通之后你手里就有了一个可复用的 ChatClient 骨架默认提示词、带参数模板、Advisor 链、ChatMemory 都装配好了。接下来往里面加业务逻辑或者换成持久化记忆、接入向量库做 RAG都是在这个骨架上扩展不用再动通道配置。