Diagram of Thought (DoT)

[object Object]

Diagram of Thought (DoT, «диаграмма мыслей») — reasoning pattern, в котором рассуждение строится как directed acyclic graph, а не линейная цепочка или дерево. В 2026 его полезно понимать не как "красивую визуальную метафору", а как critique-oriented graph pattern для задач, где ценность даёт не просто ветвление, а явный цикл proposal -> criticism -> refinement.

Представьте совещание, где один человек предлагает идею (Proposer), второй задаёт каверзные вопросы и указывает на слабые места (Critic), а третий подводит итог обсуждения (Summarizer). В Diagram of Thought модель играет все три роли сама: предлагает мысль, тут же критикует её, уточняет — и так строит «карту рассуждений», где каждая мысль связана с предыдущими стрелками «вытекает из», «уточняет» или «опровергает».

Суть в двух словах

Модель строит DAG из мыслей трёх типов: предложения (P), критика (C) и уточнения (R). В отличие от Chain of Thought, где мысли идут строго по порядку, в DoT модель может вернуться к любому узлу графа, раскритиковать его и предложить улучшенную версию — всё в рамках одного промпта.

ПромптClaude
Реши задачу методом Diagram of Thought (DoT).

Задача: Компания хочет сократить расходы на 20%. Сейчас основные статьи: зарплаты (60%), аренда (20%), маркетинг (15%), прочее (5%).

Используй три роли:
- [Proposer]: предложи идею
- [Critic]: найди слабые места в предложении
- [Summarizer]: обобщи, когда накопится достаточно проверенных идей

Каждая мысль — узел графа. Указывай связи: «уточняет P1», «критикует P2» и т.д.
Ответ модели

P1 [Proposer]: Сократить маркетинговый бюджет на 50% — это даст 7.5% экономии.

C1 [Critic] → критикует P1: Сокращение маркетинга вдвое может обрушить продажи. Нужно оценить ROI каналов — урезать только неэффективные.

P2 [Proposer] → уточняет P1 с учётом C1: Провести аудит маркетинговых каналов. Убрать каналы с ROI < 1.5, сохранить остальные. Ожидаемая экономия: 5-8%.

P3 [Proposer]: Перевести часть команды на удалёнку, сократить офисные площади на 40%. Экономия: 8% от общих расходов.

C2 [Critic] → критикует P3: Аренда — долгосрочный контракт. Досрочное расторжение может стоить 3-6 месяцев аренды. Нужно проверить условия.

P4 [Proposer] → уточняет P3 с учётом C2: Не расторгать аренду, а субарендовать освободившиеся площади. Это снижает риск штрафов и даёт экономию 4-6%.

C3 [Critic] → критикует P2 + P4: P2 (5-8%) + P4 (4-6%) = 9-14%. Не достигаем цели в 20%. Нужен ещё один источник экономии.

P5 [Proposer]: Автоматизировать рутинные процессы (отчётность, поддержка L1) через AI. Ожидаемая экономия: 5-8% от ФОТ = 3-5% от общих расходов.

C4 [Critic] → критикует P5: Внедрение AI требует начальных инвестиций (3-6 мес. окупаемость). В первый год чистая экономия будет меньше.

P6 [Proposer] → уточняет P5 с учётом C4: Начать с наименее рискованной автоматизации (отчётность, шаблонные ответы). Инвестиции: 2 мес. внедрение, окупаемость через 4 мес. Чистая экономия за год: 2-3%.

[Summarizer] → обобщает P2, P4, P6: Проверенный план экономии 20%:

  1. Аудит маркетинга, отказ от каналов с ROI < 1.5 → 5-8%
  2. Субаренда освободившихся офисных площадей → 4-6%
  3. Поэтапная AI-автоматизация рутины → 2-3%
  4. Пересмотр SaaS-подписок и vendor-контрактов → 3-5% Итого: 14-22%, целевые 20% достижимы.
DoT особенно полезен для задач, где важно взвесить аргументы за и против: стратегические решения, анализ рисков, дебаты, этические дилеммы. Если задача имеет единственный правильный ответ (математика, код) — Cumulative Reasoning или Self-Consistency будут эффективнее.

Как работает Diagram of Thought

Три роли в одном промпте

Сравнение подходов: цепочка, дерево, граф

CoT / ToT (линейное / ветвящееся)
CoT: A → B → C → D (линейно, нет возврата) ToT: A → B1/B2/B3 → C1/C2 → D (ветвление, но без критики) Ошибка на шаге B распространяется дальше Нет механизма самокоррекции внутри цепочки
DoT (DAG с критикой)
P1 → C1 (критика P1) → P2 (уточнение P1) P3 → C2 (критика P3) → P4 (уточнение P3) C3 критикует P2+P4 → P5 (новая идея) Summarizer объединяет P2, P4, P5 в ответ Ошибки отсекаются критикой, а не накапливаются
ХарактеристикаCoTToTDoT
СтруктураЛинейная цепочкаДеревоDAG
СамокритикаНетНет (оценка путей, но не критика)Да, встроенная
Возврат к шагамНетЧастичный (backtracking)Полный (любой узел)
Число вызовов API1Десятки (BFS/DFS)1 (всё в одном промпте)
Подходит дляПростое рассуждениеПоисковые задачиАналитика, дебаты, решения

Преимущества и ограничения

Плюсы

  • Самокритика встроена в рассуждение — модель сама находит и исправляет ошибки
  • Один промпт — не нужна внешняя оркестрация, в отличие от ToT и Cumulative Reasoning
  • DAG-структура позволяет связывать мысли нелинейно — как реальное мышление
  • Гибкость: подходит для открытых задач без единственного правильного ответа
  • Прозрачность: весь ход рассуждения виден в виде графа с явными связями

Минусы

  • Требует сильных моделей — слабые модели плохо играют роль Critic
  • Длинный вывод: DAG с критикой занимает больше токенов, чем линейный CoT
  • Модель может быть слишком мягким критиком самой себя
  • Нет формальных бенчмарков на стандартных датасетах (в отличие от CoT, ToT)
  • Сложнее парсить — нужно извлекать структуру графа из текста

Эффективность DoT по сравнению с другими техниками

Число API-вызовов для решения одной задачи
CoT1%
DoT1%
Self-Refine4%
Cumulative Reasoning15%
ToT (BFS)25%

Где DoT реально полезен

Техника уместна там, где:

  • одна цепочка reasoning слишком хрупкая;
  • нужна встроенная критика без полноценного multi-agent runtime;
  • задача открытая и допускает competing interpretations;
  • итог должен рождаться из нескольких проверенных идей, а не из первого удачного хода.

Это хороший fit для:

  • strategy memos;
  • policy analysis;
  • debate-like reasoning;
  • design tradeoff discussions.

Но для задач с одним легко проверяемым ответом DoT часто избыточен: там проще работают ToT, verification или solver-backed workflows.

Главная слабость DoT — модель в роли Critic может быть слишком лояльной к собственным идеям. Чтобы повысить качество критики, добавьте в промпт явную инструкцию: «Ищи минимум одну слабость в каждом предложении. Если не нашёл — ищи снова. Будь скептиком, а не оптимистом». Также помогает фраза «Представь, что ты оппонент на защите диссертации».
ПромптChatGPT
Метод: Diagram of Thought (DoT).

Задача: Стоит ли стартапу из 5 человек переходить с монолита на микросервисы?

Роли:
- [P] Proposer: предложи аргумент
- [C] Critic: найди слабость
- [R] уточнение после критики
- [S] Summarizer: обобщи

Строй DAG — указывай связи между узлами.
Ответ модели

P1: Микросервисы дают независимый деплой — каждый разработчик может деплоить свой сервис отдельно.

C1 → критикует P1: В команде из 5 человек каждый и так знает весь код. Независимый деплой экономит секунды, но добавляет сложность оркестрации (Docker, K8s, service mesh). Для 5 человек это overhead.

P2: Микросервисы позволяют масштабировать только нагруженные части системы.

C2 → критикует P2: Стартапу из 5 человек обычно рано думать о масштабировании. Premature optimization. Монолит на одном сервере справится с первыми 10K пользователей.

R1 → уточняет P1 + P2 с учётом C1 + C2: Микросервисы имеют смысл для команды 5 человек только если продукт уже в продакшене с высокой нагрузкой и чётко выделенными доменами. Для MVP — однозначно монолит.

P3: Монолит проще тестировать, дебажить и онбордить новых разработчиков.

C3 → критикует P3: Это верно для маленького монолита. Но если монолит уже 200K строк с запутанными зависимостями — тестирование и дебаг тоже страдают.

R2 → уточняет P3 с учётом C3: Ключевой фактор — не архитектура, а качество кода. Чистый монолит с модульной структурой лучше плохих микросервисов.

P4: Компромисс: модульный монолит (monolith with clear module boundaries), готовый к будущему разделению.

C4 → критикует P4: Разумно, но требует дисциплины. Без code review и архитектурных границ модульный монолит быстро превращается в big ball of mud.

[S] Summarizer → обобщает R1, R2, P4, C4:

Вердикт: НЕ переходить на микросервисы.

Рекомендация:

  1. Оставить монолит, но сделать его модульным (чёткие границы между доменами)
  2. Добавить code review для контроля архитектурных границ
  3. Пересмотреть решение при достижении 15+ разработчиков или явных проблем с масштабированием
  4. Если один компонент критически нагружен — вынести только его в отдельный сервис

Техническая реализация

DoT-промпт с ролевой системой

from openai import OpenAI

client = OpenAI()

DOT_SYSTEM_PROMPT = """Ты решаешь задачи методом Diagram of Thought (DoT).

Строй рассуждение как направленный ациклический граф (DAG).
Каждая мысль — узел графа одного из трёх типов:

- [P] Proposer: предлагает новую идею, гипотезу или аргумент
- [C] Critic: критикует конкретный узел — ищет ошибки, слабые места, пропущенные факторы
- [S] Summarizer: обобщает проверенные мысли в финальный ответ

Правила:
1. Нумеруй узлы: P1, P2, C1, C2, S1 и т.д.
2. Указывай связи: "C1 → критикует P1", "P3 → уточняет P1 с учётом C1"
3. Critic ОБЯЗАН найти минимум одну слабость в каждом предложении
4. После критики Proposer уточняет идею или предлагает новую
5. Summarizer работает только когда накоплено достаточно проверенных мыслей
6. Финальный ответ Summarizer опирается только на мысли, прошедшие критику"""


def solve_with_dot(task: str, model: str = "gpt-4o") -> str:
    """Решает задачу методом Diagram of Thought в одном вызове."""
    response = client.chat.completions.create(
        model=model,
        messages=[
            {"role": "system", "content": DOT_SYSTEM_PROMPT},
            {"role": "user", "content": task}
        ],
        temperature=0.7,
        max_tokens=4096
    )
    return response.choices[0].message.content


# Пример
result = solve_with_dot(
    "Компания рассматривает переход с REST API на GraphQL. "
    "Команда: 8 backend-разработчиков, 4 frontend. "
    "Текущий API: 120 эндпоинтов, 15 мобильных клиентов. "
    "Оцени целесообразность перехода."
)
print(result)

Парсинг DAG из ответа модели

import re
from dataclasses import dataclass, field


@dataclass
class DotNode:
    """Узел DAG в Diagram of Thought."""
    id: str               # "P1", "C2", "S1"
    role: str             # "proposer", "critic", "summarizer"
    content: str          # текст мысли
    links_to: list[str] = field(default_factory=list)  # ID связанных узлов


def parse_dot_response(text: str) -> list[DotNode]:
    """Извлекает DAG-структуру из текстового ответа модели."""
    nodes: list[DotNode] = []

    # Паттерн: **P1 [Proposer]:** или **C2 [Critic] → критикует P1:**
    pattern = re.compile(
        r"\*?\*?\[?([PCS])(\d+)\]?\*?\*?"   # тип и номер узла
        r".*?(?:→\s*(?:критикует|уточняет)\s+"
        r"([PC]\d+(?:\s*\+\s*[PC]\d+)*))?"  # связи (опционально)
        r".*?:\s*(.+?)(?=\n\*?\*?\[?[PCS]\d|\Z)",  # содержимое
        re.DOTALL
    )

    role_map = {"P": "proposer", "C": "critic", "S": "summarizer"}

    for match in pattern.finditer(text):
        node_type, node_num, links_raw, content = match.groups()
        node_id = f"{node_type}{node_num}"

        links = []
        if links_raw:
            links = re.findall(r"[PC]\d+", links_raw)

        nodes.append(DotNode(
            id=node_id,
            role=role_map[node_type],
            content=content.strip(),
            links_to=links
        ))

    return nodes


def print_dag(nodes: list[DotNode]) -> None:
    """Визуализирует DAG в текстовом виде."""
    for node in nodes:
        prefix = {"proposer": "💡", "critic": "🔍", "summarizer": "📋"}
        links = f" → {', '.join(node.links_to)}" if node.links_to else ""
        print(f"{prefix[node.role]} {node.id}{links}: {node.content[:80]}...")

Итеративный DoT с несколькими раундами

def iterative_dot(
    task: str,
    model: str = "gpt-4o",
    max_rounds: int = 3
) -> dict:
    """Итеративный DoT: несколько раундов критики и уточнения.

    Раунд 1: начальные предложения + критика.
    Раунд 2+: Summarizer обобщает, Critic находит пробелы,
    Proposer дополняет.
    """
    messages = [
        {"role": "system", "content": DOT_SYSTEM_PROMPT},
        {"role": "user", "content": task}
    ]

    all_rounds = []

    for round_num in range(max_rounds):
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            temperature=0.7,
            max_tokens=4096
        )
        answer = response.choices[0].message.content
        all_rounds.append(answer)
        messages.append({"role": "assistant", "content": answer})

        # Проверяем, есть ли Summarizer в ответе
        if re.search(r"\[S\w*\].*Summarizer", answer, re.IGNORECASE):
            # Просим Critic проверить Summarizer
            messages.append({
                "role": "user",
                "content": (
                    "Теперь выступи как Critic: проверь вывод Summarizer. "
                    "Все ли аргументы учтены? Нет ли логических ошибок? "
                    "Если есть проблемы — уточни. Если всё корректно — "
                    "выведи финальный ответ с пометкой [FINAL]."
                )
            })
        else:
            messages.append({
                "role": "user",
                "content": (
                    "Продолжи рассуждение. Добавь Critic для непроверенных "
                    "предложений и Summarizer, если достаточно данных."
                )
            })

        # Если в ответе есть [FINAL] — завершаем
        if "[FINAL]" in answer:
            break

    return {
        "rounds": len(all_rounds),
        "final": all_rounds[-1],
        "full_dag": "\n\n---\n\n".join(all_rounds)
    }


# Пример
result = iterative_dot(
    "Оцени риски внедрения LLM в клиентский support-чат банка. "
    "Учти: регуляторику (152-ФЗ), галлюцинации, стоимость, "
    "удовлетворённость клиентов.",
    max_rounds=3
)

print(f"Раундов: {result['rounds']}")
print(result["final"])
  1. Critic соглашается со всем — модель в роли критика часто говорит «всё верно». Решение: в системном промпте явно требуйте «найди минимум одну слабость» и «будь скептиком».
  2. DAG вырождается в список — модель нумерует мысли, но не создаёт связи между ними. Решение: добавьте в промпт пример с явными связями (P3 → уточняет P1 с учётом C1).
  3. Summarizer игнорирует критику — обобщает все предложения, включая раскритикованные. Решение: инструкция «Summarizer учитывает только мысли, которые прошли критику или были уточнены после неё».
  4. Переизбыток узлов — модель генерирует 20+ узлов, теряя фокус. Ограничьте: «Максимум 10 узлов. Качество важнее количества».

Проверьте себя

Проверьте себя

1. Чем DoT отличается от Tree of Thoughts (ToT)?

2. Какие три роли используются в Diagram of Thought?

3. Для каких задач DoT подходит лучше всего?