Skip to content

与 LangGraph4j 对比

如果你是从 LangGraph4j(Java 版)过来学 LangGraph(Python 版),本篇就是为你准备的迁移指南。两套库出自同一思想(图、节点、边、状态、检查点),但语言范式差异让 API 长得很不一样。本篇用对照表 + 代码对照片段,帮你快速建立映射。

一、总览:同源不同貌

LangGraph(Python)是官方「第一公民」,新特性先在这里落地;LangGraph4j 是社区移植的 Java 版,概念对齐但 API 风格 Java 化(强类型、Builder、注解)。

维度LangGraph (Python)LangGraph4j (Java)
语言Python 3.10+(动态类型)Java 17+(强类型)
范式函数式为主,函数一等公民OOP 为主,类 + 注解
状态TypedDict + Annotated reducerStateRecord / AgentState + record
节点普通函数Channel / Lambda / 方法引用
工具@tool 装饰器@Tool 注解
异步async/await 原生CompletableFuture / 响应式流
构建工具pip / uvMaven / Gradle
生态成熟度高(官方)中(社区跟进)

心态

把 LangGraph4j 当成「带 Java 语法糖的 LangGraph 镜像」,核心概念 1:1,差异主要在「怎么定义」而非「是什么」。

二、核心概念对照表

1. 状态定义

PythonJava
定义方式TypedDict + Annotatedrecord 实现 AgentState
reducerAnnotated[list, add_messages]在 StateFactory 注册 reducer
消息字段MessagesState 预置MessagesState 同名类
python
# Python
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages

class State(TypedDict):
    messages: Annotated[list, add_messages]
    count: int
java
// Java (LangGraph4j)
public record State(Map<String, Object> data) implements AgentState {
    public List<Message> messages() { return this.value("messages", new ArrayList<>()); }
    public int count() { return this.<Integer>value("count"); }
}
// reducer 在 channel 定义时指定

2. 节点

PythonJava
节点定义函数 def node(state):Channel 或 Lambda
注册builder.add_node("name", fn)builder.addNode("name", channel)
返回dict(state 增量)Map<String, Object>
python
# Python
def chatbot(state: State) -> dict:
    return {"messages": [llm.invoke(state["messages"])]}
builder.add_node("chatbot", chatbot)
java
// Java
var chatbot = Channel.<State>of()
    .key("messages")
    .value(state -> Map.of("messages", llm.invoke(state.messages())))
    .build();
builder.addNode("chatbot", chatbot);

3. 边与条件边

PythonJava
普通边add_edge("a", "b")addEdge("a", "b")
条件边add_conditional_edges("a", fn, map)addConditionalEdges("a", fn, map)
起止START / ENDSTART / END
python
# Python
from langgraph.graph import START, END
builder.add_edge(START, "chatbot")
builder.add_conditional_edges("chatbot", tools_condition, "tools")
builder.add_edge("tools", "chatbot")
builder.add_edge("chatbot", END)
java
// Java
builder.addEdge(START, "chatbot");
builder.addConditionalEdges("chatbot", toolsCondition, Map.of("tools", "tools"));
builder.addEdge("tools", "chatbot");
builder.addEdge("chatbot", END);

4. compile 与执行

PythonJava
编译builder.compile(checkpointer=saver)builder.compile(checkpointer)
同步执行graph.invoke(input, config)graph.invoke(input, config)
异步执行await graph.ainvoke(...)graph.invoke(...) 内部 CompletableFuture
流式graph.stream(..., stream_mode=)graph.stream(...)
python
# Python
graph = builder.compile(checkpointer=MemorySaver())
result = await graph.ainvoke(
    {"messages": [HumanMessage("hi")]},
    config={"configurable": {"thread_id": "t1"}},
)
java
// Java
var graph = builder.compile(new MemorySaver());
var result = graph.invoke(
    Map.of("messages", List.of(new HumanMessage("hi"))),
    ThreadRunnableConfig.builder().threadId("t1").build()
).get();

5. Checkpointer

PythonJava
内存MemorySaverMemorySaver
文件SqliteSaverFileSystemSaver
数据库AsyncPostgresSaver需自实现 BaseCheckpointSaver

Java 侧差异

LangGraph4j 的持久化 saver 选择比 Python 少,Postgres 等常需自己实现 BaseCheckpointSaver 接口。Python 这边官方已提供 Postgres/SQLite。

6. 工具定义

PythonJava
装饰器@tool@Tool
参数 schemaPydantic BaseModelrecord / Bean
描述来源docstring@Tool(description=) 或注解
python
# Python
from langchain_core.tools import tool

@tool
def add(a: float, b: float) -> float:
    """两数相加"""
    return a + b
java
// Java
@Tool("两数相加")
public double add(double a, double b) {
    return a + b;
}

7. 预置 ReAct 智能体

PythonJava
APIcreate_react_agent(llm, tools, ...)createReactAgent(llm, tools, ...)
ToolNodeToolNode(tools)内置工具节点
tools_conditiontools_conditionToolsCondition
python
# Python 一行
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(llm, tools, checkpointer=saver)
java
// Java
var agent = createReactAgent(llm, tools, saver);

8. 消息类型

PythonJava
HumanMessageHumanMessage
AIMessageAiMessage
SystemMessageSystemMessage
ToolMessageToolExecutionResultMessage
AIMessageChunk(流式用 Token 消费)

9. HITL(人机交互)

PythonJava
中断interrupt(value)interrupt(value)
恢复Command(resume=...)Command(resume(...))
更新 stateupdate_state(config, values)updateState(config, values)

10. Studio / 可视化

PythonJava
官方 Studio✅ 原生支持❌ 无,需自建前端
调试可视化LangGraph Studio 桌面/网页社区方案(Mermaid 导出)

Java 同学的福音

学完 Python 版,你能在 Studio 里可视化调试图——这是 LangGraph4j 没有的体验,强烈建议试试 LangGraph 平台与 Studio

三、Java 背景者迁移注意点

1. 动态类型

Python 不声明变量类型(运行时推导),Java 同学初期会慌。靠 TypedDict 和 Pydantic 补回「类型契约」:

python
def chatbot(state: State) -> dict:  # 参数注解只是提示,运行时不强校验

习惯用 mypy 或 IDE(PyCharm/VS Code Pylance)做静态检查,相当于 Java 编译器。

2. 函数是一等公民

Python 节点就是函数,能直接传、能闭包捕获;Java 要包成 Lambda 或 Channel。迁移时把「写一个类」简化成「写一个函数」:

python
# Python:直接函数,无需类
def my_node(state):
    return {"count": state["count"] + 1}

3. 装饰器

@tool 装饰器本质是「函数包装函数」,等价于 Java 的注解 + 处理器,但更灵活:

python
@tool  # 等价 Java @Tool,但运行时即生效,无需注解处理器
def search(query: str) -> str: ...

4. async/await

Python 协程比 Java 线程轻,但和 Java 响应式(Mono/Flux)思路相通:

python
# Python 协程
async def node(state):
    resp = await llm.ainvoke(state["messages"])  # 异步调
    return {"messages": [resp]}

相当于 Java 的 Mono.fromCallable + flatMap,但语法更直接。

5. 字典即状态

Java 习惯用强类型 record 封装 state;Python 直接用 TypedDict(本质是带类型提示的 dict)。state["messages"] 等价 Java state.messages(),但前者是字典取值。

四、可直接迁移 vs 需重新理解

✅ 可直接迁移(概念 1:1)

  • 图/节点/边/条件边的拓扑思维
  • 状态 + reducer 的合并机制
  • checkpointer 持久化 + thread_id 会话隔离
  • ReAct 智能体的「LLM-工具循环」
  • HITL 中断/恢复语义
  • stream_mode 的几种模式

🔄 需重新理解(实现不同)

概念重新理解点
异步Python async/await 全链路,比 CompletableFuture 更轻;别在 async 里调同步阻塞
类型动态类型,靠注解 + mypy + IDE 提示补回安全
工具@tool 看 docstring,Java 看注解 description
持久化Python 官方 PostgresSaver 开箱即用,Java 常需自实现
多线程Python 受 GIL 影响,并发靠多进程/协程而非多线程
StudioPython 有官方可视化调试,Java 没有

五、同语义 ReAct 代码对照片段

Python 版

python
from typing import Annotated, TypedDict
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.checkpoint.memory import MemorySaver

@tool
def add(a: float, b: float) -> float:
    """两数相加"""
    return a + b

tools = [add]
llm = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools)

class State(TypedDict):
    messages: Annotated[list, add_messages]

def chatbot(state: State):
    return {"messages": [llm.invoke(state["messages"])]}

builder = StateGraph(State)
builder.add_node("chatbot", chatbot)
builder.add_node("tools", ToolNode(tools))
builder.add_edge(START, "chatbot")
builder.add_conditional_edges("chatbot", tools_condition, "tools")
builder.add_edge("tools", "chatbot")
builder.add_edge("chatbot", END)
graph = builder.compile(checkpointer=MemorySaver())

import asyncio
result = asyncio.run(graph.ainvoke(
    {"messages": [HumanMessage("3 加 5 等于几")]},
    config={"configurable": {"thread_id": "t1"}},
))
print(result["messages"][-1].content)  # 8

Java 版(LangGraph4j)

java
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.data.message.HumanMessage;
import org.bsc.langgraph4j.StateGraph;
import org.bsc.langgraph4j.state.AgentState;
import org.bsc.langgraph4j.state.MemorySaver;
import static org.bsc.langgraph4j.action.AsyncNodeAction.node_async;
import static org.bsc.langgraph4j.action.AsyncEdgeAction.edge_async;

public class State implements AgentState {
    public List<Message> messages() { return this.value("messages", new ArrayList<>()); }
}

public class AddService {
    @Tool("两数相加")
    public double add(double a, double b) { return a + b; }
}

var tools = ToolSpecifications.toolSpecificationsFrom(new AddService());
var llm = OpenAiChatModel.builder().apiKey(key).build();
// 节点
var chatbot = node_async(state -> {
    var resp = llm.generate(state.messages(), tools);
    return Map.of("messages", resp.content());
});
var toolNode = /* ToolNode 等价物 */;
// 图
var builder = new StateGraph<>(State.class);
builder.addNode("chatbot", chatbot);
builder.addNode("tools", toolNode);
builder.addEdge(START, "chatbot");
builder.addConditionalEdges("chatbot", toolsCondition, Map.of("tools","tools"));
builder.addEdge("tools", "chatbot");
builder.addEdge("chatbot", END);
var graph = builder.compile(new MemorySaver());

var result = graph.invoke(
    Map.of("messages", List.of(new HumanMessage("3 加 5 等于几"))),
    ThreadRunnableConfig.builder().threadId("t1").build()
).get();
System.out.println(result.value("messages").get(result.value("messages").size()-1));

对照可见:拓扑结构完全一致,差异在「节点用函数 vs Channel」「工具用 docstring vs 注解」「异步用 await vs CompletableFuture」。

六、迁移建议

  1. 先按本教程过一遍 Python 基础快速入门核心概念),建立 Python 心智模型
  2. 拿一个你用 LangGraph4j 写过的图,用 Python 重写一遍,对照本篇映射表
  3. 重点体验 Studio——这是 Java 版没有的红利,调试效率成倍提升
  4. 生产部署参考服务化部署,FastAPI 对应你的 Spring Boot

七、小结

  • 概念层 1:1:图、节点、边、状态、检查点、ReAct、HITL——你已会的都能迁移
  • 实现层有差异:动态类型、函数一等公民、装饰器、async——这些是 Python 范式
  • Python 版生态更全(官方 Studio、PostgresSaver、LangSmith 深度集成),值得学
  • 拿一个旧图重写一遍,是最快的迁移方式

下一篇给出后续学习资源与进阶路线。