造测试数据这件事我在三种不同形态的团队里都干过有的靠手工怼Excel有的靠SQL从生产库里抽还有一种看起来高级一点写一堆脚本循环Insert。结果殊途同归——每次提测之前数据准备至少耗掉半天跑完自动化又发现某些状态组合压根没覆盖到只能临时补造然后重新跑一遍回归。后来我们把AI生成测试数据接进了这条流程提测前只需要跑一条流水线几分钟之内就能把几百条带业务语义、字段之间逻辑能对上的模拟数据造出来而且是批量、可复现、可校验的。这篇文章把我在这轮改造里看到的门道说清楚AI到底怎么介入“造数”业务约束怎么写才不会让AI一本正经地胡说八道以及那些我替你们踩过的坑都放在后面。适合做后端测试、数据构造、接口联调和QA自动化的同学参考。1. 造数据为什么让团队抓狂从“多凑几条”到“数据的表达力”很多人觉得造数嘛不就是往表里插几条记录有什么难的。真正扎心的是当你需要的不只是“几条”而是“几十条、上千条、分布覆盖各种边界条件、跨表引用还能闭环”的数据时手工方式的效率和质量就会同时崩盘。1.1 手工造数的四种“隐性成本”先说第一种字段“看着对”但语义不对。手工填数据的人通常会凭自己对业务的理解去编邮箱、手机号、状态值写出来的人觉得没问题用数据的人却不知道这条数据到底代表什么场景。比如某位组员为了凑一条退款记录把退款金额随手填成了负数接口却把这个负数当正常参数吞了进去测试等于白做。第二种是关联关系靠人脑记忆。订单系统里一条订单要同时有下单用户、支付单、物流单、商品明细这些表之间的外键关系一旦靠手填很容易出现“订单已经发货但支付单还不存在”这种逻辑残缺。更麻烦的是不同的人对业务关系的理解不一致A同学认为必须先有支付单才有物流单B同学觉得可以先发货后支付两边造出来的数据风格完全不一样测试结果根本无法横向对比。第三种是环境割裂。本地数据库一套数据、测试环境另一套数据联调时发现“我这有这条数据你那边没有”排查半天不是在测代码而是在对数据。第四种才是大家最容易忽略的提测前集中造数的时间压力。版本越赶数据准备越仓促最后全靠加班补造出来的数据还没人review就直接进了自动化。1.2 AI真正解决的不是“造得快”而是“造得准”如果把AI生成测试数据单纯理解成“用大模型多给我生成几条”那就太小看这件事了。它真正的杠杆在于把“规则”和“实例”分离。传统造数方案是硬编码几十条insert语句规则被埋在具体的值里别人拿到代码根本看不出设计意图。AI造数的思路是反过来——你先定义清楚业务规则和字段约束然后由AI负责产出一份结构化配置或样例再由本地引擎按这份配置去做大规模实例化。规则清单可以被review、被版本管理、被校验器逐条检查实例则可以被无限批量生成。这意味着团队终于不用把时间花在重复“造值”上而是把时间花在把业务规则表达得更准确上。一旦“规则”和“数据”分离开造数就从“一次性手工活”变成了“可复用的生产线”。这也是为什么很多团队明明有现成的造数脚本最后还是会转向AI方案——脚本本身造的也是值规则还是埋在代码里而AI方案能让规则本身成为团队资产。2. 两条AI生成技术路线哪种适合哪种场景规则渲染与LLM直出AI生成测试数据目前主流就两条路一条是让AI先生成配置模板再由本地随机引擎按模板渲染出大量数据另一条是让大语言模型根据自然语言提示词直接“直出”一批带业务语义的数据。两者不是替代关系而是互补关系选错了才会觉得“AI不靠谱”。2.1 路线AAI增强的规则渲染适合大批量稳定产数这条路径的原始形态很多后端同学都见过——用一些开源的假数据生成库比如常见的Faker类工具按字段类型随机产数。问题是这类工具只能保证“格式像”无法保证“业务语义像”。给一个字段配置了name和city它确实能生成姓名和城市但它不理解“下单用户必须在用户表里存在”这种跨表约束。AI增强之后就不一样了你先用自然语言把业务表结构、字段枚举、取值范围、跨表引用描述给大模型让模型帮你生成一份结构化的数据生成器配置本地引擎再根据这份配置做真正的高速随机渲染。举例来说一份订单配置大概是这种形态tables: users: count: 100 fields: user_id: {type: sequence, start: 1001} user_name: {type: fake, category: name} orders: count: 500 fields: order_id: {type: sequence, start: 10001} user_id: {type: ref, table: users} status: {type: enum, values: [PENDING, PAID, SHIPPED, COMPLETED, CANCELLED]} amount: {type: decimal, min: 0.01, max: 10000, precision: 2}生成引擎拿到这份配置后可以在一秒内产出上千条符合约束的记录不消耗模型token也不存在输出不稳定的问题。这正是它适合大批量场景的原因造10万条用户、买一张订单表规则渲染几乎是唯一靠谱的答案。2.2 路线BLLM直接产出业务语义数据适合小批量复杂场景有时候你需要的是“几条特别像真实业务的数据”比如联调环境里要和第三方系统对账数据量不大但字段之间语义要求极高。这时候可以让大模型直接生成样例数据核心是把约束在提示词里说透。我常用的提示词模板大概是这样你是一个测试数据生成助手请生成10条订单记录。 字段订单号、用户ID、商品ID、订单金额、订单状态、创建时间、支付时间、发货时间。 要求 1. 状态只能从 PENDING、PAID、SHIPPED、COMPLETED、CANCELLED 中取 2. 如果状态是 CANCELLED不允许出现支付时间 3. 支付时间必须晚于创建时间 4. 发货时间如果存在必须晚于支付时间 5. 订单金额保留两位小数且大于0 6. 用户ID和商品ID必须是数字且在1到1000之间。LLM直出的优势是生成的记录读起来非常“像人写的”日期不会全部挤在同一个整点金额不会全部取整评论字段也不会像模板机一样重复。缺点也很明显输出长度受限、一次生成数量有限、容易出现偶发的不稳定而且成本比本地引擎高很多。所以它更适合做“小批量语义数据种子”再由人工或脚本扩展成大批量。2.3 选型判据数据量、关联深度与可复现性具体选哪条路我通常用这张表来判断维度AI增强的规则渲染LLM直出单次数据量可以轻松上万甚至百万受输出长度限制一般几条到几十条关联字段保障通过配置显式引用跨表关系稳定靠提示词约束偶发不稳定可复现性固定seed即可复现依赖模型版本和温度参数相对困难生成速度本地渲染毫秒级网络调用级别几秒到几十秒维护成本配置模板需要维护提示词版本需要维护适合场景大批量、表结构固定联调样例、复杂业务语义小批量真实项目里往往是混用的先用规则渲染产出一批基础数据集再针对“异常场景集”这种小批量高语义场景用LLM直出补几条最后统一过一遍校验器。两条腿走路才能兼顾效率和可信度。3. 实战把订单系统改成AI造数生产线原理聊得再多不如看一遍完整落地的过程。我拿一套常见的电商订单系统举例讲一讲我们是怎么一步步把手工造数改成AI造数流水线的。3.1 梳理业务对象与数据依赖画不出依赖图就别动手这一步最容易被跳过但恰恰最重要。AI不会自动理解你的业务它所有的“理解”都来自你喂给它的信息。动手写任何提示词之前先把系统里要造数的核心对象和关联关系列出来users用户表被orders引用products商品表被order_items引用orders订单表状态有PENDING、PAID、SHIPPED、COMPLETED、CANCELLEDpayments支付单表一个订单必须至少对应一条支付记录且支付金额总和要等于订单应付金额shipments物流表只有已支付且未取消的订单才可能有物流记录。这些依赖关系不需要画多复杂但一定要保证团队里所有人都对齐。我见过太多翻车案例最后复盘发现根本不是AI的问题而是业务方和开发对“订单能不能先发货后支付”这种基本问题的理解本身就一致不了。3.2 把业务规则写成“机器能校验的约束清单”梳理完对象和关系下一步是把“人知道的业务常识”转成“机器能逐条校验的约束清单”。我一般按三个层次来写字段级约束枚举值、格式、范围。比如订单状态只能取那几个枚举金额必须大于0且保留两位小数用户ID必须是正整数。记录级约束同一条记录内部字段之间的逻辑。比如“CANCELLED订单不能有支付时间”“发货时间必须晚于下单时间”“已取消订单的物流状态必须是空”。跨表约束表与表之间的引用和计数。比如“每条订单必须至少对应一条payments记录”“payments总额等于orders订单应付金额”“order_items里的商品必须存在。”清单写好后要让AI做的事情就很明确了要么根据清单生成配置模板要么根据清单生成小批量样例。如果清单本身写不明白那AI生成多少条都是白搭。3.3 让AI生成“生成器”而不是裸数据这是整条流水线最核心的设计决策。我第一次尝试的时候也让AI直接生成过一批订单数据效果还行但问题在于每批数据都需要单独调一次模型没法复用而且一旦业务字段变了前一批数据立刻全部作废。后来改成让AI负责产出“生成器配置”由本地引擎批量实例化。举个例子先让AI根据上面那份约束清单生成一个JSON或YAML模板人类工程师只负责review模板里的字段、枚举、引用关系确认无误之后引擎就可以无限量产出数据。这种做法的最大好处是配置稳定、可版本管理、可由专人维护而生成本身不再消耗模型资源。{ table: orders, count: 1000, fields: { order_id: {rule: sequence, start: 10001}, user_id: {rule: ref, table: users}, amount: {rule: decimal, min: 1.0, max: 9999.99, digits: 2}, status: {rule: weighted_enum, values: { PENDING: 0.1, PAID: 0.2, SHIPPED: 0.3, COMPLETED: 0.3, CANCELLED: 0.1} } } }这里特别要注意的是“status”字段我用了带权重的枚举而不是均匀枚举。原因很简单真实业务里订单状态根本不会平均分布绝大多数订单是完成和发货状态极少是待支付和取消状态。测试数据如果分布太均匀反而会掩盖长尾问题。3.4 加一个回归校验器当守门员生成器只负责“产数据”校验器负责“判真假”。我们给这条流水线加了一个非常小的校验脚本每批数据生成后自动跑一遍所有外键引用是否在对应表中存在枚举值是否都在允许集合内派生字段是否满足表达式比如金额合计时间类字段是否满足先后关系空值和异常字符是否只出现在预设的边界样本里。这个脚本一开始只有几十行维护成本很低但它把所有“AI可能翻车”的点都兜住了。只要校验不过数据就不会进入测试环境。有人觉得这多了一道环节但实际跑下来这道环节省掉的排障时间远大于它本身的耗时。4. 生成数据可信度一致性、真实分布与合规底线用AI造数绕不开一个问题这些数据到底能不能信测试的人不信数据测什么都不踏实。我把可信度拆成四个维度每个都值得单独讲清楚。4.1 “长得像”不算数字段之间的账要算平很多AI生成的样例数据单看每个字段都正常合在一起就露馅了。最典型的就是金额逻辑订单总额不是凭空出来的它等于“商品原价合计 运费 - 优惠金额”。如果AI只是给amount随机生成了一个数字再给优惠金额随机生成了一个数字大概率两边对不上。处理办法很简单凡是能由其他字段推导出来的值一律不要让它独立生成而是在配置里写成表达式由生成引擎在渲染时现算。比如订单金额先随机生成商品明细和运费再让总金额等于明细之和加上运费。只要规则引擎在源头保证了推导关系校验器那边几乎不会出问题。4.2 别只给AI“平均数据”边界场景才是测试的价值所在有一类常见失误是让AI生成了1000条“看起来都差不多”的订单字段分布均匀、金额不大不小、状态四平八稳。这种数据跑接口没问题但一旦要测超时重试、库存不足、金额溢出、并发下单这些场景数据完全不顶用。我现在的做法是按比例混入边界样本90%的正常数据用于常规回归10%的边界数据用于特定场景测试包括空字段、超长字符串、极端金额、非法状态、时间倒挂等。AI在这里的价值是能快速生成“语义上像真实业务、但数值上刻意极端”的数据而不是靠人手工一条条改。4.3 合成数据在合规上的天然优势但该做的甲方不能省用AI造数据还有个好处它产的是“合成的假数据”不直接关联真实用户所以相比直接从生产库拖数据隐私顾虑小很多。测试环境里甚至可以放心地造包含姓名、手机号、地址的样例而不用先做一遍脱敏。但这不等于可以放松管理。合成数据一旦进入测试环境同样要按照敏感数据来对待访问权限要控制、生成记录要留痕、用到的字段字典和规则清单要当作文档维护好。尤其当数据被用于联调或验收时必须有据可查否则出了问题谁也说不清数据怎么来的。4.4 固定随机种子与生成版本让每条数据都可追溯这是容易被忽略但极其实用的一点所有生成器都需要支持固定随机种子并且在产出的数据文件里写入生成器版本号。有了这两个信息任何一条测试数据都可以反推“是谁在哪个版本、哪个随机种子的配置下生成的”。排查问题时能直接回答“这条数据为什么会出现”和“A环境为什么和B环境不一样”比在测试群里反复截图高效得多。5. 踩坑复盘AI造数据最常翻车的六个瞬间这一节是实战里最值得看的部分。我们在推广AI造数的过程中踩过不少坑有些坑简直可以说是AI生成测试数据的“必经之路”。5.1 AI“一本正经”地编造出不存在的状态组合第一次用LLM直出订单数据时生成结果里出现了一条很离谱的记录订单状态是CANCELLED却同时有支付时间、有物流单号、还有评价内容。单看这个输出格式完全正常但按业务规则根本不可能存在。根因是大模型只学到了一堆文本的联合概率并不会真的去执行状态机。解决方式是在提示词里显式写明状态扭转过程同时在生成器配置里直接写死“按状态过滤字段”的逻辑。从此我们有个不成文的规定凡是跨字段的强逻辑绝不能只依赖提示词必须在生成器里用规则把它锁死。5.2 一次性生成百万级数据直接把进程搞崩团队刚开始用AI配置渲染数据时有同事图省事直接在配置里把count设成了100万然后本地引擎一次性把100万条记录读进内存再写文件。结果16G内存的机器直接OOM数据库连接也差点被拖死。这事的教训不是“别生成这么多”而是“要分块生成”。后来我们把引擎改成每5000条一批写入文件写入完成再清空内存百万条也要不了几十秒。数据量和内存不是一回事流式处理才是批量造数的基本素养。5.3 字段分布过于均匀像“人工假数据”有段时间生成的订单记录金额全部落在200到800之间状态也四平八稳。做性能测试的同事抱怨说这种数据压测压不出真实系统的毛刺。原因是生成器配置里用了均匀分布而真实业务是长尾分布大量小额订单、少量大额订单、极少数超大额异常订单。改成加权枚举和偏态分布后数据立刻“活”了。测试数据不追求平均追求的是对真实场景的模拟。5.4 提示词一换数据全变脚本却全绿有一回某个联调环境的数据因为提示词里加了一句“日期集中在最近一周”导致整个数据集变了但自动化脚本全绿。问题的严重性在于“全绿”是因为脚本只校验了接口返回没校验数据本身的业务分布。后来我们把提示词也纳入版本管理并且对每个生成器固定seed、固定温度参数。只要不是有意修改重新生成的数据应该和上一次完全一致。可复现性一旦保证数据变更才能变成“可审查的事件”而不是“随机的噪声”。5.5 生成了“合法”但时间线混乱的数据时间字段是最容易被忽略的。AI生成的订单表里出现过创建时间是2024年6月10日、但支付时间在2024年6月8日的情况。每个字段单独看都是标准的日期格式放在一起就穿帮了。解决方式是给时间类字段建立“参照系”支付时间以创建时间为基准加一个随机偏移量发货时间以支付时间为基准再加偏移量。让字段之间形成相对先后关系而不是各随机各的。5.6 团队把AI当“字典”没人维护约束清单最大的坑不是技术而是组织造数需求一多各组都来找AI生成数据有人直接在提示词里加字段有人绕过校验器往环境里插数据。没过多久约束清单和实际数据开始漂移测试组开始分不清真值是什么。后来我们立了一个规矩所有生成器配置和约束清单的变更必须走代码review校验器一旦判失败就当线上故障处理。这个规矩立完之后数据质量才真正稳定下来。6. 走向数据工厂AI造数和工程化的最后一公里光会写提示词、会生成几条样例离“让团队不再头疼造数”还很远。我个人的体会是AI造数必须走向工程化变成一条持续运转的数据工厂而不是一堆散落的脚本。6.1 生成器、校验器、基线库三层解耦我们最后沉淀下来的架构是三个各司其职的部分生成器负责按配置产出数据校验器负责在数据进入环境前把住质量关基线库负责存放那些“已知可靠”的数据集版本供各环境复用。三层之间互不依赖哪一层出问题都能单独替换。这样做最直接的好处是新人也能上手想给某环境造一批数据只需要选一个基线版本、跑一次生成器、确认校验通过然后导入即可不需要理解整条业务链路。造数从“资深测试的个人手艺”变成了“团队的标准流程”。6.2 人机协作的迭代循环让AI改模板比让人改模板快流程稳定之后我们开始把一个工作方式固定下来每当业务有字段变化负责的工程师先用自然语言写一句“订单表新增了发票类型字段枚举值有PERSONAL和COMPANY”然后让AI基于变化更新生成器配置模板。人类工程师只负责审核AI改过的配置而不是自己动手改字段。这个循环跑顺之后造数的响应速度提高了非常多。以前加一个字段要翻代码、改脚本、重新造数据现在几分钟就能产出一批新数据而且校验器还会帮你把关。真正花时间的不是AI生成而是约束清单本身的准确性这一点任何工具都替代不了。6.3 先从哪些团队试点以及我最后的实际体会如果想在团队里推AI生成测试数据我建议先找一个“数据关系清晰、字段不算多、校验指标明确”的小型系统切入比如订单中心先跑通整条流水线再横向扩展到账户中心、库存中心。不要一开始就挑战数百张表的复杂领域那样只会让AI配置和校验器都变得难以维护。我自己的实际体会是说“AI造数据不再头疼”其实只说对了一半。真正让造数不再头疼的不是AI本身而是AI逼着你把业务规则变成了一份可维护的清单。规则理清了AI才能像个不知疲倦的流水线工人规则一团糟AI生成得越快翻车得越快。先把约束写好再让AI上场这条流水线最终会超出你对手工造数的所有预期。
阅读完成 · 觉得有帮助?