iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
AI & Data

30 天從 0 至 1 建立一個自已的 AI 學習工具人系列 第 27

30-27: [知識] AI Application Evaluation ( 3 ) 之 Experiments 篇

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20251009/20089358akyciLC4or.png

上一篇文章中,我們已經學會評估的方式後,接下來我們要來談 Experiments,然後主要的目的是 :

系統性的來比較你所設計的 AI Application 的 Prompt、參數、Retriveal 策略的效果,而不在是用感覺來評估這些東西

那這問個問題。

🤔 我們前天那篇文章有提到那些評分方式,用那個判斷不就好了 ?

因為範圍與情境太小了,它還不能客觀的判斷。但不代表昨天學的沒用,因為評估方式會是 Experiments 的其中一個部份。

🤔 整個 Experiments 流程

  1. 定義目標、變因與指標 : 例如我們設計這個實驗的目的,例如是提升正確率/忠實度、降低幻覺,然後接下來就會選擇可以表達這些目的指標。對了還有設計實驗變因(Variants)例如假設我們是評估 RAG,其中 RAG 的 Chunking 數量就是一個變因。
  2. 準備 Dataset : 蒐集代表性「輸入」與(可選)標準答案,其中標準答案是可選的原因在於,很多情況下,我們的輸出是那種沒標準答案的東西,例如問 AI 說你覺得這篇文章寫的好嗎。
  3. 建立 Evaluator,就是用來評分的東東。( 就是前一篇文章提的 )
  4. 執行實驗。
  5. 透過 Dasdboard 分析結果,來判斷用那個 Prompt、參數比較好。

接下來我們就來詳細的說明一下每一個流程。

🚀 流程 1 : 定義實驗目的與指標

這個地方的指標就是昨天那些文章中提到的這些 :

30-26: [知識] AI Application Evaluation ( 2 ) 之 Langfuse 支援的 Evaluator 與 Ragas 指標

首先會先決定這個實驗的目的,以下為範例 :

  1. 例如驗證不同類型的 Prompt 可以增加 Context 的效率。
  2. 因為 Faithfulness 太低,所以接下來我們要想辦法增加個 20%。
  3. 驗證我們調整 Chunk size,是否可以減少 AI 回應錯誤的問題之類的。

接下來我們會根據我們要驗證的服務與功能,來決定用什麼指標,以下為我簡單腦袋有想過的情境來列出一些適合的指標,下面只是大概,我還沒詳細的判斷過 :

情境 目的(實驗假設) 可參考指標
1) 課程字幕做 RAG 問答品質評估 提升答案是否根據提供的片段 Faithfulness、Response Groundedness、Context Precision、Context Recall、Response Relevancy
**2) Chunk 策略 A/B 的優化實驗 ** 提升取用 Chunk 的精準度 Context Precision、Context Recall、Noise Sensitivity
3) Rerank 是否增加品質 降低不相干片段進入生成 Noise Sensitivity、Context Precision、Response Relevancy
4) 日期/事實型 QA (有標準答案)的準確性 提高客觀正確性 Answer Accuracy、Factual Correctness、Faithfulness
5) 開放式主觀評論(無標準答案)的品質 讓回答更貼題、更聚焦要點 Response Relevancy、Rubrics based scoring、Aspect critic

🚀 流程 2 : 準備 Dataset

https://langfuse.com/docs/evaluation/experiments/datasets

這個 Dataset 就是會用來進行實驗的資料集,它只有以下三個資訊要輸入 :

  • input: 就是你要問 LLM 的 ( 不包含一些 prompt,它就是最簡單的用戶問題 )。
  • expected output: 就是你預設的輸出 ( 有些情況可以不用,但可以將你覺得 LLM 比較好的輸出還是放進來,然後用相似度比較 )
  • metadata: 就放一些額外的資訊。

然後在 Langfuse 有兩種方式可以建立 :

  1. 我們自已手動匯入 CSV。
  2. 自已寫程式透過 LLM 來產生資料到 Dataset。
  3. 將現有的 Trace 放入到 Dataset。

以下為這三種的範例。

🤔 1. 我們自已手動匯入 CSV。
如下圖,然有提到 mapping 欄位的功能。

https://ithelp.ithome.com.tw/upload/images/20251011/20089358lKrQLUMF1Z.png
https://ithelp.ithome.com.tw/upload/images/20251011/20089358UcMTNAjP1A.png

🤔 2.自已寫程式透過 LLM 來產生資料到 Dataset。

如下程式碼,還算簡單。

import { Langfuse } from "langfuse";

(async () => {
  const langfuse = new Langfuse({
    publicKey: process.env.LANGFUSE_PUBLIC_KEY,
    secretKey: process.env.LANGFUSE_SECRET_KEY,
    baseUrl: process.env.LANGFUSE_BASE_URL,
  });

  try {
    await langfuse.api.datasetItemsCreate({
      datasetName: "RouteAI",
      input: "你很棒棒嗎",
      expectedOutput: "other",
      metadata: {
        model: "llama3",
      },
    });
  } catch (error) {
    console.error(error);
  }
})();

🤔 3. 將現有的 Trace 放入到 Dataset
如下圖。

https://ithelp.ithome.com.tw/upload/images/20251011/20089358se2EUkUNvF.png

https://ithelp.ithome.com.tw/upload/images/20251011/20089358xsjbUUJP9b.png

❗小提醒,有時後三不五時可以去看 trace,然後定期的將它加入到你的 Dataset 中

🤔 然後我們這次的測試的 Dataset 長的如下
我的模擬情境是,這個 AI 是個 RouteAI 然後他會根據使用者的問題,來判斷意圖,然後回傳意圖,如下圖,例如我想學習 AI 就會預期回傳 learning。

https://ithelp.ithome.com.tw/upload/images/20251011/20089358RcglDswAYl.png

🚀 流程 3 : 設定 Evaluator

這裡分兩種情況:

  1. 使用 Langfuse 提供的 Evaluator。
  2. 使用 Local 端的 Evaluator ( 這個等等會說。

你要先在 UI 上設定好,如下圖,然後其中 filter 要設定你的那要測試的那個 dataset。

https://ithelp.ithome.com.tw/upload/images/20251011/20089358bNLQUe6oE5.png

‼️ 但是如果是用 Local Dataset 的情況下,好像我就找不到方法了,可能就還是要將 Local Dataset 建立到 Langfuse Dataset

🚀 流程 4 : 執行實驗-方法 1 在 UI 上建立實驗與執行

執行實驗有兩種方式 :

  1. 在 UI 上建立實驗與執行。
  2. 透過 SDK 來建立與執行實驗。

然後我們先來說說第一種,如下圖,然後有以下欄位要填寫 :

  1. Dataset run name、Description (optional) : 這兩個就是單純的寫寫字,說它是幹麻的。
  2. Prompt : 這個就要注意一下了,這裡要寫,就代表你的 Prompt 要放在 Lanfuse。
  3. Model : 就是 LLM Model。
  4. Evaluator : 就是我們前面提到的那些,然後這裡要注意一下,要看一下你的 input 與 output 有沒有對。

https://ithelp.ithome.com.tw/upload/images/20251011/20089358PnImtD9bLh.png

https://ithelp.ithome.com.tw/upload/images/20251011/20089358vuGJXLsSO8.png

🚀 流程 4 : 執行實驗-方法 2 透過 SDK 來建立與執行實驗

這個功能就是可以使用 SDK 來建立與實驗,以下為最簡單過的執行方式。

import { NodeSDK } from "@opentelemetry/sdk-node";
import { OpenAI } from "@langchain/openai";

import {
  LangfuseClient,
  ExperimentTask,
  ExperimentItem,
} from "@langfuse/client";
import { observeOpenAI } from "@langfuse/openai";
import { LangfuseSpanProcessor } from "@langfuse/otel";

const otelSdk = new NodeSDK({ spanProcessors: [new LangfuseSpanProcessor()] });
otelSdk.start();

const langfuse = new LangfuseClient();
const dataset = await langfuse.dataset.get("RouteAI");

const myTask: ExperimentTask = async (item) => {
  const question = item.input;

  const response = await observeOpenAI(
    new ChatOpenAI({
      modelName: "gpt-5-nano",
    })
  ).invoke([
    {
      role: "system",
      content: `
      學生問題: ${question}
      ## Instructions:
        根據學生問題,來判斷意圖 (intent),並且回傳結果
        意圖只能有以下幾種:
        - 學習 
        - 總結 
        - other
      
      ## Example
      Example 1:
      學生問題: 我想學習 AI
      結果:學習

      Example 2:
      學生問題: 幫我總結一下今天的課程
      結果:總結

      Example 3:
      學生問題: 馬克很棒棒嗎
      結果:other
      `,
    },
    {
      role: "user",
      content: question,
    },
  ]);
  return response.content;
};


(async () => {
  const result = await dataset.runExperiment({
    name: "RouteAI 實驗-2025-10-11",
    description: "RouteAI 實驗-2025-10-11",
    task: myTask
  });

  // Print formatted result
  console.log(await result.format());
  await otelSdk.shutdown();
})();

然後他有提供很多用 UI 沒辦法做的事情

  1. 我們可以使用 Local Dataset 來執行。
  2. 也可以使用 Local Evaluator 來執行。
  3. 可以在最後實驗完後,執行一個 Run-level Evaluators 來將結果 aggregate 成一個結果。
  4. 可以使用 concurrency 讓實驗跑的更快。

🤔 SDK 額外功能 1. 我們可以使用 Local Dataset 來執行

const localData: ExperimentItem[] = [
  { input: "我想學習 AI" },
  { input: "幫我總結一下今天的課程" },
  { input: "馬克很棒棒嗎" },
];

(async () => {
  const result = await langfuse.experiment.run({
    name: "RouteAI 實驗-2025-10-11",
    description: "RouteAI 實驗-2025-10-11",
    data: localData,
    task: myTask,
  });

  console.log(await result.format());
  await otelSdk.shutdown();
})();

🤔 SDK 額外功能 2. 可以使用 Local Evaluator 來執行

如下官網的範例

onst accuracyEvaluator = async ({ input, output, expectedOutput }) => {
  if (
    expectedOutput &&
    output.toLowerCase().includes(expectedOutput.toLowerCase())
  ) {
    return {
      name: "accuracy",
      value: 1.0,
      comment: "Correct answer found",
    };
  }
  return {
    name: "accuracy",
    value: 0.0,
    comment: "Incorrect answer",
  };
};
 
// Use multiple evaluators
const result = await langfuse.experiment.run({
  name: "Multi-metric Evaluation",
  data: testData,
  task: myTask,
  evaluators: [accuracyEvaluator],
});

🤔 SDK 額外功能 3. 可以在最後實驗完後,執行一個 Run-level Evaluators 來將結果 aggregate 成一個結果

如下 averageAccuracy,它最後會將每一筆的測試結果,匯總成一個平均。

const averageAccuracy = async ({ itemResults }) => {
  // Calculate average accuracy across all items
  const accuracies = itemResults
    .flatMap((result) => result.evaluations)
    .filter((evaluation) => evaluation.name === "accuracy")
    .map((evaluation) => evaluation.value as number);
 
  if (accuracies.length === 0) {
    return { name: "avg_accuracy", value: null };
  }
 
  const avg = accuracies.reduce((sum, val) => sum + val, 0) / accuracies.length;
 
  return {
    name: "avg_accuracy",
    value: avg,
    comment: `Average accuracy: ${(avg * 100).toFixed(1)}%`,
  };
};
 
const result = await langfuse.experiment.run({
  name: "Comprehensive Analysis",
  data: testData,
  task: myTask,
  evaluators: [accuracyEvaluator],
  runEvaluators: [averageAccuracy],
});
 
console.log(await result.format());

🤔4. 可以使用 concurrency 讓實驗跑的更快。

const result = await langfuse.experiment.run({
  name: "Async Experiment",
  data: testData,
  task: asyncLlmTask,
  maxConcurrency: 5, // Control concurrent API calls
});

🚀 流程 5 : 看結果

然後下面這個地方,就可以看到你這次實驗指定的 Evaluators 跑的平均分數,不過這裡就是簡單的範例,好像也沒說這個結果。

❗然後我有發現 Token 與 Cost 沒有正常顯示,還在研究中

然後下面這張是我們上面點進去後看到的每個結果,先說一下我們的 Dataset 有 4 筆,所以這個實驗就是每 1 筆都會去跑,然後如下圖就會有 4 筆的結果,其中幾個欄位可以注意一下 :

  • trace input: 這個就是我們實驗時,問 AI 的問題。
  • output: 這個就是我們上面的流程 4 那個 prompt 跑出的結果,然後我是故意讓他有錯的,可以看看我流程 2 的 Dataset 的預期與流程 4 的 prompt,因為我想看看他最後他整個實驗的分數會不會有變化。
  • 評估 RouteAI 是否運行 : 這個是我自已建立的 Evaluator 它就是很簡單的判斷 output 與 expect 是否相同,0 與 1 的很正確,但那個 0.5 是怎麼給分的。

https://ithelp.ithome.com.tw/upload/images/20251011/20089358JypTeJ7Yr2.png

最後這個就是整個實驗的分數。

https://ithelp.ithome.com.tw/upload/images/20251011/2008935863J9NSuCXe.png

🚀 小總結

到了今天事實上我們已經將 AI Application Evaluation 整個體系都已經基本的講過了 :

  1. 評估指標 : 目前主要還是以 Ragas 為主,當然在一些情境下我們也可以自已設計。
  2. 評估方式 : 目前主要有提到三種評估方式,人力、LLM 與我自已寫個評分程式。

然後這篇文章的 Experiments 就是將這個 Evaluation 體系串起來的東西,不過這次鐵人賽寫的事實上也只是寫個基本與串起來整個體系,如果真的往下挖還有不少呢 ~~

不過鐵人賽總於快結束了 ~

🚀 參考資料


上一篇
30-26: [知識] AI Application Evaluation ( 2 ) 之 Ragas 評分指標 ( Langfuse 版本 )
系列文
30 天從 0 至 1 建立一個自已的 AI 學習工具人27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言