生活分享

Claude Code|把 claude -p 接進有驗證的 JSON 流程

處理合法結果、錯誤、逾時與不完整輸出。這次輸出只要兩個欄位:summary 是非空的繁體中文摘要,taskIds 是不重複的待辦識別碼陣列。先把契約寫清楚,才能決定什麼資料不應往下傳。如果只是要求「回傳 JSON」,模型即使回傳一個空物件,語法上仍是合法 JSON,卻不能完成工作。

閱讀時間約 7 分鐘

把 claude -p 接進有驗證的 JSON 流程:文件、螢幕與完成記號的幾何插圖
圖片:Mokaair (© Mokaair)
本篇目錄
  1. 先定義後續程式需要什麼
  2. 分清楚 CLI 外殼與業務資料
  3. 建立失敗即停止的解析器
  4. 先跑離線的正常與錯誤案例
  5. 使用參數陣列執行 Claude
  6. 串流輸出要等真正結束
  7. 逾時、取消與重跑
  8. 讓失敗輸出保留診斷價值
  9. 完成判準與小練習

把 claude -p 放進腳本後,最重要的問題是程式如何判斷工作真的成功。本篇建立一條結構化資料流程:讀取假待辦資料、請 Claude 產生 JSON、驗證結果,再交給下一步。正常結果、錯誤結果、格式不符與不完整串流都有各自的處理方式。

先讀與。下載第 91 篇材料,在 starter 操作。需要 Node.js 22,只有真實模型呼叫需要有效 Claude 登入;預估閱讀 20 分鐘、實作 45 分鐘。

先定義後續程式需要什麼

先定義後續程式需要什麼 → 分清楚 CLI 外殼與業務資料 → 建立失敗即停止的解析器
先定義後續程式需要什麼 → 分清楚 CLI 外殼與業務資料 → 建立失敗即停止的解析器 · 圖片:Mokaair (© Mokaair)
閱讀完整文字說明

把 claude -p 接進有驗證的 JSON 流程,以流程和文件圖形呈現教學重點。

這次輸出只要兩個欄位:summary 是非空的繁體中文摘要,taskIds 是不重複的待辦識別碼陣列。先把契約寫清楚,才能決定什麼資料不應往下傳。如果只是要求「回傳 JSON」,模型即使回傳一個空物件,語法上仍是合法 JSON,卻不能完成工作。

材料中的 automation/schema.json 描述欄位型別與必要條件。Schema 驗證與業務驗證仍有差別:陣列裡都是字串,只能證明型別對了;是否真的涵蓋輸入中的 a、b、c,還要由呼叫者比對。不要把格式正確當成內容正確。

寫入 automation/schema.json · json
{
  "type": "object",
  "properties": {
    "summary": { "type": "string", "minLength": 1 },
    "taskIds": {
      "type": "array",
      "items": { "type": "string", "minLength": 1 },
      "uniqueItems": true
    }
  },
  "required": ["summary", "taskIds"],
  "additionalProperties": false
}

分清楚 CLI 外殼與業務資料

JSON 輸出通常不只是你要求的物件,還包含 CLI 的結果類型、狀態及其他 metadata。使用結構化輸出時,先核對這一版回傳中放業務資料的位置,再解析其中欄位。本材料以 structured_output 為目標;不要把整個外殼直接存成產品需要的資料列。

下面的 fixture 是合成資料,用於測試解析器,並不是作者這次成功呼叫模型的證明。把合成與真實輸出分開命名,可以避免後續整理證據時誤把範例當成實測。

fixtures/result-ok.json:成功結果的合成 fixture · json
{
  "type": "result",
  "subtype": "success",
  "is_error": false,
  "structured_output": {
    "summary": "三筆練習待辦",
    "taskIds": ["a", "b", "c"]
  }
}

建立失敗即停止的解析器

打開 automation/result.mjs。解析器先確認外層是成功結果,再檢查欄位型別、摘要是否空白及 id 是否重複。這裡是針對本課程契約的驗證器,不是通用 JSON Schema 引擎;若契約變複雜,應改用合適的標準驗證工具。

automation/result.mjs:本課程結果驗證的核心 · javascript
export function parseResult(text) {
  const envelope = JSON.parse(text);
  if (envelope.type !== 'result'
      || envelope.subtype !== 'success'
      || envelope.is_error === true) {
    throw new Error('Claude did not return a successful result');
  }
  const data = envelope.structured_output;
  if (!data || typeof data.summary !== 'string' || !data.summary.trim()
      || !Array.isArray(data.taskIds)
      || data.taskIds.some(id => typeof id !== 'string' || !id)) {
    throw new Error('Invalid structured_output');
  }
  if (new Set(data.taskIds).size !== data.taskIds.length) {
    throw new Error('Duplicate task ids');
  }
  return { summary: data.summary, taskIds: data.taskIds };
}

不合法時拋出錯誤,比回傳空陣列更容易察覺問題。若你把錯誤吞掉並預設 taskIds=[],下游程式可能把資料清空,卻留下成功狀態。本篇的命令列包裝會寫入 stderr 並使用非零退出碼,讓排程或 CI 能辨認失敗。

先跑離線的正常與錯誤案例

依序執行三個 fixture。第一個應顯示摘要及三個 id,第二個是模型執行錯誤,第三個把 taskIds 改成字串。後兩者都不能進入成功分支;檢查 $LASTEXITCODE 或 Bash 的 $?,確認它們真的回報非零。

專案終端機:三次命令分開執行並各自看退出碼 · text
node automation/parse-result.mjs fixtures/result-ok.json
node automation/parse-result.mjs fixtures/result-error.json
node automation/parse-result.mjs fixtures/result-bad-schema.json

再手動建立空檔、截斷 JSON 與重複 id 案例。錯誤位置應指向解析或驗證問題,而不是一律要求重新登入。如果連 fixture 都解析不了,先修本機程式;還不需要啟動真正的 Claude 呼叫。

使用參數陣列執行 Claude

材料的 automation/run-claude.mjs 用 Node spawn 呼叫 CLI,將 JSON Schema 當成單一,輸入資料則透過 stdin 傳入。這能避免把 JSON 內的引號、換行或使用者文字直接拼進 shell 命令。程式不使用 shell:true,也不把外部文字當成可以執行的指令。

專案終端機:需要 Claude 已登入,會使用帳號用量 · text
node automation/run-claude.mjs

腳本設定小額預算上限、90 秒逾時、無工具模式與單次結果輸出;它不需要讀取其他專案,也沒有資料庫寫入。預算值是這份練習的停止條件,不能把它當成所有帳號的完整計費保證。若 CLI 不在 PATH,請先用 claude --version 確認安裝,再調整自己的環境。

登入狀態的檢查也不能只看本機是否留有帳號資訊。本次作者測試時,登入紀錄存在,但真正呼叫回報 OAuth 過期,因此實機驗證未通過。解析器仍應拒絕沒有合法 structured_output 的結果,不能因外層看似成功便繼續工作。

串流輸出要等真正結束

stream-json 會逐行輸出不同事件,不應把第一行 system 或中途 assistant 訊息當作最終結果。材料的 lastResult 先解析每一行,再確認只有一個最終 result,最後仍交給同一個 parseResult 驗證。中途網路斷線留下的半段文字,不能自動變成成功摘要。

專案終端機:離線驗證解析、錯誤及不完整串流 · text
node --test tests/automation.test.mjs

測試包括只有啟動事件、沒有最終結果的情況。你也可以將兩次執行的輸出接在同一檔案,觀察解析器拒絕兩個 result。這個設計能避免排程意外覆用 log 檔時,把上一輪成功當成這一輪的成功。

訊號能證明什麼還需要什麼
程序退出碼 0命令正常結束結果類型與欄位驗證
JSON 語法正確文字可解析Schema 與業務條件
structured_output 合法欄位符合需求與原始資料比對
最終 id 正確這個案例內容通過保存版本及輸入證據

逾時、取消與重跑

逾時後先確認呼叫程序已結束,將結果標為未完成。不要立刻重跑一個會寫外部系統的任務,因為上一輪可能已產生副作用卻還沒回報。本篇只摘要假資料,因此重試比較單純;加入檔案或 API 寫入後,還要設計。

Windows 上終止一個程序不一定代表它自行啟動的所有後代程序都已關閉。本練習禁用工具以縮小範圍;日後開放工具時,需要使用適當的程序管理與明確的清理紀錄,不能把一行 kill 呼叫描述成通用的工作樹取消方案。

讓失敗輸出保留診斷價值

結構驗證失敗時,先區分程序沒有成功結束、外層結果標示失敗,以及內層資料不符合 schema。這三種情況的下一步不同:可能需要處理環境、重新安排任務,或調整資料契約。不要把所有失敗都改成空陣列,否則下游會把錯誤當成真的沒有資料。

保留退出碼、錯誤分類與必要摘要即可,含有使用者資料的完整輸出留在受控本機位置。正式流程讀取的是驗證後資料,診斷紀錄則用來說明為何某次執行沒有提供結果。

完成判準與小練習

交付原始輸入、Schema、解析器、正常及失敗 fixtures,並保存一次真實呼叫的版本與結果。驗收先看故障是否被攔住,再看正常資料能否通過;一個永遠拒絕所有輸入的解析器也不是完成。

至少確認四點:摘要不是空白、id 不重複、id 與輸入一致、錯誤不會被存成空成功結果。若你尚未完成有效登入,離線測試仍可完成,但驗收表要將真實模型呼叫標示為待測。不要從範例 JSON 推論帳號連線正常。

小練習是增加一個 completedCount 欄位,同時修改 Schema、解析器、fixture 與測試。故意只改其中兩處,觀察契約不同步如何被檢出。接著可將這條流程接到或 ,沿用相同的結果驗證原則。

回總目錄

  • 生活分享

    Claude Code|建立第一個 mod:在 Claude Code 行程內數工具呼叫

    寫一個三檔案的 mod,用驗證器與測試確認它掛上的事件。文件把 mod 定義成多了入口檔的 plugin:入口檔叫 hooks module,Claude Code 在事件發生時呼叫裡面的函式,函式可以觀察、改寫或接手事件。

  • 生活分享

    Claude Code|Git Worktree 平行工作

    隔離多個任務的檔案與分支。Git Worktree 讓同一儲存庫擁有多個工作目錄,各自使用分支與檔案。本篇會把待辦篩選與文件整理分開,確認兩個 session 不會直接改到彼此的檔案,再把其中一個成果整合回主分支。你也會知道何時可以安全清理工作目錄。

  • 生活分享

    Claude Code|雙 Worktree 實作與衝突整合

    隔離兩項功能,最後完成整合與回歸。兩個 Claude 工作階段同時編輯專案,最容易出現的問題是互相改到同一份檔案,或各自測試通過、整合後卻失敗。本篇用兩個 Worktree 分別處理篩選預設值與介面文字,故意製造一次小衝突,再完成整合、驗證與清理。你不需要先啟用 Agent Teams。

  • 生活分享

    Claude Code|比較流程品質、用量與執行時間

    以同一資料集比較兩種工作方法。比較兩種 Claude 工作方法時,不能只挑成功那一次,也不能只看第一個答案有多快。本篇用固定案例、原始紀錄和一致判準,比較品質、重試、等待與人工整合時間,最後寫出有樣本數與限制的報告,而不是保證某個方法一定省錢。

最新旅遊情報攻略

資料來源

生活分享