コンテンツにスキップ

エージェント設計の基礎 学習ノート — Harness / Eval / Agent Design

開始日: 2026-06-10 動機: ai-engineering-digest で config/harness.yaml(判断基準の外化)を自作したが、「Claude Code の真似」の域を出ていない。harness・eval・エージェント設計を原理から説明でき、自分のプロジェクトに eval を整備できる状態になる 参考: ~/ai-engineering-digest/docs/architecture_multi_agent.md~/nano-code(書籍「作って学ぶAIエージェント」写経)、software-design/11(ReAct)、software-design/23(Supervisor/Swarm)、software-design/28(GEPA + LLM-as-a-Judge) 写経教材: lectures/eval_basics/ — STEP 3〜5 に対応する 6 例(決定論チェッカー / golden dataset / LLM-as-a-Judge / judge バイアス実測 / ハイブリッド評価 / 回帰ゲート)

学習ロードマップ

  • [ ] STEP 0: 概念整理 — Anthropic「Building Effective Agents」を読み、workflow と agent の区別、5つのワークフローパターン(prompt chaining / routing / parallelization / orchestrator-workers / evaluator-optimizer)を自分の言葉で「メモ」節に書く。harness = モデルの外側にあるループ・ツール・基準・権限の総体、という定義を自分の実例(harness.yaml、Claude Code)で説明できるようにする
  • [ ] STEP 1: 最小エージェントループを素手で書くs01_minimal_agent.py)— フレームワークなし、OpenAI SDK の tool calling だけで while ループを実装。終了条件(tool 呼び出しが無くなったら終わり)、tool 結果のメッセージ履歴への追記、max_turns ガードの3点を押さえる
  • [ ] STEP 2: harness の構成要素を既存実装から逆引き~/nano-code のソースを読み、①エージェントループ ②ツール定義 ③コンテキスト管理 ④permission の4要素がどのファイルにあるか対応表を作る。自分の harness.yaml(基準の外化)がどの要素に相当するかも位置づける
  • [ ] STEP 3: 決定的 evals02_eval_deterministic.py)— 「正しいツールを選んだか」「禁止操作を拒否したか」を assert する最小 eval を書く。テスト(毎回 pass すべき)と eval(pass 率で測る)の違い、温度・非決定性の扱いをメモ化する
  • [ ] STEP 4: LLM-as-a-Judges03_llm_judge.py)— ルーブリック設計→judge 実装→judge 自体の検証(人手ラベル 20 件と突き合わせて一致率を測る)まで。position bias(順序入替で判定が変わる)対策も試す
  • [ ] STEP 5: eval を回帰スイートにする — promptfoo または inspect-ai に STEP 3/4 を載せ、「プロンプトや基準を変えたらスコア差分が見える」状態を作る。Langfuse 学習ノートの STEP 5(オンライン評価)とつなぎ、オフライン eval / オンライン評価の役割分担を整理する
  • [ ] STEP 6: 自プロジェクト適用 — ai-engineering-digest の Phase 2(分類)に対し、過去 digest から正解 30 件の eval セットを作る。harness.yaml の基準を変えると precision/recall がどう動くかを測れるようにする(v0.6 の DSPy optimizer 導入の土台になる)
  • [ ] STEP 7: セキュリティ / ガードレール — 写経教材 lectures/guardrails_basics/(6 例)を一周し、prompt injection(直接/間接)→ 決定論フィルタ → 権限ゲート(allow/ask/deny)→ 出力ガード → LLM ガード → lethal trifecta、の多層防御を素手で組む。「確率の防御(プロンプト)」と「構造の防御(権限・分離)」の違いを自分の言葉で説明し、自分の ~/.claude の permissions・gitleaks hook・secret-handling がこの6層のどこに対応するかを整理する。research-orchestrator(3リポジトリ横断)を lethal trifecta の3辺で点検する
  • [ ] STEP 8: loop engineering(トリガー設計) — 写経教材 lectures/loop_basics/(6 例)で loop の2要素「トリガー / 検証可能なゴール」を素手で組む。トリガー3類型(人間 / スケジュール / イベント)を区別し、STEP 1 の最小ループに「いつ起動するか」を足す。検証可能なゴール(STEP 3〜5 の eval)と合わせて「prompt を投げる」から「ゴールに達するまでループを回す」への移行を体得する。大規模化は ~/temporal-workflows~/research-orchestrator で既に実践済みなので、その schedules/ や Temporal cron がこの3類型のどれかを整理して接続する

メモ

2026-06-26 ハーネス×ループを実プロダクトに適用してみた(STEP 0 / STEP 8 の実例編)

学習教材を写経する前に、harness と loop を自分の実プロダクト(個人で作っているブラウザ絵本アプリ。HTML/CSS/JS のみの公開リポジトリ)に当てはめて設計・実装した記録。STEP 0(概念整理)と STEP 8(loop engineering)を「自分の実例で説明できる」状態にするのが狙い。チェックボックスは写経/読書の達成基準を満たしていないので未チェックのまま、ここに応用ログとして残す。

まず一言で

ハーネス=AIが転ばず走るための足場。ループ=人の代わりにAIへ自動でプロンプトを出し続ける制御系。 モデルを賢くするより、AIが「やったつもり」で終わらない環境を作るほうが効く、という体験をした。

なぜ足場が要るのか(初学者がつまずく所)

AIに「このアプリ作って」とだけ頼むと、だいたい次の3つで失敗する。これは「モデルが馬鹿だから」ではなく足場が無いからで、人間の新入りでもマニュアル・進捗ノート・テストが無ければ同じ失敗をする。

失敗 中身 足場のどの要素で防ぐ
記憶喪失 会話が切れると何をしたか忘れる ①指示書 ②状態
やったつもり 「できました」と言うが動いていない ③検証
暴走・破綻 1回で全部やろうとして手を広げる ④範囲

足場の5要素(harness の本体)

要素 何のため 一般的な実体
① Instructions(指示書) やり方を毎回ファイルから読ませる AGENTS.md / CLAUDE.md
② State(状態) 進捗を会話の外(ファイル)に置く state.json / 進捗ログ
③ Verification(検証) 「できた」をテストで証明する テスト・CI(1コマンドで合否)
④ Scope(範囲) 一度に1機能だけ渡す 機能リスト(1機能=1単位)
⑤ Lifecycle(始末) 毎回同じ手順で始め、同じ状態で終える 初期化スクリプト

一番大事なのは③検証。完了判定を「エージェントの自己申告」にすると平気で嘘をつく(悪意でなく、そう錯覚する)。だからテストが green になったかで判定し、しかもテストは人間が先に書いた「契約」にして、AIには「テストを通すコードを書く」だけをやらせる。作った本人に採点させない、が肝。

loop engineering の本質(STEP 8)

loop は「prompt を投げる」から「ゴールに達するまでループを回す」への移行。2要素は トリガー(いつ起動するか)検証可能なゴール(何が green か)。ハーネスが「1回を確実にする足場」なら、ループは「その1回を何度も自動で回す」もの。maker(作る人)と checker(点検する人)を分離するのが核心。

flowchart LR
    L["ループ制御<br/>(トリガー + 上限)"] -->|次の機能を1つ渡す| M["maker<br/>(実装する)"]
    M -->|コード| C["checker<br/>(テストで検証)"]
    C -->|緑| D["done"]
    C -->|赤: 失敗を渡して再試行| M

暴走させない安全装置(総回数上限 / 機能ごとリトライ上限 / 予算上限 / 段階レベル L1→L2→L3)を必ず付ける。L1=レポートのみ → L2=実装するが人間がマージ → L3=無人、と信頼を積んでから権限を上げる。

実例: 自分の絵本アプリへの適用

このアプリには既に「Issue 起票 → 人間が承認 → AIが実装して Draft PR → 人間がマージ」という自動化があったが、実装が一発勝負だった(初稿を1回出すだけで、赤なら green まで粘るループが無い)。

ここで効いたのが、検証の資産がすでにあったこと。実ブラウザの E2E テスト(本棚に出る / ページ送りが効く / チャイルドロックが効く…)が「正しい絵本」の契約になっている=足場の③検証は手元にある。足りないのは maker→checker のループだけだった。

設計の核を3つに絞った。

  1. Issue を spec として扱う — 承認された Issue を「人間用の仕様+機械用の機能リスト+受け入れE2E」に変換
  2. 赤/緑の基準を1コマンドに集約 — ①E2E(シナリオ網羅)②単体テスト(網羅率80%床)③プライバシー(実名0件)④契約の不可侵(テストを書き換えていない)の4ゲート全部緑で「完了」
  3. maker エンジンを切り替え可能に — 手元は claude -p(ローカル本命)、無人運用は別エンジン、オフライン検証はモック。起動オプション1つで差し替え(Maker 基底+ファクトリ=Strategy パターン)

学び: UIの品質は「カバレッジ%」よりシナリオ網羅で測るほうが直感的。絶対値の%を追うより「本棚に出る・送れる・抜けない」が全部緑か、のほうが意味がある。

設計で止めず、第一歩の実装まで進めた(TDD + セルフレビュー)

  • テストを先に書いて落とす(TDD)→ 不変な状態機械(Feature / LoopState)と設定オブジェクトを実装して green
  • 状態遷移は新しいオブジェクトを返す(元を書き換えない)。バグ混入と追いにくい副作用を防ぐ
  • 状態は JSON でファイル保存 → 途中で落ちても再開できる

そして「マージ前に必ずセルフレビュー」を回したら、自分で書いたコードから本物のバグが3つ出た。3つとも回帰テストを先に足してから直した(最終 28 件 green)。

バグ なぜ問題か 直し方
保存が非アトミック 書込中にプロセスが死ぬと状態ファイルが壊れ再開不能。「再開可能にする」部品が、保存処理自身で契約を破っていた 一時ファイルに書いてから os.replace(同一FSでアトミック)
不変オブジェクトが内部辞書の参照を漏らす 返り値をいじると元が無音で汚れる(frozen の意味が無効化) dataclasses.asdict で再帰コピーを返す
空の仕様で「何もせず全完了」 空集合に対する all([])True 入力境界(spec 読込)で空を弾く

学び: 「セルフレビューを必ず回す」を仕組みにしておくと、自分のコードでもこれだけ拾える。レビューを工程に埋め込む価値の実証。

用語集

用語 一言 補足
ハーネス(harness) AIが転ばず走るための足場 モデルの外側にあるループ・ツール・基準・権限の総体。5要素(指示書/状態/検証/範囲/始末)
ループ(loop) AIへ自動でプロンプトを出し続ける制御系 トリガー + 検証可能なゴールの2要素
maker / checker 分離 作る人と点検する人を分ける 作った本人に採点させない。checker は決定的テストで判定
テスト=契約 正解を先にテストで固定し、AIに通させる 人間(or 別主体)が契約を握る。AIにテストを書かせない
自動化レベル L1/L2/L3 段階的に権限を上げる L1=報告のみ / L2=実装+人間マージ / L3=無人
シナリオ網羅 UI品質を「%」でなく必須シナリオの緑/赤で測る カバレッジ%の代替指標

roadmap との接続

  • STEP 0(概念整理): 本メモで harness/loop を自分の実例(絵本アプリ)で説明できた。残り=「Building Effective Agents」の5ワークフローパターンを自分の言葉で整理する写経
  • STEP 1(最小ループを素手で): 今回は claude -p を maker に使う高レベル適用。素手の while ループ実装(s01_minimal_agent.py)は別途
  • STEP 8(loop engineering): トリガー3類型(人間/スケジュール/イベント)のうち、今回は「人間が approved を付けたら起動」=人間トリガー + 検証可能ゴール(4ゲート)の実例。スケジュール/イベント型は ~/temporal-workflows~/research-orchestrator(Temporal cron)で実践済みなので、3類型のどれに当たるか整理して接続する

作成: 2026-06-10 / 最終更新: 2026-06-26