Token导航 LogoToken导航TokenDH.com
开发需要联网github未标认证来源可访问许可证需确认审计通过

langgraph-fundamentals语言图基础知识

Agent Skill

langgraph-fundamentals 用于记录任务执行中的错误、用户纠正、经验和能力缺口,适合在 Codex、Claude、Cursor、Gemini CLI 中希望让 Agent 持续沉淀问题、修正和最佳实践时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

144,336

周安装

6,208

GitHub Stars

638

下载量

50,592
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:langgraph-fundamentals(语言图基础知识)
来源仓库:https://github.com/langchain-ai/langchain-skills
仓库路径:skills/langgraph-fundamentals
安装命令:
npx skills add https://github.com/langchain-ai/langchain-skills --skill langgraph-fundamentals
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/langchain-ai/langchain-skills --skill langgraph-fundamentals

简介

用于构建具有细粒度控制的有状态、多步骤代理工作流程的定向图框架。

  • 具有类型化状态模式的 StateGraph、用于累积列表/值的缩减器以及返回部分状态更新的节点
  • 用于固定流的静态边、用于分支的条件边以及用于将状态更新与动态路由相结合的命令
  • 将用于扇出并行性的 API 发送到工作节点,并通过减速器进行结果聚合
  • 调用单次执行和流模式(值、更新、消息、自定义)以进行实时监控和令牌流
  • 用于瞬时错误的 RetryPolicy 和用于 LLM 可恢复故障的错误处理的 ToolNode;通过中断进行用户输入的人机交互

SKILL.md

  • StateGraph: Main class for building stateful graphs
  • Nodes: Functions that perform work and update state
  • Edges: Define execution order (static or conditional)
  • START/END: Special nodes marking entry and exit points
  • State with Reducers: Control how state updates are merged

Graphs must be compile()d before execution.

Designing a LangGraph application

Follow these 5 steps when building a new graph:

  1. Map out discrete steps — sketch a flowchart of your workflow. Each step becomes a node.
  2. Identify what each step does — categorize nodes: LLM step, data step, action step, or user input step. For each, determine static context (prompt), dynamic context (from state), retry strategy, and desired outcome.
  3. Design your state — state is shared memory for all nodes. Store raw data, format prompts on-demand inside nodes.
  4. Build your nodes — implement each step as a function that takes state and returns partial updates.
  5. Wire it together — connect nodes with edges, add conditional routing, compile with a checkpointer if needed.
Use LangGraph WhenUse Alternatives When
Need fine-grained control over agent orchestrationQuick prototyping → LangChain agents
Building complex workflows with branching/loopsSimple stateless workflows → LangChain direct
Require human-in-the-loop, persistenceBatteries-included features → Deep Agents

State Management

NeedSolutionExample
Overwrite valueNo reducer (default)Simple fields like counters
Append to listReducer (operator.add / concat)Message history, logs
Custom logicCustom reducer functionComplex merging

class State(TypedDict): name: str # Default: overwrites on update messages: Annotated[list, operator.add] # Appends to list total: Annotated[int, operator.add] # Sums integers

</python>
<typescript>
Use StateSchema with ReducedValue for accumulating arrays.

import { StateSchema, ReducedValue, MessagesValue } from "@langchain/langgraph"; import { z } from "zod";

const State = new StateSchema({ name: z.string(), // Default: overwrites messages: MessagesValue, // Built-in for messages items: new ReducedValue( z.array(z.string()).default(() => []), { reducer: (current, update) => current.concat(update) } ), });


# Node 1 returns: {"messages": ["A"]}

# Node 2 returns: {"messages": ["B"]}

# Final: {"messages": ["B"]} # "A" is LOST!

# CORRECT: Use Annotated with operator.add

from typing import Annotated import operator

class State(TypedDict): messages: Annotated[list, operator.add]

# Final: {"messages": ["A", "B"]}

</python> <typescript> Without ReducedValue, arrays are overwritten not appended.

// WRONG: Array will be overwritten
const State = new StateSchema({
  items: z.array(z.string()),  // No reducer!
});
// Node 1: { items: ["A"] }, Node 2: { items: ["B"] }
// Final: { items: ["B"] }  // A is lost!

// CORRECT: Use ReducedValue
const State = new StateSchema({
  items: new ReducedValue(
    z.array(z.string()).default(() => []),
    { reducer: (current, update) => current.concat(update) }
  ),
});
// Final: { items: ["A", "B"] }

CORRECT: Return dict with only the updates

def my_node(state: State) -> dict: return {"field": "updated"}

</python>
<typescript>
Return partial updates only, not the full state object.

// WRONG: Returning entire state const myNode = async (state: typeof State.State) => { state.field = "updated"; return state; // Don't do this! };

// CORRECT: Return partial updates const myNode = async (state: typeof State.State) => { return { field: "updated" }; };


---

## Nodes

Node functions accept these arguments:

| Signature | When to Use |
| --- | --- |
| `def node(state: State)` | Simple nodes that only need state |
| `def node(state: State, config: RunnableConfig)` | Need thread_id, tags, or configurable values |
| `def node(state: State, runtime: Runtime[Context])` | Need runtime context, store, or stream_writer |

from langchain_core.runnables import RunnableConfig from langgraph.runtime import Runtime

def plain_node(state: State): return {"results": "done"}

def node_with_config(state: State, config: RunnableConfig): thread_id = config["configurable"]["thread_id"] return {"results": f"Thread: {thread_id}"}

def node_with_runtime(state: State, runtime: Runtime[Context]): user_id = runtime.context.user_id return {"results": f"User: {user_id}"}


| Signature | When to Use |
| --- | --- |
| `(state) => {...}` | Simple nodes that only need state |
| `(state, config) => {...}` | Need thread_id, tags, or configurable values |

import { GraphNode, StateSchema } from "@langchain/langgraph";

const plainNode: GraphNode<typeof State> = (state) => { return { results: "done" }; };

const nodeWithConfig: GraphNode<typeof State> = (state, config) => { const threadId = config?.configurable?.thread_id; return { results: Thread: ${threadId} }; };


---

## Edges

| Need | Edge Type | When to Use |
| --- | --- | --- |
| Always go to same node | `add_edge()` | Fixed, deterministic flow |
| Route based on state | `add_conditional_edges()` | Dynamic branching |
| Update state AND route | `Command` | Combine logic in single node |
| Fan-out to multiple nodes | `Send` | Parallel processing with dynamic inputs |

class State(TypedDict): input: str output: str

def process_input(state: State) -> dict: return {"output": f"Processed: {state['input']}"}

def finalize(state: State) -> dict: return {"output": state["output"].upper()}

graph = (StateGraph(State).add_node("process", process_input).add_node("finalize", finalize).add_edge(START, "process").add_edge("process", "finalize").add_edge("finalize", END).compile())

result = graph.invoke({"input": "hello"}) print(result["output"]) # "PROCESSED: HELLO"

</python> <typescript> Chain nodes with addEdge and compile before invoking.

import { StateGraph, StateSchema, START, END } from "@langchain/langgraph";
import { z } from "zod";

const State = new StateSchema({
  input: z.string(),
  output: z.string().default(""),
});

const processInput = async (state: typeof State.State) => {
  return { output: `Processed: ${state.input}` };
};

const finalize = async (state: typeof State.State) => {
  return { output: state.output.toUpperCase() };
};

const graph = new StateGraph(State)
  .addNode("process", processInput)
  .addNode("finalize", finalize)
  .addEdge(START, "process")
  .addEdge("process", "finalize")
  .addEdge("finalize", END)
  .compile();

const result = await graph.invoke({ input: "hello" });
console.log(result.output);  // "PROCESSED: HELLO"

class State(TypedDict): query: str route: str result: str

def classify(state: State) -> dict: if "weather" in state["query"].lower(): return {"route": "weather"} return {"route": "general"}

def route_query(state: State) -> Literal["weather", "general"]: return state["route"]

graph = (StateGraph(State).add_node("classify", classify).add_node("weather", lambda s: {"result": "Sunny, 72F"}).add_node("general", lambda s: {"result": "General response"}).add_edge(START, "classify").add_conditional_edges("classify", route_query, ["weather", "general"]).add_edge("weather", END).add_edge("general", END).compile())

</python>
<typescript>
addConditionalEdges routes based on function return value.

import { StateGraph, StateSchema, START, END } from "@langchain/langgraph"; import { z } from "zod";

const State = new StateSchema({ query: z.string(), route: z.string().default(""), result: z.string().default(""), });

const classify = async (state: typeof State.State) => { if (state.query.toLowerCase().includes("weather")) { return { route: "weather" }; } return { route: "general" }; };

const routeQuery = (state: typeof State.State) => state.route;

const graph = new StateGraph(State) .addNode("classify", classify) .addNode("weather", async () => ({ result: "Sunny, 72F" })) .addNode("general", async () => ({ result: "General response" })) .addEdge(START, "classify") .addConditionalEdges("classify", routeQuery, ["weather", "general"]) .addEdge("weather", END) .addEdge("general", END) .compile();


---

## Command

Command combines state updates and routing in a single return value. Fields:

- **`update`**: State updates to apply (like returning a dict from a node)
- **`goto`**: Node name(s) to navigate to next
- **`resume`**: Value to resume after `interrupt()` — see human-in-the-loop skill

class State(TypedDict): count: int result: str

def node_a(state: State) -> Command[Literal["node_b", "node_c"]]: """Update state AND decide next node in one return.""" new_count = state["count"] + 1 if new_count > 5: return Command(update={"count": new_count}, goto="node_c") return Command(update={"count": new_count}, goto="node_b")

graph = (StateGraph(State).add_node("node_a", node_a).add_node("node_b", lambda s: {"result": "B"}).add_node("node_c", lambda s: {"result": "C"}).add_edge(START, "node_a").add_edge("node_b", END).add_edge("node_c", END).compile())

</python> <typescript> Return Command with update and goto to combine state change with routing.

import { StateGraph, StateSchema, START, END, Command } from "@langchain/langgraph";
import { z } from "zod";

const State = new StateSchema({
  count: z.number().default(0),
  result: z.string().default(""),
});

const nodeA = async (state: typeof State.State) => {
  const newCount = state.count + 1;
  if (newCount > 5) {
    return new Command({ update: { count: newCount }, goto: "node_c" });
  }
  return new Command({ update: { count: newCount }, goto: "node_b" });
};

const graph = new StateGraph(State)
  .addNode("node_a", nodeA, { ends: ["node_b", "node_c"] })
  .addNode("node_b", async () => ({ result: "B" }))
  .addNode("node_c", async () => ({ result: "C" }))
  .addEdge(START, "node_a")
  .addEdge("node_b", END)
  .addEdge("node_c", END)
  .compile();

Python: Use Command[Literal["node_a", "node_b"]] as the return type annotation to declare valid goto destinations.

TypeScript: Pass {ends: ["node_a", "node_b"]} as the third argument to addNode to declare valid goto destinations.

Warning: Command only adds dynamic edges — static edges defined with add_edge / addEdge still execute. If node_a returns Command(goto="node_c") and you also have graph.add_edge("node_a", "node_b"), both node_b and node_c will run.


Send API

Fan-out with Send: return [Send("worker", {...})] from a conditional edge to spawn parallel workers. Requires a reducer on the results field.

class OrchestratorState(TypedDict): tasks: list[str] results: Annotated[list, operator.add] summary: str

def orchestrator(state: OrchestratorState): """Fan out tasks to workers.""" return [Send("worker", {"task": task}) for task in state["tasks"]]

def worker(state: dict) -> dict: return {"results": [f"Completed: {state['task']}"]}

def synthesize(state: OrchestratorState) -> dict: return {"summary": f"Processed {len(state['results'])} tasks"}

graph = (StateGraph(OrchestratorState).add_node("worker", worker).add_node("synthesize", synthesize).add_conditional_edges(START, orchestrator, ["worker"]).add_edge("worker", "synthesize").add_edge("synthesize", END).compile())

result = graph.invoke({"tasks": ["Task A", "Task B", "Task C"]})

</python>
<typescript>
Fan out tasks to parallel workers using the Send API and aggregate results.

import { Send, StateGraph, StateSchema, ReducedValue, START, END } from "@langchain/langgraph"; import { z } from "zod";

const State = new StateSchema({ tasks: z.array(z.string()), results: new ReducedValue( z.array(z.string()).default(() => []), { reducer: (curr, upd) => curr.concat(upd) } ), summary: z.string().default(""), });

const orchestrator = (state: typeof State.State) => { return state.tasks.map((task) => new Send("worker", { task })); };

const worker = async (state: { task: string }) => { return { results: [Completed: ${state.task}] }; };

const synthesize = async (state: typeof State.State) => { return { summary: Processed ${state.results.length} tasks }; };

const graph = new StateGraph(State) .addNode("worker", worker) .addNode("synthesize", synthesize) .addConditionalEdges(START, orchestrator, ["worker"]) .addEdge("worker", "synthesize") .addEdge("synthesize", END) .compile();


# CORRECT

class State(TypedDict): results: Annotated[list, operator.add] # Accumulates

</python> <typescript> Use ReducedValue to accumulate parallel worker results.

// WRONG: No reducer
const State = new StateSchema({ results: z.array(z.string()) });

// CORRECT
const State = new StateSchema({
  results: new ReducedValue(z.array(z.string()).default(() => []), { reducer: (curr, upd) => curr.concat(upd) }),
});

Running Graphs: Invoke and Stream

Call graph.invoke(input, config) to run a graph to completion and return the final state.

ModeWhat it StreamsUse Case
valuesFull state after each stepMonitor complete state
updatesState deltasTrack incremental updates
messagesLLM tokens + metadataChat UIs
customUser-defined dataProgress indicators

def my_node(state): writer = get_stream_writer() writer("Processing step 1...") # Do work writer("Complete!") return {"result": "done"}

for chunk in graph.stream({"data": "test"}, stream_mode="custom"): print(chunk)

</python>
<typescript>
Emit custom progress updates from within nodes using the stream writer.

import { getWriter } from "@langchain/langgraph";

const myNode = async (state: typeof State.State) => { const writer = getWriter(); writer("Processing step 1..."); // Do work writer("Complete!"); return { result: "done" }; };

for await (const chunk of graph.stream({ data: "test" }, { streamMode: "custom" })) { console.log(chunk); }


---

## Error Handling

Match the error type to the right handler:

| Error Type | Who Fixes | Strategy | Example |
| --- | --- | --- | --- |
| Transient (network, rate limits) | System | `RetryPolicy(max_attempts=3)` | `add_node(..., retry_policy=...)` |
| LLM-recoverable (tool failures) | LLM | `ToolNode(tools, handle_tool_errors=True)` | Error returned as ToolMessage |
| User-fixable (missing info) | Human | `interrupt({"message":...})` | Collect missing data (see HITL skill) |
| Unexpected | Developer | Let bubble up | `raise` |

workflow.add_node("search_documentation", search_documentation, retry_policy=RetryPolicy(max_attempts=3, initial_interval=1.0))

</python> <typescript> Use retryPolicy for transient errors.

workflow.addNode(
  "searchDocumentation",
  searchDocumentation,
  {
    retryPolicy: { maxAttempts: 3, initialInterval: 1.0 },
  },
);

tool_node = ToolNode(tools, handle_tool_errors=True)

workflow.add_node("tools", tool_node)

</python>
<typescript>
Use ToolNode from @langchain/langgraph/prebuilt to handle tool execution and errors. When handleToolErrors is true, errors are returned as ToolMessages so the LLM can recover.

import { ToolNode } from "@langchain/langgraph/prebuilt";

const toolNode = new ToolNode(tools, { handleToolErrors: true });

workflow.addNode("tools", toolNode);


---

## Common Fixes

# CORRECT

graph = builder.compile() graph.invoke({"input": "test"})

</python> <typescript> Must compile() to get executable graph.

// WRONG
await builder.invoke({ input: "test" });

// CORRECT
const graph = builder.compile();
await graph.invoke({ input: "test" });

CORRECT

def should_continue(state): return END if state["count"] > 10 else "node_b" builder.add_conditional_edges("node_a", should_continue)

</python>
<typescript>
Use conditional edges with END return to break loops.

// WRONG: Loops forever builder.addEdge("node_a", "node_b").addEdge("node_b", "node_a");

// CORRECT builder.addConditionalEdges("node_a", (state) => state.count > 10 ? END : "node_b");


# Command return type needs Literal for routing destinations (Python)

def node_a(state) -> Command[Literal["node_b", "node_c"]]: return Command(goto="node_b")

# START is entry-only - cannot route back to it

builder.add_edge("node_a", START) # WRONG! builder.add_edge("node_a", "entry") # Use a named entry node instead

# Reducer expects matching types

return {"items": ["item"]} # List for list reducer, not a string
// Always await graph.invoke() - it returns a Promise
const result = await graph.invoke({ input: "test" });

// TS Command nodes need { ends } to declare routing destinations
builder.addNode("router", routerFn, { ends: ["node_b", "node_c"] });
  • Mutate state directly — always return partial update dicts from nodes
  • Route back to START — it's entry-only; use a named node instead
  • Forget reducers on list fields — without one, last write wins
  • Mix static edges with Command goto without understanding both will execute

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.16%
按下载量换算17,282

Claude

28.41%
按下载量换算14,373

Cursor

20.1%
按下载量换算10,169

Gemini CLI

9.06%
按下载量换算4,584

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills