惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
U
Unit 42
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
J
Java Code Geeks
D
DataBreaches.Net
B
Blog RSS Feed
D
Docker
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
F
Fortinet All Blogs
Y
Y Combinator Blog
A
About on SuperTechFans
V
V2EX
罗磊的独立博客
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
MongoDB | Blog
MongoDB | Blog
博客园 - 【当耐特】
Last Week in AI
Last Week in AI
S
SegmentFault 最新的问题
月光博客
月光博客
Vercel News
Vercel News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
阮一峰的网络日志
阮一峰的网络日志

博客园 - 菩提树下的杨过

langchain4j 学习系列(10)-Skill使用示例 利用SWIG实现JAVA调用C/C++代码 LangGraph4j 学习系列(9)-人机协同(human_in_the_loop) LangGraph4j 学习系列(8)-checkpoint检查点 LangGraph4j 学习系列(7)-流式响应 LangGraph4j 学习系列(5)-Hook勾子 LangGraph4j 学习系列(4)-SCHEMA和Channel LangGraph4j 学习系列(3)-循环工作流 LangGraph4j 学习系列(2)-条件工作流 LangGraph4j 学习系列(1)-顺序工作流 Agent设计模式学习(基于langchain4j实现)(11) - PlanAndExecute Agent设计模式学习(基于langchain4j实现)(10) - ReACT Agent设计模式学习(基于langchain4j实现)(9) - 人机协同 Agent设计模式学习(基于langchain4j实现)(8) - 非AI智能体 Agent设计模式学习(基于langchain4j实现)(7) - 监督者模式 Agent设计模式学习(基于langchain4j实现)(6) - 组合复杂工作流 Agent设计模式学习(基于langchain4j实现)(5) - 条件工作流 Agent设计模式学习(基于langchain4j实现)(4) - 并行工作流 Agent设计模式学习(基于langchain4j实现)(3) - 循环工作流 Agent设计模式学习(基于langchain4j实现)(2) - 顺序工作流
LangGraph4j 学习系列(6)-并行工作流
菩提树下的杨过 · 2026-03-01 · via 博客园 - 菩提树下的杨过

上节继续,本篇将学习如何实现并行工作流。

image

 上面这张图,用代码很容易绘制,参考以下代码。

核心代码

public static StateGraph<AgentState> getParallelGraph() throws GraphStateException {
    return new StateGraph<>(AgentState::new)
            .addNode("node-1", node_async(new Node1Action()))
            .addNode("node-2", node_async(new Node2Action()))
            .addNode("node-3", node_async(new Node3Action()))
            .addEdge(START, "node-1")
            .addEdge("node-1", "node-2")
            .addEdge("node-1", "node-3")
            .addEdge("node-2", GraphDefinition.END)
            .addEdge("node-3", GraphDefinition.END);
}

性能问题

虽然图上看着貌似node-2,node-3并行在跑,但真的如此吗?我们把node-2和node-3的apply()里加点sleep

public class Node2Action implements NodeAction<AgentState> {
    @Override
    public Map<String, Object> apply(AgentState state) throws Exception {
        System.out.println("current Node: node-2");
        Thread.sleep(1000);
        return Map.of("myData", "node2-my-value",
                "node2Key", "node2-value");
    }
}
public class Node3Action implements NodeAction<AgentState> {
    @Override
    public Map<String, Object> apply(AgentState state) throws Exception {
        System.out.println("current Node: node-3");
        Thread.sleep(1000);
        return Map.of("myData", "node3-my-value",
                "node3Key", "node3-value");
    }
}

然后在node-1里,记录下start时间戳

public class Node1Action implements NodeAction<AgentState> {
    
    @Override
    public Map<String, Object> apply(AgentState state) throws Exception {
        System.out.println("current Node: node-1");
        Thread.sleep(1000);
        return Map.of(
                "myData", "node1-my-value",
                "node1Key", "node1-value",
                //记录开始时间
                "start", System.currentTimeMillis());
    }
    
}
getParallelGraph().compile()
        .invoke(Map.of("test", "test-init-value"))
        .ifPresent(c -> {
            long start = (long) c.data().getOrDefault("start", 0L);
            System.out.println(c.data());
            long end = System.currentTimeMillis();
            System.out.println((end - start) + "ms");
        });

运行结果

current Node: node-1
current Node: node-2
current Node: node-3
{node1Key=node1-value, start=1770719927373, test=test-init-value, node2Key=node2-value, node3Key=node3-value, myData=node3-my-value}
2017ms

多线程提速

LangGraph4可以手动指定线程池实现真正的并发处理。

StateGraph<AgentState> graphNoThreadPool = getParallelGraph();

ExecutorService executorService = Executors.newFixedThreadPool(2);
RunnableConfig rc = RunnableConfig.builder()
        //从node-1开始并行执行node-2和node-3(使用线程池)
        .addParallelNodeExecutor("node-1", executorService)
        .build();
graphNoThreadPool.compile()
        .invoke(Map.of("test", "test-init-value"), rc) //调用时,使用特定的RunnableConfig
        .ifPresent(c -> {
            long start = (long) c.data().getOrDefault("start", 0L);
            System.out.println(c.data());
            long end = System.currentTimeMillis();
            System.out.println((end - start) + "ms");
            //记得关闭线程池
            executorService.shutdown();
        });

运行结果

current Node: node-1
current Node: node-2
current Node: node-3
{node1Key=node1-value, start=1770722528938, test=test-init-value, node2Key=node2-value, node3Key=node3-value, myData=node3-my-value}
1015ms


明显快多了。如果是jdk 25版本,也可以使用虚拟线程:

ExecutorService virtualThreadPerTaskExecutor = Executors.newVirtualThreadPerTaskExecutor();
RunnableConfig rc2 = RunnableConfig.builder()
        //从node-1开始并行执行node-2和node-3(使用线程池)
        .addParallelNodeExecutor("node-1", virtualThreadPerTaskExecutor)
        .build();
graphNoThreadPool2.compile()
        .invoke(Map.of("test", "test-init-value"), rc2)
        .ifPresent(c -> {
            long start = (long) c.data().getOrDefault("start", 0L);
            System.out.println(c.data());
            long end = System.currentTimeMillis();
            System.out.println((end - start) + "ms");
        });

文中源码:langgraph4j-study/src/main/java/org/bsc/langgraph4j/agent/_07_parallel at main · yjmyzz/langgraph4j-study · GitHub