你是否遇到过这样的情况:精心设计的 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,这里总结了几个最佳实践:

  1. 保持单一职责:每个 Advisor 应该只做一件事,比如日志、缓存、重试或像我们今天的 Re2。
  2. 注意执行顺序:通过 getOrder() 控制 Advisor 的执行顺序,确保逻辑正确。
  3. 兼容流式与非流式:尽可能同时实现 CallAroundAdvisorStreamAroundAdvisor 接口,让你的 Advisor 更通用。
  4. 保持高效:避免在 Advisor 中执行耗时操作,以免阻塞整个调用链。
  5. 充分测试:特别是边界情况,确保 Advisor 的健壮性。
  6. 善用 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); // 响应后处理
}
  1. 共享状态(进阶):使用 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 “三思而后行”的更多相关文章

  1. 6.使用桌面版AI伴侣或手机版AI伴侣实时预览编程效果

    1.根据自己系统下载对应版本AI伴侣,最好解压到D盘根目录. 运行ailaunch.bat ,可以启动原本自带的2.46版AI伴侣.运行AI伴侣247.bat可以启动汉化2.47版的AI伴侣.并且默认 ...

  2. 一个AI产品经理怎么看AI的发展

    一个AI产品经理怎么看AI的发展 https://www.jianshu.com/p/bed6b22ae837 最近一直在思考这个问题,人工智能接下来的几年会有什么样的发展,是否真的能够在很多工作岗位 ...

  3. Meta AI 开源万物可分割 AI 模型(SAM)

    开始 4 月 6 日,根据 Meta AI 官方博客,Meta AI 宣布推出了一个 AI 模型 Segment Anything Model(SAM,分割一切模型).据介绍,该模型能够根据文本指令等 ...

  4. AI:从游戏引擎--到AI

    原文链接:http://blog.csdn.net/left_la/article/details/6358911#t9 这是我在Gameres上看到的一篇文章,文章很长,全文分为11个部分,看后感觉 ...

  5. 视觉AI风口一触即发,虹软AI沙龙点金深圳

    7月26日,虹软AI沙龙在深圳湾科技生态园空间举办.AI沙龙是基于虹软视觉开放平台的开发者交流沙龙,旨在通过分享最新的实战案例,帮助开发者解决技术及落地难题,让技术更贴近实用场景. 本次活动中,深圳市 ...

  6. Thiago2(TPO AI.ROSTO):集成式AI换脸软件(Autodesk Flame)

    如标题一样,Thiago2 是一款集成式AI换脸软件(TPO AI.ROSTO),需要与Autodesk Flame结合使用,从demo来看完成度还是很高的,算是一种完全GUI版的DeepFaceLa ...

  7. 会编程的 AI + 会修 Bug 的 AI,等于什么 ?

    2017-02-25 Python开发者 (点击上方公众号,可快速关注) 关于人工智能未来的畅想,除了家庭服务机器人,快递无人机,医用机器人等等,Lucas Carlson 认为人工智能在另外一个领域 ...

  8. Poe – Fast AI Chat 一款集成AI工具

    前言 Poe – Fast AI Chat是由知名问答社区 Quora 开发的 AI 产品,提供实时在线与多个 AI 机器人交流的功能.在去年12月,Quora首次推出Poe作为封闭测试版,并于2月份 ...

  9. AI测试101:测试AI系统的实用技巧&ML和AI自动化工具

    基于人工智能的系统,也称为神经网络(NN Neural Networks),和其他应用程序一样是 "系统",因此需要测试.本文将指导你测试AI和基于NN的系统,并理解相关概念. 测 ...

  10. [UE4]在AI Character中要获得AI的controller,需要使用Get AIController

随机推荐

  1. harmonyOS基础- 快速弄懂HarmonyOS ArkTs基础组件、布局容器(前端视角篇)

    大家好!我是黑臂麒麟,一位6年的前端: if you're change the world, you're workingon important things. you're excited to ...

  2. MCP开发应用,使用python部署sse模式

    一.概述 MCP服务端当前支持两种与客户端的数据通信方式:标准输入输出(stdio)  和 基于Http的服务器推送事件(http sse) 1.1 标准输入输出(stdio) 原理:  标准输入输出 ...

  3. Python科学计算系列5—导数

    1.一元函数的导数 例1:求下列函数的导数 例2:求下列函数的50阶导数 代码如下: from sympy import * x = symbols('x') f1 = diff(tan(x)) f2 ...

  4. 测试工作中用到的MongoDB命令

    1.远程连接MongoDB mongo host:port/dbname (host和port根据自己需要修改) 连接成功页面如下: 2.显示所有数据库 show dbs 3.切换到oversea-a ...

  5. 机器人操作系统ROS2之安装(Ubuntu 24)

    根据官网说明,ROS2是支持MAC的,本来打算在手头的MAC 15.3.2装一个,虽然要自己编译ROS2系统,但是想着比虚拟机性能好,就兴冲冲的开始了,也没在意官网提示尽量还是装安装版.最后折腾了几天 ...

  6. 聊聊四种实时通信技术:长轮询、短轮询、WebSocket 和 SSE

    这篇文章,我们聊聊 四种实时通信技术:短轮询.长轮询.WebSocket 和 SSE . 1 短轮询 浏览器 定时(如每秒)向服务器发送 HTTP 请求,服务器立即返回当前数据(无论是否有更新). 优 ...

  7. MCP云托管最优解,揭秘国内最大MCP中文社区背后的运行时

    作者:封崇 近期,中国第一AI开源社区魔搭(ModelScope)推出全新MCP广场,上架千余款热门的 MCP 服务.从当下火热的高德地图.网页抓取再到独家的支付宝,开发者/机构可以查看近1500种M ...

  8. Manus邀请码,Manus:科技圈新“炸点”,还是又一场狂欢?

    嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 想要邀请码获取方式往下看哟,同学~~~ 2025年3月6日,AI圈被一款名为Manus的产品 ...

  9. 使用C#构建一个同时问多个LLM并总结的小工具

    前言 在AI编程时代,如果自己能够知道一些可行的解决方案,那么描述清楚交给AI,可以有很大的帮助. 但是我们往往不知道真正可行的解决方案是什么? 我自己有过这样的经历,遇到一个需求,我不知道有哪些解决 ...

  10. vue3 基础-API-watch 和 watchEffect

    前篇对 computed 属性如何在 api 中基本使用, 即从 vue 中引入, 然后通过直接传函数或者传对象的方式, 开箱即用, 非常清晰易懂. 本篇继续来对之前的 watch 进行扩展使用啦. ...