小さく始めるハーネスエンジニアリング
Date2026/09/03
Last Modified2026/09/03
概要
ハーネスエンジニアリングという単語が話題になっている。
どうやらそれらを採用している人たちの技術が高いようで、自分とは遠いのかなと思っていたけれど、案外身近なのかもしれないと気づいた。
平易に表現するなら「AIとうまく付き合うための仕組みづくり」である。
ならば、自分でもやっていることがいくつか思いつくなぁと思い、普段Codexとやり取りする中で学んだハーネスをまとめていくとする。
プロンプトからハーネスへ
ちょっと寄り道。ハーネスエンジニアリングに対する解釈をまとめておく。
最近あった出来事で、スタイルの修正をPlaywrightで確認してもらうという流れを組んでいたのだが、
「利用可能なブラウザが見つからなかったので確認しませんでした!」とたまーに言ってくることに気付いた。
調べてみたところ、Codex自身がChatGPTアプリ版とIDE拡張との区別がついておらず、アプリ版のPlaywright MCPを参照して失敗し、IDEの方は確認すらせずに失敗したという顛末だった。
これをきっかけに、初めは「スタイルを修正したのでWindsurfのPlaywrightを参照してね」とプロンプトで対応していたのだが、毎回言うのは面倒になってきたので、skillとして登録するようになった。これでプロンプトエンジニアリングを卒業。
ここから「具体的にスタイルの修正とは何で、Playwrightで確認したとは何を指すのか」を詰めていく。
「CIでCSS系のファイルの変更を検知したとき、Playwrightを実行したログがあるかを確認し、なければ再実行を促す」とすれば、もっと確実にたずなを握ることができるようになる。
仕組みを作り、再現可能な環境を整えることができて初めてハーネスエンジニアリングという理解である。
ハーネスのためには環境作りが必要で、そこに専門的な知識が介在するけれど「AIとうまく付き合う」という出発点は同じ。
Dockerはその一例だが、今回はそんな事例をいくつか集めてみた。
ハーネスエンジニアリングの例
- ドキュメント管理 エージェントの精度を高めるには、コンテキストを与えるのが大切。そしてアクセスをよくすることが必要である。
プロジェクト内のドキュメントツリー構造を決める
上記は一つの実運用例。試行錯誤しているうちに、いったん上記の形になった。具体的には
CONTEXT.md: プロジェクト内の用語整理
.agents/: グローバルのskillsの読み込み
docs/: ローカルスコープのskills定義ファイル
というようになっている。
このような構造ができたら、AGENTS.mdと、各ディレクトリにREADME.mdを置き、そのディレクトリ内の探索の仕方を手引きする説明を添えておく。
これで、全体にライトが行き届いているような感じになる。
さらにハーネスする
-
更新指示 このドキュメント構造を最新で維持できるよう、必ず作業後はドキュメントを更新するように定めている。
-
ライフサイクルを決める ドキュメントのほとんどが要件定義に必要なmdファイル群であるが、仕様を更新していくうちに過去の仕様が失われていくことがある。
それを勝手に上書きしないよう、システムに跡が残らない破壊的変更をする場合は過去ログとして必ず残すようにし、最終的には人の判断でその過去仕様を記録しておくかを決めるようにしている。
- テスト検証
エージェント単体でテストを実装させた場合、実装者として都合の悪い部分を隠してしまうことができる。
テストの質を担保するためにサブエージェントを導入し、役割を分けて中立の立場から検証させる。
エージェントの分類
| 役割 | 実装を読む | テストを書く・変更する | 実装を書く・変更する | テスト実行 |
|---|---|---|---|---|
| 親エージェント | できる | 必要に応じて管理 | 必要に応じて管理 | 実行担当 |
test-writer |
できる | できる | できない | 親が依頼した場合のみ |
test-reviewer |
できる | できない | できない | できない |
worker |
できる | 原則変更しない | できる | 親の指示範囲 |
-
親エージェント 最初にユーザーの指示を受けて、内容を整理し、下位エージェントに作業を振り分ける。
各エージェントからの報告を待ち、成果物を確認して、次のエージェントへ渡す。
PHPUnit、Artisan、Migrationや、Infectionなどツールの実行を担当し、その結果を引き渡す役割。
指示役なので変更を伴う実作業は担当しない。 -
test-writer 親エージェントからの指示を受けて、まずは仕様をもとにテストを作成する。テスト駆動開発のイメージ。
必要に応じてproductionコードを読むことができるがread-only。
2回目以降のサイクルでは、ツールによるテスト判定を受けて、テストコードの修正を行う。 -
test-reviewer test-writerのテスト実装を評価する。仕様とコードを取得して、中立的な立場としてテストの有効性を確認する。
何かを変更する権限は持っていないが、テストとproductionコードを俯瞰して見る役割。 -
worker productionコードの実装をすべて担当する。
reviewerの指示に従って、実装を修正することもある。
workerまで進んだら、親エージェントがテストを実行して結果をtest-writerに返す。
これを2巡繰り返し、それでも解消できない部分については保留対象として返す。
具体的に見つかった部分
-
NUL除去に関するテスト CSV読み込みの際に、NULの有無に関するテストが導入されていなかったことが、mutationテストで発見された。仕様にまつわる部分なので、確認を求められた。
-
strtolower()の動作に関するテスト ASCII文字は大文字と小文字を同一視する仕様になっていたが、Unicode全体に適用するかどうかについてはテストで確認できなかったとのこと。これも確認を求められた。
まだこのくらいだが、重箱の隅まで調べてくれている気がする。
しかしトークン消費が3倍くらいになっているので、実用性があるかどうかはわからない……。