CoT Decoding в 2026: inference-time search trick, где reasoning-path извлекается через альтернативные варианты декодирования, а не через wording промпта.
Chain-of-Thought Decoding (CoT-Decoding) — метод, позволяющий извлечь reasoning path из модели без специального prompting. В 2026 его полезно понимать как inference-time search trick: вы меняете не формулировку запроса, а сам способ декодирования, чтобы найти путь генерации, который запускает более качественное рассуждение.
Представьте, что вы спрашиваете у эрудита: «Какая столица Австралии?» Он мгновенно отвечает: «Сидней». Но если попросить его чуть задуматься, он скажет: «Подожди... Сидней — крупнейший город, но столица — Канберра». Ответ всегда был у него в голове — просто первая реакция «на автомате» вела не по тому пути. CoT-Decoding делает то же самое с моделью: вместо первого «автоматического» слова проверяет альтернативные начала ответа — и находит те, что запускают правильное рассуждение.
Когда языковая модель генерирует текст, она на каждом шаге выбирает наиболее вероятный токен — это называется greedy decoding (жадное декодирование). Проблема в том, что самый вероятный первый токен часто ведёт к короткому, поверхностному ответу без рассуждений.
CoT-Decoding предлагает простую идею: посмотреть на альтернативные варианты первого токена (top-k). Оказывается, среди них часто находятся токены, которые запускают полноценную цепочку рассуждений — и приводят к правильному ответу.
Модель уже «знает», как рассуждать. Просто greedy decoding выбирает не тот путь.
Greedy decoding (стандартный)
Вопрос: Если у Джона 3 яблока, он купил ещё 5, отдал 2, сколько осталось?
Модель сразу выбирает первый токен: «6»
Ответ: 6
Один токен, никакого рассуждения.
Greedy-путь — самый вероятный, но поверхностный.
CoT-Decoding (top-k альтернативы)
Вопрос: Если у Джона 3 яблока, он купил ещё 5, отдал 2, сколько осталось?
Модель рассматривает top-k первых токенов:
k=0: «6» → 6 (без рассуждения)
k=1: «У» → «У Джона было 3, +5=8, -2=6. Ответ: 6»
k=2: «Дав» → «Давайте посчитаем: 3+5=8, 8-2=6»
Выбираем путь с наивысшей уверенностью → 6 (с рассуждением)
Ключевая идея: CoT-промптинг заставляет модель рассуждать «извне» — через формулировку промпта. CoT-Decoding раскрывает рассуждения, которые уже заложены «внутри» модели, — через анализ альтернативных путей генерации.
CoT-Decoding доказывает, что способность к рассуждению — это внутреннее свойство предобученных моделей, а не навык, привнесённый промптингом. Модель всегда «умела» рассуждать — greedy decoding просто не давал ей этого сделать.
Стандартная генерация текста работает так: на каждом шаге модель вычисляет вероятности всех возможных следующих токенов и выбирает самый вероятный. Это называется greedy decoding — жадный алгоритм.
Проблема: для многих задач самый вероятный первый токен — это сразу ответ (число, «Да», «Нет»), без какого-либо рассуждения. Модель «знает» правильный формат: вопрос → короткий ответ. Но этот путь часто ведёт к ошибкам на задачах, требующих логики.
Wang и Zhou из Google DeepMind обнаружили закономерность: если вместо самого вероятного первого токена взять альтернативные варианты (2-й, 3-й, 5-й по вероятности), многие из них естественно запускают цепочку рассуждений.
Например, для математической задачи:
Top-1 токен: «8» → модель сразу выдаёт число (часто неверное)
Top-3 токен: «Давайте» → модель продолжает: «Давайте разберёмся шаг за шагом...» и приходит к правильному ответу
Top-5 токен: «Сначала» → модель рассуждает: «Сначала найдём...»
Модель уже обучена на текстах с рассуждениями, поэтому альтернативные пути декодирования часто содержат CoT-паттерны.
Промпт: «Думай шаг за шагом. Задача: ...»
Модель: генерирует рассуждения по инструкции.
+ Работает с любой моделью через API
+ Не требует доступа к logprobs
- Удлиняет промпт, тратит входные токены
- Качество зависит от формулировки
- Требует prompt engineering
CoT через декодирование
Промпт: «Задача: ...» (никаких инструкций)
Модель: исследуются top-k первых токенов,
находятся пути с рассуждениями.
+ Не нужен специальный промпт
+ Рассуждения — собственные, не навязанные
- Требует доступа к logprobs / top-k
- Вычислительно дороже (k генераций)
- Не всегда доступно через API
Главная находка авторов — метрика для автоматического выбора лучшего пути. Для каждого сгенерированного пути вычисляется:
Decoding confidence = разница (дельта) между логарифмической вероятностью топ-1 токена ответа и топ-2 токена ответа на финальной позиции.
Интуиция: если модель после рассуждений очень уверена в одном конкретном ответе (большой разрыв с альтернативами), значит, рассуждения были полезными и ответ, скорее всего, правильный.
Не требует prompt engineering — рассуждения извлекаются из модели как есть
Может превосходить CoT-промптинг — модель использует собственные, а не навязанные паттерны рассуждений
Доказывает наличие скрытых способностей — помогает понять, что модель реально знает
Применимо к любой задаче — не нужно подбирать формулировку промпта
Минусы
Требует k генераций вместо одной — вычислительные затраты растут линейно
Нужен доступ к logprobs — не все API его предоставляют
Не работает через стандартный чат-интерфейс — нужен программный доступ
Latency: время ответа увеличивается в k раз без параллелизации
CoT-Decoding — исследовательский метод, а не продуктовая техника. На практике он требует доступа к logprobs и top-k токенам через API, а также k-кратного увеличения вычислений. Для большинства задач стандартный CoT-промптинг проще и дешевле. CoT-Decoding особенно полезен для исследования возможностей модели и для задач, где prompt engineering не даёт результатов.
CoT-Decoding можно реализовать через API, поддерживающие logprobs. OpenAI API возвращает top_logprobs — вероятности альтернативных токенов на каждой позиции.
from openai import OpenAI
import math
client = OpenAI()
def cot_decoding(
question: str,
k: int = 10,
model: str = "gpt-4o",
max_tokens: int = 512,
) -> dict:
"""
CoT-Decoding: генерация k альтернативных путей
и выбор наиболее уверенного.
1. Получаем top-k первых токенов через logprobs
2. Для каждого токена генерируем полный ответ
3. Оцениваем уверенность каждого пути
4. Возвращаем путь с максимальной уверенностью
"""
# Шаг 1: получить top-k первых токенов
first_token_response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": question}],
max_tokens=1,
logprobs=True,
top_logprobs=k,
)
top_tokens = (
first_token_response
.choices[0]
.logprobs
.content[0]
.top_logprobs
)
# Шаг 2: для каждого первого токена сгенерировать
# полный ответ
paths = []
for token_info in top_tokens:
prefix = token_info.token
prefix_logprob = token_info.logprob
# Генерируем продолжение, начиная с этого
# токена, через assistant prefill
response = client.chat.completions.create(
model=model,
messages=[
{"role": "user", "content": question},
{
"role": "assistant",
"content": prefix,
},
],
max_tokens=max_tokens,
logprobs=True,
top_logprobs=5,
temperature=0,
)
choice = response.choices[0]
full_text = prefix + (choice.message.content or "")
# Шаг 3: вычислить уверенность пути
confidence = compute_path_confidence(choice)
paths.append({
"first_token": prefix,
"first_token_logprob": prefix_logprob,
"full_text": full_text,
"confidence": confidence,
})
# Шаг 4: выбрать путь с максимальной уверенностью
best = max(paths, key=lambda p: p["confidence"])
return {
"answer": best["full_text"],
"confidence": best["confidence"],
"paths_explored": len(paths),
"all_paths": paths,
}
def compute_path_confidence(choice) -> float:
"""
Метрика уверенности пути.
Считаем среднюю дельту между top-1 и top-2
логарифмическими вероятностями по всем токенам.
Высокая дельта = модель уверена в каждом токене.
"""
if not choice.logprobs or not choice.logprobs.content:
return 0.0
deltas = []
for token_lp in choice.logprobs.content:
top = token_lp.top_logprobs
if len(top) >= 2:
delta = top[0].logprob - top[1].logprob
deltas.append(delta)
return sum(deltas) / len(deltas) if deltas else 0.0
# Пример использования
result = cot_decoding(
"Джон купил 3 пакета яблок по 4 штуки в каждом. "
"Он отдал 5 яблок другу. Сколько яблок осталось?"
)
print(f"Ответ: {result['answer']}")
print(f"Уверенность: {result['confidence']:.3f}")
print(f"Путей исследовано: {result['paths_explored']}")
Anthropic API не возвращает logprobs напрямую, но можно использовать подход с принудительным префиксом (assistant prefill) для исследования альтернативных путей:
import anthropic
client = anthropic.Anthropic()
# Типичные CoT-стартеры, которые запускают
# рассуждения в моделях
COT_PREFIXES = [
"", # без префикса (baseline)
"Давайте разберёмся", # русский CoT-стартер
"Для решения", # русский CoT-стартер
"Let me think", # английский CoT-стартер
"Step 1:", # пошаговый стартер
"First,", # последовательный стартер
]
def cot_decoding_anthropic(
question: str,
prefixes: list[str] = COT_PREFIXES,
model: str = "claude-sonnet-4-20250514",
max_tokens: int = 1024,
) -> dict:
"""
CoT-Decoding для Claude через assistant prefill.
Вместо top-k токенов используем заранее
определённые CoT-стартеры.
"""
paths = []
for prefix in prefixes:
messages = [{"role": "user", "content": question}]
# Используем assistant prefill, если есть
# префикс
if prefix:
messages.append({
"role": "assistant",
"content": prefix,
})
response = client.messages.create(
model=model,
max_tokens=max_tokens,
messages=messages,
temperature=0,
)
full_text = prefix + response.content[0].text
# Эвристика уверенности: длина рассуждений
# коррелирует с качеством ответа
has_reasoning = any(
marker in full_text.lower()
for marker in [
"шаг", "step", "значит", "итого",
"получаем", "therefore", "thus",
"сначала", "во-первых",
]
)
paths.append({
"prefix": prefix or "(greedy)",
"full_text": full_text,
"has_reasoning": has_reasoning,
"length": len(full_text),
})
# Предпочитаем пути с рассуждениями
reasoning_paths = [p for p in paths if p["has_reasoning"]]
best = (
max(reasoning_paths, key=lambda p: p["length"])
if reasoning_paths
else paths[0]
)
return {
"answer": best["full_text"],
"prefix_used": best["prefix"],
"has_reasoning": best["has_reasoning"],
"paths_explored": len(paths),
}
В оригинальной статье ключевая метрика — уверенность именно в финальном ответе (а не во всей цепочке):
import re
def extract_final_answer(text: str) -> str | None:
"""Извлечь финальный числовой ответ из текста."""
patterns = [
r"(?:ответ|answer)[:\s]*(\d+[\.,]?\d*)",
r"(?:итого|total|=)\s*(\d+[\.,]?\d*)",
r"(\d+[\.,]?\d*)\s*$",
]
for pattern in patterns:
match = re.search(pattern, text, re.IGNORECASE)
if match:
return match.group(1).replace(",", ".")
return None
def cot_decoding_with_voting(
question: str,
k: int = 10,
model: str = "gpt-4o",
) -> dict:
"""
CoT-Decoding с голосованием по ответам.
Комбинирует CoT-Decoding с Self-Consistency:
- Генерируем k путей через top-k
- Извлекаем финальный ответ из каждого
- Взвешиваем ответы по confidence
- Выбираем ответ с максимальным взвешенным счётом
"""
result = cot_decoding(question, k=k, model=model)
paths = result["all_paths"]
# Группируем по ответам с взвешиванием
answer_scores: dict[str, float] = {}
answer_paths: dict[str, list] = {}
for path in paths:
answer = extract_final_answer(path["full_text"])
if answer is None:
continue
weight = max(path["confidence"], 0.01)
if answer not in answer_scores:
answer_scores[answer] = 0
answer_paths[answer] = []
answer_scores[answer] += weight
answer_paths[answer].append(path)
if not answer_scores:
return result
best_answer = max(
answer_scores, key=answer_scores.get
)
return {
"answer": best_answer,
"total_confidence": answer_scores[best_answer],
"votes": len(answer_paths[best_answer]),
"all_answers": answer_scores,
"best_path": answer_paths[best_answer][0],
}
Не все API поддерживают logprobs. OpenAI API — да (logprobs=True, top_logprobs=5). Anthropic API — нет. Для Claude используйте подход с assistant prefill.
Токен != слово. Top-k токенов — это не top-k слов. Токен может быть частью слова ("Дав", "айте"), и prefix continuation может сломать грамматику.
Стоимость растёт линейно. k=10 означает 10 вызовов API. Для GPT-4o при 500 выходных токенов это ~$0.05 за один вопрос. Используйте k=3-5 для баланса цена/качество.
Temperature=0 обязательна. При temperature > 0 greedy decoding нарушается, и результаты становятся нестабильными. CoT-Decoding работает с детерминированной генерацией.