Java AI 应用搞定复杂编排: 5 种链式编排模式
适合人群:了解 j-langchain 基础的 Java 开发者
前置阅读:文章1:5分钟构建第一个AI应用
什么是链式编排?
在 AI 应用开发中,单纯调用一次 LLM 往往不够用。实际场景需要:
- 先分类问题,再路由到专业处理链
- 先生成内容,再对内容做质量检查
- 多个子任务并行执行,最后汇总结果
- 结合对话历史,动态改写问题
j-langchain 提供了 6 种开箱即用的链式编排模式,覆盖 90% 的 AI 应用场景。
模式总览
顺序链:A → B → C → D 条件链:A → [条件1→B | 条件2→C | 默认→D] 组合链:[A→B→C] → [上一链的输出→D→E] 并行链:[A→B] 和 [A→C] 并行 → 合并结果 路由链:先用 LLM 分类 → 路由到对应专业链 动态链:并行执行多个分支 → 汇总上下文 → 最终答复模式1:顺序链(Simple Chain)
最基础的线性流水线,节点按顺序依次执行。
@TestpublicvoidsimpleChain(){BaseRunnable<StringPromptValue,?>prompt=PromptTemplate.fromTemplate("讲一个关于 ${topic} 的笑话");ChatOllamallm=ChatOllama.builder().model("qwen2.5:0.5b").build();FlowInstancechain=chainActor.builder().next(prompt).next(llm).next(newStrOutputParser()).build();ChatGenerationresult=chainActor.invoke(chain,Map.of("topic","程序员"));System.out.println(result.getText());}适用场景:问答、翻译、摘要等单轮任务。
模式2:条件链(Switch Chain)
根据输入参数中的条件,动态选择不同的处理分支。
@TestpublicvoidswitchChain(){ChatOllamaollamaModel=ChatOllama.builder().model("qwen2.5:0.5b").build();FlowInstancechain=chainActor.builder().next(prompt).next(Info.c("vendor == 'ollama'",ollamaModel),// 条件表达式 + 分支节点Info.c(input->"暂不支持该模型供应商")// 默认分支).next(newStrOutputParser()).build();// 传入 vendor 参数控制走哪个分支chainActor.invoke(chain,Map.of("topic","Java","vendor","ollama"));}关键 API:Info.c(condition, node)— 条件表达式支持 SpEL,也支持 Lambda。
适用场景:多模型切换、A/B 测试、权限分发。
模式3:组合链(Compose Chain)
将一个链的输出作为另一个链的输入,实现多步推理。
@TestpublicvoidcomposeChain(){// 第一个链:生成笑话FlowInstancejokeChain=chainActor.builder().next(jokePrompt).next(llm).next(parser).build();// 第二个链:分析笑话FlowInstanceanalysisChain=chainActor.builder().next(newInvokeChain(jokeChain))// 内嵌第一个链.next(input->Map.of("joke",((Generation)input).getText()))// 转换格式.next(analysisPrompt).next(llm).next(parser).build();chainActor.invoke(analysisChain,Map.of("topic","程序员"));}关键 API:new InvokeChain(subChain)— 将子链作为一个节点嵌入。
适用场景:先生成再审核、多步骤推理、链式思考(CoT)。
模式4:并行链(Parallel Chain)
多个子链同时执行,执行完毕后合并结果。相比顺序执行,大幅降低延迟。
@TestpublicvoidparallelChain(){FlowInstancejokeChain=chainActor.builder().next(jokePrompt).next(llm).build();FlowInstancepoemChain=chainActor.builder().next(poemPrompt).next(llm).build();FlowInstanceparallelChain=chainActor.builder().concurrent(jokeChain,poemChain)// 并行执行两个链.next(input->{Map<String,Object>map=(Map<String,Object>)input;// 用 flowId 获取对应子链的结果,兼容 AIMessage 和其他类型ObjectjokeResult=map.get(jokeChain.getFlowId());ObjectpoemResult=map.get(poemChain.getFlowId());Stringjoke=jokeResultinstanceofAIMessage?((AIMessage)jokeResult).getContent():String.valueOf(jokeResult);Stringpoem=poemResultinstanceofAIMessage?((AIMessage)poemResult).getContent():String.valueOf(poemResult);returnMap.of("joke",joke,"poem",poem);}).build();Map<String,String>result=chainActor.invoke(parallelChain,Map.of("topic","猫"));System.out.println("笑话:"+result.get("joke"));System.out.println("诗歌:"+result.get("poem"));}关键 API:chainActor.builder().concurrent(chain1, chain2, ...)— 并行执行,用子链 flowId 取结果。
适用场景:同时生成多种内容、并发搜索多个数据源、多模型投票。
模式5:路由链(Route Chain)
先用 LLM 对输入内容自动分类,再根据分类结果路由到对应的专业链。
@TestpublicvoidrouteChain(){// 分类链:判断问题类型FlowInstanceclassifyChain=chainActor.builder().next(classifyPrompt).next(llm).next(newStrOutputParser()).build();FlowInstancefullChain=chainActor.builder().next(newInvokeChain(classifyChain)).next(input->Map.of("category",input.toString(),"question",((Map<?,?>)ContextBus.get().getFlowParam()).get("question"))).next(Info.c("category == '技术'",techChain),// 路由到技术专家Info.c("category == '业务'",bizChain),// 路由到业务专家Info.c(generalChain)// 默认通用回答).build();chainActor.invoke(fullChain,Map.of("question","如何优化 Java 内存?"));}关键点:ContextBus.get().getFlowParam()可以在任意节点获取链的原始输入。
适用场景:智能客服、多领域问答、专家路由系统。
模式6:动态上下文链(Dynamic Chain)
结合对话历史,将"接上文的问题"改写为独立问题,再进行检索和回答。这是多轮对话 RAG 的核心模式。
@TestpublicvoiddynamicChain(){// 上下文改写:有历史时改写问题,无历史直接透传FlowInstancecontextualizeIfNeeded=chainActor.builder().next(Info.c("chatHistory != null",newInvokeChain(contextualizeChain)),Info.c(input->Map.of("question",((Map<String,String>)input).get("question")))).build();FlowInstancefullChain=chainActor.builder().all(Info.c(contextualizeIfNeeded),// 并行:改写问题Info.c(input->"印度尼西亚2024年人口约2.78亿").cAlias("retriever")// 并行:检索上下文).next(input->Map.of("question",ContextBus.get().getResult(contextualizeIfNeeded.getFlowId()).toString(),"context",ContextBus.get().getResult("retriever"))).next(qaPrompt).next(llm).next(newStrOutputParser()).build();// 第二轮对话:问题依赖第一轮上下文chainActor.invoke(fullChain,Map.of("question","那印度呢","chatHistory",List.of(Pair.of("human","印度尼西亚有多少人口"),Pair.of("ai","约2.78亿"))));}关键 API:
chainActor.builder().all(...)— 所有分支并行执行,用cAlias给分支命名ContextBus.get().getResult(id)— 按节点 ID 或别名获取中间结果
适用场景:多轮对话、带记忆的 AI 助手、上下文感知问答。
模式对比
| 模式 | 关键 API | 核心特点 | 典型场景 |
|---|---|---|---|
| 顺序链 | .next() | 线性流水线 | 问答、翻译 |
| 条件链 | Info.c(condition, node) | 运行时分支选择 | 模型切换、权限控制 |
| 组合链 | new InvokeChain(chain) | 链嵌套,多步推理 | 生成+审核 |
| 并行链 | .concurrent(chain1, chain2) | 多链同时执行 | 并发生成、多源检索 |
| 路由链 | LLM分类 +Info.c(条件, chain) | 智能路由 | 智能客服、专家系统 |
| 动态链 | .all()+ContextBus | 并行+上下文汇聚 | 多轮对话RAG |
完整代码见:
src/test/java/org/salt/jlangchain/demo/article/Article02ChainPatterns.java
