{"slug":"workflow-design","title":"workflow-design","summary":"Imported from mrpulor-gh/nuphus/plugin/skills/builtin/workflow-design.","platform":"Claude","tags":["workflow"],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-30T20:55:57.112549Z","repo":{"url":"https://github.com/mrpulor-gh/nuphus","stars":76,"forks":16,"license":"Apache-2.0","updatedAt":"2026-09-22T12:32:19Z"},"bodyHtml":"<hr>\n<h2>title: 工作流设计经验手册\nid: workflow-design\ntype: skill\ntags: [workflow, 设计, 编排, schema, 调试, 闭环]</h2>\n<h1>工作流设计经验手册</h1>\n<blockquote>\n<p>完整工作流编排能力：步骤 schema、变量语法、条件表达式、params 固化、设计模式、验证闭环、经验闭环。\nL2 提示词只给阶段门禁与交互纪律；本文档是可执行的方法论全集。</p>\n</blockquote>\n<hr>\n<h2>〇、编排闭环总览</h2>\n<pre><code>接收任务\n  ├─ [查] ui_maps_search 检索同类经验 → 有 screen/experience 直接复用，跳过重复探索\n  ├─ [探] 逐屏探索 → ui_maps_save_screen 固化布局（每屏经用户确认）\n  ├─ [固] 生成 params.json + workflow.json + guide.md（参数即契约，全部有界面证据）\n  ├─ [验] workflow_validate 编译校验 → workflow_run 执行 → 连续 3 次一致 + 至少一个异常路径\n  └─ [馈] 跑通后 ui_maps_save_experience 提炼经验；新异常回写 params.json exceptions\n</code></pre>\n<hr>\n<h2>一、步骤 Schema（V2，唯一真相源 <code>src/workflow/step_schema.json</code>）</h2>\n<h3>公共字段</h3>\n<table>\n<thead>\n<tr>\n<th>字段</th>\n<th>必填</th>\n<th>说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>✅</td>\n<td>步骤唯一标识（断点续连按 id 跳过已完成步骤）</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td>✅</td>\n<td>人类可读名称</td>\n</tr>\n<tr>\n<td><code>description</code></td>\n<td>可选</td>\n<td>详细说明</td>\n</tr>\n<tr>\n<td><code>on_error</code></td>\n<td>可选</td>\n<td><code>\"abort\"</code>(默认) / <code>\"skip\"</code> / <code>{retry:{max,backoff_ms?,backoff_multiplier?}}</code> / <code>{allow_codes:{codes:[...]}}</code></td>\n</tr>\n<tr>\n<td><code>capture</code></td>\n<td>可选</td>\n<td><strong>字符串</strong>：步骤输出存入变量名（无对象格式）</td>\n</tr>\n<tr>\n<td><code>timeout_secs</code></td>\n<td>可选</td>\n<td>步骤超时秒数</td>\n</tr>\n<tr>\n<td><code>do</code></td>\n<td>✅</td>\n<td>动作定义，仅下列一种 key</td>\n</tr>\n</tbody>\n</table>\n<h3>动作类型（do 的 13 种形态）</h3>\n<table>\n<thead>\n<tr>\n<th>kind</th>\n<th>写法</th>\n<th>要点</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>tool</td>\n<td><code>{\"tool\":\"desktop_mouse\",\"with\":{...}}</code></td>\n<td>with 支持 <code>{{var}}</code> 模板</td>\n</tr>\n<tr>\n<td>seq</td>\n<td><code>{\"seq\":[...]}</code></td>\n<td>顺序容器，可嵌套</td>\n</tr>\n<tr>\n<td>loop</td>\n<td><code>{\"loop\":{\"for_each\"\\|\"repeat\"\\|\"until\":..., \"max\":100, \"do\":[...]}}</code></td>\n<td>until=条件<strong>满足即停</strong>；max 防死循环</td>\n</tr>\n<tr>\n<td>if</td>\n<td><code>{\"if\":{\"condition\":{...},\"then\":[...],\"else\":[...]}}</code></td>\n<td>else 可省略</td>\n</tr>\n<tr>\n<td>call</td>\n<td><code>{\"call\":\"wf-id\",\"with\":{\"inputs\":{...},\"outputs\":{...}}}</code></td>\n<td>inputs 传子变量；outputs 子变量名→父变量名回写</td>\n</tr>\n<tr>\n<td>wait</td>\n<td><code>{\"wait\":\"提示语\",\"auto\":[...]}</code></td>\n<td>auto=等待期自动执行步骤（可选）</td>\n</tr>\n<tr>\n<td>chat</td>\n<td><code>{\"chat\":\"LLM任务描述\",\"with\":{...}}</code></td>\n<td>LLM 决策节点（原 chat_agent）</td>\n</tr>\n<tr>\n<td>script</td>\n<td><code>{\"script\":{\"runtime\":\"python\"\\|\"node\"\\|\"ahk\"\\|\"pwsh\",\"code\":\"...\",\"cwd\":\"?\"}}</code></td>\n<td>code 支持 <code>{{var}}</code> 替换</td>\n</tr>\n<tr>\n<td>assert</td>\n<td><code>{\"assert\":{\"condition\":{...},\"message\":\"?\"}}</code></td>\n<td>on_error=skip 时变非阻断校验</td>\n</tr>\n<tr>\n<td>mcp</td>\n<td><code>{\"mcp\":{\"server\":\"key\",\"tool\":\"name\",\"with\":{...}}}</code></td>\n<td>server 对应 servers.yaml</td>\n</tr>\n<tr>\n<td>sleep</td>\n<td><code>{\"sleep\":N}</code></td>\n<td>秒，0.1–3600</td>\n</tr>\n<tr>\n<td>break</td>\n<td><code>{\"break\":true}</code></td>\n<td>跳出当前循环</td>\n</tr>\n<tr>\n<td>continue</td>\n<td><code>{\"continue\":true}</code></td>\n<td>跳过当前迭代</td>\n</tr>\n</tbody>\n</table>\n<h3>chat 步骤 with（LLM 决策配置）</h3>\n<p><code>agent_id</code>（ChatAgentConfig ID）/ <code>screenshot</code>（执行前截图注入）/ <code>tools</code>（白名单）/ <code>knowledge</code>（知识库路径）/ <code>model</code> / <code>temperature</code> / <code>max_tokens</code> / <code>system_prompt</code> / <code>persona</code> / <code>goal</code> / <code>constraints</code> / <code>requirements</code> / <code>max_iterations</code>（ReAct 最大轮数，<strong>与 max_steps 语义重叠，统一用 max_iterations</strong>）</p>\n<h3>容器 on_error</h3>\n<p>seq / loop / if 容器同样支持 on_error；子步骤失败且容器设置了 skip 时继续执行容器内后续步骤。</p>\n<hr>\n<h2>二、变量与模板语法</h2>\n<h3>三套引用，边界必须分清</h3>\n<table>\n<thead>\n<tr>\n<th>写法</th>\n<th>语义</th>\n<th>适用</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>{{var}}</code></td>\n<td>模板替换。<strong>整串</strong>时保留原始类型（数字/布尔/对象不字符串化）；<strong>内嵌文本</strong>（如 <code>\"x={{var}}px\"</code>）时字符串化</td>\n<td>with 参数值、script code</td>\n</tr>\n<tr>\n<td><code>{{var \\| get \"f\"}}</code> / <code>{{var \\| json \"k\"}}</code> / <code>{{var \\| len}}</code> / <code>{{ENV:HOME}}</code> / <code>{{var \\| default \"v\"}}</code></td>\n<td>管道表达式</td>\n<td>同上</td>\n</tr>\n<tr>\n<td><code>{params.window.url}</code></td>\n<td><strong>单花括号</strong>，仅整串引用 params.json 字段，返回原始类型；点号路径下钻</td>\n<td>引用固化参数</td>\n</tr>\n<tr>\n<td><code>{ \"var\": \"name\" }</code></td>\n<td>对象形式变量引用（VarRef），支持点号路径 <code>{ \"var\": \"coords.x\" }</code></td>\n<td>条件表达式、loop.for_each.items</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>坑：坐标字段若内嵌 <code>{{x}}</code> 会字符串化，务必整串引用或用 <code>| get</code> 下钻保持数字类型。</p>\n</blockquote>\n<h3>变量池来源</h3>\n<p><code>workflow_run(inputs)</code> 注入 → params.json（<code>{params.x}</code> 兑现）→ 各步骤 <code>capture</code> 写入。子工作流有独立变量池，靠 <code>call.with.inputs/outputs</code> 跨池传递。</p>\n<hr>\n<h2>三、条件表达式（Condition，12 种）</h2>\n<p>二元（[VarRef, 值] 两元数组）：<code>equals</code> / <code>not_equals</code> / <code>contains</code> / <code>starts_with</code> / <code>regex</code> / <code>gt</code> / <code>lt</code> / <code>gte</code> / <code>lte</code>\n一元：<code>not_empty</code> / <code>empty</code>\n恒真：<code>always</code></p>\n<pre><code>{ \"if\": { \"condition\": { \"equals\": [ { \"var\": \"login_status\" }, \"LOGGED_IN\" ] }, \"then\": [...] } }\n</code></pre>\n<hr>\n<h2>四、params.json 固化规范</h2>\n<table>\n<thead>\n<tr>\n<th>字段</th>\n<th>内容</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>workflow_id</code></td>\n<td>工作流唯一标识</td>\n</tr>\n<tr>\n<td><code>window</code></td>\n<td>尺寸 / URL / 标题模式（<strong>窗口尺寸必须固化</strong>，W2）</td>\n</tr>\n<tr>\n<td><code>login_detection</code></td>\n<td>登录态判定特征</td>\n</tr>\n<tr>\n<td><code>regions</code></td>\n<td>区域定义 + 定位特征（每参数有界面证据）</td>\n</tr>\n<tr>\n<td><code>navigation_graph</code></td>\n<td>屏间跳转关系</td>\n</tr>\n<tr>\n<td><code>exceptions</code></td>\n<td>异常路径 + 降级策略（探索中异常即时记录，W4）</td>\n</tr>\n</tbody>\n</table>\n<p>模板骨架：</p>\n<pre><code>{\n  \"workflow_id\": \"demo-flow\",\n  \"window\": { \"title_pattern\": \"App 标题\", \"width\": 1280, \"height\": 800 },\n  \"login_detection\": { \"indicator\": [\"登录\", \"Sign in\"] },\n  \"regions\": [{ \"name\": \"chat-list\", \"rect\": { \"x\": 0, \"y\": 100, \"w\": 300, \"h\": 600 }, \"anchor\": { \"type\": \"text\", \"value\": \"会话\" } }],\n  \"navigation_graph\": { \"chat-list\": { \"to\": [\"chat-window\"], \"trigger\": \"click-contact\" } },\n  \"exceptions\": [{ \"condition\": \"登录弹窗\", \"fallback\": \"wait 用户介入\" }]\n}\n</code></pre>\n<hr>\n<h2>五、设计模式库</h2>\n<h3>模式 A：登录态检测守卫</h3>\n<pre><code>{ \"id\": \"guard\", \"name\": \"登录保障\", \"do\": { \"seq\": [\n  { \"id\": \"check\", \"name\": \"判断登录态\",\n    \"do\": { \"chat\": \"根据 login_detection 特征判断是否已登录\", \"with\": {\n      \"agent_id\": \"login-checker\", \"screenshot\": true,\n      \"requirements\": [\"只输出 LOGGED_IN 或 LOGIN_REQUIRED\"] } },\n    \"capture\": \"login_status\" },\n  { \"id\": \"branch\", \"name\": \"按登录态分支\",\n    \"do\": { \"if\": {\n      \"condition\": { \"equals\": [ { \"var\": \"login_status\" }, \"LOGIN_REQUIRED\" ] },\n      \"then\": [\n        { \"id\": \"manual\", \"name\": \"手动登录\", \"do\": { \"wait\": \"请完成登录后点击继续\" } }\n      ],\n      \"else\": [] } } }\n] } }\n</code></pre>\n<p>要点：<strong>语义判断</strong>（chat+screenshot）而非文案匹配；登录动作交用户，不碰凭据。</p>\n<h3>模式 B：for_each 遍历</h3>\n<pre><code>{ \"id\": \"tour\", \"name\": \"遍历\", \"do\": { \"loop\": {\n  \"for_each\": { \"items\": { \"var\": \"panels\" }, \"as\": \"p\" },\n  \"max\": 100,\n  \"do\": [ { \"id\": \"hit\", \"name\": \"点击\", \"do\": { \"tool\": \"desktop_mouse\",\n    \"with\": { \"action\": \"click\", \"x\": \"{{p | get \\\"ix\\\"}}\", \"y\": \"{{p | get \\\"iy\\\"}}\" } } } ]\n} } }\n</code></pre>\n<h3>模式 C：表单提交 + 结果验证</h3>\n<pre><code>seq: 提交\n├─ 填写 + 提交（desktop_input 输入+发送一次调用，不拆分）\n├─ browser_wait_for(结果页元素)\n├─ assert: 成功标志存在\n└─ if: 失败 → screenshot → chat 分析 → 重试或终止\n</code></pre>\n<h3>模式 D：多窗口操作</h3>\n<p>每次操作前 <code>desktop_windows_list</code> 重取 hwnd（hwnd 会变）→ activate → 操作。</p>\n<h3>模式 E：大工作流拆分</h3>\n<p>单层 &gt;15 步或嵌套 &gt;3 层 → 拆子工作流。主文件含 <code>call</code> 步骤，子工作流 JSON 同目录。用 <code>with.outputs</code> 回传结果。</p>\n<h3>模式 F：SPA 搜索框提交（优先级从高到低）</h3>\n<ol>\n<li><code>browser_snapshot</code> 找 @eN ref → click</li>\n<li>无 ref → <code>browser_screenshot</code> → OCR 找按钮坐标 → JS 模拟点击</li>\n<li>都不行 → <code>browser_evaluate</code> 触发 form.submit()（最后手段）</li>\n</ol>\n<h3>模式 G：验证码/滑块</h3>\n<p><code>desktop_mouse_drag</code> 起点→终点；无法自动处理 → <code>wait</code> 用户介入并标记 exceptions。</p>\n<hr>\n<h2>六、验证闭环方法论</h2>\n<pre><code>workflow_validate（编译校验：步骤合法性/工具名/必填/变量引用/call 环）\n  → 干净环境 workflow_run（第 1 次：探路，记录偏差）\n  → 分析异常 → 修正 params / workflow（设计缺陷才改文件；运行时阻塞就地解决）\n  → 重跑（同 id 断点续连，禁新建复制）→ 连续 3 次结果一致\n  → 至少触发一个异常路径验证降级\n</code></pre>\n<p>验收：跑通 ∧ 3 次一致 ∧ 异常路径生效 ∧ 降级不丢数据不重复提交 ∧ 无敏感数据残留。</p>\n<p><strong>运行时故障恢复</strong>：失败 → 识别阻塞（验证码/弹窗/登录态/网络）→ 就地解决（browser_<em>/desktop_</em> 同会话，状态保留）→ 同 id 续跑。同一步骤同阻塞连续 3 次失败 → 停止，用 completed_steps 汇报。</p>\n<hr>\n<h2>七、经验检索 / 提炼</h2>\n<h3>两级检索</h3>\n<ol>\n<li>骨架：<code>ui_maps_search(query=\"微信 im\")</code> → 有哪些 screen / experience</li>\n<li>详情：<code>ui_maps_search(query=\"微信\", screen_name=\"chat-list\")</code> → 完整 regions + 关联经验</li>\n</ol>\n<h3>什么值得存（存「法」不存「案」）</h3>\n<ul>\n<li>✅ 非显而易见操作序列 / 跨应用可复用模式 / 踩过的坑 / 特殊定位技巧</li>\n<li>❌ 常规操作（browser_navigate）/ 一次性案例 / 提示词已覆盖内容</li>\n</ul>\n<h3>summary 写法</h3>\n<p><code>做什么 → 怎么做 → 为什么 → 跨应用适用性</code>（非传统思路要标注省了几步）。</p>\n<hr>\n<h2>八、工具使用要点</h2>\n<table>\n<thead>\n<tr>\n<th>场景</th>\n<th>首选</th>\n<th>备选</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>定位网页元素</td>\n<td><code>browser_snapshot</code> → @eN ref</td>\n<td>screenshot + OCR</td>\n</tr>\n<tr>\n<td>桌面布局解析</td>\n<td>Vision 全窗口语义分析</td>\n<td>perceive 精确坐标</td>\n</tr>\n<tr>\n<td>定位桌面文字</td>\n<td>Vision 划定功能区</td>\n<td><code>desktop_find_text</code>（需字库）</td>\n</tr>\n<tr>\n<td>等待加载</td>\n<td><code>browser_wait_for(selector)</code></td>\n<td>system_sleep（不得已）</td>\n</tr>\n<tr>\n<td>验证状态</td>\n<td>snapshot + chat 语义判断</td>\n<td>extract 文本匹配</td>\n</tr>\n<tr>\n<td>查经验</td>\n<td>ui_maps_search 两级检索</td>\n<td>Read ui-maps JSON</td>\n</tr>\n</tbody>\n</table>\n<p><strong>坐标体系</strong>：<code>desktop_mouse</code> 一律用<strong>屏幕绝对坐标</strong>；perceive 结果为客户区坐标时手动加 <code>screen_x/screen_y</code> 偏移。</p>\n<p><strong>输入</strong>：<code>desktop_input</code> 输入+发送一次调用；普通文本直接输入，&gt;500 字用 clipboard 并事后 clean；敏感内容禁用 clipboard。</p>\n<hr>\n<h2>九、陷阱清单</h2>\n<table>\n<thead>\n<tr>\n<th>陷阱</th>\n<th>正确做法</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>跳过布局解析直接找元素（W1）</td>\n<td>逐屏 vision+perceive 解析，保存 ui-maps</td>\n</tr>\n<tr>\n<td>窗口尺寸未固化（W2）</td>\n<td>params.json window 字段固化</td>\n</tr>\n<tr>\n<td>探索阶段写步骤（W3）</td>\n<td>核心路径手动跑通后才设计</td>\n</tr>\n<tr>\n<td>if contains 文案做登录检测</td>\n<td>chat 语义判断 + screenshot</td>\n</tr>\n<tr>\n<td>忘记 SPA 状态残留</td>\n<td>新流程前重置（about:blank / resize 固化尺寸）</td>\n</tr>\n<tr>\n<td>tooltip OCR 截到其他窗口</td>\n<td>先 desktop_window_info 拿客户区边界，截图限域</td>\n</tr>\n<tr>\n<td>重试重复提交表单</td>\n<td>重试前检测状态，已完成步骤跳过</td>\n</tr>\n<tr>\n<td>纯色/低纹理模板匹配误报</td>\n<td>find_image 模板需含纹理；用 region 限定加速</td>\n</tr>\n<tr>\n<td>动态 UI 区匹配失败</td>\n<td>识别为动态区域，改用文本/语义定位</td>\n</tr>\n</tbody>\n</table>\n","files":[{"path":"skill.json","sizeBytes":737,"isText":true},{"path":"SKILL.md","sizeBytes":17208,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-22T13:50:56.497505Z","sha256":"09808D09D6CA49330CF6E962E84491488E4F32CE4E6CCF4B542EAAD6201D5CBF","sizeBytes":9253},"review":null,"source":{"repositoryUrl":"https://github.com/mrpulor-gh/nuphus","path":"plugin/skills/builtin/workflow-design","license":"Apache-2.0","commit":"4926d84d74ec88cf80e5a420420232e583ce0df8","subtreeSha":"6836F9AC394193BFA94AF5C5BC875A77CBC82AE22B7CA8FFDF76FE2185A33AC1","lastSyncedAt":"2026-09-22T13:50:31.448591Z"},"reviewedAt":"2026-09-22T13:56:10.109408Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/mrpulor-gh/nuphus/tree/main/plugin/skills/builtin/workflow-design"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install mrpulor-gh-nuphus@llmmart"},{"target":"git","command":"git clone https://github.com/mrpulor-gh/nuphus.git"}]}