ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring AI (第三章) 自定义拦截器+系统提示词(基础总结)

Spring AI (第三章) 自定义拦截器+系统提示词(基础总结) Spring AI (第三章) 自定义拦截器系统提示词基础总结文章目录Spring AI (第三章) 自定义拦截器系统提示词基础总结一、章节目的二、拦截器2.1 拦截器是什么2.2 拦截器的作用三、常见内置实现类Spring AI 已经帮你做好了四、自定义拦截器4.1 代码实现五、系统提示词5.1 系统提示词的作用5.2 提示词编写格式5.3 提示词指南5.4 代码中引用系统提示词的方式六、代码测试6.1 构建AI大模型对象代码6.2 测试代码七、基础小结7.1 ChatClient是什么7.2 ChatClient创建场景7.3 ChatClient全局和局部配置一、章节目的了解拦截器常见的拦截器自定义拦截器系统提示词的用法小结第一章、第二章、第三章的基础知识二、拦截器2.1 拦截器是什么在 Spring AI 中Advisor拦截器是一种用于拦截并增强 AI 调用过程的机制。它类似于 Spring AOP面向切面编程允许开发者在请求前、调用中、响应后插入自定义逻辑。2.2 拦截器的作用拦截器是 Spring AI 框架中用于扩展大模型应用功能的重要机制。通过在模型调用链中注册多个拦截器可以在请求前、响应中、响应后等阶段对模型交互过程进行干预和增强从而实现更高的可控性与灵活性、增强AI大模型的回复质量、安全性、异常处理等。常见的应用场景有敏感词过滤、日志记录、权限校验、上下文管理、响应清洗、结构化解析等功能• 功能增强在不修改核心逻辑的情况下对模型进行功能扩展例如自动补全上下文、增强回复逻辑等• 安全防护实现敏感词过滤、权限校验、输入输出合规性检查等安全措施• 可观测性与运维支持记录日志、跟踪调用链、监控响应时间等便于系统调优与问题排查• 响应优化在响应阶段对模型输出进行清洗、结构化解析或格式化处理提高结果的可用性与一致性。总的来说拦截器在 Spring AI 调用链 中扮演“可插拔增强层”的角色使开发者能够以解耦的方式构建更安全、智能、稳定的大模型应用。三、常见内置实现类Spring AI 已经帮你做好了实现类功能说明SimpleLoggerAdvisor打印请求与响应日志RetryAdvisor出错时自动重试模型调用ResponseParserAdvisor将模型输出解析成 JSON、对象等结构化数据PromptTemplateAdvisor支持使用模板生成 promptSimpleSafetyAdvisor检测和过滤敏感内容ContextAdvisor管理对话上下文记忆系统FunctionCallingAdvisor支持函数调用Function Calling功能SystemPromptAdvisor统一注入系统级提示词CompositeAdvisor组合多个拦截器顺序执行知道应用场景就行了、后面需要用到根据拦截器查官方示例代码即可四、自定义拦截器接下来自定义实现一个日志打印拦截器这个拦截器方便新手调试AI大模型、可以打断点观察AI大模型请求前、请求后的数据包括后续AI大模型配置了Rag向量数据库检索、Mcp服务等、工具类方法、都可以在日志拦截器里手动调试、分析数据4.1 代码实现自定义实现拦截器代码importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.ai.chat.client.advisor.api.*;importorg.springframework.ai.chat.model.MessageAggregator;importreactor.core.publisher.Flux;/** * 通过实现 CallAroundAdvisor 和 StreamAroundAdvisor 两个接口你就能 在 AI 调用的前后包括流式和非流式请求插入自定义逻辑。 * CallAroundAdvisor 处理普通同步调用例如 .call()的拦截逻辑 * StreamAroundAdvisor 处理流式响应例如 .stream()的拦截逻辑 * * 自动执行一些“前置”和“后置”逻辑比如打印日志、记录性能、修改请求内容、存储响应等。 * */publicclassMyLoggerAdvisorimplementsCallAroundAdvisor,StreamAroundAdvisor{privatestaticfinalLoggerlogLoggerFactory.getLogger(MyLoggerAdvisor.class);publicStringgetName(){returnthis.getClass().getSimpleName();// 返回当前类名作为拦截器名称}publicintgetOrder(){return100;// 从0开始按顺序从小往大执行}privateAdvisedRequestbefore(AdvisedRequestrequest){log.info(AI Request: {},request.userText());// 打印用户的提示词returnrequest;}privatevoidobserveAfter(AdvisedResponseadvisedResponse){log.info(AI Response: {},advisedResponse.response().getResult().getOutput().getText());}publicStringtoString(){returnorg.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor.class.getSimpleName();}/** * 普通调用的环绕拦截逻辑 * 在AI聊天普通调用前后执行日志记录 * * param advisedRequest 请求对象 * param chain 拦截器链用于继续执行后续拦截器 * return 处理后的响应对象 */publicAdvisedResponsearoundCall(AdvisedRequestadvisedRequest,CallAroundAdvisorChainchain){advisedRequestthis.before(advisedRequest);AdvisedResponseadvisedResponsechain.nextAroundCall(advisedRequest);// 读取上下文、多个拦截器传递全局变量对象// String userMsg advisedResponse.adviseContext().get(userMsg).toString();// log.info(全局变量对象 userMsg{}, userMsg);this.observeAfter(advisedResponse);returnadvisedResponse;}/** * 流式调用的环绕拦截逻辑 * 在AI聊天流式调用前后执行日志记录 * * param advisedRequest 请求对象 * param chain 拦截器链用于继续执行后续拦截器 * return 处理后的流式响应 */publicFluxAdvisedResponsearoundStream(AdvisedRequestadvisedRequest,StreamAroundAdvisorChainchain){// 1. 请求前处理记录请求日志advisedRequestthis.before(advisedRequest);// 2. 执行实际的AI聊天流式调用FluxAdvisedResponseadvisedResponseschain.nextAroundStream(advisedRequest);// 3. 使用MessageAggregator聚合流式响应并在完成后记录日志return(newMessageAggregator()).aggregateAdvisedResponse(advisedResponses,this::observeAfter);}}五、系统提示词5.1 系统提示词的作用虽然代码中系统提示词是可选的参数、但是在实际应用中是必不可少5.2 提示词编写格式角色扮演、定义AI大模型是干什么的、一般用一个具体的岗位去定义、比如Python高级开发工程师回复格式、增加输出约束比如根据上一个问题引导用户去了解相关的信息限制条件、比如敏感问题不回答语言风格、根据智能体角色去选择回复语气、比如智能客服可以选择和谐、可爱、小甜妹的语气回复提示词里面可以定义模板占位符{}、在代码中可以动态替换占位符、比如替换成用户的信息、让大模型知道自己在跟谁进行对话5.3 提示词指南由于提示词是根据需求场景去调整的、所以有些场景对提示词的要求比较高、需要自行研究学习Prompt Engineering Guide 提示工程指南OpenAI 提示词工程指南Spring AI 提示词工程指南智谱 AI Prompt 设计指南5.4 代码中引用系统提示词的方式纯文本privatestaticfinalStringEXI_PROMPT扮演EXI-小洲的贴身顾问。开场向用户表明身份告知用户可咨询关于小洲的一切信息。围绕小洲喜欢的事物、工作、生活、兴趣、感情展开主动引导用户了解小洲的各个方面我们的目的就是把小洲这个人跟用户介绍清楚仔细、让用户对小洲这个人有着非常清晰的了解回复用户的信息中要可爱、和谐、讨人喜欢;ChatClientchatClientChatClient.builder(dashscopeChatModel).defaultSystem(SYSTEM_PROMPT)// 配置提示词.build();文件提示词test_prompt.st# 角色说明扮演EXI-小洲的贴身顾问。开场向用户表明身份告知用户可咨询关于小洲的一切信息。## 回复格式1. 问题分析2. 相关依据3. 梳理和建议## 语言风格1.回复用户的信息中要可爱、和谐、讨人喜欢## 限制条件1.字数不要过多、回复内容不要有过多的重复词、减少长篇大论的情况 **特别注意** - 围绕小洲喜欢的事物、工作、生活、兴趣、感情展开主动引导用户了解小洲的各个方面 - 我们的目的就是把小洲这个人跟用户介绍清楚仔细、让用户对小洲这个人有着非常清晰的了解 当前服务的用户: 姓名{name}, 年龄{age}, 性别{sex}// 加载自定义 提示词文件ResourcepromptResourcenewClassPathResource(static/prompt/test_prompt.st);ChatClientchatClientChatClient.builder(dashscopeChatModel).defaultSystem(promptResource)// 配置自定义提示词.build();以上2种方式二选一即可、在学习阶段推荐使用文件的方式去调试更好好维护六、代码测试6.1 构建AI大模型对象代码importlombok.extern.slf4j.Slf4j;importorg.exi.exiaiagent.advisor.MyLoggerAdvisor;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;importorg.springframework.ai.chat.memory.ChatMemory;importorg.springframework.ai.chat.memory.InMemoryChatMemory;importorg.springframework.ai.chat.model.ChatModel;importorg.springframework.ai.chat.model.ChatResponse;importorg.springframework.core.io.ClassPathResource;importorg.springframework.core.io.Resource;importorg.springframework.stereotype.Component;importstaticorg.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;importstaticorg.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;/** * 构建自定义拦截大模型聊天对象 */ComponentSlf4jpublicclassChatAdvisorApp{privatefinalChatClientchatClient;/** * 构造器 初始化大模型聊天对象 * param dashscopeChatModel */publicChatAdvisorApp(ChatModeldashscopeChatModel){// 加载自定义 提示词文件ResourcepromptResourcenewClassPathResource(static/prompt/test_prompt.st);// 创建内存存储对象ChatMemorychatMemoryUseMemoryChatMemory();chatClientChatClient.builder(dashscopeChatModel).defaultSystem(promptResource)// 配置自定义系统提示词.defaultAdvisors(newMessageChatMemoryAdvisor(chatMemory),// 配置上下文存储拦截器newMyLoggerAdvisor()// 配置自定义日志拦截器).build();}/** * 基于计算机内存存储、实现读取、写入聊天上下文 * return */publicChatMemoryUseMemoryChatMemory(){/** * 默认使用MessageWindowChatMemory * 存储位置: JVM 内存 (InMemoryChatMemoryRepository) * 数据持久化: 不持久化应用重启后丢失 * 消息窗口: maxMessages 20默认可配置 */InMemoryChatMemorychatMemorynewInMemoryChatMemory();returnchatMemory;}/** * 根据用户消息和用户的聊天ID进行回复 * param message * param chatId * return */publicStringdoChat(Stringmessage,StringchatId){ChatResponsechatResponsechatClient.prompt().user(message)// 用户消息// 根据用户信息动态调整系统提示词模板姓名{name}, 年龄{age}, 性别{sex}.system(p-p.param(name,小美).param(age,21).param(sex,女)).advisors(advisorSpec-advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY,chatId)// 指定聊天记忆存储ID.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY,10)// 获取最近10条聊天记忆).call().chatResponse();StringcontentchatResponse.getResult().getOutput().getText();// 获取chatResponse的结果数据log.info(【对话请求】用户消息{},message);log.info(【模型响应】内容{},content);returncontent;}}6.2 测试代码importjakarta.annotation.Resource;importorg.junit.jupiter.api.Test;importorg.springframework.boot.test.context.SpringBootTest;SpringBootTestclassChatAdvisorAppTest{/** * Resource 注解的作用是先根据字段名后根据类型 来自动匹配注入对应的 Bean */ResourceprivateChatAdvisorAppchatAdvisorApp;TestvoiddoChat(){StringchatIda5daa1bb-e5e2-427e-9a74-68650459511f;Stringmessage自我介绍下;chatAdvisorApp.doChat(message,chatId);}}拦截器断点调试大模型回复结果上图通过拦截器打印了用户发送和模型响应的数据、并且通过系统提示词模板占位符替换让大模型知道当前在服务那个用户七、基础小结7.1 ChatClient是什么ChatClient 是 Spring AI 提供的一个轻量级客户端基于 ChatModel 的上层封装用于构建、发送聊天请求并处理大模型的回复。核心能力易用封装: 基于 ChatModel 的 builder API减少直接拼 JSON 的负担。消息结构: 支持 system、user、assistant 多角色消息。上下文与记忆: 可接入如 MessageChatMemoryAdvisor 之类的记忆/拦截器。工具/函数调用: 可注册工具以启用函数调用不同模型支持度不同。流式响应: 支持逐 token/段落流式消费。可组合: 通过拦截器/Advisor 叠加安全、重试、日志等能力。7.2 ChatClient创建场景系统级创建在系统启动时统一创建一个全局的 ChatClient 实例所有用户共享同一个大模型服务。该方式适用于模型配置固定、对话上下文相对独立的业务场景可提高资源复用性和响应效率。用户级创建根据用户自定义的模型配置信息例如模型类型、温度、上下文策略等在每次对话时动态创建对应的 ChatClient 实例并执行回复。该方式灵活性更高适用于需要根据用户偏好或业务需求进行个性化模型配置的场景。7.3 ChatClient全局和局部配置ChatClient 在初始化时可以配置全局参数例如拦截器Interceptors、系统提示词System Prompt、模型参数等。这些配置在整个应用生命周期内持续生效适用于所有调用场景。同时ChatClient 也支持在具体方法调用时进行局部配置例如在某次对话中临时添加拦截器、修改系统提示词或调整模型参数等。这类配置仅在当前方法调用期间生效调用结束后会自动释放不会影响全局设置。
返回列表