API 開發

動手建一條 prompt 評測管線:資料集、程式評分與模型評分

一條 prompt 評測管線有五步:草擬 prompt、建立測試資料集、逐筆丟給 Claude、交給評分器打分、修改後再跑一輪。評分器分程式評分與模型評分兩種:格式與語法交給程式檢查,內容品質交給另一次模型呼叫評估,兩種分數合併成可追蹤的客觀指標。
動手建一條 prompt 評測管線:資料集、程式評分與模型評分:文章重點卡

動手建一條 prompt 評測管線:資料集、程式評分與模型評分

上一篇談了為什麼 prompt 需要評測,這一篇就捲起袖子動手做,從零建出一條完整的評測管線:先產生測試資料集,再把管線本體跑起來,最後接上兩種評分器。

範例的目標 prompt 很具體:協助使用者完成 AWS 相關任務,輸出 Python 程式、JSON 設定檔或正規表達式,而且要乾淨輸出,不准夾帶多餘的說明、開頭或結尾。

你將學到什麼

五個步驟總覽

從草擬 prompt 到改版重跑,一條管線的完整循環。

用 Claude 產生資料集

prefill 加 stop sequence,讓測試資料自動生出來。

三個核心函式

run_prompt、run_test_case、run_eval 各管一件事。

兩種評分器

程式評分管格式語法,模型評分管內容品質。

一條評測管線的五個步驟

1 草擬prompt2 建立資料集3 逐筆丟給Claude4 評分器打分取平均5 改 prompt再跑一輪帶著新版本回到起點,比較平均分數,上升才算真的進步
五個步驟形成循環:每一輪都拿到一個可比較的平均分數
  1. 草擬 prompt:先有一版基準,簡單也沒關係。
  2. 建立評測資料集:收集一批有代表性的輸入。
  3. 逐筆丟給 Claude:把每筆輸入套進 prompt 模板送出。
  4. 交給評分器:對每個輸出打 1 到 10 分並取平均。
  5. 修改 prompt 再跑一輪:平均分數上升,才算真的進步。

組裝這條管線的方式很多,市面上也有各種開源與付費工具,但先徒手做一次小規模的,之後要換工具或擴大都容易得多。

建立資料集:請 Claude 代工

資料集是一個 JSON 陣列,每個物件帶一個 task 欄位描述要完成的任務。你可以手工建,也可以寫一個函式請 Claude 產生。因為只是產生測試資料,很適合改用速度較快的 Haiku 等級模型。

def generate_dataset():
    prompt = """
Generate an evaluation dataset for a prompt evaluation.
The dataset will be used to evaluate prompts that generate
Python, JSON, or Regex specifically for AWS-related tasks.
Generate an array of JSON objects, each representing a task.

* Focus on tasks solvable with a single function, object, or regex
* Focus on tasks that do not require much code

Please generate 3 objects.
"""
    messages = []
    add_user_message(messages, prompt)
    add_assistant_message(messages, "```json")
    text = chat(messages, stop_sequences=["```"])
    return json.loads(text)

收尾兩招是關鍵:用 assistant prefill 先幫 Claude 起頭一個程式碼區塊,再用 stop sequence 在區塊結束時停下來,回傳的內容就能直接用 json.loads 解析。產好的資料集存成 dataset.json,之後每一輪評測都重複使用同一份,分數才有可比性。

三個核心函式,把管線跑起來

def run_prompt(test_case):
    prompt = f"""
Please solve the following task:

{test_case["task"]}
"""
    messages = []
    add_user_message(messages, prompt)
    return chat(messages)

def run_test_case(test_case):
    output = run_prompt(test_case)
    score = 10  # TODO: real grading
    return {"output": output, "test_case": test_case, "score": score}

def run_eval(dataset):
    results = []
    for test_case in dataset:
        results.append(run_test_case(test_case))
    return results

run_prompt 負責把測試案例塞進 prompt 模板送給 Claude;run_test_case 跑單一案例並打分;run_eval 走訪整個資料集收集結果。此刻分數還是寫死的 10 分,但整條管線已經能動了。

實際跑一次,你會拿到一個結構化的結果陣列,每個物件有三樣東西:output 是 Claude 的完整回應、test_case 是原始測試案例、score 是分數。因為我們還沒給任何格式指示,這時的輸出會相當囉嗦,前後夾著大段說明。這正是之後改 prompt 要解決的問題,也是評測要抓的東西。

老實說,你剛剛已經做完一條評測管線的主體,剩下的複雜度全在細節裡,尤其是評分。

評分器有三種

評分器擅長評的東西特性
程式評分器輸出長度、關鍵字檢查、JSON 與 Python 與 regex 的語法驗證、可讀性分數快、便宜、完全客觀
模型評分器回答品質、遵循指示程度、完整性、有用性、安全性彈性最大,但分數會有些浮動
人工評分器整體品質、深度、簡潔度、相關性最靈活,也最花時間

評分器的共同點只有一個:接收模型的輸出,回傳某種可用的訊號,通常是 1 到 10 的數字。程式評分器能實作任何你寫得出來的檢查;模型評分器是把輸出丟進另一次 API 呼叫請模型評估;人工評分最靈活,但又慢又累,適合抽查而不是全量。

打分之前要先訂標準。以這個代碼生成 prompt 為例,評估標準有三條:格式(只回 Python、JSON 或 regex,不准解釋)、語法有效(產出的程式碼要能解析)、正確回應任務。前兩條非黑即白,交給程式評分器;最後一條需要理解力,交給模型評分器。

模型評分:要分數,也要理由

def grade_by_model(test_case, output):
    eval_prompt = """
    You are an expert code reviewer. Evaluate this AI-generated solution.

    Task: {task}
    Solution: {solution}

    Provide your evaluation as a structured JSON object with:
    - "strengths": An array of 1-3 key strengths
    - "weaknesses": An array of 1-3 key areas for improvement
    - "reasoning": A concise explanation of your assessment
    - "score": A number between 1-10
    """
    messages = []
    add_user_message(messages, eval_prompt)
    add_assistant_message(messages, "```json")
    eval_text = chat(messages, stop_sequences=["```"])
    return json.loads(eval_text)
實用心法除了分數,還要求評分模型先列出優點、缺點和推理過程。少了這層鋪陳,模型打分很容易通通停在 6 分左右的中庸值,失去鑑別度。

拿到分數後,把它接回 run_test_case,順便把 reasoning 一起存進結果;最後在 run_eval 裡用 statistics.mean 算出整體平均,你就有一個可以逐輪追蹤的客觀指標了。

模型評分的分數難免有些浮動,不會每次一模一樣,但作為衡量改進的基準線已經非常夠用:同一份資料集、同一個評分器,前後兩版 prompt 的平均分數就有比較意義。

程式評分與分數合併

def validate_json(text):
    try:
        json.loads(text.strip())
        return 10
    except json.JSONDecodeError:
        return 0

def validate_python(text):
    try:
        ast.parse(text.strip())
        return 10
    except SyntaxError:
        return 0

def validate_regex(text):
    try:
        re.compile(text.strip())
        return 10
    except re.error:
        return 0

三個驗證函式的邏輯一模一樣:能成功解析就給 10 分,解析失敗就 0 分。

為了讓程式評分器知道該用哪個驗證器,資料集的每筆案例要多帶一個 format 欄位標明預期格式;同時把 prompt 的指示寫得更明確,例如「只回傳 Python、JSON 或 regex,不加任何註解或說明」,並可用 prefill 起頭一個程式碼區塊,引導 Claude 只吐純程式碼。

model_score = grade_by_model(test_case, output)["score"]
syntax_score = grade_syntax(output, test_case)

score = (model_score + syntax_score) / 2

最後把兩種分數合併,最簡單的做法是各占一半取平均;哪一邊比較重要,就依你的應用調整權重。要記住:分數本身沒有絕對的好壞,重點是你能不能靠改 prompt 把它推高。有了這條管線,prompt engineering 就從主觀猜測,變成可量測、可累積的工程。

參考出處本文取材自 Anthropic 官方 Claude Academy 免費課程「Building with the Claude API」,由酒Ann 消化後以自己的視角重新編寫。想看英文原版課程,可到 Claude Academy 修習。

延伸學習

把這篇文章分享給需要的人FacebookLINEThreadsX

常見問答

評測資料集要多大才夠?
課程範例用 3 筆方便教學,真實評測常見數十、數百甚至上千筆。可以手工整理,也可以請 Claude 產生,再人工抽查品質確保案例有代表性。
為什麼模型評分要先要求列出優缺點和理由?
直接要分數時,評分模型傾向給 6 分上下的中庸值。先要求它寫出優點、缺點與推理過程,再給分數,評分會更有鑑別度,理由本身也能幫你看出 prompt 的弱點在哪。
程式評分和模型評分該選哪一個?
不用二選一。格式與語法這類非黑即白的標準交給程式評分器,快速又客觀;任務理解與內容正確性交給模型評分器。最後把兩種分數平均或加權合併即可。
跑一輪評測大概要多久?
依資料集大小與模型而定。課程提到即使用 Haiku 這類較快的模型,跑完一份資料集也可能需要 30 秒左右;資料集變大時可以再做平行化等優化。