从零打造 AI 智能表单 (3):引入 Zod 实现 LLM 输出的鲁棒性校验

...
Next.jsAIZodTypeScriptLLM

在 SmartForm 项目中,核心卖点是 "Text-to-Form" —— 用户输入一句话,AI 自动生成表单结构。然而在早期开发中,这个功能非常脆弱。大模型(即便是 GPT-4)偶尔也会“发疯”,返回的 JSON 格式错误、字段缺失,甚至直接返回 Markdown 代码块,导致前端解析失败,白屏崩溃。

今天我们就来聊聊如何给 AI 戴上“紧箍咒”,确保它输出的数据既稳定又安全。

1. 痛点分析:AI 的不可控性

在没有校验机制时,我们的 API 逻辑非常简单粗暴:

// ❌ 错误示范:完全信任 AI const content = aiResponse.choices[0].message.content; const formJson = JSON.parse(content); // 这里很容易报错! return NextResponse.json(formJson);

遇到的典型问题包括:

  1. Markdown 污染:AI 喜欢用 ```json 包裹代码,直接 JSON.parse 会挂。
  2. 幻觉字段:AI 可能会发明一些 Schema 中不存在的属性,比如 colorstyle
  3. 类型错误:不仅是结构,有时候字段类型也不对,比如 required 应该是布尔值,它返回了字符串 "true"。

2. 解决方案:Zod 强校验

为了解决这个问题,我引入了 Zod —— 一个 TypeScript 优先的 Schema 声明和验证库。

2.1 定义 Schema

首先,我们需要用 Zod 定义我们期望的 JSON 结构。这不仅是校验逻辑,也是最好的文档。

import { z } from "zod"; const BlockTypeSchema = z.enum([ "text", "textarea", "number", "select", "radio", "checkbox", "rating", "date", "email" ]); // 单个表单项的结构 const FormBlockSchema = z.object({ type: BlockTypeSchema, label: z.string(), required: z.boolean().default(false), // 甚至可以设置默认值 placeholder: z.string().optional(), options: z.array(z.object({ label: z.string(), value: z.string(), })).optional(), }); // 完整的生成结果结构 const GenerateFormSchema = z.object({ title: z.string(), description: z.string().optional(), blocks: z.array(FormBlockSchema), });

2.2 优化 System Prompt

除了校验,我们还需要在源头(Prompt)上做文章,明确告诉 AI 我们需要的 JSON Schema。

const SYSTEM_PROMPT = ` You are an expert form builder AI. CRITICAL OUTPUT RULES: 1. Output MUST be valid JSON only. 2. Do NOT include markdown formatting. 3. Follow this JSON Schema strictly: ... `;

2.3 容错解析与校验

在收到 AI 响应后,我们不再直接信任,而是进行三步走:清洗 -> 解析 -> 校验

// 1. 清洗:去除可能存在的 Markdown 标记 const cleanContent = content.replace(/```json/g, "").replace(/```/g, "").trim(); let rawJson; try { // 2. 解析:尝试转为 JS 对象 rawJson = JSON.parse(cleanContent); } catch (e) { throw new Error("AI returned invalid JSON syntax"); } // 3. 校验:使用 Zod 进行结构验证 const validationResult = GenerateFormSchema.safeParse(rawJson); if (!validationResult.success) { // 可以在这里做更多降级处理,或者记录日志 console.error("Schema Validation Failed", validationResult.error); throw new Error("AI response structure is incorrect"); } // ✅ 安全的数据 const safeData = validationResult.data;

3. 效果与反思

经过这一轮改造,SmartForm 的生成成功率从之前的 80% 提升到了 99%。即便 AI 偶尔抽风,后端也能在第一时间捕获错误,而不是让前端直接白屏。

这种 "Prompt Engineering + Runtime Validation" 的模式,是目前构建 AI 应用最稳健的最佳实践之一。


Next Steps: 虽然现在有了校验,但如果校验失败了怎么办?目前我们是直接报错。更好的做法是引入 Auto-Retry (自动重试) 机制,当校验失败时,将错误信息喂回给 AI,让它自我修正。这将在下一篇文章中分享。