import { StateGraph, StateSchema, START } from "@langchain/langgraph";import * as z from "zod";const SubgraphState = new StateSchema({ bar: z.string(),});// Subgraphconst subgraphBuilder = new StateGraph(SubgraphState) .addNode("subgraphNode1", (state) => { return { bar: "hi! " + state.bar }; }) .addEdge(START, "subgraphNode1");const subgraph = subgraphBuilder.compile();// Parent graphconst State = new StateSchema({ foo: z.string(),});// Transform the state to the subgraph state and backconst builder = new StateGraph(State) .addNode("node1", async (state) => { const subgraphOutput = await subgraph.invoke({ bar: state.foo }); return { foo: subgraphOutput.bar }; }) .addEdge(START, "node1");const graph = builder.compile();
Full example: different state schemas
Copy
import { StateGraph, StateSchema, START } from "@langchain/langgraph";import * as z from "zod";// Define subgraphconst SubgraphState = new StateSchema({ // note that none of these keys are shared with the parent graph state bar: z.string(), baz: z.string(),});const subgraphBuilder = new StateGraph(SubgraphState) .addNode("subgraphNode1", (state) => { return { baz: "baz" }; }) .addNode("subgraphNode2", (state) => { return { bar: state.bar + state.baz }; }) .addEdge(START, "subgraphNode1") .addEdge("subgraphNode1", "subgraphNode2");const subgraph = subgraphBuilder.compile();// Define parent graphconst ParentState = new StateSchema({ foo: z.string(),});const builder = new StateGraph(ParentState) .addNode("node1", (state) => { return { foo: "hi! " + state.foo }; }) .addNode("node2", async (state) => { const response = await subgraph.invoke({ bar: state.foo }); return { foo: response.bar }; }) .addEdge(START, "node1") .addEdge("node1", "node2");const graph = builder.compile();for await (const chunk of await graph.stream( { foo: "foo" }, { subgraphs: true })) { console.log(chunk);}
import { StateGraph, StateSchema, START } from "@langchain/langgraph";import * as z from "zod";const State = new StateSchema({ foo: z.string(),});// Subgraphconst subgraphBuilder = new StateGraph(State) .addNode("subgraphNode1", (state) => { return { foo: "hi! " + state.foo }; }) .addEdge(START, "subgraphNode1");const subgraph = subgraphBuilder.compile();// Parent graphconst builder = new StateGraph(State) .addNode("node1", subgraph) .addEdge(START, "node1");const graph = builder.compile();
Full example: shared state schemas
Copy
import { StateGraph, StateSchema, START } from "@langchain/langgraph";import * as z from "zod";// Define subgraphconst SubgraphState = new StateSchema({ foo: z.string(), bar: z.string(),});const subgraphBuilder = new StateGraph(SubgraphState) .addNode("subgraphNode1", (state) => { return { bar: "bar" }; }) .addNode("subgraphNode2", (state) => { // note that this node is using a state key ('bar') that is only available in the subgraph // and is sending update on the shared state key ('foo') return { foo: state.foo + state.bar }; }) .addEdge(START, "subgraphNode1") .addEdge("subgraphNode1", "subgraphNode2");const subgraph = subgraphBuilder.compile();// Define parent graphconst ParentState = new StateSchema({ foo: z.string(),});const builder = new StateGraph(ParentState) .addNode("node1", (state) => { return { foo: "hi! " + state.foo }; }) .addNode("node2", subgraph) .addEdge(START, "node1") .addEdge("node1", "node2");const graph = builder.compile();for await (const chunk of await graph.stream({ foo: "foo" })) { console.log(chunk);}
import { createAgent, tool, toolCallLimitMiddleware } from "langchain";import { MemorySaver, Command, interrupt } from "@langchain/langgraph";import * as z from "zod";const fruitInfo = tool( (input) => `Info about ${input.fruitName}`, { name: "fruit_info", description: "Look up fruit info.", schema: z.object({ fruitName: z.string() }), });// Subagent with checkpointer=true for persistent stateconst fruitAgent = createAgent({ model: "gpt-4.1-mini", tools: [fruitInfo], prompt: "You are a fruit expert. Use the fruit_info tool. Respond in one sentence.", checkpointer: true,});// Wrap subagent as a tool for the outer agentconst askFruitExpert = tool( async (input) => { const response = await fruitAgent.invoke({ messages: [{ role: "user", content: input.question }], }); return response.messages[response.messages.length - 1].content; }, { name: "ask_fruit_expert", description: "Ask the fruit expert. Use for ALL fruit questions.", schema: z.object({ question: z.string() }), });// Outer agent with checkpointer// Use toolCallLimitMiddleware to prevent parallel calls to stateful subagents,// which would cause checkpoint conflicts.const agent = createAgent({ model: "gpt-4.1-mini", tools: [askFruitExpert], prompt: "You have a fruit expert. ALWAYS delegate fruit questions to ask_fruit_expert.", middleware: [ toolCallLimitMiddleware({ toolName: "ask_fruit_expert", runLimit: 1 }), ], checkpointer: new MemorySaver(),});
for await (const chunk of await graph.stream( { foo: "foo" }, { subgraphs: true, streamMode: "updates", })) { console.log(chunk);}
设置 subgraphs: true 以从子图流式传输输出。
Stream from subgraphs
Copy
import { StateGraph, StateSchema, START } from "@langchain/langgraph";import * as z from "zod";// Define subgraphconst SubgraphState = new StateSchema({ foo: z.string(), bar: z.string(),});const subgraphBuilder = new StateGraph(SubgraphState) .addNode("subgraphNode1", (state) => { return { bar: "bar" }; }) .addNode("subgraphNode2", (state) => { // note that this node is using a state key ('bar') that is only available in the subgraph // and is sending update on the shared state key ('foo') return { foo: state.foo + state.bar }; }) .addEdge(START, "subgraphNode1") .addEdge("subgraphNode1", "subgraphNode2");const subgraph = subgraphBuilder.compile();// Define parent graphconst ParentState = new StateSchema({ foo: z.string(),});const builder = new StateGraph(ParentState) .addNode("node1", (state) => { return { foo: "hi! " + state.foo }; }) .addNode("node2", subgraph) .addEdge(START, "node1") .addEdge("node1", "node2");const graph = builder.compile();for await (const chunk of await graph.stream( { foo: "foo" }, { streamMode: "updates", subgraphs: true, })) { console.log(chunk);}