ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

OpenMAIC 接入 ComfyUI 本地生图:工作流编排、节点适配与生产部署指南

OpenMAIC 接入 ComfyUI 本地生图:工作流编排、节点适配与生产部署指南 OpenMAIC 接入 ComfyUI 本地生图工作流编排、节点适配与生产部署指南【免费下载链接】OpenMAICOpen Multi-Agent Interactive Classroom — Get an immersive, multi-agent learning experience in just one click项目地址: https://gitcode.com/GitHub_Trending/op/OpenMAICOpenMAICOpen Multi-Agent Interactive Classroom将 ComfyUI 作为无 API Key的本地图像生成 Provider通过内置适配器把课堂 Agent 产出的图片描述注入到 ComfyUI 工作流中完成出图。本文以仓库根目录下的 comfyui-setup-instructions.md 为骨架结合 comfyui-image-adapter.ts、comfyui-workflows.ts 与 public/comfyui-workflow.json 等源码完整讲解工作流文件的存放与命名规则、必需/推荐节点的标题约定、API 格式导出、OpenMAIC 设置页配置以及生产环境下的 SSRF 安全边界与性能调优。读完本文你将能够把一个普通 ComfyUI 工作流改造成 OpenMAIC 可自动驱动的生图工作流并安全地将其部署到同机或跨机环境。一、工作流文件存放位置与命名约定OpenMAIC 通过 HTTP API 与 ComfyUI 通信其模型概念对应的是你存放在 Next.jspublic/目录下的工作流 JSON 文件。目录结构如下your-project/ public/ comfyui-workflow.json → 在下拉框中显示为 Workflow comfyui-anime-style.json → 显示为 Anime Style comfyui-line-art.json → 显示为 Line Art comfyui-portrait.json → 显示为 Portrait命名约定文件名必须以comfyui-开头或包含workflow用连字符hyphen分隔单词这些单词会直接成为 UI 下拉框中的显示名comfyui-前缀会被自动剥离示例comfyui-anime-style.json在下拉框中显示为Anime Style。这套规则在源码中有严格对应lib/media/comfyui-workflows.ts中的isComfyuiWorkflowFilename()规定文件必须以.json结尾且小写化后以comfyui开头或包含workflowfilenameToDisplayName()则负责把文件名转换为显示名——先去掉.json后缀和comfyui-/comfyui_前缀再把连字符/下划线替换为空格并按单词首字母大写Title Case。工作流发现逻辑统一收敛在 lib/media/comfyui-workflows.ts 的listComfyuiWorkflows()它读取public/目录下满足命名规则且是普通文件的 JSON 文件按显示名排序返回。这个函数同时被两个消费方引用API 路由 app/api/comfyui-workflows/route.tsGET /api/comfyui-workflows返回{ workflows: [{ id, name }] }供设置页的 Workflows 下拉列表使用ComfyUI 图像适配器校验客户端提交的工作流 id 是否为真实存在的文件。这样设计保证了UI 展示的列表与适配器实际接受的 id永远一致不会出现下拉框里能选、提交后却报找不到文件的漂移问题。二、工作流中的必需与推荐节点按标题匹配适配器**按节点的标题JSON 中的_meta.title字段**定位节点而不是按节点类型或 ID。在 ComfyUI 中设置节点标题的方法右键节点 →Title→ 输入名称。必需节点节点标题推荐类型用途Input PromptPrimitiveStringMultilineOpenMAIC 生成的图片描述会被注入到此节点的value输入推荐节点存在即自动打补丁节点标题推荐类型用途WidthPrimitiveInt输出宽度像素按请求的宽高比设置HeightPrimitiveInt输出高度像素按请求的宽高比设置KSamplerKSampler每次生成都会随机化 seed保证输出多样化Enable prompt enhancement?PrimitiveBoolean设为false跳过 LLM Prompt 增强推荐更快源码层面的匹配逻辑在 comfyui-image-adapter.ts 的findNodeIdByTitle()遍历工作流对象的所有节点找出_meta.title与目标标题不区分大小写相等的第一个节点并返回其 id。随后patchWorkflow()按照优先使用显式节点、否则回退到遗留节点的策略逐项打补丁Prompt 注入优先Input Prompt节点写入inputs.value options.prompt尺寸注入同时找到Width与Height节点时分别写入inputs.value否则回退到Empty Flux 2 Latent节点的inputs.width / inputs.heightSeed 随机化找到KSampler节点后把inputs.seed替换为一个Math.floor(Math.random() * 1e15)生成的随机整数。回退行为Fallback如果Width和Height节点均不存在适配器自动回退到直接修补Empty Flux 2 Latent节点的width、height输入——因此没有独立尺寸节点的旧工作流也能正常工作Width和Height必须同时存在才走显式节点方案如果只找到其中一个适配器会回退到 latent 节点方案并打印一条 warning 日志源码在patchWorkflow()中对widthNodeId || heightNodeId分支有明确提示Prompt 节点回退如果找不到Input Prompt适配器回退到名为String (Multiline - Prompt)的节点——仓库自带的示例工作流 public/comfyui-workflow.json 中88:94节点正是PrimitiveStringMultiline类型、标题为String (Multiline - Prompt)无需任何重命名即可直接使用兜底报错若两种标题都找不到适配器会抛出明确的错误提示add a node titled Input Prompt见patchWorkflow()第 314-320 行。尺寸还有一个重要细节resolveDimensions()会把请求的宽高比换算成像素后同时按 Provider 的maxResolution边界收缩。lib/media/image-providers.ts中comfyui-image的maxResolution为{ width: 1920, height: 1920 }因此竖屏比例如 9:16不会因为宽度钉死 1920而溢出到 3413 高度从而避免 OOM 或生成失败。三、节点连线方式Input Prompt把Input Prompt节点的输出接到提示词进入管线的地方——典型是CLIPTextEncode节点的text输入如果使用了 Prompt 模板也可以接到StringReplace节点。Width 与 Height把每个节点的输出接到你的Empty Flux 2 Latent或等效的空 Latent节点对应的width和height输入。示例连线[Input Prompt] ──→ CLIPTextEncode (text) [Width] ──→ EmptyLatentImage (width) [Height] ──→ EmptyLatentImage (height)仓库示例工作流 public/comfyui-workflow.json 展示了完整的参考接法88:94String (Multiline - Prompt)→88:97Switch由88:96的Enable prompt enhancement?布尔节点控制走原始 Prompt 还是 LLM 增强路径→88:67CLIPTextEncode→88:70KSampler尺寸则由88:71Empty Flux 2 Latent类型EmptyFlux2LatentImage提供latent_image输入。这个文件同时印证了文档中所有节点标题约定都是可运行的真实配置。四、如何导出 API 格式的工作流工作流 JSON必须是 ComfyUI 的 API 格式不是默认的保存格式否则适配器无法识别节点结构。在 ComfyUI 中进入Settings开启Dev Mode Options工具栏会出现一个新的Save (API Format)按钮点击Save (API Format)导出正确的 JSON把文件放到 Next.js 的public/目录中。⚠️ 普通的Save按钮导出的是另一种格式包含 UI 布局、位置信息等无法工作。为什么必须是 API 格式从适配器读取方式可以反推loadWorkflow()加载 JSON 后直接把它当作{ 节点id: { inputs, class_type, _meta } }的扁平映射来遍历并按标题定位节点Object.entries(workflow)这正是 ComfyUI/prompt接口期望的prompt graph格式。普通保存格式中节点不是这种扁平结构findNodeIdByTitle()无法工作nodeInputs()也会返回undefined并触发malformed错误。五、在 OpenMAIC 中配置进入Settings → Image Generation在 Provider 列表中选择ComfyUI Image设置Base URL为你的 ComfyUI 地址默认http://localhost:8188在Workflows列表中选择要使用的工作流点击Test Connection验证 ComfyUI 是否可达。无需 API Keylib/media/image-providers.ts中comfyui-image的requiresApiKey: false默认baseUrl为http://localhost:8188。值得注意的是它的models: []是刻意为之——真实可选的工作流是运行时通过GET /api/comfyui-workflows即public/目录下的文件动态发现的并不存在静态模型列表。Test Connection的底层实现是testComfyuiImageConnectivity()向${baseUrl}/system_stats发起一次 GET 探测10 秒超时、不跟随重定向返回 HTTP 200 即判定连通。测试用例 tests/media/auth-probe-adapters.test.ts 覆盖了包括 ComfyUI 在内的各 Provider 探测行为验证请求 URL、redirect 策略与错误消息。默认工作流选择如果没有显式选择工作流——例如走自主课堂媒材生成classroom-media路径或在设置页尚未点击任何工作流时——适配器会自动回退到public/中发现按显示名排序的第一个工作流文件listComfyuiWorkflows()按name.localeCompare排序后取known[0]。它不依赖任何硬编码文件名所以你不需要准备一个叫comfyui-workflow.json的文件任何一个comfyui-*.json都会被用作默认如果public/中一个工作流文件都没有生成会直接失败并抛出明确错误提示Add at least one comfyui-*.json workflow。同时工作流 id 是客户端可控参数来自x-image-model请求头适配器做了两层防护先用isComfyuiWorkflowFilename()校验必须是裸文件名不含路径分隔符与..再与listComfyuiWorkflowFilenames()返回的实时目录清单比对最后还会验证解析后的文件路径仍落在public/目录内——三重防线防止路径穿越详见loadWorkflow()服务端分支注释。六、部署拓扑与 SSRF 安全边界生产环境必读默认 Base URLhttp://localhost:8188假设OpenMAIC 与 ComfyUI 运行在同一台主机典型的本地 / 自托管部署。当 OpenMAIC 以NODE_ENVproduction运行时由客户端提供的Base URLx-base-url若指向localhost、127.0.0.1或私有/内网 IP 段会被 SSRF 防护validateUrlForSSRF以 HTTP 403 拒绝。这是有意为之与其它本地 Provider 的行为一致——防止浏览器客户端把服务端请求导向内部服务。SSRF 防护实现在 lib/server/ssrf-guard.tsvalidateUrlForSSRF()会拦截localhost、.local域名、0.0.0.0、::1以及isPrivateIP()判定的各类私网地址IPv4 的 10/8、172.16/12、192.168/16、127/8、169.254/16 等还包括 IPv4-mapped IPv6、6to4、Teredo、ISATAP 等 IPv6 隧道中内嵌私网 IPv4 的情况对非 IP 主机名还会做 DNS 解析后再校验解析结果。自托管场景可通过环境变量ALLOW_LOCAL_NETWORKStrue跳过私网检查。实际影响同机 / 自托管开箱即用。服务端解析的默认值不受客户端 URL 的 SSRF 检查约束因此 OpenMAIC 与 ComfyUI 同机时默认的localhost:8188完全可用生产环境中 ComfyUI 在另一台机器应让 OpenMAIC 通过可路由、非私网的地址访问 ComfyUI或在公共主机名后接反向代理终结。生产环境下浏览器发来的localhost/私网 URL 会被拒绝本地开发NODE_ENV≠production跳过 SSRF 检查localhost正常工作。七、生成流程与性能调优一次完整生成的调用链generateWithComfyuiImage()的完整流程源码注释与日志分段清晰可循加载工作流优先使用调用方传入的已解析workflowJson否则服务端从磁盘读取浏览器端从window.location.originfetch实际生成总在服务端 API 路由执行未指定时取public/下第一个发现的工作流打补丁patchWorkflow()注入 Prompt、Width/Height或 latent 尺寸、随机 seed入队POST {baseUrl}/promptbody 为{ prompt: workflow, client_id }若 ComfyUI 返回node_errors立即抛出带细节的错误轮询每 1500ms 请求一次/history/{prompt_id}直到status.completed单次请求超时 30s整体硬超时 5 分钟GENERATION_TIMEOUT_MS 300_000若status_str error会从执行消息中提取execution_error的真实原因快速失败而不是傻等超时取图从 history 中提取第一个输出节点的图片请求/view?filename...subfolder...type...服务端用Buffer转 base64 返回。性能建议关闭 Prompt 增强如果工作流里带 LLM 增强器把它的开关节点设为false。增强每张图可能额外花费 3-5 分钟而 OpenMAIC 生成的 Prompt 本身已经足够描述性。示例工作流中对应88:96节点PrimitiveBoolean标题Enable prompt enhancement?它控制88:97Switch 节点在原始 Prompt88:94与 LLM 增强路径88:95TextGenerate之间切换适配器会自动随机化KSampler的 seed每次生成一个 15 位随机整数无需手工干预即可保证输出多样性输出尺寸由 OpenMAIC 请求的宽高比换算而来并受 lib/media/image-providers.ts 中maxResolution限制ComfyUI 默认1920×1920竖屏比例会被等比收缩进边界框内。八、常见故障排查要点结合源码中的错误分支以下问题都有明确的对症现象可能原因处理方式下拉框没有工作流可选public/下没有符合命名规则的文件放入comfyui-*.json或含workflow的.json文件并重启missing a prompt input node工作流缺少Input Prompt或String (Multiline - Prompt)标题节点右键节点 → Title 重命名或改用 API 格式重新导出prompt node is malformed工作流不是 API 格式用Save (API Format)重新导出node_errors报错工作流节点连线断裂在 ComfyUI 中检查节点连接后重新导出超时5 分钟生成本身过慢或队列阻塞关闭 Prompt 增强、检查 ComfyUI 队列finished but returned no images工作流缺少SaveImage节点在管线末端加入 SaveImage 节点生产环境 403浏览器提交了localhost/私网 Base URL将 ComfyUI 暴露为可路由的非私网地址或设置ALLOW_LOCAL_NETWORKStrue自托管场景小结OpenMAIC 对 ComfyUI 的接入遵循按标题找节点、运行时打补丁、无 Key 直连本地的设计你只需把工作流以 API 格式放入public/、按约定命名、给关键节点设置好标题就能让课堂 Agent 自动完成描述 → 出图 → 回填课件的闭环。通过 lib/media/adapters/comfyui-image-adapter.ts、lib/media/comfyui-workflows.ts、lib/server/ssrf-guard.ts 等源码你可以进一步追踪每个补丁点与安全边界的具体实现也可以参考 public/comfyui-workflow.json 作为可直接运行的模板。【免费下载链接】OpenMAICOpen Multi-Agent Interactive Classroom — Get an immersive, multi-agent learning experience in just one click项目地址: https://gitcode.com/GitHub_Trending/op/OpenMAIC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进