iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Build on Google AI

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

Day 20 -【AI 評估與可觀測性】LLM-as-a-Judge 自動化品質評測與 OpenTelemetry 追蹤管線實戰

  • 分享至 

  • xImage
  •  

在昨天的 [Day 19] 中,我們透過 Gemini 1.5 原生 JSON Schema 與 Prompt 護欄工程,解決了結構化輸出解析與基礎內容越界問題。

但在生產環境中,光有「語法護欄」還不夠。當我們優化 Prompt、更換 Gemini 模型版本(如從 gemini-1.5-flash 切換至 gemini-1.5-pro)、或調整系統參數時,我們該如何用數據客觀評估 AI 的提煉品質是變好還是變壞? 當使用者回報「生成內容不準確」時,我們又該如何快速定位是 Prompt 瑕疵、脈絡遺失,還是模型本身的思考偏差?

今天,我們將為 OmniVibe AI 打造現代化全棧 AI 可觀測性(AI Observability)架構,導入 LLM-as-a-Judge 自動化評測管線 與 OpenTelemetry 追蹤(Tracing)機制!


📐 AI 可觀測性與評測雙軌架構

一個健全的生產級 AI SaaS 系統需要兩種層面的監控機制:

  1. 離線與即時品質評測 (Evals - LLM-as-a-Judge):針對產出內容進行「忠實度(Faithfulness)」與「相關性(Relevance)」的自動化量化打分。
  2. 線上鏈路追蹤 (Observability - OpenTelemetry):記錄每一次 Gemini API 呼叫的 Latency(延遲)、Token 消耗量、 Prompt 歷史版本與 Error Rate。
graph TD
    User[使用者請求] --> API[Next.js API Route]
    API --> OTel[OpenTelemetry Tracer]
    
    subgraph Tracing Pipeline
        OTel --> Span1[Gemini API Call Span]
        OTel --> Span2[Token & Latency Metrics]
        Span1 --> Phoenix[Arize Phoenix / OpenTelemetry Collector]
    end
    
    subgraph LLM-as-a-Judge Eval Pipeline
        Span1 --> AsyncEval[非同步評測工作]
        AsyncEval --> Judge[Gemini 1.5 Pro 裁判模型]
        Judge --> Score[產出 Faithfulness & Relevance 分數]
        Score --> DB[(品質數據庫 / Dashboard)]
    end


⚖️ 第一步:實作 Gemini 1.5 Pro 作為 LLM-as-a-Judge 裁判員

我們採用 Ragas 評測框架核心思想,定義兩個最重要的品質指標:

  • Faithfulness(忠實度):生成內容是否完全基於給定的上下文/影片逐字稿,有無憑空捏造(Hallucination)。
  • Answer Relevance(相關性):提煉出的洞見與腳本是否精準回應使用者需求,無無關廢話。

我們利用 Gemini 1.5 Pro 作為高階評測裁判,配合 Structured Outputs 直接產出 JSON 評測報告:

// src/lib/evals/llm-judge.ts
import { GoogleGenerativeAI, SchemaType } from '@google/generative-ai';
import { z } from 'zod';

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

// 評測報告 JSON Schema
const evalSchema = {
  type: SchemaType.OBJECT,
  properties: {
    faithfulnessScore: {
      type: SchemaType.NUMBER,
      description: '忠實度評分 (0.0 至 1.0),檢查生成內容是否有根據原始脈絡。',
    },
    relevanceScore: {
      type: SchemaType.NUMBER,
      description: '相關性評分 (0.0 至 1.0),檢查內容是否精準切中主題。',
    },
    reasoning: {
      type: SchemaType.STRING,
      description: '裁判給出的詳細扣分或加分原因與改進建議',
    },
    hallucinationDetected: {
      type: SchemaType.BOOLEAN,
      description: '是否檢測到明確的 AI 幻覺',
    },
  },
  required: ['faithfulnessScore', 'relevanceScore', 'reasoning', 'hallucinationDetected'],
};

export const EvalResultSchema = z.object({
  faithfulnessScore: z.number(),
  relevanceScore: z.number(),
  reasoning: z.string(),
  hallucinationDetected: z.boolean(),
});

export type EvalResult = z.infer<typeof EvalResultSchema>;

export async function evaluateDistillationQuality(
  sourceContext: string,
  generatedOutput: string
): Promise<EvalResult> {
  // 使用高推論能力的 Gemini 1.5 Pro 作為裁判員
  const judgeModel = genAI.getGenerativeModel({
    model: 'gemini-1.5-pro',
    systemInstruction: `
你是一位極其嚴苛的 AI 內容評測裁判 (LLM Judge)。
你的任務是比對【原始素材內容 (Context)】與【AI 生成的提煉結果 (Output)】,並客觀打分。

評分標準:
1. Faithfulness (0.0 - 1.0): 檢查 Output 中的每一句陳述是否都能在 Context 中找到證據。若有編造數據或無中生有,大幅扣分並將 hallucinationDetected 設為 true。
2. Relevance (0.0 - 1.0): 檢查 Output 是否精準提煉重點,有無離題。
`,
    generationConfig: {
      responseMimeType: 'application/json',
      responseSchema: evalSchema,
      temperature: 0.0, // 裁判模型使用 0 溫度確保評分客觀一致
    },
  });

  const prompt = `
---【原始素材內容 (Context)】---
${sourceContext}

---【AI 生成的提煉結果 (Output)】---
${generatedOutput}

請開始進行嚴格比對並輸出 JSON 評測結果:
`;

  const response = await judgeModel.generateContent(prompt);
  const resultText = response.response.text();
  
  return EvalResultSchema.parse(JSON.parse(resultText));
}


🛰️ 第二步:整合 OpenTelemetry 追蹤管線 (src/lib/telemetry/tracer.ts)

為了掌握 API 請求的延遲、Token 使用量與內部執行步驟,我們利用 OpenTelemetry SDK 建立標準 Span 追蹤包裝器:

// src/lib/telemetry/tracer.ts
import { trace, SpanStatusCode, Span } from '@opentelemetry/api';

const tracer = trace.getTracer('omnivibe-gemini-service', '1.0.0');

export async function traceGeminiCall<T>(
  spanName: string,
  fn: (span: Span) => Promise<T>,
  metadata?: Record<string, any>
): Promise<T> {
  return tracer.startActiveSpan(spanName, async (span) => {
    if (metadata) {
      Object.entries(metadata).forEach(([key, value]) => {
        span.setAttribute(`ai.${key}`, typeof value === 'object' ? JSON.stringify(value) : value);
      });
    }

    const startTime = Date.now();

    try {
      const result = await fn(span);
      span.setStatus({ code: SpanStatusCode.OK });
      return result;
    } catch (error: any) {
      span.setStatus({
        code: SpanStatusCode.ERROR,
        message: error?.message || 'Gemini API Execution Failed',
      });
      span.recordException(error);
      throw error;
    } finally {
      span.setAttribute('ai.latency_ms', Date.now() - startTime);
      span.end();
    }
  });
}


🔄 第三步:將可觀測性與評測融入生產 API Pipeline

我們將追蹤管線與評測機制無縫整合至 OmniVibe AI 的主 API 端點中:

// src/app/api/distill/route.ts
import { NextResponse } from 'next/server';
import { generateGuardedDistillation } from '@/lib/gemini/guarded-distill';
import { evaluateDistillationQuality } from '@/lib/evals/llm-judge';
import { traceGeminiCall } from '@/lib/telemetry/tracer';

export async function POST(req: Request) {
  const { fileUri, mimeType, rawTranscript } = await req.json();

  try {
    // 1. 帶有 OpenTelemetry Tracing 的 AI 生成 Call
    const distilledResult = await traceGeminiCall(
      'Gemini_Distill_Execution',
      async (span) => {
        const res = await generateGuardedDistillation(fileUri, mimeType);
        
        // 記錄 Token 與重要屬性
        span.setAttribute('ai.model', 'gemini-1.5-flash');
        span.setAttribute('ai.output_confidence', res.meta.confidenceScore);
        return res;
      },
      { fileUri, mimeType }
    );

    // 2. 非同步/背景執行 LLM-as-a-Judge 品質打分 (不阻塞主邏輯回應)
    if (rawTranscript) {
      traceGeminiCall('LLM_Judge_Evaluation', async (span) => {
        const evalReport = await evaluateDistillationQuality(
          rawTranscript,
          JSON.stringify(distilledResult)
        );

        span.setAttribute('ai.eval.faithfulness', evalReport.faithfulnessScore);
        span.setAttribute('ai.eval.relevance', evalReport.relevanceScore);
        span.setAttribute('ai.eval.hallucination', evalReport.hallucinationDetected);

        console.log('[AI Eval Report]', evalReport);
        
        // TODO: 將評測結果非同步寫入數據庫,提供給 Grafana / Phoenix Dashboard 監控
      }).catch((err) => console.error('[Eval Error]', err));
    }

    return NextResponse.json({ success: true, data: distilledResult });
  } catch (err: any) {
    return NextResponse.json({ success: false, error: err.message }, { status: 500 });
  }
}


📊 實測評測報表輸出範例

當 API 完成提煉並觸發 Gemini 1.5 Pro 評測時,系統會自動產出如下的數據化品質報告:

{
  "faithfulnessScore": 0.98,
  "relevanceScore": 0.95,
  "hallucinationDetected": false,
  "reasoning": "生成內容精準提煉了原始逐字稿中關於 HBM4 記憶體架構與晶片互連的重點,所有數據(如 35% 效能提升)均可在 Context 中取得佐證,無任何憑空編造事實。"
}

若某次 Prompt 調整導致模型產生了幻覺,評測器將立即捕捉:

{
  "faithfulnessScore": 0.45,
  "relevanceScore": 0.80,
  "hallucinationDetected": true,
  "reasoning": "【幻覺警示】生成內容中的時間軸標記 (18:30) 超越了原始影片長度 (15:00),且提及的『NVLink 5.0』並未在原始逐字稿中被論及。"
}


🎯 總結與明日預告

今天我們成功為 OmniVibe AI 構建了自動化 AI 品質評測與可觀測性架構:

  1. 利用 Gemini 1.5 Pro + Structured Outputs 實作了自動化的 LLM-as-a-Judge (Faithfulness / Relevance) 評測管線。
  2. 導入 OpenTelemetry 封裝 Gemini API 呼叫,實現 API 延遲與執行狀態的鏈路追蹤。
  3. 建立不阻塞主邏輯的非同步評測機制,讓團隊能以量化數據持續迭代 Prompt 與模型設定。

當用戶量爆發、API 呼叫量暴增時,頻繁呼叫大模型不僅成本高昂,重複內容的處理更會帶來不必要的 Latency。

👉 明天(Day 21),我們將進入【效能與成本最佳化篇】:實戰 Gemini Context Caching 快取機制與 Semantic Cache(語意快取)架構!看我們如何大幅降低 API 成本高達 75% 並實現毫秒級回應!

我們明天見!🔥


上一篇
Day 19 -【Prompt 護欄工程】Gemini 1.5 JSON Schema 強制結構化輸出與抗幻覺 Prompt 防護網實戰
下一篇
Day 21 -【效能與成本極限優化】Gemini Context Caching 快取機制與 Qdrant 語意快取 (Semantic Cache) 實戰
系列文
用 Google AI 生態系 30 天從零打造一個全棧 AI SaaS 服務 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言