Skip to content

什么是 Re-Reading?如何基于 Spring AI 实现 Re-Reading Advisor? ​

  • 标签:后端、编程导航

🏛 业务架构师 ​

Re-Reading(RE2)是一种提示工程技术:把问题在 prompt 里重复一遍——"用户问题:X。请再读一遍问题:X。然后回答"。配合"逐字复述问题再推理"的指令,效果更好。

原理:重复提高了问题关键信息的注意力权重,降低模型对长上下文中无关信息的过度关注——尤其用户 prompt 很长(贴了大段文档再问一句)时,真正的问题被淹没,重复一次显著减少答非所问。

基于 Spring AI 的实现就是自定义 Advisor:

before: 把用户的原始问题重组为
  "{question}\n请再读一遍问题:{question}"
after: 原样透传(或剥离复读标记)

Advisor 的好处是对业务零侵入:配置开关即启用,按场景灰度(问答场景开、闲聊场景关),效果可 A/B 验证后决定去留。

我的业务评估框架:Re-Reading 的代价几乎只有一点点 token,性价比极高的"微优化"——但要有清醒的定位:

  • 它解决的是指令遵循与问题聚焦,不解决知识不足(那是 RAG 的事)、不解决推理深度(那是 CoT 的事);
  • 不同模型对它的敏感度不同——上线前用自己的评测集跑对比,有提升才保留。

我把它与查询重写、上下文增强组成"提示工程工具箱",按评测数据逐个决定启停——AI 应用的每个小技巧都要用数据证明自己,而不是论文说什么就信什么。这也是我管理 AI 项目与传统项目最大的方法论差异:一切优化以评测集为准绳。

🏗 系统架构师 ​

Re-Reading(RE2)是一种提示工程技术:在 Prompt 中把问题重复两遍——第一遍原文,第二遍"再读一遍问题",让模型二次注意问题细节。论文证明这对复杂推理(数学、逻辑、细节遵循)有稳定提升,本质是给注意力机制"划重点":重复的 token 在 self-attention 里获得更高权重,降低模型对问题关键条件的忽略率。

基于 Spring AI 实现 Advisor(advisor 链里做请求增强):

java
public class ReReadingAdvisor implements CallAdvisor {
    public String adviseCall(AdvisedRequest req, CallAdvisorChain chain) {
        AdvisedRequest modified = req.mutate()
            .user(req.user() + "\n\n请重新读一遍问题: " + req.user())
            .build();
        return chain.nextAroundCall(modified);
    }
}

注册为 Bean 自动进链,或 .advisors(new ReReadingAdvisor()) 按需挂载。

我的使用判断(工程视角):

  • 适合:复杂指令遵循、多约束条件、数学/代码类任务——细节遗漏是主要错误源的场景;
  • 不适合:闲聊、简单问答——白付一倍问题 token,延迟也略增;
  • 通常与 few-shot、CoT 组合:Re2 管输入强化,CoT 管推理展开。

架构意义:这体现了 Advisor 机制的价值——提示工程策略代码化,新实验(重读、自洽、反思)都能以可插拔的 Advisor 沉淀复用,而不是散落在业务代码里。

💻 全栈开发专家 ​

Re-Reading(Re2 技术)= 把问题在 prompt 里重复一遍,并明确要求模型"再读一次问题"再作答。论文证明这对复杂问答(多约束、数学、指令遵循)有稳定提升,成本几乎为零——本质是强化模型对问题本身的注意力。

实现:自定义 Advisor,在请求发出前改写用户消息:

java
public class ReReadingAdvisor implements CallAdvisor<ChatClient.ChatClientRequest> {
    @Override
    public ChatClient.ChatClientRequest adviseRequest(ChatClient.ChatClientRequest req,
            CallAdvisorChain chain) {
        String question = req.prompt().getUserMessage().getText();
        String enhanced = """
            原始问题:%s
            请重新阅读原始问题:"%s",确认理解每个约束后再回答。
            """.formatted(question, question);
        return chain.nextAdvice(req.mutate()
            .prompt(req.prompt().augmentUserMessage(enhanced)).build());
    }
}

挂到链上即可:.defaultAdvisors(new ReReadingAdvisor(), memory, rag...)。

我的实测体会:

  • 对"多个条件叠加"的问题(查 3 个字段 + 排序 + 时间范围)命中率明显提升,特别是会把约束漏掉的小模型;
  • 与 CoT 组合效果好:Re-Reading 强化"读题",CoT 强化"解题步骤";
  • 注意和 RAG Advisor 的顺序:先 RAG 注入上下文再 Re-Reading,重复的是问题本身不是上下文;
  • token 开销只多了问题一遍,对长 prompt 占比可忽略。

这类"prompt 工程 + Advisor 组件化"的模式是 Spring AI 的精髓——改动被收敛在链上,业务代码零侵入。