拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Mastra 条件逻辑工作流测试指南:从 Playground 调试到分支路由验证

Mastra 条件逻辑工作流测试指南从 Playground 调试到分支路由验证【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra导读本文是 Mastra Workflow 系列课程中条件分支单元第 1821 课的收尾实战篇聚焦如何对已经构建好的条件工作流进行系统化测试与调试。你将掌握如何把条件工作流注册进 Mastra 配置、如何通过 Playground 与程序化方式验证不同输入的路由结果、条件评估的底层执行机制含源码佐证以及一套可复用的条件排查方法论。本课在课程体系中的定位在开始测试之前先回顾你已经完成的链路理解条件分支掌握.branch()的基本语法与条件为真则执行对应步骤的语义创建条件步骤实现了assessContentStep内容评估与quickProcessingStep/generalProcessingStep两个处理步骤构建条件工作流用.then(assessContentStep).branch([...]).commit()组装出conditionalWorkflow。本课第 21 课的任务是用不同类型、不同长度的内容去轰击这个条件工作流验证它是否按预期路由到不同的处理路径。测试不是可选项——条件逻辑的正确性直接决定后续功能的质量。注册新工作流让 Mastra 知道它的存在要让测试能够进行第一步是把工作流注册到 Mastra 实例中。编辑入口文件src/mastra/index.ts将条件工作流加入workflows配置// In src/mastra/index.ts import { contentWorkflow, aiContentWorkflow, parallelAnalysisWorkflow, conditionalWorkflow, } from ./workflows/content-workflow export const mastra new Mastra({ workflows: { contentWorkflow, aiContentWorkflow, parallelAnalysisWorkflow, conditionalWorkflow, // Add the conditional workflow }, // ... rest of configuration })几点说明workflows是一个以工作流 id 为键的注册表注册后工作流才能被 Playground、mastra dev与程序化调用发现条件工作流与普通工作流共用同一注册入口没有任何特殊的条件工作流注册标记从源码结构看注册后框架会基于工作流的id与步骤流step flow建立可执行的图结构后续 Playground 的流程可视化正是依赖这份图定义相关实现见 packages/core/src/workflows/workflow.ts 与 packages/core/src/workflows/evented/workflow.ts。在 Playground 中测试条件工作流注册完成后重启开发服务并在 Playground 中找到conditionalWorkflow开始系统性测试。请务必覆盖不同内容长度和不同内容类型建议按以下矩阵逐项验证测试用例输入内容特征预期路由短内容少于 50 词的简单文本平均词长 ≤ 5quick-processing快速处理中等内容50200 词general-processing通用处理长内容超过 200 词general-processing通用处理复杂内容平均词长 5 甚至 7 的文本视category组合而定对照我们之前定义的评估规则见 19-creating-conditional-steps.mdwordCount 50→mediumwordCount 200→long平均词长 5→moderate 7→complex。由于 构建条件工作流 中的分支条件是category short complexity simple只有同时满足短且简单的内容才会进入快速处理路径其余一律走通用处理路径。测试时若发现中等长度但简单的内容走了通用路径这并非 bug而是复合条件AND的预期行为——这恰恰是条件逻辑测试要确认的边界。程序化测试不依赖 UI 的验证方式除了 Playground还可以通过代码直接触发工作流便于把测试用例固化成自动化测试。Mastra 支持在注册实例上获取工作流并执行const result await mastra.getWorkflow(conditional-workflow).execute({ triggerData: { content: Short and simple text here..., // 50 词平均词长短 type: blog, }, }) console.log(result.results) // 检查 processingType 是否为 quick将不同输入封装成数组循环断言即可得到一张可重复执行的回归测试表。关于 Playground 的完整用法可参考系列课程 07-using-playground.md。理解流程条件路由的四个阶段测试时要带着模型去观察结果。条件工作流的完整执行链路分四步评估步骤Assessment stepassessContentStep先运行分析内容并产出categoryshort/medium/long与complexitysimple/moderate/complex等元数据写入工作流状态分支条件求值Branch conditions.branch()中注册的每个条件函数针对评估结果逐一求值匹配步骤执行Matching step条件为真的分支对应的步骤执行产出该路径的处理结果结果汇总Results输出数据中会体现实际走了哪条处理路径例如processingType: quick或general据此反推路由是否正确。源码视角条件是如何被并发求值的这四个阶段并非文字上的走流程其底层实现在packages/core/src/workflows/handlers/control-flow.ts的executeConditional函数中见 control-flow.ts#L348-L538。关键事实所有条件通过Promise.all并发求值L395-L496而不是串行短路——这正是系列课程反复强调的多个条件同时为真时对应步骤并行执行的来源求值为真的条件索引被收集为truthyIndexes只有这些索引对应的步骤会被运行L498求值过程会产生WORKFLOW_CONDITIONAL与WORKFLOW_CONDITIONAL_EVAL两类可观测性 Span并记录conditionCount、truthyIndexes、selectedSteps等属性L378-L392、L533-L538——这意味着你可以在追踪后端直接查看哪个条件为真、哪个分支被选中。branch()方法的签名与存储逻辑在 packages/core/src/workflows/workflow.ts#L2407-L2469它接收[条件, 步骤]元组数组将条件函数、步骤引用与序列化条件一起压入stepFlow与serializedStepFlow并从元组第二项提取步骤类型以完成 TypeScript 类型推导。条件函数的类型契约在 packages/core/src/workflows/step.ts#L74-L125 中可以看到条件函数的正式定义ConditionFunctionParams复用ExecuteFunctionParams但移除了setState与suspend——条件函数是只读判断不能修改状态ConditionFunction的返回类型是Promiseboolean即条件函数必须返回布尔值或 Promise 包裹的布尔值。这解释了为什么条件里只能做判断而不能做写入评估阶段是并发的任何副作用写入都会破坏确定性。若确需在分支前准备数据应放在评估步骤中完成。调试条件当路由不符合预期时如果某个条件没有按预期工作按照以下顺序排查这正是本课文档给出的调试清单的展开版1. 检查评估步骤的输出路由决策完全依赖assessContentStep产出的category与complexity。先在 Playground 或日志中确认这两个字段的真实值console.log( Assessment: ${category} content, ${complexity} complexity)例如你本以为输入是 short但wordCount统计的是content.trim().split(/\s/)的结果——连续多个空格、换行符、全角字符都会影响词数导致评估结果与直觉不符。2. 核对条件逻辑是否符合预期回到.branch()的注册处逐条核对.branch([ // Branch 1: Short and simple content [async ({ inputData }) inputData.category short inputData.complexity simple, quickProcessingStep], // Branch 2: Everything else [ async ({ inputData }) !(inputData.category short inputData.complexity simple), generalProcessingStep, ], ])注意这里两个条件是互斥互补的要么走快速路径要么走通用路径任何输入都恰好命中一个分支。如果你改动了第一个条件而忘记同步第二个否定形式就会出现无分支命中或双分支命中的意外。3. 在隔离环境中测试单个条件把单个条件函数抽出来单独跑排除工作流其他环节的干扰const isShortAndSimple async ({ inputData }) inputData.category short inputData.complexity simple await isShortAndSimple({ inputData: { category: short, complexity: simple }, // ... 补齐 ConditionFunctionParams 的其余字段 })4. 借助日志与可观测性追踪条件求值在条件函数内添加console.log输出中间值跟踪每个条件分支的求值结果若项目接入了可观测性直接查看WORKFLOW_CONDITIONAL_EVALSpan 的result属性见 control-flow.ts#L455-L464可以确认每个条件实际返回了true还是false从源码看条件求值若抛出异常会被捕获并等价于false处理返回null见 control-flow.ts#L467-L493同时产生WORKFLOW_CONDITION_EVALUATION_FAILED错误并记录result: false属性。因此条件没生效有时其实是条件抛错了——先看错误日志再怀疑逻辑。5. 组合条件的运算规则多条件判断支持标准逻辑运算符构建测试用例时按真值表设计输入AND两个条件都为真才命中。例如短且简单需要category short与complexity simple同时成立||OR任一条件为真即命中!NOT条件取反。例如上面 Branch 2 的否定形式与 Branch 1 构成全覆盖路由。求值规则再强调一次条件按注册顺序依次存储但并发求值多个条件为真时对应步骤并行运行全部为假时跳过整个分支继续执行后续步骤相关语义在 18-understanding-conditional-branching.md 中有完整说明。分支的好处为什么值得为它写测试条件工作流带来的价值恰恰也是测试的重点关注项智能路由Intelligent routing让合适的内容走合适的处理路径测试要确认正确的内容到了正确的路径性能优化Performance optimization简单内容跳过重处理。注意在 19-creating-conditional-steps.md 中generalProcessingStep用setTimeout(resolve, 500)模拟了更重的处理——测试时可以对比两类路径的耗时量化分支带来的收益定制化体验Customized experience不同场景走不同处理策略如快速处理只给 1 条建议通用处理给 3 条测试要验证推荐内容的差异可扩展逻辑Scalable logic新增条件与处理路径只需在.branch()数组里追加元组但每新增一个分支就应该为它补充对应的测试用例。仓库中的真实条件分支实例当前仓库的 examples 中就有两个可直接运行的条件分支示范可作为测试用例设计的参考文本长度分支examples/agent/src/mastra/workflows/index.ts#L220-L265 中的lessComplexWorkflow基于文本长度分两条路径.branch([ [async ({ inputData: { text } }) text.length 10, shortTextStep], [async ({ inputData: { text } }) text.length 10, longTextStep], ])它与课程示例几乎同构互斥互补的两个条件分支后用.map()把short-text或long-text的结果统一回写到text字段——这个分支后归一化的手法值得借鉴分支会产生以步骤 id 为键的异构结果下游需要合并处理。内容类型分支examples/agent/src/mastra/workflows/content-moderation.ts#L237-L273 中的branchingModerationWorkflow展示了基于内容特征的路由.branch([ // If message looks like it might contain PII (has or numbers), do PII check [ async ({ inputData }) { const data inputData as any; const text JSON.stringify(data.messages || []); return text.includes() || /\d{3}/.test(text); }, piiStep, ], // Otherwise, do toxicity check [async () true, toxicityStep], ])注意它的第二个条件是async () true——一个恒真兜底分支保证任何未命中 PII 检查的内容都会进入毒性检查。这与课程里否定形式的兜底写法殊途同归条件分支务必保证全覆盖否则会出现无分支命中的静默跳过。测试这类工作流时async () true兜底分支的用例是必测项。结语与下一步至此你已完成条件工作流的注册、Playground 测试、流程理解与条件调试的完整闭环。测试的产出是一张输入特征 → 预期路由的对照表内容越短越简单走快速路径其余走通用路径若发现偏差按查评估输出 → 核对条件 → 隔离单测 → 看追踪日志的顺序逐层定位。下一步课程将进入流式输出streaming学习如何把工作流结果流式地返回给用户以获得更好的交互体验见本课程下一课 22-conclusion.md 之前的流式内容。流式输出同样需要结合本课的分支测试方法确保每个分支路径都能正确产生流式结果。【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门