Spring AI 实现让你的 AI “三思而后行”
你是否遇到过这样的情况:精心设计的 AI 应用,在面对稍微复杂点的问题时,给出的答案却驴唇不对马嘴?感觉它好像“看了一眼就答”,根本没仔细“阅读理解”。
别急,今天就为你介绍一个能显著提升大模型推理能力的技巧——Re-Reading(重读),简称 Re2。这个方法有 论文 背书,效果显著。
更棒的是,在 Spring AI 中,我们可以通过 Advisor(顾问) 模式,优雅地实现这一功能,让你的 AI 在回答前真正做到“三思而后行”。
什么是 Re-Reading (Re2)?
Re2 的原理出奇地简单:让模型把问题再读一遍。
我们只需要将用户的原始问题({Input_Query})通过 Prompt 改造为以下格式:
{Input_Query}
Read the question again: {Input_Query}
通过这种方式,强制模型在生成答案前重新审视问题,从而有效减少误解,提高复杂推理任务的准确率。
友情提示:这种方法虽然能提升效果,但因为输入长度翻倍,API 调用成本也会随之翻倍。因此,在面向 C 端的、成本敏感的应用中请谨慎使用!
构建你的 Re2 Advisor
在 Spring AI 中,Advisor 是一种 AOP(面向切面编程)思想的体现,它允许我们在不侵入核心业务逻辑的情况下,对 AI 的请求和响应进行拦截和增强。
下面,我们来创建一个 ReReadingAdvisor,它会拦截用户请求并自动应用 Re2 模式。
/**
* @author BNTang
* @version 1.0
* @description 自定义 Re2 Advisor,通过让模型重读问题来提高其推理能力。
**/
public class ReReadingAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
/**
* 在 AI 调用前执行,负责改写用户请求。
*
* @param advisedRequest 原始请求
* @return 应用了 Re2 模式的新请求
*/
private AdvisedRequest before(AdvisedRequest advisedRequest) {
// 将原始查询存入参数,以便在模板中使用
Map<String, Object> advisedUserParams = new HashMap<>(advisedRequest.userParams());
advisedUserParams.put("re2_input_query", advisedRequest.userText());
// 使用新模板构建并返回 AdvisedRequest
return AdvisedRequest.from(advisedRequest)
.userText("""
{re2_input_query}
Read the question again: {re2_input_query}
""")
.userParams(advisedUserParams)
.build();
}
/**
* 环绕处理非流式调用。
*/
@NotNull
@Override
public AdvisedResponse aroundCall(@NotNull AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
// 调用 before 方法修改请求,然后传递给调用链的下一个环节
return chain.nextAroundCall(this.before(advisedRequest));
}
/**
* 环绕处理流式调用。
*/
@NotNull
@Override
public Flux<AdvisedResponse> aroundStream(@NotNull AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
// 同样,调用 before 方法修改请求,然后传递给调用链
return chain.nextAroundStream(this.before(advisedRequest));
}
/**
* 返回 Advisor 的名称。
*/
@NotNull
@Override
public String getName() {
return this.getClass().getSimpleName();
}
/**
* 定义 Advisor 的执行顺序,数值越小,优先级越高。
*/
@Override
public int getOrder() {
return 0; // 设置为高优先级
}
}
即插即用:在 ChatClient 中启用 Advisor
Advisor 写好了,用起来也非常简单。只需在构建 ChatClient 时,通过 .defaultAdvisors() 方法将其加入即可。
/**
* App 构造函数,初始化聊天客户端。
*
* @param ollamaChatModel 聊天模型实例
*/
public App(ChatModel ollamaChatModel) {
ChatMemory chatMemory = new InMemoryChatMemory();
chatClient = ChatClient.builder(ollamaChatModel)
.defaultSystem(SYSTEM_PROMPT)
.defaultAdvisors(
new MessageChatMemoryAdvisor(chatMemory), // 记忆顾问
new ReReadingAdvisor() // 启用 Re-Reading 顾问!
)
.build();
}
现在,所有通过这个 chatClient 发出的请求,都会自动被 ReReadingAdvisor 处理,实现推理增强,而我们的业务代码无需做任何改动。是不是非常优雅?
Advisor 最佳实践清单
为了让你更好地驾驭 Advisor,这里总结了几个最佳实践:
- 保持单一职责:每个 Advisor 应该只做一件事,比如日志、缓存、重试或像我们今天的 Re2。
- 注意执行顺序:通过
getOrder()控制 Advisor 的执行顺序,确保逻辑正确。 - 兼容流式与非流式:尽可能同时实现
CallAroundAdvisor和StreamAroundAdvisor接口,让你的 Advisor 更通用。 - 保持高效:避免在 Advisor 中执行耗时操作,以免阻塞整个调用链。
- 充分测试:特别是边界情况,确保 Advisor 的健壮性。
- 善用 Reactor(进阶):对于复杂的流式处理,可以利用
Reactor的操作符进行精细控制。
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
return Mono.just(advisedRequest)
.publishOn(Schedulers.boundedElastic())
.map(this::modifyRequest) // 请求前处理
.flatMapMany(chain::nextAroundStream)
.map(this::modifyResponse); // 响应后处理
}
- 共享状态(进阶):使用
advisedRequest.updateContext()和advisedResponse.adviseContext()在 Advisor 链中传递状态。
// 在 Advisor A 中更新上下文
advisedRequest = advisedRequest.updateContext(context -> {
context.put("my_key", "my_value");
return context;
});
// 在 Advisor B 中读取上下文
Object value = advisedResponse.adviseContext().get("my_key");
Spring AI 实现让你的 AI “三思而后行”的更多相关文章
- 6.使用桌面版AI伴侣或手机版AI伴侣实时预览编程效果
1.根据自己系统下载对应版本AI伴侣,最好解压到D盘根目录. 运行ailaunch.bat ,可以启动原本自带的2.46版AI伴侣.运行AI伴侣247.bat可以启动汉化2.47版的AI伴侣.并且默认 ...
- 一个AI产品经理怎么看AI的发展
一个AI产品经理怎么看AI的发展 https://www.jianshu.com/p/bed6b22ae837 最近一直在思考这个问题,人工智能接下来的几年会有什么样的发展,是否真的能够在很多工作岗位 ...
- Meta AI 开源万物可分割 AI 模型(SAM)
开始 4 月 6 日,根据 Meta AI 官方博客,Meta AI 宣布推出了一个 AI 模型 Segment Anything Model(SAM,分割一切模型).据介绍,该模型能够根据文本指令等 ...
- AI:从游戏引擎--到AI
原文链接:http://blog.csdn.net/left_la/article/details/6358911#t9 这是我在Gameres上看到的一篇文章,文章很长,全文分为11个部分,看后感觉 ...
- 视觉AI风口一触即发,虹软AI沙龙点金深圳
7月26日,虹软AI沙龙在深圳湾科技生态园空间举办.AI沙龙是基于虹软视觉开放平台的开发者交流沙龙,旨在通过分享最新的实战案例,帮助开发者解决技术及落地难题,让技术更贴近实用场景. 本次活动中,深圳市 ...
- Thiago2(TPO AI.ROSTO):集成式AI换脸软件(Autodesk Flame)
如标题一样,Thiago2 是一款集成式AI换脸软件(TPO AI.ROSTO),需要与Autodesk Flame结合使用,从demo来看完成度还是很高的,算是一种完全GUI版的DeepFaceLa ...
- 会编程的 AI + 会修 Bug 的 AI,等于什么 ?
2017-02-25 Python开发者 (点击上方公众号,可快速关注) 关于人工智能未来的畅想,除了家庭服务机器人,快递无人机,医用机器人等等,Lucas Carlson 认为人工智能在另外一个领域 ...
- Poe – Fast AI Chat 一款集成AI工具
前言 Poe – Fast AI Chat是由知名问答社区 Quora 开发的 AI 产品,提供实时在线与多个 AI 机器人交流的功能.在去年12月,Quora首次推出Poe作为封闭测试版,并于2月份 ...
- AI测试101:测试AI系统的实用技巧&ML和AI自动化工具
基于人工智能的系统,也称为神经网络(NN Neural Networks),和其他应用程序一样是 "系统",因此需要测试.本文将指导你测试AI和基于NN的系统,并理解相关概念. 测 ...
- [UE4]在AI Character中要获得AI的controller,需要使用Get AIController
随机推荐
- Echarts服务端渲染以及客户端懒加载实现方案
为了提升首屏的加载速度,考虑先用服务端渲染快速输出首屏图表,然后等待 echarts.js 加载完后,通过注水操作(Hydration),重新在客户端渲染同样的图表 tips:在客户端渲染的时候,应开 ...
- 使用Python进行切比雪夫插值
引言 在科学计算中,插值是一个非常重要的概念.简单来说,插值就是通过已知的离散数据点来估算未知点的值.今天,我们将重点介绍切比雪夫插值,它是一种非常有效的插值方法,特别适用于解决插值多项式高次时出现的 ...
- 浏览器窗口之间切换的方法(Select window指令,优先使用方法2)
Robot framework 在同一个浏览器中切换不同选项卡,通过title来定位选项卡.Title存在不唯一的情况,选择不同的选项卡有一些困难.下面的教程,通过修改selenium配置文件,来实现 ...
- 12.ZIP伪加密
题目是伪加密,打开压缩包,发现里面直接放着flag.txt,但是好像需要输入密码,此时我们在不看题目的第一反应就是破解,但是无果,看了别人的wp之后,了解了一点伪加密. ZIP文件分为:压缩源文件数据 ...
- wget--批量下载
wget--批量下载 wget -nd -r -l1 --no-parent --accept=jar http://192.168.38.38:81/js/jartest/ -nd 不创建目录, w ...
- 亚马逊aws_access_key_id和aws_secret_access_key利用
00X01 信息泄露 敏感信息泄露,例如环境变量.例如,为了配置AWS CLI,需要设置以下环境变量: $ export AWS_ACCESS_KEY_ID=AKISIOSFODNN7EXAMPLE ...
- Nacos简介—4.Nacos架构和原理
Nacos简介-4.Nacos架构和原理 大纲 1.Nacos的定位和优势 2.Nacos的整体架构 3.Nacos的配置模型 4.Nacos内核设计之一致性协议 5.Nacos内核设计之自研Dist ...
- 痞子衡嵌入式:聊聊i.MXRT1024/1064片内4MB Flash的SFDP表易丢失导致的烧录异常
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1024/1064片内4MB Flash的SFDP表易丢失导致的烧录异常. 我们知道 i.MXRT 系列本身并没有片内非易失 ...
- 应用间通信(一):详解Linux进程IPC
进程之间是独立的.隔离的,使得应用程序之间绝对不可以互相"侵犯"各自的领地. 但,应用程序之间有时是需要互相通信,相互写作,才能完成相关的功能,这就不得不由操作系统介入,实现一种通 ...
- C#之结构
结构是用户定义的数据类型,与类非常相似,它们有数据成员和函数成员,但与类最重要的区别是:类是引用类型,而结构是值类似,结构是隐式密封的,这意味这它们不能被派生,所以结构类型不能为null,两个结构变量 ...