- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- Agent 工作流
- RAG
- MCP Clients
- 强化学习
【免费下载链接】agent-core-java
openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。
com.openjiuwen.core.graph.visualization是 agent-core-java 提供工作流可视化能力的基础包:它把工作流组件树转换成一份独立的“可绘制图”(DrawableGraph),再导出为 Mermaid 文本、PNG 或 SVG,用于开发联调、文档留档与问题排查。读完本文,你将掌握可视化包的全部 public 类型与导出入口、子图与条件分支的表示方式、expandSubgraph展开语义,以及从Workflow一行调用拿到图/文本/图片的实战方法。
一、visualization 包在项目中的定位
com.openjiuwen.core.graph.visualization包(源码位于 core/src/main/java/com/openjiuwen/core/graph/visualization)只负责“把工作流画出来”,不参与图执行引擎的调度。整个 Java 版本的可视化链路可以概括为四层:
Workflow/BaseWorkflow内部维护一份实现了 HasDrawable 接口的可视化状态;HasDrawable.getDrawable()返回 Drawable;Drawable把节点、边、条件分支与循环/子工作流转换成 DrawableGraph;DrawableGraph再被导出为 Mermaid 文本,必要时继续通过渲染服务生成 PNG 或 SVG。
也就是说,Mermaid 文本、PNG、SVG 都只是同一份图结构的不同输出形式,真正的“源数据”是DrawableGraph。开发者只需面向图模型思考,输出形式可以随时切换。
二、六个 public 类型速览
可视化包对外暴露的全部 public 类型如下(API 文档见 visualization.README.md):
| 类型 | 说明 |
|---|---|
| Drawable | 将工作流组件树转换为DrawableGraph,并导出 Mermaid 文本、PNG 或 SVG 的总入口 |
| DrawableGraph | 保存节点、边、开始节点、结束节点与 break 节点的图容器 |
| DrawableNode | 可绘制节点的基础数据模型,包含id、展示名和元数据 |
| DrawableSubgraphNode | 带嵌套DrawableGraph的节点,用于循环体和子工作流 |
| DrawableEdge | 可绘制图中的一条边,支持条件边和流式边标记 |
| DrawableBranchRouter | 保存条件分支的目标节点列表与展示标签 |
Mermaid 文本生成(MermaidDiagram)与 PNG/SVG 渲染(MermaidRenderer)由同包内非 public 的 helper 完成,本包对外只暴露上述 public 类型。
2.1 DrawableGraph:可视化数据的“源图”
DrawableGraph是承载全部可视化数据的容器(源码):
nodes:Map<String, DrawableNode>,节点 ID 到节点对象的映射,采用LinkedHashMap保持插入顺序;edges:List<DrawableEdge>,图中全部边,保持添加顺序;startNodes/endNodes/breakNodes:分别保存被标记为开始、结束与 break 的节点列表(break 节点用于子图场景)。
构造方式有两种:空构造直接创建空容器;带参构造则一次性接收节点映射、边列表和三类特殊节点列表。读取端通过getNodes()、getEdges()、getStartNodes()、getEndNodes()、getBreakNodes()访问,breakNodes还提供setBreakNodes(...)整体替换。
2.2 DrawableNode 与 DrawableSubgraphNode:普通节点与嵌套节点
DrawableNode 是最基础的节点模型,包含三个字段:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | String | 必填 | 节点唯一标识 |
name | String | null | 可选展示名称 |
metadata | Map<String, Object> | null | 节点扩展元数据 |
提供getId()、getName()/setName()、getMetadata()/setMetadata()等访问器。实际导出 Mermaid 时,节点文本优先使用id(源码中 Mermaid 节点内容直接取node.getId()),name与metadata保留给上层扩展使用。
DrawableSubgraphNode 继承DrawableNode,额外持有一个subgraph字段(DrawableGraph类型),表示“图包含图”。当工作流中出现循环体或子工作流时,Java 不会把它们压平处理,而是用这种嵌套结构保留层级关系——这也是expandSubgraph能按层级展开的前提。
2.3 DrawableEdge:普通边、条件边与流式边
DrawableEdge 描述一条有向边:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
source | String | 必填 | 源节点 ID |
target | String | 必填 | 目标节点 ID |
data | Object | null | 条件边的标签或附加数据 |
conditional | boolean | false | 是否按虚线条件边渲染 |
streaming | boolean | false | 是否按流式粗线渲染 |
在 Mermaid 导出中(见Drawable.java内部genMermaidLinks):
- 普通边渲染为
-->; - 条件边渲染为
-.->,且data非空时输出标签|"标签"|; - 流式边渲染为
==>,当enableAnimation为 true 时还会附加link_xxx@动画链接与animate: true属性,实现流式边“动起来”的视觉效果。
2.4 DrawableBranchRouter:分支目标与标签
DrawableBranchRouter 是条件分支的展示模型,包含两个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
targets | List<String> | 条件分支可能跳转到的目标节点名列表 |
datas | List<String> | 与targets对齐的展示文案或分支标签 |
它的数据来源是工作流层的 BranchRouter:每次调用addBranch(condition, target)时,BranchRouter.recordDrawable会把目标节点追加进targets,并把分支标签(字符串条件文本或 branchId)追加进datas,两者按位对齐。getDrawableBranchRouter()方法暴露给可视化层消费。
三、组件到绘制节点的转换规则
Drawable.addNode(String nodeId, ComponentComposable component)是组件树到图模型的桥接方法(源码),按组件类型分派:
| 组件类型 | 转换结果 |
|---|---|
LoopComponent | 取其循环组(getLoopGroup().getDrawable())的子图,创建DrawableSubgraphNode,补齐子图结束节点并添加条件自环 |
AdvancedLoopComponent | 取其循环体(getBody().getDrawable())的子图,同样创建子图节点 + 条件自环 |
SubWorkflowComponent | 取内部子工作流(getSubWorkflowInternal().getDrawable())的子图,创建DrawableSubgraphNode |
BranchComponent | 创建普通节点,并通过其router()添加条件边集合 |
IntentDetectionComponentImpl | 创建普通节点,并通过其router()添加条件边集合 |
| 其他组件 | 仅创建包含id的普通DrawableNode |
其中循环节点有一个关键处理:addLoopSubgraphNode会把节点 ID 记入loopNodes集合,之后任何以它为源节点的addEdge都会被改写成条件自环(conditional=true, streaming=false),在 Mermaid 中以虚线自环呈现循环语义。
对于分支类组件,addEdge(source, null, true, false, router)会读取DrawableBranchRouter的targets与datas,为每个分支目标生成一条带标签的条件边——这就是分支图在页面上“一根虚线连到多个目标”的来源。对于无法直接从路由对象提取目标列表的自定义对象,Drawable.TargetProvider接口(List<String> getTargets())提供了兜底扩展点。
另外,fillEndNodesIfEmpty会在子图缺少结束节点时自动补齐:统计子图内每个节点的出度,出度为 0 的节点被自动加入endNodes,保证循环体这类没有显式结束标记的子图也能正确渲染边界。
四、图构建辅助:起止节点与边
除addNode外,Drawable还提供一组图构建方法:
addSimpleNode(String nodeId):直接添加一个只包含id的普通节点;setStartNode(nodeId)/setEndNode(nodeId)/setBreakNode(nodeId):将已存在节点标记为开始/结束/break 节点,节点不存在时分别抛出DRAWABLE_GRAPH_START_NODE_INVALID(112020)、DRAWABLE_GRAPH_END_NODE_INVALID(112021)、DRAWABLE_GRAPH_BREAK_NODE_INVALID(112022)对应异常(见 StatusCode);addEdge(source, target):默认非条件、非流式添加普通边;addEdge(source, target, conditional, streaming, data):支持Stringifiable负载数据、BranchRouter分支路由、TargetProvider自定义目标三种data形态。
被标记为开始/结束节点的普通节点在 Mermaid 中会以圆角形状(round-edge,即id(...)语法)渲染,普通节点为方角(id[...]),便于一眼识别入口与出口。
五、导出能力:Mermaid 文本、PNG 与 SVG
5.1 toMermaid:最基础的输出形式
Drawable提供三个toMermaid重载:
public String toMermaid(String title, int expandSubgraph, boolean enableAnimation) public String toMermaid(String title, boolean expandSubgraph, boolean enableAnimation) public String toMermaid() // 等价于 toMermaid("", 0, false)生成的文本是标准的 Mermaidflowchart TD脚本,包含 YAML front-matter(title字段)、节点声明、子图声明与链接声明。参数要点:
title:图为 null 时抛出DRAWABLE_GRAPH_TO_MERMAID_INVALID;expandSubgraph:int 版本要求非负,负数直接抛异常;boolean 版本把true归一化为EXPAND_ALL(即 -1,全部展开),false归一化为 0;enableAnimation:控制流式边是否附带动画属性。
Mermaid 文本适合代码评审、提交 diff、文档粘贴与 issue 复现——你可以直接看出节点 ID、边方向与条件标签。
5.2 toMermaidPng / toMermaidSvg:图片渲染
public byte[] toMermaidPng(String title, int expandSubgraph) // 也有 boolean 版本 public byte[] toMermaidSvg(String title, int expandSubgraph) // 也有 boolean 版本两者都先调用toMermaid生成文本,再交给同包内的MermaidRenderer渲染(源码)。渲染链路事实如下:
- 使用 JDK 内置
HttpClient,连接与请求超时均为 30 秒,跟随重定向; - Mermaid 文本以 UTF-8 编码后经 Base64 URL 编码拼入请求 URI;
- 渲染服务地址优先级:系统属性
MERMAID_INK_SERVER> 环境变量MERMAID_INK_SERVER> 默认值https://mermaid.ink;配置值必须是绝对 HTTP(S) URI 且不带 query/fragment,否则视为非法配置; - 失败重试:最多 3 次尝试,重试延迟按
100ms × 尝试次数递增,可重试的状态码为 408、429 及全部 5xx;多次失败后抛出DRAWABLE_GRAPH_TO_MERMAID_INVALID(112043),异常信息中携带失败原因与渲染服务地址; - 格式差异:
renderPng先请求/svg/做一次校验再请求/img/?format=png取 PNG;renderSvg返回/svg/响应体,同时也会请求/img/做格式校验,并且 SVG 导出默认开启动画语义(enableAnimation=true)。
因此,若图中有流式边,SVG 通常比 PNG 更适合展示这类连接(流式边动画只在 SVG/动画文本中体现)。由于渲染依赖远端服务,生产环境中建议配置内网可达的MERMAID_INK_SERVER,并注意网络超时与远端故障时的异常处理。
5.3 expandSubgraph 的展开语义
expandSubgraph控制子图展开层级,适合在“只看主干”与“展开全部内部结构”之间切换:
0:不展开子图,子工作流或循环体作为整体节点(subgraph块)呈现;- 正整数 N:按层级向下展开 N 层;
true:尽可能完全展开所有子图(内部归一化为 -1)。
需要特别说明:Workflow.draw(...)/Workflow.drawBytes(...)这层公共入口不接受负数作为expandSubgraph调用参数(负数会抛异常),只有内部可视化实现才把true归一化为-1交给 Mermaid 导出逻辑做“全部展开”。想先核对主路径是否连对,建议从0开始;确认需要排查子图内部边关系时,再逐步提高展开层级。
六、从 Workflow 出发的实战入口
对大多数开发者而言,并不需要直接操作Drawable,入口已经挂在Workflow上(源码):
| 方法 | 返回 | 说明 |
|---|---|---|
workflow.draw()/draw(title)/draw(title, "mermaid", expandSubgraph, enableAnimation) | String | 返回 Mermaid 文本 |
workflow.drawBytes(title, "png", expandSubgraph) | byte[] | 返回 PNG 二进制 |
workflow.drawBytes(title, "svg", expandSubgraph) | byte[] | 返回 SVG 二进制 |
workflow.getInternalDrawable() | HasDrawable | 进入内部Drawable路线,拿底层图对象 |
注意两点:draw(..., "png"/"svg", ...)会抛出UnsupportedOperationException,图片必须走drawBytes;drawBytes只接受"png"或"svg",其他格式抛IllegalArgumentException。参数会经过规范化处理:title为 null 时归一化为空串,expandSubgraph支持Boolean或非负Number,enableAnimation仅接受Boolean,类型不符时统一抛出DRAWABLE_GRAPH_TO_MERMAID_INVALID。
一个最小可运行的衔接示例(图搭好以后先画出来再执行,排查成本通常更低):
import java.nio.file.Files; import java.nio.file.Path; // 导出 Mermaid 文本 String mermaid = workflow.draw("transfer-flow", "mermaid", 0, false); System.out.println(mermaid); // 导出 PNG(渲染依赖远端 mermaid.ink,建议先判断长度再落盘) byte[] png = workflow.drawBytes("transfer-flow", "png", 0); if (png.length > 0) { Files.write(Path.of("transfer-flow.png"), png); } // 导出 SVG(展开一层子图) byte[] svg = workflow.drawBytes("transfer-flow", "svg", 1); Files.write(Path.of("transfer-flow.svg"), svg);这段代码体现了三个事实:
draw(...)负责导出文本,而不是图片;- 图片导出必须走
drawBytes(...); - 可视化展示的是当前已经注册好的节点与边,因此非常适合在真正执行前检查
addConnection(...)、addConditionalConnection(...)、addStreamConnection(...)是否符合预期。
七、何时优先使用可视化
以下几类问题,先导出 Mermaid 往往最省时间:
- 明明注册了组件,但执行路径与预期不一致;
- 条件路由很多,想先确认分支标签与目标节点是否挂对;
- 子工作流或循环体比较复杂,想先确认父子图关系;
- 流式边与普通边混用,想确认哪些连接会走 streaming 路径。
八、当前边界与继续阅读
- 本包只对外暴露 public 的可视化入口与图模型,
MermaidDiagram、MermaidRenderer等 helper 的实现细节不在 API 承诺范围内; - 可视化反映的是图结构,不是运行时 trace——图执行引擎内部调度过程不在本包职责内;
- 当前仓库未包含
visualization包的直接单元测试,本文对导出行为的描述依据源码人工核对。
继续深入可阅读:
- 实战教程:工作流可视化、构建工作流、使用组件;
- API 文档:visualization 总览 及 Drawable、DrawableGraph、DrawableNode、DrawableEdge 等;
- 核心源码:Drawable.java、DrawableGraph.java、Workflow.java、BranchRouter.java。
- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- Agent 工作流
- RAG
- MCP Clients
- 强化学习
【免费下载链接】agent-core-java
openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。
相关推荐
openjiuwen agent-core 工作流 DL 转换:DLTransformer 从 DL 到 Mermaid 与平台 DSL 的完整实现指南
openjiuwen agent core 工作流 DL 转换:DLTransformer 从 DL 到 Mermaid 与平台 DSL 的完整实现指南 本文围
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen 工作流可视化指南:基于 Mermaid 的 Workflow 图形化呈现与排查
openJiuwen 工作流可视化指南:基于 Mermaid 的 Workflow 图形化呈现与排查 openJiuwen(agent core)开发框架为构建
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen agent-core-java 工作流构建实战指南:从单工作流编排到 WorkflowAgent 多工作流路由
openJiuwen agent core java 工作流构建实战指南:从单工作流编排到 WorkflowAgent 多工作流路由 导读 本文基于 openJ
人工智能AI AgentAgent 框架工具调用Agent 工作流RAGMCP Clients强化学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考