Low-level orchestration framework for building stateful, multi-actor applications with LLMs
Complete working examples of common workflow patterns.
import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
const State = Annotation.Root({
data: Annotation<string>,
extracted: Annotation<any>(),
transformed: Annotation<any>(),
loaded: Annotation<boolean>()
});
// Extract
const extract = (state: typeof State.State) => ({
extracted: parseData(state.data)
});
// Transform
const transform = (state: typeof State.State) => ({
transformed: normalizeData(state.extracted)
});
// Load
const load = (state: typeof State.State) => {
saveToDatabase(state.transformed);
return { loaded: true };
};
const graph = new StateGraph(State)
.addNode("extract", extract)
.addNode("transform", transform)
.addNode("load", load)
.addEdge(START, "extract")
.addEdge("extract", "transform")
.addEdge("transform", "load")
.addEdge("load", END)
.compile();
const result = await graph.invoke({ data: rawData });const State = Annotation.Root({
value: Annotation<number>,
result: Annotation<string>()
});
const router = (state: typeof State.State) => {
if (state.value > 100) return "high";
if (state.value > 50) return "medium";
return "low";
};
const graph = new StateGraph(State)
.addNode("classify", (s) => s)
.addNode("high", (s) => ({ result: "High value processing" }))
.addNode("medium", (s) => ({ result: "Medium value processing" }))
.addNode("low", (s) => ({ result: "Low value processing" }))
.addEdge(START, "classify")
.addConditionalEdges("classify", router, {
high: "high",
medium: "medium",
low: "low"
})
.addEdge("high", END)
.addEdge("medium", END)
.addEdge("low", END)
.compile();
const result = await graph.invoke({ value: 75 });
// { value: 75, result: "Medium value processing" }const State = Annotation.Root({
input: Annotation<string>,
resultA: Annotation<string>(),
resultB: Annotation<string>(),
resultC: Annotation<string>(),
combined: Annotation<string>()
});
const taskA = (state: typeof State.State) => ({
resultA: `A: ${state.input}`
});
const taskB = (state: typeof State.State) => ({
resultB: `B: ${state.input}`
});
const taskC = (state: typeof State.State) => ({
resultC: `C: ${state.input}`
});
const combine = (state: typeof State.State) => ({
combined: [state.resultA, state.resultB, state.resultC].join(", ")
});
const graph = new StateGraph(State)
.addNode("taskA", taskA)
.addNode("taskB", taskB)
.addNode("taskC", taskC)
.addNode("combine", combine)
.addEdge(START, "taskA")
.addEdge(START, "taskB")
.addEdge(START, "taskC")
.addEdge("taskA", "combine")
.addEdge("taskB", "combine")
.addEdge("taskC", "combine")
.addEdge("combine", END)
.compile();const State = Annotation.Root({
count: Annotation<number>({ default: () => 0 }),
maxIterations: Annotation<number>({ default: () => 5 }),
results: Annotation<string[]>({
reducer: (a, b) => a.concat(b),
default: () => []
})
});
const shouldContinue = (state: typeof State.State) => {
return state.count < state.maxIterations ? "process" : END;
};
const process = (state: typeof State.State) => ({
count: state.count + 1,
results: [`Iteration ${state.count + 1}`]
});
const graph = new StateGraph(State)
.addNode("process", process)
.addEdge(START, "process")
.addConditionalEdges("process", shouldContinue, {
process: "process"
})
.compile();
const result = await graph.invoke({ maxIterations: 3 });
// { count: 3, maxIterations: 3, results: ["Iteration 1", "Iteration 2", "Iteration 3"] }See: Common Patterns for more workflow patterns.