For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主要導覽
2026年1月22日 Codex

運用評估,有系統地測試智慧體技能

實用指南:讓智慧體技能能夠被測試、評分,並持續改進。

作者: Dominik Kundel, Gabriel Chua

運用評估,有系統地測試智慧體技能

為 Codex 這類智慧體反覆調整技能時,很難判斷自己是真的在改進技能,還是只是改變了它的行為。某個版本感覺比較快,另一個似乎更可靠,卻又悄悄出現功能退步:技能沒有觸發、略過必要步驟,或留下多餘的檔案。

技能的本質,是提供給 LLM 的一組有組織的提示詞與指示。要持續改進技能,最可靠的方法就是像評估其他 LLM 應用程式的提示詞一樣評估它。

評估 (英文 evaluations 簡稱為 evals)用來檢查模型的輸出,以及產生輸出所採取的步驟,是否符合你的預期。不必只問「這樣感覺有比較好嗎?」或憑直覺判斷,評估讓你能提出具體問題,例如:

  • 智慧體有呼叫技能嗎?
  • 它有執行預期的指令嗎?
  • 它產生的輸出有遵循你重視的慣例嗎?

具體來說,一次評估的流程是:提示詞 → 記錄一次執行過程(追蹤紀錄 + 產出檔案)→ 少量檢查 → 可供長期比較的分數。

實務上,智慧體技能的評估很像輕量的端對端測試:執行智慧體、記錄發生的事,再依據少量規則為結果評分。

本文會逐步介紹如何使用 Codex 建立清楚的評估流程:先定義成功標準,再加入確定性檢查與依評分規準進行的評分,讓改進與退步都清楚可見。

1. 撰寫技能前,先定義成功標準

在撰寫技能本身之前,先用實際可衡量的方式寫下「成功」的定義。一個實用的思考方式,是將檢查分成幾類:

  • 成果目標: 任務完成了嗎?應用程式能執行嗎?
  • 流程目標: Codex 有呼叫技能,並依照你的預期使用工具、執行步驟嗎?
  • 風格目標: 輸出有遵循你要求的慣例嗎?
  • 效率目標: 它是否達成目標,且沒有反覆做無用功(例如執行不必要的指令或耗用過多 Token)?

這份清單應保持精簡,聚焦在必須通過的檢查。目的不是一開始就把所有偏好都寫成規則,而是涵蓋你最在意的行為。

例如,本文會評估一個用來設定示範應用程式的技能。有些檢查很具體:它有執行 npm install 嗎?有建立 package.json 嗎?本文也會搭配結構化的風格評分規準,評估慣例與版面配置。

這樣搭配是有意安排的。你需要快速且有針對性的訊號,及早發現具體的退步問題,而不只是在最後得到一個通過或失敗的判定。

2. 建立技能

Codex 技能是一個包含 SKILL.md 檔案的目錄。該檔案以 YAML 前置資料(namedescription)開頭,接著是定義技能行為的 Markdown 指示,也可以搭配資源與指令碼。名稱和描述的重要性可能超乎你的想像:Codex 主要依據它們,決定 是否 呼叫技能,以及 何時SKILL.md 的其餘內容加入智慧體的上下文。如果名稱與描述含糊不清,或涵蓋過多用途,技能就無法穩定地觸發。

最快的入門方式,是使用 Codex 內建的技能建立工具(它本身也是一項技能)。它會引導你完成以下流程:

$skill-creator

建立工具會詢問技能的用途、應在何時觸發,以及是僅包含指示,還是搭配指令碼執行(預設建議僅包含指示)。若想進一步瞭解如何建立技能,請參閱文件

技能範例

本文刻意採用一個極簡範例:以可預期、可重複的方式,設定小型 React 示範應用程式的技能。

這項技能會:

  • 使用 Vite 的 React + TypeScript 範本建立專案骨架
  • 採用官方的 Vite 外掛程式方式設定 Tailwind CSS
  • 確保檔案結構精簡且一致
  • 訂出清楚的「完成標準」,讓成功與否容易評估

以下是一份精簡草稿,你可以將它貼到下列任一位置:

  • .codex/skills/setup-demo-app/SKILL.md(適用於此程式碼庫),或
  • ~/.codex/skills/setup-demo-app/SKILL.md(適用於此使用者)。
---
name: setup-demo-app
description: Scaffold a Vite + React + Tailwind demo app with a small, consistent project structure.
---

## When to use this

Use when you need a fresh demo app for quick UI experiments or reproductions.

## What to build

Create a Vite React TypeScript app and configure Tailwind. Keep it minimal.

Project structure after setup:

- src/
  - main.tsx (entry)
  - App.tsx (root UI)
  - components/
    - Header.tsx
    - Card.tsx
  - index.css (Tailwind import)
- index.html
- package.json

Style requirements:

- TypeScript components
- Functional components only
- Tailwind classes for styling (no CSS modules)
- No extra UI libraries

## Steps

1. Scaffold with Vite using the React TS template:
   npm create vite@latest demo-app -- --template react-ts

2. Install dependencies:
   cd demo-app
   npm install

3. Install and configure Tailwind using the Vite plugin.
   - npm install tailwindcss @tailwindcss/vite
   - Add the tailwind plugin to vite.config.ts
   - In src/index.css, replace contents with:
     @import "tailwindcss";

4. Implement the minimal UI:
   - Header: app title and short subtitle
   - Card: reusable card container
   - App: render Header + 2 Cards with placeholder text

## Definition of done

- npm run dev starts successfully
- package.json exists
- src/components/Header.tsx and src/components/Card.tsx exist

這個技能範例刻意採用明確的做法與限制。沒有清楚的限制,就沒有具體的評估依據。

3. 手動觸發技能,找出隱含假設

技能是否被呼叫,很大程度取決於 SKILL.md 中的 namedescription ,因此首先要檢查的是:setup-demo-app 技能是否會在你預期的情況下觸發。

初期可以在實際的程式碼庫或臨時目錄中,透過 /skills 斜線指令,或以 $ 前綴指定技能,明確啟用它,並觀察哪裡會出問題。這樣就能找出各種未如預期的情況:技能完全沒有觸發、太容易觸發,或雖然執行了,卻偏離預定步驟。

這個階段的重點不是提升速度或精緻度,而是找出技能隱含的假設,例如:

  • 觸發條件的假設:「快速設定一個 React 示範應用程式」這類提示詞 應該 呼叫 setup-demo-app 卻沒有,或較籠統的提示詞(「加入 Tailwind 樣式」)意外觸發了它。

  • 環境的假設:技能假設自己在空目錄中執行,或假設 npm 可用,而且應優先於其他套件管理工具使用。

  • 執行流程的假設:智慧體假設相依套件已經安裝,因此略過 npm install,或在 Vite 專案尚未建立前就設定 Tailwind。

準備好讓這些執行流程可以重複進行時,就改用 codex exec。它專為自動化與 CI 設計:將進度串流輸出至 stderr,並只將最終結果寫入 stdout,讓你更容易透過指令碼執行、記錄及檢查結果。

預設情況下,codex exec 會在受限的沙盒中執行。如果任務需要寫入檔案,請搭配 --full-auto 執行。一般原則是只使用完成任務所需的最低權限,進行自動化時尤其如此。

基本的手動執行方式可能如下:

codex exec --full-auto \
  'Use the $setup-demo-app skill to create the project in this directory.'

第一次實際操作的重點,與其說是驗證正確性,不如說是找出邊界情況。你在這裡做的每一項手動修正,例如補上遺漏的 npm install、修正 Tailwind 設定,或讓觸發條件的描述更精確,都可以成為未來的評估案例,讓你在大規模評估前先確立預期行為。

4. 使用精簡且有針對性的提示詞集,及早發現退步

不必建立大型基準測試,也能從評估中獲益。對單一技能來說,10–20 個提示詞的小型集合,就足以及早發現退步並確認改進。

先從小型 CSV 檔案開始,在開發或使用過程中遇到實際失敗案例時,再逐步擴充。每筆資料都應代表一種你在意的情境:setup-demo-app 技能 會啟用 還是 不會啟用 ,以及啟用後怎樣才算成功。

例如,最初的 evals/setup-demo-app.prompts.csv 可能如下:

id,should_trigger,prompt
test-01,true,"Create a demo app named `devday-demo` using the $setup-demo-app skill"
test-02,true,"Set up a minimal React demo app with Tailwind for quick UI experiments"
test-03,true,"Create a small demo app to showcase the Responses API"
test-04,false,"Add Tailwind styling to my existing React app"

這些案例各自測試的重點略有不同:

  • 明確呼叫(test-01
    這個提示詞直接指定技能名稱,用來確保 Codex 能依要求呼叫 setup-demo-app,而且技能名稱、描述或指示的變更,不會導致直接呼叫技能時出錯。

  • 隱含呼叫(test-02
    這個提示詞描述的 正是 技能適用的情境,也就是設定極簡的 React + Tailwind 示範應用程式,但沒有提到技能名稱。它測試的是 SKILL.md 中的名稱與描述,是否足以讓 Codex 自行選用這項技能。

  • 帶有情境資訊的呼叫(test-03
    這個提示詞加入了特定領域的上下文(Responses API),但所需的基礎設定仍然相同。它用來檢查技能是否能在貼近實際使用、略含雜訊的提示詞中觸發,以及產生的應用程式是否仍符合預期的結構與慣例。

  • 陰性對照(test-04
    這個提示詞 不應 呼叫 setup-demo-app。這是一種常見的相近需求(「為現有應用程式加入 Tailwind」),卻可能意外符合技能的描述(「React + Tailwind 示範應用程式」)。至少納入一個 should_trigger=false 案例,有助於找出 偽陽性:使用者只是想在現有專案中做增量修改,Codex 卻太輕易選用這項技能,建立了新專案骨架。

這樣搭配是有意安排的。有些評估應確認技能在被明確呼叫時行為正確;其他評估則應檢查,在使用者完全沒有提到技能的實際提示詞中,技能是否仍會啟用。

發現未如預期的情況、無法觸發技能的提示詞,或輸出偏離預期的案例時,就將它們新增為資料列。隨著時間推移,這份小型 CSV 會成為持續更新的紀錄,涵蓋 setup-demo-app 技能必須一直正確處理的情境。

隨著時間推移,這個小型資料集會成為持續更新的紀錄,記下技能必須一直做對的事。

5. 從輕量的確定性評分器開始

評估步驟的核心在於:使用 codex exec --json,讓評估任務執行框架能針對 實際發生的事評分,而不只是看最終輸出是否看起來正確。

啟用 --json 後,stdout 會成為由結構化事件組成的 JSONL 串流。這讓你可以輕鬆撰寫確定性檢查,直接檢驗你重視的行為,例如:

  • 它有執行 npm install 嗎?
  • 它有建立 package.json 嗎?
  • 它是否依照預期順序執行了預期的指令?

這些檢查刻意保持輕量,讓你在加入模型評分之前,就能快速取得容易解讀的結果。

精簡的 Node.js 執行器

一個「夠用就好」的做法如下:

  1. 針對每個提示詞,執行 codex exec --json --full-auto "<prompt>"
  2. 將 JSONL 追蹤記錄儲存到磁碟
  3. 剖析追蹤記錄,並對其中的事件執行確定性檢查
// evals/run-setup-demo-app-evals.mjs
import { spawnSync } from "node:child_process";
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
import path from "node:path";

function runCodex(prompt, outJsonlPath) {
  const res = spawnSync(
    "codex",
    [
      "exec",
      "--json", // REQUIRED: emit structured events
      "--full-auto", // Allow file system changes
      prompt,
    ],
    { encoding: "utf8" }
  );

  mkdirSync(path.dirname(outJsonlPath), { recursive: true });

  // stdout is JSONL when --json is enabled
  writeFileSync(outJsonlPath, res.stdout, "utf8");

  return { exitCode: res.status ?? 1, stderr: res.stderr };
}

function parseJsonl(jsonlText) {
  return jsonlText
    .split("\n")
    .filter(Boolean)
    .map((line) => JSON.parse(line));
}

// deterministic check: did the agent run `npm install`?
function checkRanNpmInstall(events) {
  return events.some(
    (e) =>
      (e.type === "item.started" || e.type === "item.completed") &&
      e.item?.type === "command_execution" &&
      typeof e.item?.command === "string" &&
      e.item.command.includes("npm install")
  );
}

// deterministic check: did `package.json` get created?
function checkPackageJsonExists(projectDir) {
  return existsSync(path.join(projectDir, "package.json"));
}

// Example single-case run
const projectDir = process.cwd();
const tracePath = path.join(projectDir, "evals", "artifacts", "test-01.jsonl");

const prompt =
  "Create a demo app named demo-app using the $setup-demo-app skill";

runCodex(prompt, tracePath);

const events = parseJsonl(readFileSync(tracePath, "utf8"));

console.log({
  ranNpmInstall: checkRanNpmInstall(events),
  hasPackageJson: checkPackageJsonExists(path.join(projectDir, "demo-app")),
});

這個做法的價值在於,一切都 具有確定性,而且可以偵錯

如果某項檢查失敗,你可以開啟 JSONL 檔案,查看實際發生了什麼事。每次指令執行都會依序記錄為 item.* 事件。這讓行為退化的原因容易釐清,也容易修正,正是這個階段所需要的。

6. 使用 Codex 和評分規準進行質性檢查

確定性檢查能回答 「它完成基本要求了嗎?」 ,卻無法回答 「它是按照你期望的方式完成的嗎?」

對於 setup-demo-app 這類技能,許多要求都屬於質性要求,例如元件結構、樣式慣例,或 Tailwind 是否採用預期的組態。單靠基本的檔案存在檢查或指令計數,很難判斷這些要求是否達成。

一個務實的做法,是在評估流程中加入第二個由模型輔助的步驟:

  1. 執行設定技能(這會將程式碼寫入磁碟)
  2. 對產生的程式碼庫執行 唯讀風格檢查
  3. 要求輸出 結構化回應 ,讓任務執行框架能以一致的方式評分

Codex 透過 --output-schema 直接支援這個做法,要求最終回應符合你定義的 JSON Schema。

精簡的評分規準結構描述

先定義一個精簡的結構描述,涵蓋你在意的檢查項目。例如,建立 evals/style-rubric.schema.json

{
  "type": "object",
  "properties": {
    "overall_pass": { "type": "boolean" },
    "score": { "type": "integer", "minimum": 0, "maximum": 100 },
    "checks": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "pass": { "type": "boolean" },
          "notes": { "type": "string" }
        },
        "required": ["id", "pass", "notes"],
        "additionalProperties": false
      }
    }
  },
  "required": ["overall_pass", "score", "checks"],
  "additionalProperties": false
}

這個結構描述提供固定的欄位(overall_passscore、各項檢查結果),方便你彙整、比較差異並持續追蹤。

風格檢查提示詞

接著,再執行一次 codex exec,讓它 只檢查程式碼庫 ,並輸出符合評分規準的 JSON 回應:

codex exec \
  "Evaluate the demo-app repository against these requirements:
   - Vite + React + TypeScript project exists
   - Tailwind is configured via @tailwindcss/vite and CSS imports tailwindcss
   - src/components contains Header.tsx and Card.tsx
   - Components are functional and styled with Tailwind utility classes (no CSS modules)
   Return a rubric result as JSON with check ids: vite, tailwind, structure, style." \
  --output-schema ./evals/style-rubric.schema.json \
  -o ./evals/artifacts/test-01.style.json

這時 --output-schema 就派上用場了。你得到的不是難以剖析或比較的自由格式文字,而是格式可預期的 JSON 物件,讓評估任務執行框架能對多次執行的結果進行評分。

如果之後將這套評估移入 CI,Codex GitHub Action 明確支援透過 codex-args 傳入 --output-schema,因此你可以在自動化工作流程中強制使用相同的結構化輸出。

7. 隨著技能成熟,擴充評估

核心循環建立後,你就可以針對技能最重要的面向擴充評估。先從小規模開始,只在確實能讓你更有把握的地方,逐步加入更深入的檢查。

以下是一些例子:

  • 指令數量與無效反覆操作: 計算 JSONL 追蹤記錄中的 command_execution 項目數量,找出智慧體開始陷入迴圈或重複執行指令的退化情況。你也可以從 turn.completed 事件取得 Token 用量。

  • Token 預算: 追蹤 usage.input_tokensusage.output_tokens,找出提示詞意外膨脹的情況,並比較不同版本的效率。

  • 建置檢查: 技能完成後執行 npm run build。這能提供更有力的端對端驗證結果,並找出匯入失敗或工具組態錯誤。

  • 執行階段冒煙測試: 執行 npm run dev 啟動開發伺服器,再用 curl 向它傳送請求;如果已有輕量的 Playwright 檢查,也可以執行該檢查。請視需要採用,因為這雖然能讓你更有把握,也會花費時間。

  • 程式碼庫整潔度: 確認執行過程沒有產生不需要的檔案,且 git status --porcelain 的輸出為空(或符合明確列出的允許清單)。

  • 沙盒與權限退化: 確認技能仍能正常運作,且不需要將權限提升至超出你預期的範圍。開始自動化後,預設採用最小權限尤其重要。

原則始終一致:先使用速度快、能解釋行為的檢查,只有在能降低風險時,才加入較慢、較耗資源的檢查。

8. 重點整理

這個簡單的 setup-demo-app 範例,展示了如何從「感覺變好了」走向「有證據可驗證」:執行智慧體、記錄實際發生的事,再用少量檢查項目評分。建立這個循環後,每次微調的效果都更容易確認,每次退化也都更清楚可見。以下是重點整理:

  • 衡量真正重要的事。 好的評估能讓退化清楚可見,也讓失敗原因容易釐清。
  • 先訂出可檢查的完成標準。 使用 $skill-creator 建立初稿,再逐步完善指示,直到成功標準明確無歧義。
  • 以實際行為為評估依據。 使用 codex exec --json 擷取 JSONL,並針對 command_execution 事件撰寫確定性檢查。
  • 用 Codex 補足規則的不足。 透過 --output-schema 加入一輪依據評分規準、輸出結構化結果的檢查,可靠地評估風格與慣例。
  • 根據實際失敗擴大測試涵蓋範圍。 每次手動修正都是一個訊號。將它轉化為測試,讓技能持續正確處理同類情況。