AI 自动生成 Mock 数据:微服务接口的 Schema 解析与 Prompt 注入机制
AI 自动生成 Mock 数据:微服务接口的 Schema 解析与 Prompt 注入机制
一、为什么 Mock 数据需要结构解析?
传统的微服务接口 Mock 平台通常依靠规则或简单的正则表达式来填充测试数据,生成的数据往往缺乏业务语义,导致前端联合调试与自动化测试体验不佳。虽然 AI 大模型具备根据描述生成逼真测试数据的能力,但直接把一大堆 Swagger 或 OpenAPI 的原始 JSON 甩给大模型,常常会因为上下文过长、多级嵌套对象解析错误,导致大模型生成的数据不符合类型规范,甚至出现缺失字段等问题。
因此,在大模型为我们生成 Mock 数据之前,系统必须拥有一套高精度的结构解析器。通过提取接口的底层 Schema、推导嵌套引用、提取校验约束,转化为高可读性的中间表示(IR),再精准注入到 Prompt 中,这是确保 AI 生成数据合格的唯一途径。
二、解析流程与约束提取策略
2.1 结构解析生命周期流程
从接口定义到最终被注入至大模型的 Prompt 中,数据需要经过以下解析生命周期的转换:
graph LR A[原始接口定义] --> B[语法解析] B --> C[Schema 树生成] C --> D[核心约束提取] D --> E[IR 中间表示] E --> F[Prompt 动态构建]2.2 核心校验约束映射策略
在语法解析阶段,我们需要将接口定义文件(如 OpenAPI)中的各种校验信息归类为五大约束,并制订出大模型在生成时必须遵守的生成限制:
| 约束维度 | Schema 源字段 | 典型示例 | 大模型生成(Mock)指导原则 |
|---|---|---|---|
| 基础类型 | type | string/integer/boolean | 强制匹配,严禁隐式转换 |
| 边界长度 | minLength/maxLength | 手机号11-11,密码6-20 | 生成完全符合范围的业务值 |
| 数值范围 | minimum/maximum | 年龄0-150 | 边界值覆盖与常规数值随机生成 |
| 枚举集合 | enum | ["PENDING", "SUCCESS", "FAILED"] | 仅能在给定的集合内进行选取 |
| 语义校验 | pattern/format | 邮箱正则、手机号正则 | 根据正则生成具有真实语义的内容 |
| 递归引用 | $ref | User关联对象 | 深度展开解析,形成层级数据 |
三、代码实战:Schema 解析与 Prompt 生成器
3.1 核心 Schema 递归解析器
用 Python 构建的解析器可以针对 OpenAPI 定义中的多重依赖、跨引用关系进行解耦和递归展开:
class SchemaParser: def parse(self, schema: dict, spec: dict) -> dict: ref = schema.get('$ref', '') if ref: # 解决引用,获取真实的类型结构 schema = self._resolve_ref(ref, spec) result = { 'type': schema.get('type', 'object'), 'required': schema.get('required', []), 'constraints': self._extract_constraints(schema) } # 处理嵌套对象 if result['type'] == 'object': result['properties'] = {} for name, prop in schema.get('properties', {}).items(): result['properties'][name] = self.parse(prop, spec) result['properties'][name]['name'] = name result['properties'][name]['required'] = name in result['required'] # 处理数组集合 elif result['type'] == 'array': result['items'] = self.parse(schema.get('items', {}), spec) return result def _extract_constraints(self, schema: dict) -> dict: # 完整提取 OpenAPI 属性限制 return { 'minLength': schema.get('minLength'), 'maxLength': schema.get('maxLength'), 'minimum': schema.get('minimum'), 'maximum': schema.get('maximum'), 'enum': schema.get('enum', []), 'pattern': schema.get('pattern'), 'format': schema.get('format') } def _resolve_ref(self, ref: str, spec: dict) -> dict: # 支持递归拆解组件,定位真实结构 parts = ref.replace('#/', '').split('/') current = spec for part in parts: current = current.get(part, {}) return current3.2 Prompt 构建器与上下文注入
大模型对纯结构化的 JSON 解析往往不够敏感,我们需要将中间表示(IR)转化为易于理解的伪代码描述并拼接具体的指示说明:
class PromptStrategy: def build(self, parsed_schema: dict, business_context: str = "") -> str: sections = [] sections.append("# 接口 Schema 定义约束(请严格遵守)") sections.append(self._format_schema(parsed_schema, 0)) sections.append("") sections.append("# 业务逻辑上下文") sections.append(business_context or "通用后台管理微服务接口") sections.append("") sections.append("# 核心生成准则") sections.append("1. 输出的数据结构与成员属性类型必须 100% 对应上述定义的 Schema。") sections.append("2. 字符串类型(如姓名、地址)请根据上下文自动生成生动真实的业务数据,拒绝硬编码。") sections.append("3. 如果属性中声明了枚举值,只能从 enum 列表中选取。") sections.append("4. 生成的数组数据行数控制在 5 至 10 条之间,需包含典型数据、边界值及空值场景。") sections.append("5. 仅返回标准的 JSON Array 数据,严禁包含任何 Markdown 格式前缀或注释。") return "\n".join(sections) def _format_schema(self, schema: dict, indent: int) -> str: prefix = " " * indent lines = [] t = schema.get('type', 'object') lines.append(f"{prefix}类型: {t}") if schema.get('constraints'): c = schema['constraints'] parts = [] if c.get('enum'): parts.append(f"可选枚举值={c['enum']}") if c.get('minLength'): parts.append(f"最小长度={c['minLength']}") if c.get('maxLength'): parts.append(f"最大长度={c['maxLength']}") if c.get('minimum'): parts.append(f"最小值={c['minimum']}") if c.get('maximum'): parts.append(f"最大值={c['maximum']}") if c.get('pattern'): parts.append(f"正则表达式={c['pattern']}") if parts: lines.append(f"{prefix}规范约束: {', '.join(parts)}") if t == 'object' and schema.get('properties'): for name, prop in schema['properties'].items(): req = "必填" if prop.get('required') else "非必填" lines.append(f"{prefix}- 字段: {name} ({req})") lines.append(self._format_schema(prop, indent + 1)) elif t == 'array' and schema.get('items'): lines.append(f"{prefix}子项列表结构:") lines.append(self._format_schema(schema['items'], indent + 1)) return "\n".join(lines)四、解析与注入最佳实践
- 深度优先展开与防循环引用:在处理像
Organization嵌套User,且User内部又引用Organization的对象图时,解析器必须在递归时记录解析路径的visited集合,防止发生无限递归导致内存溢出。 - 严格的结构验证层(Guard):切忌只依赖大模型的生成结果。在接收到大模型返回的 JSON 数据后,系统必须使用刚解析生成的 Schema 对 JSON 数据进行一次强类型的 JSON Schema Validation 验证,验证不通过则自动重试或使用静态方案兜底。
- 上下文语义增强:仅提供
email类型,AI 可能会生成类似a@b.com这样无意义的数据。如果能结合business_context传入类似“电商客服反馈列表接口”,大模型就能配合生成符合该上下文的客服邮箱和反馈文字,使测试仿真度提升数倍。
五、总结
在基于大模型自动生成微服务 Mock 数据的链路中,结构解析扮演了不可或缺的基石角色。用自建解析器代替大模型的暴力直读,将繁杂的接口定义抽取为紧凑而精确的中间表示,能从根本上避免数据的类型错乱与字段遗漏。解析精准度加提示词控制,才是企业级 AI 自动化联调平台的可靠保障。
