Rethinking with Retrieval (RwR, переосмысление через поиск) — техника, которая верифицирует каждый шаг цепочки рассуждений через поиск по внешним знаниям. Модель рассуждает пошагово как в обычном CoT, но после каждого шага система находит подтверждающее или опровергающее свидетельство из базы знаний.
В 2026 году RwR удобнее понимать как verification pattern поверх reasoning, а не как просто ещё один вид RAG. Его сильная сторона не в том, что он “добавляет контекст”, а в том, что он навязывает промежуточным шагам дисциплину проверки до того, как они начнут влиять на следующие выводы.
Представьте журналиста, который пишет статью. Обычный подход: написать текст из головы и отправить в печать. RwR — это как если бы редактор после каждого абзаца останавливался, проверял факты через справочники и источники, и только после подтверждения переходил к следующему абзацу. Итоговая статья — фактологически выверена, а не основана на догадках.
Обычный Chain of Thought (CoT) генерирует всю цепочку рассуждений за раз. Модель опирается на внутренние знания, которые могут быть неточными — особенно в деталях: датах, числах, именах. Ошибка на раннем шаге каскадирует через все последующие.
Rethinking with Retrieval добавляет фактчекинг:
Модель генерирует шаг рассуждения (CoT step)
По этому шагу формируется поисковый запрос
Из базы знаний (Wikipedia, документация, корпоративная БЗ) извлекается evidence
Evidence подтверждает или опровергает шаг — если опровергает, шаг корректируется
Только верифицированный шаг используется для дальнейшего рассуждения
ПромптClaude
Ответь на вопрос, рассуждая пошагово. После каждого шага проверяй свои утверждения через поиск.
Вопрос: Кто написал роман, по которому снят фильм «Бегущий по лезвию»? Какие ещё экранизации произведений этого автора существуют?
Шаг 1 (рассуждение): Фильм «Бегущий по лезвию» (Blade Runner, 1982) снят по роману.
[Поиск: 'Blade Runner фильм 1982 первоисточник роман']
[Найдено: Фильм основан на романе Филипа К. Дика «Мечтают ли андроиды об электроовцах?» (1968)]
Шаг 1 (верифицирован): Фильм снят по роману Филипа К. Дика «Мечтают ли андроиды об электроовцах?» (1968). Подтверждено.
Шаг 2 (рассуждение): Другие экранизации Дика — «Вспомнить всё» и «Особое мнение».
[Поиск: 'экранизации произведений Филип Дик список']
[Найдено: Более 10 экранизаций: Total Recall (1990, 2012), Minority Report (2002), A Scanner Darkly (2006), The Man in the High Castle (сериал, 2015-2019), The Adjustment Bureau (2011), Next (2007).]
Шаг 2 (уточнён): Экранизаций значительно больше двух. Помимо «Вспомнить всё» и «Особого мнения» — «Помутнение» (2006), «Человек в высоком замке» (2015-2019), «Меняющие реальность» (2011), «Пророк» (2007) и другие.
Итог: Роман написал Филип К. Дик. Его экранизации включают «Вспомнить всё», «Особое мнение», «Помутнение», «Человек в высоком замке» и ряд других фильмов и сериалов.
Ответ модели
RwR выявил неполноту на шаге 2: модель назвала только 2 экранизации из 10+. Поиск расширил ответ. Без RwR ответ был бы формально верным, но неполным — типичная проблема CoT на фактоёмких вопросах.
RwR (He et al., 2023) и RAT (Wang et al., 2024) решают схожую задачу — retrieval на каждом шаге CoT. Ключевое отличие: RwR фокусируется на верификации (подтвердить или опровергнуть шаг), а RAT — на ревизии (переписать шаг с учётом найденного). RwR ближе к фактчекингу, RAT — к итеративному уточнению.
Шаг 1: Кофе изобрели в Бразилии в XVII веке.
Шаг 2: Бразилия стала крупнейшим экспортёром.
Шаг 3: Поэтому бразильский кофе считается эталоном.
Итог: Содержит галлюцинацию — кофе открыт в Эфиопии, не в Бразилии. Все выводы построены на ложной предпосылке.
Rethinking with Retrieval
Шаг 1: Кофе изобрели в Бразилии.
[Evidence: Кофе обнаружен в Эфиопии (IX-XV вв.), привезён в Бразилию в 1727 г.]
Шаг 1 (исправлен): Кофе открыт в Эфиопии, привезён в Бразилию в XVIII в.
Шаг 2: Бразилия стала крупнейшим производителем.
[Evidence: С XIX века — да, крупнейший в мире.]
Итог: Факты верны, каждый шаг подтверждён источником.
Точность RwR vs базовых методов на фактоёмких задачах (%)
RwR — CommonsenseQA81%
CoT — CommonsenseQA73%
RwR — StrategyQA72%
CoT — StrategyQA65%
RwR — TempQA68%
CoT — TempQA57%
RwR показывает наибольший прирост на задачах, где:
Ответ зависит от конкретных фактов, которые модель может не знать или путать
Требуется multi-hop reasoning — связывание нескольких фактов в цепочку
Ошибка в одном факте каскадирует и портит весь вывод
ПромптChatGPT
Используй Rethinking with Retrieval для ответа:
Вопрос: Верно ли, что автор «Мастера и Маргариты» родился в Киеве, а умер в Москве?
Шаг 1 (рассуждение): Автор «Мастера и Маргариты» — Михаил Булгаков.
[Поиск: 'автор Мастер и Маргарита']
[Evidence: Роман написан Михаилом Афанасьевичем Булгаковым, работа над ним велась в 1928-1940 гг.]
Шаг 1: Подтверждено. Автор — Булгаков.
Шаг 2 (рассуждение): Булгаков родился в Киеве.
[Поиск: 'Михаил Булгаков место рождения']
[Evidence: Булгаков родился 3 (15) мая 1891 года в Киеве.]
Шаг 2: Подтверждено. Родился в Киеве.
Шаг 3 (рассуждение): Булгаков умер в Москве.
[Поиск: 'Михаил Булгаков дата и место смерти']
[Evidence: Умер 10 марта 1940 года в Москве от гипертонического нефросклероза.]
Шаг 3: Подтверждено. Умер в Москве.
Итог: Да, утверждение верно. Булгаков родился в Киеве (1891), умер в Москве (1940). Все три факта подтверждены через поиск.
Ответ модели
Каждый факт проверен отдельно: авторство, место рождения, место смерти. Модель не полагалась на внутренние знания — каждое утверждение подкреплено evidence. Даже на «простом» вопросе это гарантирует точность.
Задачи без фактологии: математические вычисления, формальная логика, генерация кода — retrieval не даст полезного evidence.
Отсутствие базы знаний: если информация нигде не задокументирована, верифицировать нечем.
Субъективные вопросы: «Какой язык программирования лучший?» — нет однозначного evidence.
Жёсткие ограничения latency: каждый шаг — это дополнительный retrieval + LLM-вызов.
Если RAT больше похож на iterative revision, то RwR ближе к reasoning quality control. В современных системах его имеет смысл использовать как слой промежуточной верификации:
до финального ответа
до tool execution
до передачи шага следующему агенту или маршруту
То есть RwR хорошо встраивается в trace-first пайплайны, где важно не просто получить ответ, а понимать, какие промежуточные утверждения были проверены и где система изменила курс.
нужно не просто найти факты, а проверить уже сформулированный шаг
регуляторные, policy или compliance-вопросы требуют evidence-backed reasoning
downstream action зависит от корректности промежуточного вывода
вам нужен audit trail: какое утверждение было проверено, чем и с каким вердиктом
В этих сценариях RwR часто полезнее, чем “более умная модель”, потому что проблема не в силе reasoning как таковой, а в отсутствии дисциплины промежуточной проверки.
RwR не стоит тащить в каждый маршрут. Обычно лучше остановиться и не применять его, если:
шаг не формулируется как проверяемый claim
evidence регулярно не находит ничего лучше, чем исходная догадка модели
latency budget меньше, чем цена нескольких retrieval-итераций
Практическое правило простое: если шаг можно однозначно проверить через источник, RwR полезен. Если шаг в основном интерпретационный или генеративный, verification layer быстро превращается в дорогую формальность.
from openai import OpenAI
from dataclasses import dataclass
client = OpenAI()
@dataclass
class VerificationResult:
"""Результат верификации одного шага."""
original_step: str
evidence: list[str]
verdict: str # "confirmed", "corrected", "unverified"
corrected_step: str
COT_PROMPT = """Разбей ответ на вопрос на отдельные шаги рассуждения.
Каждый шаг должен содержать одно конкретное, проверяемое утверждение.
Вопрос: {question}
Формат:
Step 1: ...
Step 2: ...
Step N: ..."""
QUERY_PROMPT = """Сформулируй поисковый запрос для проверки этого утверждения.
Запрос должен быть коротким, конкретным и содержать ключевые сущности.
Утверждение: {step}
Верни только поисковый запрос, ничего больше."""
VERIFY_PROMPT = """Сопоставь утверждение с найденным evidence.
Утверждение: {step}
Evidence:
{evidence}
Предыдущие верифицированные шаги:
{previous_steps}
Определи:
1. Утверждение ПОДТВЕРЖДЕНО, ОПРОВЕРГНУТО или НЕЛЬЗЯ ПРОВЕРИТЬ?
2. Если опровергнуто — дай исправленную версию.
Формат ответа:
VERDICT: confirmed | corrected | unverified
CORRECTED: <исправленное утверждение или "N/A">"""
FINAL_PROMPT = """Сформулируй финальный ответ на основе верифицированных шагов.
Вопрос: {question}
Верифицированные шаги:
{steps}
Дай точный, фактологически верный ответ."""
def generate_cot_steps(question: str) -> list[str]:
"""Шаг 1: генерация CoT."""
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": COT_PROMPT.format(
question=question
)}],
temperature=0,
)
lines = response.choices[0].message.content.strip().split("\n")
steps = []
for line in lines:
line = line.strip()
if line.lower().startswith("step"):
step = line.split(":", 1)[1].strip() if ":" in line else line
steps.append(step)
return steps
def formulate_query(step: str) -> str:
"""Шаг 2: формирование поискового запроса."""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": QUERY_PROMPT.format(
step=step
)}],
temperature=0,
)
return response.choices[0].message.content.strip()
def retrieve_evidence(query: str, retriever) -> list[str]:
"""Шаг 3: retrieval из базы знаний.
retriever — любая функция str -> list[str]:
- BM25 по Wikipedia
- Vector search (Qdrant, Chroma)
- Web search API (Tavily, Exa)
"""
return retriever(query)
def verify_step(
step: str,
evidence: list[str],
previous_steps: list[str]
) -> VerificationResult:
"""Шаг 4: верификация с учётом evidence."""
evidence_text = "\n---\n".join(evidence) if evidence else "(нет evidence)"
prev_text = "\n".join(
f" {i+1}. {s}" for i, s in enumerate(previous_steps)
) or "(нет)"
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": VERIFY_PROMPT.format(
step=step,
evidence=evidence_text,
previous_steps=prev_text,
)}],
temperature=0,
)
content = response.choices[0].message.content.strip()
# Парсинг ответа
verdict = "unverified"
corrected = step
for line in content.split("\n"):
line = line.strip()
if line.startswith("VERDICT:"):
v = line.split(":", 1)[1].strip().lower()
if v in ("confirmed", "corrected", "unverified"):
verdict = v
elif line.startswith("CORRECTED:"):
c = line.split(":", 1)[1].strip()
if c != "N/A":
corrected = c
return VerificationResult(
original_step=step,
evidence=evidence,
verdict=verdict,
corrected_step=corrected if verdict == "corrected" else step,
)
def rethinking_with_retrieval(
question: str,
retriever, # Callable[[str], list[str]]
top_k: int = 3,
) -> dict:
"""Полный пайплайн Rethinking with Retrieval."""
# 1. Генерация CoT
steps = generate_cot_steps(question)
# 2-4. Для каждого шага: query -> retrieve -> verify
verified_steps: list[str] = []
verification_log: list[VerificationResult] = []
for step in steps:
query = formulate_query(step)
evidence = retrieve_evidence(query, retriever)[:top_k]
result = verify_step(step, evidence, verified_steps)
verification_log.append(result)
verified_steps.append(result.corrected_step)
# 5. Финальный ответ
steps_text = "\n".join(
f" {i+1}. [{v.verdict}] {v.corrected_step}"
for i, v in enumerate(verification_log)
)
final = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": FINAL_PROMPT.format(
question=question,
steps=steps_text,
)}],
temperature=0,
)
return {
"answer": final.choices[0].message.content.strip(),
"steps": [
{
"original": v.original_step,
"corrected": v.corrected_step,
"verdict": v.verdict,
"evidence_count": len(v.evidence),
}
for v in verification_log
],
"total_steps": len(steps),
"corrected_count": sum(
1 for v in verification_log if v.verdict == "corrected"
),
}
# — Пример с BM25 retriever ---
# pip install rank-bm25
from rank_bm25 import BM25Okapi
def build_bm25_retriever(corpus: list[str]):
"""Простой BM25 retriever по корпусу текстов."""
tokenized = [doc.lower().split() for doc in corpus]
bm25 = BM25Okapi(tokenized)
def search(query: str, k: int = 3) -> list[str]:
scores = bm25.get_scores(query.lower().split())
top_indices = sorted(
range(len(scores)), key=lambda i: scores[i], reverse=True
)[:k]
return [corpus[i] for i in top_indices if scores[i] > 0]
return search
# Пример использования
knowledge_base = [
"Санкт-Петербург основан 27 мая 1703 года Петром I.",
"Санкт-Петербург был столицей Российской империи с 1712 по 1918 год.",
"Население Санкт-Петербурга — около 5.6 млн человек (2024).",
"Эрмитаж — один из крупнейших музеев мира, основан в 1764 году.",
"Московский Кремль построен в XV веке при Иване III.",
]
retriever = build_bm25_retriever(knowledge_base)
result = rethinking_with_retrieval(
question="Когда был основан Санкт-Петербург и кем?",
retriever=retriever,
)
print(result["answer"])
print(f"Исправлено шагов: {result['corrected_count']}/{result['total_steps']}")
Где N — число шагов, S — число пропущенных (модель уверена в шаге). На практике 30-40% шагов не требуют верификации, если модель обладает надёжными знаниями в предметной области.
Слишком общие поисковые запросы — шаг «анализируем контекст» порождает бесполезный поиск. Решение: добавьте промпт для переформулирования шага в конкретный запрос с ключевыми сущностями.
Слепое доверие evidence — не все найденные документы корректны. Добавьте scoring релевантности: если top-1 результат имеет низкий score, лучше отметить шаг как unverified, чем «подтверждать» нерелевантным текстом.
Retriever не покрывает предметную область — если в базе знаний нет информации о теме вопроса, RwR деградирует до обычного CoT. Решение: используйте web search как fallback, когда vector search не даёт результатов с высоким score.
Излишняя гранулярность шагов — если CoT разбит на 15 микрошагов, retrieval на каждом становится избыточным. Оптимально: 3-7 шагов, каждый содержит одно проверяемое утверждение.