摘要:企业测试造数难,难点不在"会不会调接口",而在业务链路长、上下游依赖多、状态流转复杂、参数规则分散、失败路径难排查。本文是一个企业测试造数 Skill 的系列总览:先讲清楚"为什么难",再讲整体怎么分层------用 Agent 做参数收口,用 Python 编排引擎控制流程,用 YAML 描述业务步骤,用 Jinja2 治理复杂请求体,把 Dify 作为只做 HTTP 和 SQL 的薄执行层。它用到了 AI 的能力,但不是一个"自主执行"的 Agent,而是把 AI 关进一条确定流程,让熟手脑子里的造数经验,沉淀成可配置、可复用、可排障、可交付的工程资产。
写在前面
适合谁看: 测试开发、质量工程师、平台工具开发、正在做企业内部 AI 工具落地的人。
核心结论: 造数工具的关键不是让 AI 自由执行,而是把业务经验拆成可描述的流程、可治理的模板、可复用的动作和可验证的执行记录------让 Skill 承载业务编排,让 Dify 只做 HTTP 和 SQL 的稳定执行通道。
这是系列第 1 篇(总览)。 本篇只搭骨架、讲清"为什么这么分",每一层的细节由后续 7 篇分别展开:Dify 做薄(02)、多模态入口(03)、YAML 编排(04)、参数收口(05)、模板治理(06)、失败路径(07)、工程化经验(08)。贯穿全系列的一条主线是:参数即契约,Dify 做薄,Skill 闭环,报告交付。
一、先说一个很常见的测试开发困境
很多测试开发都遇到过这种情况:用例写完了,环境也有了,但卡在"没有一条能跑通全链路的数据"。
更麻烦的是,造一条数据不是调一个接口,而是要知道该用哪个物料、哪个供应商、哪个组织、哪个审批状态、哪个合同条件。熟手 10 分钟能搞定,新人可能折腾半天。
如果只是单接口测试,造数确实很简单:
text
准备参数 -> 调创建接口 -> 拿到 id
但企业业务系统里的造数,经常长这样:
text
准备业务参数
-> 校验基础资料
-> 创建上游单据
-> 等待落库
-> 查询业务主键
-> 触发审批
-> 查询合同 / 价格 / 组织关系
-> 转换下游单据
-> 再次审批
-> 等待异步推送
-> 查询最终结果
这已经不是"写一个脚本调接口"的问题,而是一个长链路、多系统、多状态、多分支的流程编排问题。
我在这个项目里真正解决的,也不是"自动调用接口"。真正解决的是:把原本散落在熟手经验里的造数流程,拆成可描述、可执行、可复用、可排障的工程资产。
这也是这篇文章想讲清楚的核心:我做的是一个跑在 OpenClaw 上的造数 Skill,它用到了 AI Agent 的能力(意图识别、参数收口、多模态识图、失败诊断),但它不是一个"自主决策、自由执行"的 Agent------恰恰相反,它的设计目标是把 AI 关进一条确定的流程里。Dify 只是它的执行层之一,不是主角。
二、用一个匿名例子看清造数复杂度
为了避免贴真实业务细节,下面用一个匿名化的采购订单场景说明。
假设我们要生成一条"采购订单测试数据"。
用户输入看起来很简单:
| 输入项 | 示例含义 |
|---|---|
| 订单类型 | 标准采购 / 特殊采购 / 半成品采购 |
| 供应商 | 某个测试供应商编码 |
| 物料 | 一个或多个测试物料 |
| 组织 | 采购组织、库存组织或业务组织 |
用户真正想要的输出也很明确:
| 输出项 | 用途 |
|---|---|
| 采购申请号 | 用于上游流程验证 |
| 采购订单号 | 用于订单相关测试 |
| 下游单号 | 用于集成链路或回归验证 |
但中间要走的链路并不简单:
- 校验物料是否存在。
- 校验物料和供应商是否匹配。
- 判断订单类型应该走哪个流程。
- 创建采购申请。
- 查询采购申请是否落库。
- 触发审批。
- 查询合同、价格或组织信息。
- 将申请转换成订单。
- 查询订单主键。
- 再次触发审批。
- 等待下游系统异步处理。
- 查询最终单号。
这里面每一步都可能失败,而且失败原因不一样。
物料不存在,是参数问题。审批失败,是状态问题。查不到订单,可能是异步延迟。SQL 查到旧数据,可能是查询条件不够精确。字段传了空字符串,可能会触发后端校验。
如果这些经验只存在于某几个熟手脑子里,团队的造数能力就会一直停留在"谁熟谁来做"的状态。
所以,我没有把目标定成"写一个更长的脚本",而是做成了一个可复用的造数 Skill。
三、为什么继续堆脚本会失控
脚本一开始是最有效的。
比如:
python
create_request()
query_request_no()
approve_request()
query_contract()
create_order()
approve_order()
query_final_no()
单场景这样写没有问题。问题会在第三个、第五个、第十个场景出现。
典型变化包括:
- 不同订单类型要走不同接口。
- 不同组织要查不同合同条件。
- 有的场景需要额外校验库存或配额。
- 有的接口字段为空时不能传。
- 有的步骤要等待异步结果。
- 有的 SQL 必须限制时间范围和数量。
- 有的失败可以重试,有的失败必须立刻终止。
继续复制脚本,会出现几个后果:
| 问题 | 结果 |
|---|---|
| 公共逻辑重复 | Cookie、HTTP、SQL、审批、重试散落在各处 |
| 场景差异混在代码里 | 新增场景只能复制旧脚本再改 |
| 失败现场不可恢复 | 中间步骤失败后只能从头再跑 |
| 参数规则不可见 | 新人不知道哪些字段必填、哪些字段条件必填 |
| 排障依赖熟人 | 出错后只能找写脚本的人 |
脚本不是不能用,而是不能让所有业务复杂度都堆进脚本。
我最后采用的拆法是:
| 类型 | 放在哪里 |
|---|---|
| 稳定能力 | Python 编排引擎 |
| 业务差异 | YAML 流程配置 |
| 复杂请求体 | Jinja2 模板 |
| 参数收集和确认 | Agent |
| HTTP / SQL 执行 | Dify |
这个拆法的好处是:稳定的东西沉淀成能力,变化的东西留在配置里。
四、整体架构:Skill 是主体,Dify 是薄执行层
整个造数 Skill 的结构可以概括成五层。

text
用户
↓
AI Agent 对话层
- 识别造数意图
- 收集必填参数
- 处理条件必填
- 做业务名到系统编码的映射
- 展示执行前确认
↓
Skill 内部 Python 编排引擎
- 读取 YAML 流程配置
- 控制条件 / 循环 / 路由
- 渲染 Jinja2 模板
- 调用执行层
- 提取步骤结果
- 保存状态快照
↓
YAML + Jinja2 工程资产
- 描述业务流程
- 管理复杂请求体
- 沉淀共享步骤
↓
Dify 执行层
- HTTP 调用
- SQL 查询
↓
企业测试环境
- 业务系统
- 审批系统
- 下游系统
- 测试数据库
这里最重要的边界是:Skill 负责业务编排,Dify 只做稳定执行通道。
Dify 层只需要保留少量通用能力,例如:
json
{
"tool": "http_call",
"inputs": {
"url": "${url}",
"method": "POST",
"headers": "${headers}",
"body": "${body}"
}
}
以及:
json
{
"tool": "sql_query",
"inputs": {
"db_uri": "${TEST_DB_URI}",
"query": "SELECT ... LIMIT 1",
"format": "json"
}
}
为什么不把所有业务节点都画进 Dify 工作流?
因为低代码平台很适合连接工具、承接执行、做简单流程,但不适合长期承载大量业务判断。复杂度一旦上来,节点会变多,分支会变乱,模板不好维护,版本管理也不舒服。
所以这个设计反过来:让 Dify 保持薄,让 Skill 承接复杂度。
这不是贬低低代码平台,而是给它一个清晰边界。边界清楚了,平台才稳定,工程资产也更容易维护。
五、五层各自解决什么问题(总览)
前面那张图把五层画了出来,这里用一句话说清每层的职责,以及"为什么单独成一层"。每层的细节,本系列后面都有一篇专门展开。
| 层 | 一句话职责 | 为什么单独成层 | 展开篇 |
|---|---|---|---|
| Agent 对话层 | 把自然语言收敛成可执行、可确认的参数 | 造数会真实写测试环境,AI 猜错就是脏数据,必须先收口再执行 | 第 05 篇 |
| Python 编排引擎 | 读 YAML、控制条件/循环/路由/重试/状态 | 稳定能力沉淀成引擎,可测试、可版本管理、失败可复盘 | 第 04 篇 |
| YAML 流程配置 | 声明式描述每种订单的完整步骤 | 把变化的业务差异从代码里挪出来,新增场景改配置而非复制脚本 | 第 04 篇 |
| Jinja2 模板 | 渲染多层嵌套、带条件字段的复杂请求体 | 复杂 JSON 散在脚本里最难维护,集中治理才可审查、可复用 | 第 06 篇 |
| Dify 执行层 | 只提供 http_call 和 sql_query 两个通用工具 |
低代码平台适合稳定执行,不适合长期承载业务判断 | 第 02 篇 |
这套设计的取舍可以浓缩成一句话:稳定的能力下沉成引擎,变化的业务上移到配置。
举个例子,前面那条采购订单链路,用这套 action 拆出来大致是:
text
loop 校验多个物料 → condition 判断是否继续 → route 按订单类型选子流程
→ template 生成请求体 → http_call 创建申请 → sql_query 查申请号
→ http_call 触发审批 → sql_query 查合同 → template 生成订单体
→ http_call 创建订单 → retry 查询下游单号
新增一个订单类型时,多数情况只需新增一份 YAML 和一个模板,不改 Python 引擎------这就是从"脚本自动化"走向"配置化编排"的关键。(引擎和 9 种 Action 的完整设计见第 04 篇。)
六、三个决定"能不能交付"的关键取舍
五层是骨架,但真正决定这套东西"能不能给别人用"的,是三个容易被忽略的取舍。它们分别对应后面三篇,这里先各点一句。
① 复杂请求体交给模板,不让 AI 拼大 JSON。 企业接口的请求体是多层嵌套 + 数组循环 + 条件字段的混合体。让模型直接拼,字段容易漏、结构容易漂。更稳的是模型只产参数、Jinja2 模板产请求体。这里最典型的坑是"空字符串 ≠ 不传字段"------{"projectCode":""} 和 {} 对后端是两种语义,前者可能直接触发校验失败。(模板治理详见第 06 篇。)
② Agent 只收口参数,不替用户冒险。 很多人做 Agent 工具爱强调"一句话自动执行"。但造数会真实写环境,Agent 猜错供应商/组织/物料,产出的不是智能结果而是脏数据。所以它的定位是:识别意图 → 追问缺失字段 → 业务名映射编码 → 执行前确认,缺参数时绝不执行。(三道闸详见第 05 篇。)
③ 失败路径要产品化,不只设计成功路径。 工具一旦给别人用,失败会被放大。重试、等待、状态快照、日志脱敏、静态校验、可读错误------这些"不处理也能跑一次,但不处理就没法交付"的东西,才是工程化价值所在。(失败路径详见第 07 篇。)
这三条我会在后面各用一整篇展开。放在总览里先点出来,是想说明一件事:这套 Skill 花时间最多的地方,不是调通第一个接口,而是这些让别人也敢用的细节。 下面就讲我在这上面踩过的三个真实的坑。
八、三个踩坑小故事:工程化价值藏在失败路径里
这个项目真正花时间的地方,不是调通第一个接口,而是处理那些"看起来很碎,但不处理就没法交付"的失败路径。
1. 大请求体被低代码变量截断
最开始我把复杂请求体直接传给执行层,单物料时没问题。后来一换成多物料场景,请求体变大,接口开始返回各种奇怪的参数错误。
一开始以为是模板字段拼错了,逐个字段排查后才发现:请求体在进入执行节点前已经被截断了。
这个问题的教训是:低代码平台的变量、节点输入、日志展示都可能有长度限制。复杂业务请求体不能只看最终接口报错,还要检查每一层传递过程中有没有被截断。
后面的处理方式是:
- 大请求体尽量由 Skill 侧模板完整渲染。
- 执行前保存请求体摘要和必要快照。
- 对关键输入做长度检查。
- 让执行层只负责发送,不负责拼装复杂结构。
这也是为什么我不把复杂 JSON 都塞进 Dify 节点里。
2. 动态 Header 和 Cookie 传递不稳定
另一个坑是鉴权。
有些接口依赖动态 Header 或 Cookie。刚开始我希望所有 Header 都从流程参数透传到执行层,但实际跑起来会遇到各种差异:有的节点能拿到,有的节点拿不到,有的环境里 Cookie 更新不及时。
如果这个问题不兜住,流程就会表现得很随机:同样的参数,今天能跑,明天不能跑;A 场景能跑,B 场景失败。
后面我把处理逻辑收回到客户端侧:
- 执行前统一准备 Header。
- 必要时从受控配置读取 Cookie 获取方式。
- 执行层收到的就是最终 Header。
- 失败日志里记录脱敏后的鉴权上下文。
这里的设计原则是:易变的鉴权细节不要散在每个流程节点里,要收口在一个稳定边界。
3. SQL 不加限制,查到的可能不是你刚造的数据
造数流程里经常需要查数据库确认状态。
一开始最容易写出这样的 SQL:
sql
SELECT order_no
FROM purchase_order
WHERE supplier_code = '${supplierCode}'
ORDER BY created_at DESC;
看起来没问题,但真实测试环境里历史数据很多。如果查询条件不够精确,可能查到别人刚造的数据,或者查到历史残留数据。
这个问题会带来非常隐蔽的误判:流程以为自己成功了,实际拿到的是别人的单号。
后面的约束是:
- 查询必须带足够业务条件。
- 优先使用本次链路产生的上游主键关联。
- 时间范围要收窄。
- 必要时加
LIMIT 1。 - SQL 结果要做结构化提取和校验。
造数工具不是只要"能查到一条数据"就成功,而是要查到"本次流程刚刚生成的那条数据"。
九、静态校验:让错误尽量在执行前暴露
当流程配置变多后,仅靠人工检查 YAML 很不可靠。
所以我补了一层静态校验,用来检查这些问题:
| 校验项 | 目的 |
|---|---|
| YAML 是否能加载 | 避免格式错误 |
| action 是否合法 | 避免写错动作类型 |
| step id 是否重复 | 避免结果覆盖 |
| goto / then / else 是否存在 | 避免跳到不存在的步骤 |
| route 目标是否存在 | 避免路由失败 |
| template 文件是否存在 | 避免执行到一半才发现模板缺失 |
| collect 命名是否冲突 | 避免循环结果互相覆盖 |
| 敏感信息扫描 | 避免 Token、内部地址、数据库连接泄露 |
这层校验的价值不是"显得规范",而是减少低级错误进入真实执行。
以前一个配置写错,可能要跑到第 8 步才失败。现在很多问题在提交前就能暴露。
对于企业内部工具来说,这类工程化能力很重要。因为工具一旦给别人用,失败路径就会被放大。你不能只设计成功路径,还要让失败可定位、可复盘、可修复。
十、这个设计带来的真实变化
做完这个 Skill 后,造数方式发生了明显变化。
先给一组量化对比,避免只停留在"感觉更好用了":
| 指标 | 改造前 | 改造后 |
|---|---|---|
| 单场景造数耗时 | 熟手 1-3 人天(含查资料、试错、排障) | 一条全链路 2-4 分钟跑完 |
| 链路复杂度 | 跨 7+ 系统、40+ 步操作,散在熟手脑中 | 一份 YAML 描述完整步骤 |
| 新增场景成本 | 复制一套脚本再改,指数级维护成本 | 新增 YAML + 模板,不改引擎代码 |
| 异步等待处理 | 手动重跑、盯着刷新 | 重试上限 10 次 × 10s,自动轮询 |
| 失败定位 | 靠熟手看日志猜 | 状态快照 + 结构化错误 + 失败步骤 |
| 谁能用 | 少数熟手 | 团队成员、新人对话即可触发 |
注:耗时和步数是这条采购链路的真实量级;性能上限(单链路 2-4 分钟、超时 8 分钟、单步重试 10 次 × 10s)是引擎里写死的约束,不是宣传口径。
以前造数更像个人经验:
- 熟手知道先查哪个表。
- 熟手知道哪个字段不能传空。
- 熟手知道接口失败后该等多久。
- 熟手知道不同订单类型要走哪条链路。
- 熟手知道最终结果应该从哪里查。
现在这些经验被拆进了系统:
| 原来 | 现在 |
|---|---|
| 人工记流程 | YAML 描述流程 |
| 手写脚本拼请求 | Jinja2 模板生成 |
| 手动查数据库 | sql_query 步骤查询 |
| 口头传经验 | 踩坑指南和共享步骤沉淀 |
| 单场景脚本 | 多场景配置化 |
| 出错靠熟人排查 | 日志、状态快照、静态校验辅助定位 |
| Agent 直接猜参数 | Agent 收集、校验、确认参数 |
这个变化背后的价值,不只是节省几分钟。
更重要的是:造数能力从"个人手艺"变成了"团队资产"。
团队资产有三个特点:
- 新人可以复用,不必从头摸索。
- 变更可以审查,不靠口头传递。
- 失败可以定位,不只靠经验排查。
这也是我在这个项目里的核心价值:不是写了一个能跑的工具,而是把一个高依赖经验的测试开发动作,工程化成了可维护的 Skill。
十一、如果你也想做类似工具,我的建议
如果你正在做企业内部测试造数、流程自动化或 AI Agent 工具,可以先问自己几个问题。
1. 低代码平台的边界是什么?
不要一开始就把所有业务逻辑画进平台节点。
更稳的做法是:平台做执行和连接,复杂业务编排放到可测试、可版本管理的工程层。
2. 流程能不能拆成少量 action?
不要一上来就设计很大的框架。
先抽象最常见的动作:
- HTTP
- SQL
- 模板
- 条件
- 循环
- 路由
- 提取
- 重试
如果这些动作能覆盖 80% 的场景,配置化才有价值。
3. 请求体有没有模板治理?
复杂 JSON 不要散落在脚本里,也不要塞满低代码节点。
模板化之后,请求体结构、变量、条件字段都更容易维护。
4. Agent 有没有执行边界?
Agent 不应该在参数不完整时直接执行。
至少要做到:
- 必填参数检查。
- 条件必填提示。
- 业务编码映射。
- 执行前确认。
- 结果结构化返回。
5. 有没有把失败路径产品化?
企业工具不是演示 demo,能跑一次不代表能交付。
要考虑:
- 重试。
- 等待。
- 状态快照。
- 日志脱敏。
- 静态校验。
- 错误提示。
- 可恢复执行。
成功路径决定效果能不能验证,失败路径决定工具能不能交付。
十二、诚实说边界:它不是万能的
写这类文章很容易只讲"能做什么",但一个可交付的工具,边界同样要说清楚。这套造数 Skill 当前的边界是:
已经覆盖:
- 采购订单核心链路:标准采购、成品采购的 PR→PO 全流程;
- 文本 / SOP / 截图 / 失败图四类多模态入口;
- 状态回查、UI 验收、失败诊断、HTML 证据包的闭环交付。
还没覆盖(不藏着):
- 合同造数、付款造数、库存全链路等其他单据类型;
- 寄售、跨公司、委外等非标准订单(配置已预留字段,但尚未接通);
- 多行物料的批量并行造数(当前一次跑一条链路,不支持并发)。
外部依赖:
- 依赖被测系统接口稳定,接口大改需要同步更新对应 YAML / 模板;
- 依赖低代码执行平台可用;
- 审批和 ERP 推送是异步的,受环境性能影响,极端情况可能超时(超时上限 8 分钟后中止并报告已完成步骤)。
我把这些边界写进文档和 Skill 声明里,是因为**"能覆盖一类场景"如果不配一句"哪些还没覆盖",反而会让人不敢信**。工具的可信度,一半来自它能做什么,一半来自它坦白自己不能做什么。
十三、总结:造数 Skill 的关键不是 AI,而是工程化
这个造数 Skill 本质上不是一个"调接口工具",也不是一个"Dify 工作流示例"。
它更像一个面向复杂企业测试数据生成的轻量编排系统。
它的核心设计是:
- Skill 是主体,承载业务流程和工程化治理。
- Agent 是入口,负责参数收集、业务映射和执行确认。
- Python 编排引擎负责条件、循环、路由、状态和重试。
- YAML 描述业务场景,降低新增场景成本。
- Jinja2 管理复杂请求体,避免拼接逻辑散落。
- Dify 做薄,只负责 HTTP 和 SQL 执行。
- 静态校验、状态快照、踩坑沉淀保证可维护性。
如果只看表面,这个项目是在做"自动造数"。
但从测试开发的角度看,它真正解决的是另一个问题:如何把高度依赖个人经验的业务测试准备工作,沉淀成团队可复用的工程能力。
这也是我认为 AI Agent 在企业内部落地最值得关注的方向:不要只追求"会聊天",而要让它进入真实流程,把参数、规则、状态、失败路径和工程治理串起来。
FAQ
1. 这个方案里 Dify 到底负责什么?
Dify 主要负责通用执行能力,例如 HTTP 调用和 SQL 查询。复杂的条件、循环、路由、模板渲染、状态管理不放在 Dify 里,而是放在 Skill 的 Python 编排引擎里。
2. 为什么不直接用 Dify 工作流把所有节点串起来?
因为企业造数流程会不断增加分支、循环、模板、SQL、重试和状态处理。如果全部放进低代码工作流,后期会难以复用、难以测试、难以版本管理,也不利于静态校验。
3. YAML 配置化最大的收益是什么?
最大收益是把"不同业务场景的差异"从代码里拿出来。新增场景时,优先新增或调整 YAML 和模板,而不是复制一整套脚本。
4. Agent 在这里是不是可有可无?
不是。Agent 的价值不在于替代编排引擎,而在于降低使用门槛:识别用户意图、收集参数、映射业务编码、执行前确认、返回结构化结果。
5. 这个方案只适合采购类造数吗?
不只适合采购。只要测试数据生成流程具备多接口、多状态、多系统、多分支、需要查询中间结果等特点,都可以借鉴这个架构。例如合同、订单、库存、财务单据、审批流测试数据生成,都可以用类似方式改造。
6. 这个设计和普通自动化脚本最大的区别是什么?
普通脚本通常把流程、参数、请求体、查询、重试都写在一起。这个设计把它们拆成 Agent、编排引擎、YAML、模板和执行层,让变化部分更容易配置,稳定部分更容易复用。
7. 如果团队刚开始做,第一步应该做什么?
先选一条真实高频链路,不要一开始覆盖所有场景。把这条链路拆成 HTTP、SQL、模板、条件、循环、路由几类 action,跑通后再沉淀共享步骤和静态校验。