iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
Build on Google AI

用 Google AI 生態系 30 天從零打造一個全棧 AI SaaS 服務系列 第 19 篇

Day 19 -【Prompt 護欄工程】Gemini 1.5 JSON Schema 強制結構化輸出與抗幻覺 Prompt 防護網實戰

  • 分享至 

  • xImage
  •  

在昨天的 [Day 18] 中,我們成功整合了 Stripe Payment + Webhook 訂閱制金流,為 OmniVibe AI 建立了健全的商業變現管道。

當使用者開始掏錢訂閱 Pro 方案時,他們對產出品質的要求將提升到商業等級。此時,我們面臨全棧 AI SaaS 最常見的兩大災難:

  1. JSON 格式不穩定與 UI 崩潰:大語言模型(LLM)有時會在輸出的 JSON 中多包含 Markdown 標記(如 ````json)、遺漏閉合括號,或是擅自變更欄位名稱(如將 social_posts寫成socialPosts),導致前端頁面 JSON.parse()` 報錯,直面白屏。
  2. AI 幻覺(Hallucination)與資訊造假:模型憑空捏造影片中從未出現過的時間軸(Timestamp)、數據或專家引言,嚴重損害產品信任度。

今天,我們將結合 Gemini 1.5 原生的 JSON Schema 強制結構化輸出(Structured Outputs) 與 Prompt 防護網(Guardrail Engineering),在程式碼層級徹底杜絕格式錯誤與 AI 幻覺!


🛡️ 傳統 Prompt 提示 vs. 原生 JSON Schema 護欄

在過去,開發者只能靠在 Prompt 裡寫「請嚴格輸出 JSON,不要包含任何額外說明」來祈禱模型聽話;而 Gemini 1.5 SDK 提供了原生的引擎級強約束:

graph TD
    subgraph 傳統 Prompt 祈禱法 (Unsafe)
        A[Prompt: 請輸出 JSON] --> B[Gemini 推論]
        B --> C[偶發 Markdown 或語法錯誤]
        C --> D[前端 JSON.parse() 崩潰 💥]
    end

    subgraph 原生 JSON Schema 強制約束 (Production Grade)
        E[定义 Strict SchemaType Definition] --> F[帶入 generationConfig.responseSchema]
        F --> G[Gemini 1.5 引擎原生語法約束]
        G --> H[100% 符合型別的 JSON 串流 🎯]
    end

使用 Gemini 的 Structured Outputs,Gemini 在生成每一個 Token 時都會受到語法樹(Grammar Tree)的嚴格約束,從根本上 100% 保證輸出的 JSON 格式符合定義,再也不需要寫複雜的 Regex 正規表達式去剔除垃圾字元!


🛠️ 第一步:定義嚴格的 Gemini Response Schema

我們利用 @google/generative-ai 提供的 SchemaType,為 OmniVibe AI 提煉結果定義精準的結構化 Schema:

// src/lib/gemini/schema.ts
import { Schema, SchemaType } from '@google/generative-ai';

export const omniVibeDistillSchema: Schema = {
  type: SchemaType.OBJECT,
  properties: {
    meta: {
      type: SchemaType.OBJECT,
      properties: {
        summary: {
          type: SchemaType.STRING,
          description: '資產的核心精華總結,不超過 100 字',
        },
        confidenceScore: {
          type: SchemaType.NUMBER,
          description: 'AI 對於此資產分析的可信度評分 (0.0 至 1.0)',
        },
      },
      required: ['summary', 'confidenceScore'],
    },
    takeaways: {
      type: SchemaType.ARRAY,
      description: '3 到 5 個關鍵洞見點',
      items: {
        type: SchemaType.STRING,
      },
    },
    socialPosts: {
      type: SchemaType.OBJECT,
      properties: {
        threads: {
          type: SchemaType.STRING,
          description: '適合 Threads / Twitter 的爆款短文案,包含 Hashtags',
        },
        linkedIn: {
          type: SchemaType.STRING,
          description: '適合 LinkedIn 的專業知識型長文案',
        },
      },
      required: ['threads', 'linkedIn'],
    },
    script: {
      type: SchemaType.OBJECT,
      properties: {
        title: { type: SchemaType.STRING, description: '短影音腳本標題' },
        timeline: {
          type: SchemaType.ARRAY,
          description: '短影音分鏡腳本時間軸',
          items: {
            type: SchemaType.OBJECT,
            properties: {
              timestamp: { type: SchemaType.STRING, description: '例如 00:00 - 00:15' },
              visual: { type: SchemaType.STRING, description: '畫面視覺描述' },
              audio: { type: SchemaType.STRING, description: '旁白或台詞' },
            },
            required: ['timestamp', 'visual', 'audio'],
          },
        },
      },
      required: ['title', 'timeline'],
    },
  },
  required: ['meta', 'takeaways', 'socialPosts', 'script'],
};


🧱 第二步:建構抗幻覺 Prompt 防護網 (System Instructions)

除了格式限制外,內容的「真實性(Grounding)」才是商業品質的核心。我們要在 System Instruction 中導入 Prompt 防護綱領,設計三大抗幻覺原則:

  1. 嚴格基於源資產 (Strict Grounding):凡是影片/PDF 中未提及的數據、人名或結論,絕不憑空臆測。
  2. 邊界防護 (Boundary Defense):若影音音質太差或內容無法辨識,必須明確回報 confidenceScore < 0.5 並指出原因,而非敷衍撰寫。
  3. 時間軸真偽驗證 (Timestamp Integrity):短影音腳本對應的時間標記必須精確存在於原影片時間軸內。
// src/lib/gemini/prompts.ts
export const OMNIVIBE_GUARDRAIL_SYSTEM_PROMPT = `
你是一位嚴謹的頂級多模態內容提煉專家,服務於 OmniVibe AI 生產級平台。
請遵循以下【抗幻覺與真實性原則】:

1. 【忠實度原則】:所有核心洞見 (takeaways) 與摘要,必須 100% 來自用戶提供的原始影音或 PDF 檔案。嚴禁引入未於資產中出現的外部未證實事實。
2. 【數據精確性】:若原始內容提及具體數字 (例如 "營收成長 35%"), 必須精確引用;若不確定數字,請使用範疇描述,不得編造數據。
3. 【時間軸對齊】:生成短影音腳本時,時間標記 (timestamp) 必須符合真實影片時間長度,不可生成超越影片總長度的標記。
4. 【邊界防禦】:若檔案無法清晰辨識,或內容屬於不可分析之噪訊,請將 meta.confidenceScore 設為 0.3 以下,並於 summary 中誠實說明限制。
`;


⚡ 第三步:整合完整 API 服務與 Zod 驗證管線 (src/lib/gemini/guarded-distill.ts)

我們在伺服器端將 Gemini 1.5 API + Response Schema + Zod 雙重驗證 封裝成可安全呼叫的函數:

// src/lib/gemini/guarded-distill.ts
import { GoogleGenerativeAI } from '@google/generative-ai';
import { omniVibeDistillSchema } from './schema';
import { OMNIVIBE_GUARDRAIL_SYSTEM_PROMPT } from './prompts';
import { z } from 'zod';

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || '');

// 使用 Zod 進行 TypeScript 執行期二次型別保障
export const DistillResultZodSchema = z.object({
  meta: z.object({
    summary: z.string(),
    confidenceScore: z.number().min(0).max(1),
  }),
  takeaways: z.array(z.string()),
  socialPosts: z.object({
    threads: z.string(),
    linkedIn: z.string(),
  }),
  script: z.object({
    title: z.string(),
    timeline: z.array(
      z.object({
        timestamp: z.string(),
        visual: z.string(),
        audio: z.string(),
      })
    ),
  }),
});

export type DistillResult = z.infer<typeof DistillResultZodSchema>;

export async function generateGuardedDistillation(
  fileUri: string,
  mimeType: string
): Promise<DistillResult> {
  // 配置具備 JSON Schema 的模型實例
  const model = genAI.getGenerativeModel({
    model: 'gemini-1.5-flash',
    systemInstruction: OMNIVIBE_GUARDRAIL_SYSTEM_PROMPT,
    generationConfig: {
      responseMimeType: 'application/json', // 指定輸出 MIME 類型
      responseSchema: omniVibeDistillSchema, // 綁定原生的 JSON Schema 護欄
      temperature: 0.2, // 降調低創造力,提升輸出穩定性與真實度
    },
  });

  console.log('[Gemini Guardrail] 發起結構化提煉請求...');

  const result = await model.generateContent([
    {
      fileData: { fileUri, mimeType },
    },
    '請根據上述資產,產出符合 Schema 規範的結構化洞見與社群文案。',
  ]);

  const rawText = result.response.text();

  try {
    // 1. 原生 JSON 解析
    const jsonParsed = JSON.parse(rawText);

    // 2. 使用 Zod 進行 TypeScript 嚴格執行期驗證
    const validatedData = DistillResultZodSchema.parse(jsonParsed);
    console.log('[Gemini Guardrail] 成功通過 Schema 與 Zod 防護網驗證!');

    return validatedData;
  } catch (err: any) {
    console.error('[Gemini Guardrail Error] 結構化解析失敗:', err);
    throw new Error(`AI 輸出違反內容護欄規範: ${err.message}`);
  }
}


🧪 實測驗證:無護欄 vs. 有護欄 輸出對比

我們使用一份講述「AI 晶片架構發展」的 15 分鐘 MP4 影片進行測試對比:

❌ 傳統無護欄模式 (Plain Prompt):

  • 輸出狀況:模型回傳了帶有 ````json` 標記的字串,包含開頭引言「這是我為您整理的 JSON 格式內容:」。
  • 下場:前端 JSON.parse() 拋出 SyntaxError: Unexpected token '這' 異常,網頁直接崩潰。
  • 內容問題:腳本時間軸出現了 18:30 - 20:00,但原影片長度僅有 15 分鐘(發生幻覺!)。

✅ 引入 Gemini JSON Schema 護欄後:

  • 輸出狀況:0 個多餘字元,直接輸出純淨、可被 100% 解析的合規 JSON:
{
  "meta": {
    "summary": "本影片探討 2026 年新一代 AI 晶片在記憶體頻寬與高能效運算上的突破技術。",
    "confidenceScore": 0.95
  },
  "takeaways": [
    "HBM4 記憶體技術大幅緩解 LLM 推理階段的 Memory-wall 瓶頸。",
    "晶片間互連協定 (Interconnect) 成為多卡平行訓練的效能關鍵。"
  ],
  "socialPosts": {
    "threads": "🚀 2026 AI 晶片大革命!還在嫌大模型推理太慢?\n這支影片帶你一次拆解 HBM4 與晶片互連技術的最佳實踐... #AI #Hardware",
    "linkedIn": "在近期的 AI 系統架構演進中,記憶體頻寬已全面取代算力成為最顯著的瓶頸..."
  },
  "script": {
    "title": "3分鐘看懂 2026 AI 晶片演進",
    "timeline": [
      {
        "timestamp": "00:00 - 00:10",
        "visual": "快速切換伺服器機房與晶片微觀結構",
        "audio": "「為什麼模型參數越來越大,推論速度卻變慢了?」"
      }
    ]
  }
}


🎯 總結與明日預告

今天我們成功為 OmniVibe AI 構建了工業級的 Prompt 護欄工程:

  1. 掌握了 Gemini 1.5 原生的 JSON Schema (Structured Outputs) 機制,徹底摒棄了脆弱的 Markdown 解析。
  2. 實作了 Zod + Gemini SDK 雙重型別驗證管線,確保前端 100% 渲染安全。
  3. 導入了 Anti-Hallucination System Instruction 防護網,大幅提升輸出品質與商業信任度。

有了完美的 UI、穩健的金流與不崩潰的 Prompt 護欄後,在真正的雲端生產環境中,我們該如何監控 LLM 輸出的品質演變?如何知道新版 Prompt 是變好還是變壞?

👉 明天(Day 20),我們將進入【AI 評估與監控篇】:實戰 Ragas / LLM-as-a-Judge 自動化品質評測與 OpenTelemetry 追蹤管線!看我們如何用數據量化 AI 服務的忠實度與品質!

我們明天見!🔥


上一篇
Day 18 -【商業變現】實戰 Stripe Payment + Credit 訂閱制金流整合:Checkout 結帳與 Webhook 自動充值變現
下一篇
Day 20 -【AI 評估與可觀測性】LLM-as-a-Judge 自動化品質評測與 OpenTelemetry 追蹤管線實戰
系列文
用 Google AI 生態系 30 天從零打造一個全棧 AI SaaS 服務 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言