最新资讯
dev.to osFoundry的Loop和Graph是什么,何时该用哪个? dev.to 限制上下文而非限制评审:面向开源补丁的字节预算证据包 dev.to 约束自主智能体:用 GKE Agent Sandbox 实现亚秒级零信任执行 dev.to 实测:给 Claude Code 十个翻译工具,三次运行中有一次完全不用 unite.ai Ramp 数据:企业 AI token 用量增速超过支出增速 pub.towardsai.net AI 生成的 ICLR 评审对被拒论文更宽松:如何压力测试你的 rebuttal blogs.nvidia.com NVIDIA 开源工具如何助力研究者构建下一代 6G 网络 wired.com AI 公司正积极收购企业工作文件与邮件用于模型训练 wechat 网友用AI搓出来的“App”,可以直接在小红书玩起来了? bloomberg.com 科技股抛售后,Anthropic IPO 估值承压 dev.to 当“按设计工作”成为问题:Claude Code 与 .NET 用户机密 dev.to 用代理修复 3500 个 Sonar 问题花 44 美元,让结果可信花 520 美元
多元动态
登录 注册
大模型 dev.to · @deepak marineni

基于 Spring AI 的上下文感知聊天微服务

原文 我的收藏

教程介绍如何用 Spring Boot 与 Spring AI 构建连接 Google Gemini 的聊天微服务:由于 LLM 默认无状态,作者使用 Spring AI 的 ChatMemory Advisor 在请求中注入历史上下文,并通过 H2 数据库(H2ChatMemoryRepositoryDialect)按唯一用户会话持久化对话记录,从而在多轮对话中保持记忆。

AI推荐理由 给出可复现的技术方案:用 Spring Boot + Spring AI 的 ChatClient 与 MessageChatMemoryAdvisor 为无状态的 Gemini API 注入会话历史,并用 H2 数据库按用户会话持久化记忆。对 Java 生态开发者落地多轮对话有直接参考价值,属教程类内容,非官方首发。

66

正文

Keeping State in a Stateless World: Building a Context-Aware Gemini Microservice with Spring AI and H2 By default, Large Language Models (LLMs) are completely stateless. Every API call you make to Google Gemini is treated like a first-time introduction. If a user says "My name is Alex" in request one, and "What is my name?" in request two, Gemini will not know the answer. To build a true chatbot experience, your microservice needs to remember the conversation history. In this post, we will build a Spring Boot microservice that connects to the Gemini API, uses Spring AI's ChatMemory Advisor to maintain context, and backs up that history using a persistent H2 database mapped to unique user sessions. The Architecture Google Gemini API: Handles the natural language processing. Spring AI ChatClient: Orchestrates the prompts and LLM interactions. MessageChatMemoryAdvisor: Intercepts outgoing prompts to inject historical context. H2 Database (H2ChatMemoryRepositoryDialect): Persists the chat history locally. HTTP Session Header: Captures a unique session-id from the client to isolate individual user conversations. 1. Dependencies Setup Add the required dependencies to your pom.xml. This includes the Spring AI starter for Gemini, the chat memory module, and the H2 database driver. org.springframework.boot spring-boot-h2console org.springframework.ai spring-ai-starter-model-chat-memory org.springframework.ai spring-ai-starter-model-chat-memory-repository-jdbc org.springframework.ai spring-ai-starter-model-google-genai Enter fullscreen mode Exit fullscreen mode Configure Properties: Update the application.properties with chat model and get your API key from Google AI Studio spring.ai.model.chat=google-genai spring.ai.google.genai.api-key=API-KEY-GOES-HERE spring.ai.google.genai.chat.model=gemini-3.5-flash Enter fullscreen mode Exit fullscreen mode 2. Configuring the Chat Memory Instead of losing chat history on application restarts (which happens with default in-memory arrays), we configure a persistent ChatMemory bean backed by H2 using the JdbcChatMemoryRepository. import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.MessageWindowChatMemory; import org.springframework.ai.chat.memory.repository.jdbc.H2ChatMemoryRepositoryDialect; import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; @Configuration public class ChatConfig { @Bean public JdbcChatMemoryRepository chatMemoryRepository(JdbcTemplate jdbcTemplate) { // Enforces H2 syntax quirks for database execution return JdbcChatMemoryRepository.builder().jdbcTemplate(jdbcTemplate) .dialect(new H2ChatMemoryRepositoryDialect()) .build(); } @Bean public ChatMemory chatMemory(JdbcChatMemoryRepository repository) { return MessageWindowChatMemory.builder() .chatMemoryRepository(repository).build(); } } Enter fullscreen mode Exit fullscreen mode Configure properties: include the below in application.properties to maintain the session across application restarts and to enable h2-console # H2 Database configuration (File-based storage to persist across restarts) spring.datasource.url=jdbc:h2:file:~/data/demochat;DB_CLOSE_ON_EXIT=FALSE spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password # Enable H2 Console to view your tables manually at http://localhost:8080/h2-console spring.h2.console.enabled=true spring.h2.console.path=/h2-console # Spring AI - Auto-initialize the schema for H2 spring.ai.chat.memory.repository.jdbc.initialize-schema=always Enter fullscreen mode Exit fullscreen mode 3. Service Layer We build the ChatClient and attach the MessageChatMemoryAdvisor. This advisor acts as an interceptor: it fetches past messages from H2 before sending the prompt to Gemini, and saves Gemini's response right after. import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.stereotype.Service; @Service public class ChatService { private final ChatClient chatClient; public ChatService(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory){ this.chatClient = chatClientBuilder.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) .build(); } public String getResponse(String sessionId, String queryString){ return this.chatClient.prompt(queryString) .advisors(x -> x.param(ChatMemory.CONVERSATION_ID, sessionId)) .call().content(); } } Enter fullscreen mode Exit fullscreen mode Exposing the REST Endpoint Finally, we expose a POST endpoint. We use @RequestHeader("x-session-id") to extract the unique tracking key provided by the client application. import ai.chat_bot.gemini.demo.service.ChatService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api") public class ChatController { @Autowired private ChatService chatService; @PostMapping("/ai/prompt") public String chat(@RequestHeader("x-session-id") String sessionId, @RequestBody String query){ return chatService.getResponse(sessionId, query); } } Enter fullscreen mode Exit fullscreen mode Testing the setup You can test the context awareness using curl or Postman. Request establishing a context: curl --location --request POST 'http://localhost:8080/api/ai/prompt' \ --header 'x-session-id: 8757788243' \ --header 'Content-Type: application/json' \ --data-raw '{ "query": "I love mangoes" }' Enter fullscreen mode Exit fullscreen mode Response: Mangoes are absolutely elite! There is a very good reason they are called the "King of Fruits." There is nothing quite like a perfectly ripe, juicy, sweet mango. Request to verify history recall curl --location --request POST 'http://localhost:8080/api/ai/prompt' \ --header 'x-session-id: 8757788243' \ --header 'Content-Type: application/json' \ --data-raw '{ "query": "what do you think is my favorite fruit" }' Enter fullscreen mode Exit fullscreen mode Response: I’m going to go out on a limb here and make a wild guess... mangoes? 🥭 😉 Call it a hunch, but you seemed pretty enthusiastic about them a moment ago! If you send the second request with a different session-id value, Gemini will correctly respond that it doesn't know and can give a generic response proving that multi-user session isolation is fully working. Conclusion By combining Spring AI's Advisor API with an H2 JDBC store, you can turn a stateless LLM endpoint into a fully stateful, context-aware chatbot microservice with minimal boilerplate code. You can view the source code directly in my GitHub Repository

来源报道 · 1 篇 · 以下链接均前往原始媒体

deepak marineni 基于 Spring AI 的上下文感知聊天微服务 09-14 · 原文发布
← 返回精选动态 原文

更多内容