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)指导原则
基础类型typestring / integer / boolean强制匹配,严禁隐式转换
边界长度minLength / maxLength手机号 11-11,密码 6-20生成完全符合范围的业务值
数值范围minimum / maximum年龄 0-150边界值覆盖与常规数值随机生成
枚举集合enum["PENDING", "SUCCESS", "FAILED"]仅能在给定的集合内进行选取
语义校验pattern / format邮箱正则、手机号正则根据正则生成具有真实语义的内容
递归引用$refUser 关联对象深度展开解析,形成层级数据

三、代码实战: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 current

3.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 自动化联调平台的可靠保障。

更多推荐