芥末
发布于 2026-01-22 / 0 阅读
0
0

Prompt 重复:用复制粘贴提升非推理大模型答题准确率

有一种 Prompt 技巧非常朴素:把同一个问题连续输入两遍。

原来这样问:

梵蒂冈的圣伯多禄大教堂门口有几根柱子?

改成这样问:

梵蒂冈的圣伯多禄大教堂门口有几根柱子?

梵蒂冈的圣伯多禄大教堂门口有几根柱子?

这不是让模型“更有礼貌”,也不是加复杂模板,而是单纯重复问题。Google 的研究《Prompt Repetition Improves Non-Reasoning LLMs》对这种做法做了系统测试:在 70 组“模型 × 基准任务”对比中,重复 Prompt 赢了 47 组,持平 23 组,没有出现失败组;在部分任务上,准确率从 21.33% 提升到 97.33%。

这个技巧主要作用在非推理模型上,也就是没有显式“深度思考”过程、通常直接输出答案的模型。它的价值在于:不改变模型、不微调、不接工具,只通过输入格式让模型更容易抓住问题里的关键信息。


Prompt 重复到底怎么写

Prompt 重复的基本形式很简单:

<问题>

<问题>

也可以写成公式:

Q  ->  Q + Q

这里的 Q 是完整任务,包括题目、选项、约束、输出格式等内容。

例如一个选择题原本是:

选项:
A. 把蓝色方块放到红色方块左边
B. 把红色方块放到蓝色方块左边

场景说明:
现在红色在左,蓝色在右。

问题:
哪一个选项会改变画面?

只输出 A 或 B。

重复后变成:

选项:
A. 把蓝色方块放到红色方块左边
B. 把红色方块放到蓝色方块左边

场景说明:
现在红色在左,蓝色在右。

问题:
哪一个选项会改变画面?

只输出 A 或 B。

选项:
A. 把蓝色方块放到红色方块左边
B. 把红色方块放到蓝色方块左边

场景说明:
现在红色在左,蓝色在右。

问题:
哪一个选项会改变画面?

只输出 A 或 B。

这个技巧不需要加“请一步一步思考”,也不需要额外示例。它改变的不是语言风格,而是模型处理输入时的上下文结构。


实验结果说明了什么

Google 的实验覆盖了多个常见非推理大模型,包括 Gemini 2.0 Flash、Gemini 2.0 Flash Lite、GPT-4o、GPT-4o-mini、Claude 3 Haiku、Claude 3.7 Sonnet、DeepSeek V3 等,并使用官方 API(Application Programming Interface,应用程序编程接口)进行测试。

测试任务既包含常见基准,也包含专门设计的位置和匹配类任务。

任务类型例子考察能力
常见知识与推理基准ARC、OpenBookQA、GSM8K、MMLU-Pro、MATH常识、数学、知识问答、复杂选择
NameIndex给出 50 个名字,询问第 25 个是谁序列位置定位
MiddleMatch给出包含重复名字的列表,询问两个字符之间的名字局部匹配、上下文定位

整体结果可以概括为:

对比项结果
对比方式原始 Prompt vs 重复一遍的 Prompt
测试组合数量70 组
重复 Prompt 胜出47 组
持平23 组
失败0 组
最高提升案例部分任务准确率从 21.33% 到 97.33%

这里的关键不是“重复一定让所有任务都暴涨”,而是它在大量非推理模型和任务组合中表现得非常稳定:至少没有明显损害,很多场景还会显著变好。


为什么复制一遍会有用

大多数大语言模型(LLM,Large Language Model)采用因果语言模型结构。它们生成内容时,从左到右读取 token,并预测下一个 token。

在 Transformer 中,每个 token 的隐藏状态只能看到它左边的内容,不能看到右边还没出现的内容。这叫因果掩码。

flowchart LR
    A[前面的 token] --> B[当前 token]
    B -.不能看到.-> C[后面的 token]

这会带来一个容易被忽略的问题:Prompt 里越靠前的内容,在被模型编码时,能看到的信息越少。

还是看刚才的选择题:

选项:
A. 把蓝色方块放到红色方块左边
B. 把红色方块放到蓝色方块左边

场景说明:
现在红色在左,蓝色在右。

模型处理到选项 A、B 时,还没有读到后面的场景说明。也就是说,选项对应的内部表示一开始并不包含“红色在左,蓝色在右”这个条件。

单次 Prompt 的处理过程大致是:

flowchart LR
    A[选项 A/B] --> B[场景说明]
    B --> C[问题]
    C --> D[生成答案]

因为选项出现在场景说明之前,选项 token 的内部表示不能提前吸收场景条件。虽然最终答案 token 可以看到整个 Prompt,但模型内部对早期内容的表示已经是在“信息不足”的状态下形成的。

重复 Prompt 后,结构变成:

flowchart LR
    A1[第一遍:选项 A/B] --> B1[第一遍:场景说明]
    B1 --> C1[第一遍:问题]
    C1 --> A2[第二遍:选项 A/B]
    A2 --> B2[第二遍:场景说明]
    B2 --> C2[第二遍:问题]
    C2 --> D[生成答案]

第二遍的选项 A、B 出现时,模型已经读过第一遍的完整题目。于是第二遍选项的隐藏状态,可以同时利用:

  • 第一遍的选项;
  • 第一遍的场景说明;
  • 第一遍的问题;
  • 第二遍当前正在处理的选项。

这相当于让模型在第二遍“带着题目背景重新读题”。重复不是魔法,它只是让一部分关键 token 在更完整的上下文中重新被编码了一次。

可以把它理解成一种轻量级的自我复述。


非推理模型为什么更容易受益

非推理模型通常追求低延迟和直接输出。它们不会显式展开长推理过程,也不一定会主动复述题目、整理条件、重新检查约束。

推理模型则不同。很多经过 RL(Reinforcement Learning,强化学习)或推理任务优化的模型,会自然产生类似这样的内部流程:

题目要求的是……
已知条件包括……
需要判断的是……

这种行为本身就像在帮自己重写题目、重排信息。Prompt 重复能提供的额外收益就会变小。

模型类型常见表现Prompt 重复的作用
非推理模型直接回答,速度快,容易漏条件可能明显提高准确率
推理模型会复述问题、拆条件、逐步推导收益通常较小
长思考模型输出前会花更多时间进行内部推理重复可能变成额外 token 成本

所以这个技巧特别适合放在“需要速度,但又希望提高一点准确率”的场景里,比如分类、选择、短问答、字段抽取、位置定位等任务。


怎么在实际 Prompt 中使用

1. 完整重复

适合短 Prompt,尤其是选择题、判断题、短问答。

def repeat_prompt(prompt: str, times: int = 2) -> str:
    prompt = prompt.strip()
    return "\n\n".join([prompt] * times)


question = """
选项:
A. 把蓝色方块放到红色方块左边
B. 把红色方块放到蓝色方块左边

场景说明:
现在红色在左,蓝色在右。

问题:
哪一个选项会改变画面?

只输出 A 或 B。
"""

final_prompt = repeat_prompt(question, times=2)
print(final_prompt)

如果使用 Chat API,通常只需要重复用户消息里的任务内容,不要重复 system 指令。

messages = [
    {
        "role": "system",
        "content": "你是一个严格按要求输出答案的助手。"
    },
    {
        "role": "user",
        "content": repeat_prompt(question, times=2)
    }
]

2. 只重复核心问题

如果输入里有很长的背景材料,完整复制会浪费上下文窗口,也会增加成本。此时可以只重复问题、选项、输出约束。

背景材料:
<这里是一大段资料,不重复>

任务:
根据背景材料,判断下面哪个选项正确。
A. ...
B. ...
C. ...
D. ...

只输出选项字母。

任务:
根据背景材料,判断下面哪个选项正确。
A. ...
B. ...
C. ...
D. ...

只输出选项字母。

这种写法保留了“重新读题”的优势,同时避免把长上下文复制两遍。

3. 重复关键约束

有些任务容易错在输出格式,例如本来要求 JSON,模型却输出解释文字。可以重复格式要求,而不是重复全部内容。

从下面文本中抽取姓名、公司、职位,输出 JSON。

文本:
张三目前在星河智能担任算法工程师。

输出格式:
{"name": "...", "company": "...", "title": "..."}

只输出 JSON,不要解释。

输出格式:
{"name": "...", "company": "...", "title": "..."}

只输出 JSON,不要解释。

哪些场景适合用

场景是否适合原因
短选择题适合重复成本低,容易让模型重新绑定选项和条件
数学题的题干较短可以尝试对非推理模型可能有帮助,但复杂数学仍建议用推理模型
信息抽取可以尝试重复字段要求和格式约束,能减少漏字段
分类任务适合类别定义和输入文本重复后,模型更容易对齐标签
长文档问答谨慎复制长文档会占用上下文窗口,成本高
摘要任务谨慎重复正文可能让模型误判重复内容是语义重点
已经启用深度思考的模型收益不稳定模型自身可能已经会复述和检查题目
上下文接近窗口上限不适合重复可能挤掉关键信息

一个简单判断标准是:如果任务短、答案明确、模型经常漏看条件,可以试试重复;如果任务长、上下文宝贵、重复会让输入翻倍,就不要直接复制全文。


成本和坑

token 成本会上升

复制一遍 Prompt 会让输入 token 接近翻倍。对 API 调用来说,这意味着:

  • 输入费用增加;
  • 首 token 延迟可能上升;
  • 更容易触发上下文长度限制。

短任务里这个成本通常可以接受,长任务里需要谨慎。

重复不等于推理

Prompt 重复能改善模型对题目的编码方式,但它不会让模型真正拥有更强的多步推导能力。遇到复杂证明、长链数学推理、代码调试时,推理模型、工具调用、程序校验仍然更可靠。

不要重复系统指令

system 指令负责定义角色、安全边界和全局规则,一般不要拿来复制。更好的做法是保留 system 指令,只重复 user 里的任务。

推荐:
system: 你是一个严格遵守输出格式的助手。
user: <任务><任务>

不推荐:
system: <系统规则><系统规则>
user: <任务>

重复次数不是越多越好

重复两遍已经能提供“重新读题”的效果。重复三遍、四遍可能继续改变结果,但也会带来更多 token 成本,并且可能让模型把重复本身当成特殊信号。

实际使用时可以做一个小规模 A/B 测试:

版本Prompt 形式观察指标
A原始 Prompt准确率、格式错误率、平均延迟
B重复两遍准确率、格式错误率、平均延迟
C只重复问题和格式准确率、格式错误率、平均延迟

如果 B 或 C 的准确率提升明显,而延迟和成本仍能接受,就可以保留。


一个实用模板

短任务可以直接使用这个模板:

{任务说明}

{输入内容}

{输出要求}

{任务说明}

{输入内容}

{输出要求}

长任务可以使用压缩版本:

背景资料:
{长上下文,只放一次}

任务:
{问题}
{选项或字段}
{输出要求}

请再次确认任务:
{问题}
{选项或字段}
{输出要求}

更适合工程落地的版本是:

def build_prompt(context: str, task: str, repeat_task: bool = True) -> str:
    context = context.strip()
    task = task.strip()

    if repeat_task:
        return f"""背景资料:
{context}

任务:
{task}

请再次按同一任务要求作答:
{task}
"""
    return f"""背景资料:
{context}

任务:
{task}
"""

这种写法不会复制长上下文,只复制真正需要模型反复对齐的任务目标和输出约束。


关键点

Prompt 重复的核心价值不在“复制粘贴”本身,而在于它改变了模型处理输入时的信息位置:第二遍题目里的 token 可以看到第一遍完整题目,从而形成更充分的内部表示。

在非推理模型上,它是一个低门槛、容易测试的技巧。适合短问题、选择题、分类、抽取、格式约束强的任务;不适合无脑复制长文档,也不能替代真正的推理模型。

如果一个非推理模型总是漏看条件、选错选项、输出格式不稳定,可以先试一个最小改动:把任务重复一遍。


评论