跳转至

LLM Compiler: Compile A Task Into A Dependency Graph

Some tasks are not simple chains and not fully independent batches. A travel report may need city background first, then route suggestions based on it, then a final report.

You need to know what can run in parallel and what must wait.

LLM Compiler asks the model to produce a task graph, then executes by dependency.

One Sentence

LLM Compiler turns sequential execution into a dependency DAG plus scheduler, so independent subtasks do not wait on each other.

What Breaks Without It

Problem What it looks like Risk
Everything runs serially Simple Independent work is slow
Everything runs in parallel Fast Dependencies are missing
Dependencies live in prose Flexible Python cannot schedule or audit

What This Pattern Changes

Who Owns
Compiler model Creates task nodes, deps, final instruction
Python scheduler Executes by dependency
Worker model/tool Runs each task
Final step Combines dependency results

Walk Through One Trace

Node Dependencies Output
t1: Write X none X
t2: Write Y t1 Y (using X)
final t1, t2 Final: X + Y

Flow

flowchart TD
  T["Task"] --> C["Compile DAG"]
  C --> A["t1: no deps"]
  A --> B["t2: depends on t1"]
  A --> F["final"]
  B --> F
  F --> O["Final answer"]

Code Walk

The model first returns a task graph:

model = MockLLM(
    [
        '{"tasks":[{"id":"t1","instruction":"Write X","deps":[]},{"id":"t2","instruction":"Write Y","deps":["t1"]}],"final":{"instruction":"Combine t1 and t2"}}',
        "X",
        "Y (using X)",
        "Final: X + Y",
    ]
)

Full example:

from __future__ import annotations

from pathlib import Path

from agent_patterns_lab.patterns.llm_compiler import llm_compiler
from agent_patterns_lab.runtime import MockLLM, Tracer


def main() -> None:
    tracer = Tracer()
    model = MockLLM(
        [
            '{"tasks":[{"id":"t1","instruction":"Write X","deps":[]},{"id":"t2","instruction":"Write Y","deps":["t1"]}],"final":{"instruction":"Combine t1 and t2"}}',
            "X",
            "Y (using X)",
            "Final: X + Y",
        ]
    )

    out = llm_compiler(model, task="Produce X then Y, then combine.", tracer=tracer)
    print(out)

    trace_path = tracer.export_jsonl(Path(".traces") / "53_llm_compiler.jsonl")
    print(f"[trace] {trace_path}")


if __name__ == "__main__":
    main()

Run:

UV_CACHE_DIR=.uv_cache PYTHONPATH=src uv run --no-sync python examples/53_llm_compiler.py

Nearby Patterns

Pattern Who decides next Use when
Prompt Chaining Python fixes linear steps Order is known
ReWOO Plan a batch of tool calls Calls are mostly independent
LLM Compiler Model creates dependency graph Dependencies and parallelism both matter
Manager-Worker Manager delegates dynamically Task types emerge at runtime

When To Use It

  • Subtasks have clear dependencies.
  • Some work can run in parallel.
  • You want scheduler control.
  • The DAG can be structurally validated.

When Not To Use It

  • The task is short.
  • Dependencies are unclear.
  • The model often writes wrong plans.
  • Dynamic expert delegation is a better fit.

Costs And Common Failures

Failure Symptom Fix
Wrong deps Downstream lacks upstream result Validate DAG and cycles
Tiny nodes Scheduling overhead dominates Merge small tasks
Final loses info Merge omits node output Include all dependency results
Hard debugging Unknown broken node Trace node id, deps, output

LLM Compiler fits task graphs, not all planning.

For simple plan-then-execute, read Plan & Solve. For dynamic expert delegation, read Manager-Worker.

References