Graph of Thoughts diagramProblem, Split, Sort 1, Sort 2, Sort 3, Sort 4, Merge A, Merge B, Final merge, Scorer, Sorted. Step captions follow the diagram.ProblemSplitSort 1Sort 2Sort 3Sort 4Merge AMerge BFinal mergeScorerSortedGraph of Thoughts diagramProblem, Split, Sort 1, Sort 2, Sort 3, Sort 4, Merge A, Merge B, Final merge, Scorer, Sorted. Step captions follow the diagram.ProblemSplitSort 1Sort 2Sort 3Sort 4Merge AMerge BFinal mergeScorerSorted

All steps
Parts of this pattern
Problem Input / output
The task, adapted from the paper's sorting task: sort a list of 32 numbers that contains duplicates.
Split Tool
Plain code: breaks the list into four chunks of 8 numbers, each small enough for the model to sort reliably.
Sort 1 LLM call
One thought: chunk 1 sorted. The same code check as the scorer counts its errors before anything is merged.
Sort 2 LLM call
One thought: chunk 2 sorted. The code check finds its first attempt dropped a number, so it is generated again and the best kept.
Sort 3 LLM call
One thought: chunk 3 sorted, and checked by the same error count.
Sort 4 LLM call
One thought: chunk 4 sorted, and checked by the same error count.
Merge A Aggregator
A model call that merges the sorted chunks 1 and 2 into one sorted list of 16. Two thoughts become one.
Merge B Aggregator
A model call that merges the sorted chunks 3 and 4 into one sorted list of 16.
Final merge Aggregator
Merges the two lists of 16 into all 32 numbers, then refines this one thought while the check still finds errors.
Scorer Evaluator
Plain code: counts numbers out of order or missing against the input. The same check scores every chunk and merge; zero errors passes.
Sorted Input / output
The final sorted list of 32 numbers, returned once the scorer finds no errors.
Problem → Split
The full list goes to the split step.Sort: 5 1 9 3 3 8 0 7 2 6 4 9 1 5 8 2 7 0 3 6 9 4 1 8 2 5 7 0 6 3 4 9
Split → Sort 1
Chunk 1, the first 8 numbers, becomes its own thought.Sort these 8 numbers: 5 1 9 3 3 8 0 7
Split → Sort 2
Chunk 2 becomes its own thought, sorted in parallel with the others.Sort these 8 numbers: 2 6 4 9 1 5 8 2
Split → Sort 3
Chunk 3 becomes its own thought.Sort these 8 numbers: 7 0 3 6 9 4 1 8
Split → Sort 4
Chunk 4 becomes its own thought.Sort these 8 numbers: 2 5 7 0 6 3 4 9
Sort 1 → Merge A
Sorted chunk 1 flows into the first merge.0 1 3 3 5 7 8 9
Sort 2 → Merge A
Sorted chunk 2 flows into the same merge, after it was regenerated to fix a dropped number.1 2 2 4 5 6 8 9
Sort 3 → Merge B
Sorted chunk 3 flows into the second merge.0 1 3 4 6 7 8 9
Sort 4 → Merge B
Sorted chunk 4 flows into the second merge.0 2 3 4 5 6 7 9
Merge A → Final merge
The first list of 16 goes to the final merge.0 1 1 2 2 3 3 4 5 5 6 7 8 8 9 9
Merge B → Final merge
The second list of 16 goes to the final merge.0 0 1 2 3 3 4 4 5 6 6 7 7 8 9 9
Final merge → Scorerscore
The merged list of 32 is checked against the input: every number present, in order.0 0 0 1 1 1 2 2 2 3 3 3 3 4 4 4 5 5 5 6 6 6 7 7 8 8 8 9 9 9 9 (31 numbers)
Scorer → Final mergerefine
The errors go back so the model fixes exactly them in the same thought, rather than starting over.1 error: one 7 is missing (input has three 7s, result has two). Fix exactly this error.
Scorer → Sorted0 errors
When the count of errors is zero, the list leaves the graph.0 0 0 1 1 1 2 2 2 3 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 9 9 9

← → neighboursesc atlas

Planning & Search

Graph of Thoughts

Also known as GoT · Thought graph

Thoughts form a graph, not a tree. Partial results are scored and regenerated, merged many-to-one, and refined until the whole is right.

Introduced by Besta et al. (2023) · ETH Zurich, Warsaw University of Technology and others

Published at AAAI 2024. One of the paper's tasks is sorting numbers with duplicates by sorting sublists and merging them back; the diagram here adapts it to four chunks of 8.

Measured over one run

Nodes
11. Boxes in the diagram: models, tools, stores, people and plain code.
LLM calls
5. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
Tool calls
1. Messages sent to a tool node in the first scenario.
Steps
7. Steps in the first scenario, with repeated steps counted every time they run.
Scenarios
1. Distinct example runs you can switch between on the diagram.
Loop
yes. Whether the flow cycles back on itself until a condition is met.
Parallel
yes. Whether two or more messages are in flight at the same time.
Branch
yes. Whether the flow takes one path out of several, chosen at run time.
Human in the loop
no. Whether a person appears as a node, to approve, correct or answer.
Autonomy
medium. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
Cost
high. Relative token spend per request.
Latency
high. Relative wall-clock time per request.

Counted from the first scenario's timeline when the site is built.

Problem

Ask a model to sort 32 numbers that include duplicates and it will usually hand back something close: a list in order, with a number dropped or one repeated. Long, exact outputs are where single calls fail. The task itself splits naturally: sort small chunks, then merge them. But neither a single prompt nor a search tree can express “take these two partial answers and combine them”. Tree of Thoughts can branch and prune, yet every thought in a tree has exactly one parent.

How it works

Graph of Thoughts, from Besta et al., treats each intermediate result as a node in a graph and lets you wire those nodes together freely. You design the graph in advance, as a list of operations: generate a thought, score it, keep the best, merge several thoughts into one, refine a thought in place. The model fills in the thoughts; your code decides how they connect.

In the sorting example, the problem goes to a split step, plain code, that cuts the list into four chunks of 8. Each chunk becomes its own thought, and Sort 1 to Sort 4 run in parallel. Each result is scored by the same code check the scorer uses, counting errors. Chunk 2 dropped a number, so Sort 2 is generated again, and only that thought; the other three are kept.

Then the graph converges. Merge A takes two sorted chunks and asks the model to combine them into one sorted list of 16; Merge B does the same for the other two. The final merge combines the two lists of 16. This many-to-one step is what a tree cannot draw.

The scorer is plain code. It compares the merged list with the input and counts what is missing or out of order. Here one 7 went missing, so the error goes back to the final merge as a refine step: fix exactly this, change nothing else. The refined list scores zero and goes to the output.

The scores are what make it more than a split-and-join. Every thought can be checked, retried and compared before it feeds the next operation, so one bad chunk does not poison the final answer.

When to use

  • The problem splits into parts whose results must be combined: sorting, set operations, merging several documents, summarising many sources into one.
  • Each partial result can be scored, ideally in code: counted errors, a test, a schema check.
  • A long output is unreliable in one call, but short pieces are reliable.

When to avoid

  • Branching and pruning are enough, with nothing to merge. Use tree of thoughts.
  • The parts are independent and need no scoring or retry. Sectioning is cheaper and simpler.
  • You cannot justify many calls. Four sorts, a retry, three merges and a refine is already at least nine model calls for one list.

Trade-offs

Graph of Thoughts trades call count for accuracy on long, exact outputs. Each model call sees a small, easy piece, so quality goes up, but the number of calls grows with the size of the graph. The graph is also something you must design per task: it is not a general agent loop, and the model does not choose its own operations. In exchange the run is predictable, the operations are easy to log, and independent operations run in parallel, so latency grows with the depth of the graph, not its width.

Failure modes

  • Lossy merges: the merge prompt quietly drops or duplicates items. Score every merge, not only the final result, and merge again when a merge scores badly.
  • No real scorer: if a thought cannot be checked, the retries and the keep-best steps are guesses. Use a code check wherever one exists.
  • Refine drift: a refine pass fixes the reported error and breaks something else. Keep the refined thought only if it scores better.
  • Graph sprawl: a graph with many levels multiplies calls fast. Cap regenerations and refine passes, and count calls per run.

Build it with your AI

Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.

Implement the Graph of Thoughts pattern in this codebase, using the LLM client and language we already use.

## Goal

Solve a task that splits into sub-results by running a fixed graph of model operations (generate, score, merge, refine) over partial thoughts, and return the best final thought.

## How it works

1. Write the graph of operations in code before any model call: which thoughts are generated, how each is scored, which ones are merged together, and where refinement happens. The model fills in thoughts; it never changes the graph.
2. Split the input into parts. Do it in code when the split is mechanical, as for a list of numbers or a set of documents.
3. For each part, call the model with the Part prompt to produce a thought, and score it with a check (in code where possible, such as counting sorting errors). If the score is below the bar, generate it again and keep the best attempt.
4. Merge thoughts as the graph says, two at a time, by calling the model with the Merge prompt. Score each merged thought the same way; if it has errors, merge again and keep the best (default 1 extra attempt).
5. Score the final merged thought. While it still has errors, call the model with the Refine prompt, passing the thought and the errors found, and keep the refined version only if it scores better.
6. Return the best final thought with its score.

## Prompts

### Part prompt

```markdown
Solve this part of a larger task. Work only on the part below.

<task>{{task}}</task>
<part>{{part}}</part>

{{#if previous_errors}}
A previous attempt at this part had these errors. Avoid them:
<errors>{{previous_errors}}</errors>
{{/if}}

Return only the result for this part, in the format: {{format}}
```

### Merge prompt

```markdown
Combine the two partial results below into one result for the task.
Keep everything that is correct in each; do not drop or duplicate items.

<task>{{task}}</task>
<a>{{result_a}}</a>
<b>{{result_b}}</b>

Return only the merged result, in the format: {{format}}
```

### Refine prompt

```markdown
The result below is close, but a check found errors in it.

<task>{{task}}</task>
<result>{{result}}</result>
<errors>{{errors}}</errors>

Fix exactly these errors and change nothing else.
Return only the corrected result, in the format: {{format}}
```

## Stop rule

Stop when the final thought scores perfectly, or after 2 refine passes. If the budget runs out, return the best-scoring final thought with its remaining errors and a status saying it is not clean.

## Requirements

- Keep the graph of operations as data (a list of operations and their inputs), so it can be logged and changed without touching the model calls.
- Cap regenerations per thought (default 2), extra merge attempts per pair (default 1) and refine passes (default 2); log the total number of model calls.
- Prefer a scoring function in code over a model judgement whenever the task allows one; fall back to a model score only for parts that code cannot check.
- Run independent operations, such as the per-part thoughts and the merges at one level, in parallel.
- Add a test with a stub LLM that drops one number from the second chunk on its first try and is correct afterwards; assert the solve prompt was called 5 times for 4 chunks and the output equals the input sorted.

Prompt templates

Part prompt
Solve this part of a larger task. Work only on the part below.
<task>{{task}}</task>
<part>{{part}}</part>
{{#if previous_errors}}
A previous attempt at this part had these errors. Avoid them:
<errors>{{previous_errors}}</errors>
{{/if}}
Return only the result for this part, in the format: {{format}}
Merge prompt
Combine the two partial results below into one result for the task.
Keep everything that is correct in each; do not drop or duplicate items.
<task>{{task}}</task>
<a>{{result_a}}</a>
<b>{{result_b}}</b>
Return only the merged result, in the format: {{format}}
Refine prompt
The result below is close, but a check found errors in it.
<task>{{task}}</task>
<result>{{result}}</result>
<errors>{{errors}}</errors>
Fix exactly these errors and change nothing else.
Return only the corrected result, in the format: {{format}}

Related patterns

Composes well with:

Sources

  1. Graph of Thoughts: Solving Elaborate Problems with Large Language Models (Besta et al., 2023)

From the Agentic Atlas by Joran Kikke · Edit on GitHub · Suggest a correction