Разработка ИИ-агентов · Модуль 1 · Урок 1.7

Extended thinking: режим рассуждения и tool-цикл

Что такое расширенное мышление

У современных моделей есть режим extended thinking (он же reasoning / «размышление»): прежде чем дать ответ или запросить инструмент, модель генерирует отдельный блок рассуждения — черновик мыслей, который не является финальным ответом. Это как дать модели «черновик», где она раскладывает задачу на шаги, проверяет себя и только потом действует.

Важно: thinking — это не то же самое, что просто попросить «думай пошагово» в промпте. Это отдельный режим API: модель выделяет на размышление заданный бюджет токенов, а сам блок мыслей возвращается отдельно от ответа. Детали (имя поля, заголовки, формат блоков) версионно-зависимы — сверяйтесь с актуальными доками провайдера.

Как thinking встраивается в агентный цикл

Цикл из урока 1.4 почти не меняется — добавляется один нюанс. На каждом ходу модель может сначала выдать thinking-блок, затем либо финальный ответ, либо запрос инструментов (tool_use). Ваш код:

  • читает thinking как отдельную часть ответа (можно показать пользователю «ход мыслей» или скрыть);
  • по-прежнему смотрит на стоп-сигнал, чтобы понять — это финал или нужен инструмент;
  • при дозаписи истории сохраняет порядок блоков так, как требует провайдер (часто thinking нужно вернуть обратно вместе с tool-результатами, иначе следующий ход «забывает» рассуждение).

Главная мысль: thinking улучшает качество выбора следующего шага в сложных задачах (многошаговое планирование, математика, отладка), потому что модель «думает» до того, как зафиксирует действие.

Бюджет размышления и стоимость

За размышление вы платите: thinking-токены тарифицируются как вывод (обычно дороже ввода). Поэтому у режима есть бюджет — сколько токенов модели разрешено потратить на мысли. Больше бюджет → глубже рассуждение, но выше цена и задержка.

Практическое правило: thinking оправдан для сложных задач, где цена ошибки высока, а число шагов заранее неясно (планирование, анализ, многошаговая отладка). Для простых задач (классификация, короткий ответ, очевидный вызов одного инструмента) он лишний — добавит стоимость и латентность без выигрыша. Включайте его осознанно, как и любой другой рычаг стоимости (подробнее — в продвинутом курсе, глава про стоимость и латентность).

Один ход цикла с extended thinking
flowchart LR
  M{{LLM}} --> TH["thinking-блок (черновик мыслей)"]
  TH --> D{Стоп-сигнал?}
  D -->|tool_use| T["Выполнить инструмент"]
  T --> M
  D -->|end_turn| A["Финальный ответ"]
Включение thinking и разбор ответа (схематично; поля сверяйте с доками)
// Запрос с включённым режимом размышления. Имена полей и формат блоков
// зависят от провайдера и версии SDK — СВЕРЯЙТЕСЬ С АКТУАЛЬНЫМИ ДОКАМИ.
type ThinkingConfig struct {
    Enabled      bool
    BudgetTokens int // сколько токенов разрешаем на размышление
}

type Reply struct {
    Thinking   string     // черновик мыслей (можно показать или скрыть)
    Text       string     // финальный ответ (если есть)
    ToolCalls  []ToolCall // запрошенные инструменты (если есть)
    StopReason string     // "end_turn" | "tool_use" | ...
}

func step(messages []Message, tools []Tool, think ThinkingConfig) (Reply, error) {
    // callLLM проставляет режим thinking в теле запроса, если think.Enabled.
    return callLLM(messages, tools, think)
}

func runWithThinking(messages []Message, tools []Tool) (string, error) {
    think := ThinkingConfig{Enabled: true, BudgetTokens: 2000} // только для сложных задач
    for turn := 0; turn < 12; turn++ { // safety-cap из урока 1.4
        r, err := step(messages, tools, think)
        if err != nil {
            return "", err
        }
        if r.Thinking != "" {
            log.Printf("ход %d, размышление: %s", turn, r.Thinking) // для отладки/прозрачности
        }
        if r.StopReason == "end_turn" {
            return r.Text, nil
        }
        // Важно: вернуть ассистентский ход (включая thinking, если того требует
        // провайдер) и результаты инструментов — иначе следующий ход «забудет» мысль.
        messages = append(messages, assistantMessage(r))
        messages = append(messages, runTools(r.ToolCalls)...)
    }
    return "", fmt.Errorf("превышен safety-cap")
}

Anti-patterns

Анти-паттернПочему плохоКак правильно
Включать thinking всегдаЛишние токены и задержка на простых задачахВключать только для сложных/многошаговых задач
Путать thinking с «думай пошагово» в промптеЭто разные механизмы; ожидания не совпадутИспользовать режим API, а текстовый CoT — отдельно
Не возвращать thinking-блок в историюСледующий ход теряет контекст рассужденияДозаписывать ход модели так, как требует провайдер
Бесконечный бюджет размышленияНеконтролируемая стоимость и латентностьЗадавать budget_tokens под сложность задачи
Показывать сырые мысли как финальный ответthinking — черновик, не ответ пользователюБрать ответ из финального блока, мысли — опционально/для отладки

Практическое задание

  • Возьмите задачу с неочевидным планом (например, «составь маршрут из 3 пересадок по условиям») и прогоните агента без thinking.
  • Включите режим thinking с небольшим бюджетом (например, 1–2k токенов) и сравните качество и число шагов.
  • Залогируйте thinking-блок отдельно от ответа; убедитесь, что финальный ответ берётся не из мыслей.
  • Проверьте, что при дозаписи истории рассуждение сохраняется так, как требует ваш провайдер (иначе цикл «забывает» план).
  • Прогоните простую задачу (классификация) с thinking и без — сравните стоимость и латентность, сделайте вывод, когда он не нужен.

Проверка знаний

Чем extended thinking отличается от инструкции «думай пошагово» в промпте?

  • A Ничем, это синонимы
  • B Это отдельный режим API с выделенным бюджетом токенов на размышление; блок мыслей возвращается отдельно от ответа
  • C Thinking работает только без инструментов
  • D Thinking бесплатен, а CoT в промпте — нет

Команда включила thinking для всех запросов агента, в том числе для простой классификации писем по 5 категориям. Счёт вырос, скорость упала.

Что разумнее сделать?

  • A Оставить как есть — thinking всегда полезен
  • B Отключить thinking для простых задач и включать только там, где план неочевиден и цена ошибки высока
  • C Увеличить бюджет размышления
  • D Перейти на модель побольше

Почему важно сохранять thinking-блок при дозаписи истории (если того требует провайдер)?

  • A Иначе ответ не отрендерится в UI
  • B Чтобы следующий ход модели не потерял ход рассуждения и согласованность плана
  • C Это уменьшает стоимость запроса
  • D Без этого инструменты не выполнятся