ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Claude Code Routine工程化:多Agent编排与闭环自愈实战

Claude Code Routine工程化:多Agent编排与闭环自愈实战 1. 项目概述这不是一个“插件安装教程”而是一次对智能编码工作流底层逻辑的手术式解剖你有没有过这种体验在 VS Code 里敲下CtrlK对着 Claude Code 提问“帮我写个 Python 脚本解析 CSV 并生成统计图表”它回你一段代码你复制粘贴、运行、报错再把错误信息复制回去“第17行 KeyError: date 是什么意思”——它又给你改一行你再试又出新错循环五次后你发现时间过去了40分钟而那个本该5分钟搞定的小工具还没跑通。这不是模型能力不行而是人机协作范式出了根本性问题我们还在用“单步问答”这种20世纪的交互方式去驱动一个本应具备工程化思维的智能体。标题里说的“告别低效单步聊天”指的就是彻底跳出这个陷阱。Claude Code 不该是你的“高级搜索引擎”而应是嵌入开发流程的可编排、可自愈、可脚本化的协同工程师。多 Agent 编排不是让五个 Claude 同时在线聊天而是把“需求理解→代码生成→静态检查→单元测试→环境部署→结果验证”这些原本由人类大脑串行调度的环节拆解成职责清晰、通信契约明确的独立智能体并通过标准化协议串联闭环自愈不是等你截图发错再重来而是当测试失败时Agent 自动抓取错误堆栈、定位变更点、生成修复补丁、重新触发验证流水线整个过程无人工干预Routine 脚本化则是把这套复杂协作固化为可复用、可版本管理、可参数注入的 YAML 或 JSON 流程定义就像 GitOps 之于基础设施Routine 就是 AI 工程化的 IaCInfrastructure as Code。我过去三个月在三个真实项目中落地这套架构一个金融风控规则引擎的自动化重构、一个电商后台订单状态机的合规性校验脚本生成、一个物联网设备固件升级包的签名与分发流水线搭建。实测下来单次任务平均交付周期从原来的 22 分钟压缩到 3 分 47 秒人工介入率从 83% 降至 9%且所有 Routine 都能直接提交进 Git 仓库和业务代码一起做 CI/CD。这背后没有魔法只有对 Claude Code 底层通信机制、状态管理模型和执行沙箱约束的深度理解。接下来我会像带一个资深后端工程师那样带你一层层剥开它的内核——不讲概念只讲你明天就能抄作业的硬核细节。2. 核心架构设计为什么必须放弃“对话式编程”转向“编排式工程”2.1 单步聊天失效的本质状态断裂与上下文熵增很多人以为 Claude Code 的瓶颈在模型本身其实更深层的问题在于交互协议的设计缺陷。当你在聊天窗口输入“写个函数计算斐波那契数列”Claude Code 接收到的是一个孤立的文本 token 序列。它内部会做三件事1基于当前 prompt 模板做意图识别2调用其内置的 code generation model 生成代码3将结果以 Markdown 块形式返回。整个过程没有持久化状态没有执行环境反馈没有错误溯源路径。提示你可以自己验证这一点——在同一个聊天窗口连续问“写个斐波那契函数” → “加个缓存装饰器” → “改成迭代实现”。你会发现第二次请求时模型完全不记得第一次生成的函数名第三次甚至可能把前两次的代码混在一起改。这不是模型“健忘”而是系统压根没设计状态存储机制。真正的工程化协作需要状态锚定State Anchoring每个 Agent 必须在一个明确定义的上下文快照中工作。比如“代码生成 Agent”只接收结构化的需求描述如 OpenAPI spec 或 UML 类图片段输出严格符合 PEP8 的 .py 文件“测试 Agent”则只接收该文件路径和预设的 test suite 配置输出 pytest 的 XML 报告。它们之间不靠“聊天记录”传递信息而是通过共享文件系统或轻量级消息队列如 Redis Stream交换 JSON Schema 定义的数据包。这样当测试失败时“修复 Agent”能精准拿到原始源码、错误日志、测试覆盖率报告三者关联的完整快照而不是一段模糊的自然语言描述。2.2 多 Agent 编排的三种可行路径对比目前社区常见的“多 Agent”方案有三类但绝大多数都踩了坑。我用实际压测数据对比它们在 100 次并发 Routine 执行中的稳定性方案类型实现方式平均延迟故障率状态一致性适合场景Chat-Chain 模式在单个聊天窗口里用 system prompt 强制角色切换如“你现在是测试工程师请检查上段代码”8.2s37%❌ 完全不可控学习演示不可用于生产Process Orchestrator 模式用 LangChain / LlamaIndex 构建 workflow每个 step 调用 Claude Code API12.6s19%⚠️ 依赖外部 DB 存储中间态中小规模自动化需额外运维Native Routine 模式直接使用 Claude Code 内置的routine功能通过 VS Code 插件或 CLI 触发预定义 YAML 流程3.4s2.1%✅ 全链路原子性保证推荐所有生产级场景关键结论Claude Code 的routine不是另一个 SDK而是其原生执行引擎的暴露接口。它绕过了 Web UI 层的所有状态管理包袱直接在本地沙箱中加载 YAML 定义的 DAG有向无环图每个节点对应一个预编译的 Agent 模块。这意味着——你写的 YAML 就是部署清单VS Code 插件就是 kubectl而 Claude Code 本体就是你的 Kubernetes 集群。后面所有实操都将基于此模式展开。2.3 闭环自愈的底层支撑Claude Code 的 Execution Sandbox 机制很多教程教你“用 shell command 让 Claude 执行命令”但这只是表层。真正支撑自愈能力的是其沙箱的三重隔离设计进程级隔离每个 Routine 运行在独立的node --no-deprecation子进程中PID 可追踪OOM 时自动 kill文件系统视图隔离通过chrootoverlayfs技术为每个 Routine 创建专属的/workspace目录外部文件不可见内部修改不污染宿主网络策略白名单默认禁用所有外网访问仅允许localhost:3000本地 mock server和127.0.0.1:6379本地 Redis两个地址防止模型偷偷调用第三方 API。正是这套机制让“自愈”成为可能当测试步骤失败时沙箱会自动捕获 exit code、stdout/stderr、core dump如果有的话并将其序列化为标准错误事件Error Event。Routine 引擎检测到该事件后不会终止流程而是触发预设的on_failurehandler——它可以是一个重试策略如指数退避、一个降级脚本如 fallback to static analysis、或最关键的一个指向“修复 Agent”的跳转指令。这个跳转不是重新发起一次聊天而是将错误事件连同原始输入快照作为新输入直接喂给修复 Agent 的专用 prompt template。注意不要试图在 Routine YAML 里写shell: npm test。Claude Code 的shellaction 本质是child_process.execSync()的封装它无法捕获结构化错误。正确做法是用action: test它会调用内置的 pytest runner返回标准 junit.xml 格式报告这才是自愈链路能消费的数据。3. 核心细节解析Routine YAML 的每一个字段都在解决一个具体工程问题3.1 最小可行 Routine从“Hello World”到生产就绪的演进先看一个绝对最小的、能跑通的 Routine保存为hello.routine.yamlname: Hello World Demo description: 最简 Routine 验证环境 version: 1.0.0 triggers: - type: command name: run-hello steps: - id: generate action: code input: language: python prompt: 写一个函数输入名字返回 Hello, {name}! output: file: hello.py - id: execute action: shell input: command: python hello.py output: stdout: output.txt别小看这 15 行。它已经隐含了四个关键设计决策triggers定义了入口协议command类型意味着你可以在 VS Code 命令面板里搜到Run Hello World Demo而不是必须打开聊天窗口steps是 DAG 的节点id是全局唯一标识后续任何 step 都能通过depends_on: [generate]显式声明依赖action: code不是调用 API而是启动内置的 code generation engine它比外部 API 快 3.2 倍实测数据且支持input.context字段注入项目根目录下的requirements.txt内容output.file是状态锚定的关键hello.py被写入沙箱 workspace后续所有 step 都能安全引用它无需担心路径拼接错误。现在把它升级为生产就绪版本hello-prod.routine.yamlname: Hello World Production version: 2.0.0 # 新增强制类型校验防止非预期输入 input_schema: type: object properties: name: type: string minLength: 1 maxLength: 50 required: [name] steps: # Step 1: 生成带类型注解的代码 - id: generate action: code input: language: python prompt: | 写一个函数 greet(name: str) - str要求 - 使用 type hints - 添加 Google-style docstring - 包含输入校验空字符串抛 ValueError - 输入来自 {{ inputs.name }} context: | # 项目上下文 # 当前 Python 版本3.11 # 已安装包pydantic2.7.1 output: file: src/greet.py # Step 2: 静态检查mypy - id: lint action: shell depends_on: [generate] input: command: mypy src/greet.py on_failure: # 自愈第一步尝试修复类型错误 jump_to: fix-type # Step 3: 单元测试 - id: test action: shell depends_on: [lint] input: command: pytest tests/test_greet.py -v on_failure: # 自愈第二步生成缺失的测试用例 jump_to: gen-test # Step 4: 打包发布模拟 - id: publish action: shell depends_on: [test] input: command: echo Package built successfully dist/RELEASED # 自愈分支修复类型错误 - id: fix-type action: code input: language: python prompt: | 修复以下 mypy 错误 {{ steps.lint.stderr }} 原始代码在 src/greet.py请只输出修正后的完整文件内容。 output: file: src/greet.py # 自愈分支生成测试用例 - id: gen-test action: code input: language: python prompt: | 根据 src/greet.py 的函数签名生成 pytest 测试用例 - 测试正常输入 - 测试空字符串输入应抛 ValueError - 测试超长字符串输入应抛 ValueError 输出完整 test_greet.py 文件内容。 output: file: tests/test_greet.py这个升级版解决了六个核心工程问题输入契约input_schema强制前端传参格式避免greet(None)这类运行时错误上下文注入input.context把项目真实依赖注入 prompt模型生成的代码能直接import pydantic依赖显式化depends_on让执行引擎知道lint必须等generate写完文件才能开始错误结构化on_failure不是重试而是跳转到专门的修复 Agent且能拿到{{ steps.lint.stderr }}这种精确错误源自愈专业化fix-type和gen-test是两个不同 prompt 的 Agent前者专注类型系统后者专注测试设计职责单一产物可追溯最终dist/RELEASED文件是 Routine 成功的原子性标志CI 系统可直接监控它。3.2 关键字段深度解读那些文档里没说清但决定成败的参数input.context不是“提示词增强”而是“环境镜像”官方文档说context是“提供额外信息”这严重误导。实际上context字段的内容会被 Claude Code 的 code generation engine 当作当前项目的完整环境快照来解析。它会做三件事自动提取#开头的注释行作为代码生成的约束条件如# Python 3.11→ 生成typing.Literal而非typing.Union解析pip list输出格式的包列表决定是否使用pydantic.BaseModel还是dataclasses.dataclass识别requirements.txt中的--index-url在生成的 import 语句后自动添加# from private-pypi注释。实操心得我曾遇到一个 bug——模型总生成from fastapi import FastAPI但项目实际用的是starlette. 后来发现context里漏写了# Framework: starlette这行注释。补上后生成准确率从 42% 提升到 98%。context不是可选的“补充说明”而是必须和prompt一样严谨编写的环境契约。output.file的路径规则沙箱内的“绝对真理”Claude Code 的 workspace 沙箱结构是固定的/workspace ├── src/ ├── tests/ ├── dist/ └── .routine/ └── cache/ # 临时缓存output.file的路径必须相对于/workspace。常见错误❌output.file: src/greet.py→ 正确写入/workspace/src/greet.py❌output.file: /src/greet.py→ 错误沙箱会拒绝写入根目录❌output.file: greet.py→ 危险写入/workspace/greet.py可能被其他 Routine 覆盖更关键的是file路径决定了后续 step 的引用方式。比如你在generatestep 写了output.file: src/greet.py那么在lintstep 的input.command里必须写mypy src/greet.py不能写mypy ./src/greet.py或mypy /workspace/src/greet.py。因为沙箱的cwd就是/workspace所有相对路径都以此为基准。这是很多初学者卡住的点。on_failure.jump_to不是 goto而是状态机跳转jump_to的目标 step 必须满足两个条件已定义目标 id 必须在当前 YAML 的steps列表里存在无循环依赖不能形成A → B → A这样的环。引擎会在加载时做拓扑排序校验失败则报Routine validation failed: cyclic dependency detected。但更重要的是语义jump_to不是“重新执行”而是“带着当前失败状态进入新上下文”。比如fix-typestep 能访问{{ steps.lint.stderr }}是因为引擎在跳转时把lintstep 的全部输出包括stderr作为新输入注入了fix-type的 prompt context。这意味着你可以在fix-type的 prompt 里写修复以下 mypy 错误 {{ steps.lint.stderr }} 注意原始代码在 {{ steps.generate.output.file }}请只输出修正后的完整文件内容。这里的{{ steps.generate.output.file }}是动态解析的值就是src/greet.py。jump_to的本质是状态机的状态迁移而非流程控制的分支。4. 实操过程从零搭建一个“自动修复 SQL 注入漏洞”的 Routine4.1 场景还原为什么这个 Routine 能替代 80% 的安全审计人力我们有个老项目PHP 代码里大量使用mysql_query(SELECT * FROM users WHERE id $_GET[id])这种写法。安全团队每月人工扫描平均发现 12 个高危点修复耗时 3-5 小时/个。我用 Claude Code Routine 把这个过程自动化输入一个 PHP 文件路径如./legacy/user.php输出一个修复后的 PHP 文件./legacy/user_fixed.php所有mysql_*函数替换为PDO::prepare()且参数化查询占位符正确自愈当正则匹配失败或 PDO 语法错误时自动降级为 AST 解析模式或提示人工介入整个 Routine 在 17 秒内完成准确率 94.3%测试集 217 个真实漏洞文件且修复结果 100% 通过 PHPUnit 功能测试。4.2 完整 YAML 实现与逐行注释# sql-inject-fix.routine.yaml name: SQL Injection Auto-Fix version: 1.1.0 description: 自动识别并修复 PHP 中的 SQL 注入漏洞 input_schema: type: object properties: php_file: type: string pattern: ^\\.\\/.*\\.php$ description: 待修复的 PHP 文件路径相对 workspace 根目录 required: [php_file] triggers: - type: command name: Fix SQL Injection in {{ inputs.php_file }} description: 一键修复指定 PHP 文件中的 SQL 注入漏洞 steps: # Step 1: 读取原始文件内容安全第一绝不直接执行可疑代码 - id: read-source action: shell input: command: cat {{ inputs.php_file }} output: stdout: .routine/cache/original.php # Step 2: 静态分析用正则快速定位 mysql_query 调用 - id: scan-mysql action: shell depends_on: [read-source] input: command: | # 提取所有 mysql_query 调用及其参数 grep -n mysql_query .routine/cache/original.php | \ sed s/^[^:]*://; s/.*mysql_query[[:space:]]*([^)]*)/mysql_query()/ | \ awk {print NR : $0} .routine/cache/mysql_calls.txt # 统计数量 wc -l .routine/cache/mysql_calls.txt | awk {print $1} .routine/cache/call_count.txt output: stdout: .routine/cache/mysql_calls.txt stderr: .routine/cache/scan_error.log # Step 3: 决策分支根据漏洞数量选择修复策略 - id: decide-strategy action: shell depends_on: [scan-mysql] input: command: | count$(cat .routine/cache/call_count.txt) if [ $count -eq 0 ]; then echo NO_VULNERABILITY .routine/cache/strategy.txt elif [ $count -le 5 ]; then echo REGEX_FIX .routine/cache/strategy.txt else echo AST_FIX .routine/cache/strategy.txt fi output: stdout: .routine/cache/strategy.txt # Step 4a: 正则修复模式小规模漏洞 - id: regex-fix action: code depends_on: [decide-strategy] when: {{ steps.decide_strategy.stdout }} REGEX_FIX input: language: php prompt: | 你是一名资深 PHP 安全工程师。请将以下 PHP 代码中的所有 mysql_query 调用 替换为 PDO::prepare() 参数化查询。要求 - 保留原有逻辑结构 - 为每个查询生成唯一的 PDO 句柄变量如 $pdo1, $pdo2 - 使用 ? 占位符不使用命名占位符 - 添加 try-catch 包裹 - 原始代码 {{ steps.read_source.stdout }} - 已识别的 mysql_query 调用位置 {{ steps.scan_mysql.stdout }} context: | # PHP 环境 # 版本7.4 # 已启用扩展pdo_mysql # 项目配置$pdo new PDO(mysql:hostlocalhost;dbnametest, $user, $pass); output: file: fixed/{{ inputs.php_file }} # Step 4b: AST 修复模式大规模或复杂漏洞 - id: ast-fix action: shell depends_on: [decide-strategy] when: {{ steps.decide_strategy.stdout }} AST_FIX input: command: | # 调用外部 PHP-Parser 工具需提前安装 php-parse -f .routine/cache/original.php --json .routine/cache/ast.json # 此处应调用 Claude Code 的 AST 修复 Agent但当前版本暂不支持 # 故降级为人工介入提示 echo AST mode requires manual review. Please check .routine/cache/ast.json fixed/{{ inputs.php_file }} echo MANUAL_REVIEW_REQUIRED .routine/cache/status.txt output: stdout: fixed/{{ inputs.php_file }} # Step 5: 验证修复结果 - id: verify-fix action: shell depends_on: [regex-fix, ast-fix] input: command: | # 检查是否还有 mysql_query if grep -q mysql_query fixed/{{ inputs.php_file }}; then echo VULNERABILITY_STILL_PRESENT .routine/cache/verify_status.txt exit 1 else echo FIX_SUCCESSFUL .routine/cache/verify_status.txt fi on_failure: jump_to: manual-review # Step 6: 生成修复报告 - id: generate-report action: code depends_on: [verify-fix] input: language: markdown prompt: | 生成一份安全修复报告包含 - 原始文件{{ inputs.php_file }} - 漏洞数量{{ steps.scan_mysql.stdout | length }} - 修复模式{{ steps.decide_strategy.stdout }} - 验证结果{{ steps.verify_fix.stdout }} - 修复后文件路径fixed/{{ inputs.php_file }} - 关键修改摘要从 diff 中提取 原始代码片段 {{ steps.read_source.stdout | slice:0:200 }} 修复后代码片段 {{ steps.regex_fix.output.file | read_file | slice:0:200 }} output: file: reports/fix_{{ inputs.php_file | replace:.php, }}.md # 自愈分支人工介入流程 - id: manual-review action: shell input: command: | echo MANUAL REVIEW REQUIRED .routine/cache/manual_review.md echo File: {{ inputs.php_file }} .routine/cache/manual_review.md echo Scan Result: .routine/cache/manual_review.md cat .routine/cache/mysql_calls.txt .routine/cache/manual_review.md echo .routine/cache/manual_review.md echo Original Code: .routine/cache/manual_review.md head -n 20 .routine/cache/original.php .routine/cache/manual_review.md echo .routine/cache/manual_review.md echo Please review and fix manually. .routine/cache/manual_review.md output: stdout: manual_review/{{ inputs.php_file | replace:.php, }}.md4.3 关键实操技巧与避坑指南技巧 1用when字段实现动态流程分支when不是简单的 if-else而是基于 Jinja2 模板引擎的布尔表达式。它支持字符串比较{{ steps.decide_strategy.stdout }} REGEX_FIX数值比较{{ steps.scan_mysql.stdout | length }} 10正则匹配{{ steps.read_source.stdout }} matches mysql_query但要注意steps.xxx.stdout的值是字符串即使你echo 123它也是123\n。所以做数值比较时必须用| int过滤器{{ steps.scan_mysql.stdout | int }} 10。否则12\n 10会返回 false。技巧 2read_file过滤器是处理大文件的救命稻草在generate-reportstep 里我用了{{ steps.regex_fix.output.file | read_file | slice:0:200 }}。read_file是 Claude Code 内置的 Jinja2 过滤器它会同步读取沙箱内指定路径的文件内容。slice:0:200则取前 200 字符。这比在shellaction 里写head -c 200 fixed/xxx.php更可靠因为后者可能因编码问题截断中文字符。实测read_file对 UTF-8 文件 100% 安全。技巧 3.routine/cache/是你的私有状态空间所有写入.routine/cache/目录的文件都会在 Routine 结束后自动清理。这是设计给中间态数据用的“临时硬盘”。比如scan-mysqlstep 生成的mysql_calls.txt只供decide-strategy和manual-review使用绝不应该出现在最终产物里。而fixed/和reports/目录下的文件则是 Routine 的正式输出会保留在 workspace 中供你后续使用。注意不要在shellaction 的command里用rm -rf .routine/cache/*。沙箱有自动清理机制手动清理可能导致状态不一致。我曾因此导致verify-fixstep 读不到mysql_calls.txt报错No such file or directory。技巧 4triggers的name字段支持模板但有长度限制name: Fix SQL Injection in {{ inputs.php_file }}会让命令面板显示为Fix SQL Injection in ./legacy/user.php。但inputs.php_file如果很长如./very/long/path/to/a/very/long/file.php会超出 VS Code 命令面板的显示宽度约 60 字符。此时建议用| basename过滤器name: Fix {{ inputs.php_file | basename }}显示为Fix user.php更清爽。5. 常见问题与排查技巧实录那些文档里绝不会写的血泪教训5.1 “Routine not found” 错误的 5 种真实原因及定位方法这个错误看似简单但背后原因千差万别。我整理了 107 次报错记录归为五类错误现象根本原因定位命令解决方案Routine not found: sql-inject-fixYAML 文件未放在.routine/目录下find . -name *.routine.yaml -type f将文件移动到项目根目录的.routine/子目录Routine not found: sql-inject-fix文件名含大写字母或空格ls -la .routine/重命名为sql-inject-fix.routine.yaml全小写连字符Routine not found: sql-inject-fixVS Code 插件未启用 Routine 功能CmdShiftP→Claude Code: Toggle Routine Support在设置里开启claudeCode.enableRoutinesRoutine not found: sql-inject-fixYAML 语法错误导致加载失败claude-code-cli validate .routine/sql-inject-fix.routine.yaml用官方 CLI 工具校验修复缩进或冒号缺失Routine not found: sql-inject-fix当前 workspace 不是 Routine 文件所在目录pwd对比.routine/路径在 VS Code 中用File → Open Folder重新打开项目根目录最隐蔽的是第五种VS Code 的 workspace 是你打开的文件夹而.routine/必须在该文件夹内。如果你在/home/user/project下有.routine/但 VS Code 打开的是/home/user/project/src那么插件就找不到 Routine。解决方案永远是确保 VS Code 的 Explorer 左侧显示的根目录和.routine/目录在同一层级。5.2 “Action failed: code” 的深度排查清单当action: code失败时错误信息往往很模糊。我的标准排查流程是检查输入长度Claude Code 对prompt字段有 8192 token 限制。用wc -w估算单词数超过 1200 词大概率触发截断。解决方案用{{ steps.xxx.stdout | truncate:500 }}控制输入大小检查 context 冲突如果context里写了# Python 3.11但prompt里要求import asyncio3.11 才支持没问题但如果写了# Python 3.7就会失败。解决方案context必须与实际环境一致检查文件路径权限output.file: src/greet.py要求src/目录存在。如果不存在codeaction 会静默失败。解决方案在codestep 前加一个shellstep 创建目录mkdir -p src检查模型能力边界Claude Code 的 code generation engine 对某些语言支持有限。比如它能完美生成 Python/JS/Java但对 Rust 的asynctrait 实现常出错。解决方案查看官方支持语言列表或降级为shellaction 调用rustfmt检查沙箱网络策略如果prompt里要求“从 https://api.example.com 获取 schema”会失败因为沙箱默认禁网。解决方案改用input.context注入 schema 内容或在shellstep 里用curl下载后写入文件。5.3 自愈失败的三大典型模式与应对策略模式一无限循环自愈Infinite Loop表现Routine 卡在fix-type→lint→fix-type循环CPU 占用 100%。原因fix-type生成的代码仍有 mypy 错误但错误信息和上次一样导致lint总是失败。解决方案在fix-type的prompt末尾加一句“本次修复必须解决所有已报告的错误如果仍存在相同错误请直接抛出异常不要尝试二次修复。” 这会强制模型要么一次修好要么放弃。模式二状态丢失State Loss表现gen-teststep 生成的test_greet.py里函数名写成了test_greet2()和greet()不匹配。原因gen-test的prompt里只写了“根据 src/greet.py 的函数签名”但没明确说“函数名是 greet”。解决方案在gen-test的prompt里用{{ steps.generate.output.file | read_file | regex_find:def ([a-zA-Z_])\( }}提取函数名然后写“测试函数{{ function_name }}”。模式三降级失效Fallback Failure表现ast-fixstep 本应降级为人工介入但shellaction 里echo MANUAL_REVIEW_REQUIRED后流程却继续执行了verify-fix。原因shellaction 默认exit code 0即成功即使你echo了提示。verify-fix的depends_on是[regex-fix, ast-fix]只要其中一个成功它就执行。解决方案在ast-fix的shellcommand 末尾加exit 2非零退出码表示失败并把verify-fix的depends_on改为[regex-fix]同时加一个when: {{ steps.regex_fix.status }} success。这样只有regex-fix成功时才验证ast-fix失败则走manual-review。5.4 性能优化实战让 Routine 从 12s 降到 3.4s 的 4 个操作在金融项目中一个含 8 个 step 的 Routine初始耗时 12.3s。通过以下四步优化
返回列表