ハーネスエンジニアリング:AIエンジニアリングの次の進化
エンジニアがAIとどのように向き合うかに、静かだが重要な変化が起きています。多くの人はまだプロンプトエンジニアリングの話をしています。コンテキストエンジニアリングへ移った人もいます。しかし、いま切り開かれている最前線はもっと深いものです:ハーネスエンジニアリング。
そして、それは私たちがソフトウェアを作る方法だけでなく、実際に重要になるスキルそのものを変えます。
3つの時代
時代1:プロンプトエンジニアリング
ここからほとんどのエンジニアは始めました。正しい言葉、正しい指示、正しい例を作り込みます。そしてモデルは、より良い出力を返してくれます。
うまく機能します。ですが本質的には、単発かつステートレスなやり取りです。あなたは依然として、すべてのオーケストレーションを頭の中で行っています。
時代2:コンテキストエンジニアリング
次のステップは、「単語」よりも「情報」が重要だと気づくことでした。モデルは答えるときに何を知っていますか? どんなドキュメント、履歴、取得されたデータ、メモリがウィンドウ内にありますか?
RAGパイプライン、メモリシステム、ナレッジベースはすべてここに属します。あなたはもう単にプロンプトを作り込むだけではなく、モデルが見るものをキュレーションしているのです。
時代3:ハーネスエンジニアリング
これが現在のフロンティアです。モデルが「何を言うか/何を見ているか」を制御するのではなく、あなたはモデルが動作する「システム」そのものを設計する。
モデルはコンポーネントになります——より大きなループの中にある推論エンジンです。あなたは、モデルが使えるスキル、呼び出せるツール、成果物を検証する検証器、そしてループするのか/エスカレーションするのか/停止するのか——その条件を定義します。
転換点: もはやプロンプトを書いているのではありません。あなたはプログラムを書いています——ただし関数やライブラリではなく、プリミティブはスキル、ツール、そしてMCPサーバです。
ハーネスが実際にどういうものか
中核となるパターンはシンプルです:
スキルが実行される → 出力を生成する → 検証器が出力を判定する → ループに戻るか前進する
各ステップは構造化された入力を受け取り、1つ以上のスキル(モデル呼び出し、ツール、APIなど)を実行して出力を生成し、それを検証器に渡します。検証器は判断します:前進してよいだけの出来か、それとも新しいコンテキストでやり直すべきか?
その上にあるオーケストレーターは、全体のステートを管理し、反復をまたいだ履歴を追跡し、永遠にループしないためにいつ人間へエスカレーションするかを知っています。
これは比喩的にプログラムのようなものではありません。構造的にそのものです——コードではなくスキルとツールで書かれているだけです。
実例:自律的なマイクロサービスのデバッグ
実際に私が作ったものを共有しましょう——このループを現場で使える形にしたシンプルなバージョンです。
私は、デプロイ後にずっと失敗し続けるECSマイクロサービスのトラブルシューティングをしていました。よくある手順はこうです:GHAパイプラインを確認する、ECSタスクのステータスを見る、Cloudwatchログを掘り下げる、修正を試す、再デプロイする、そして繰り返す。面倒で手作業で、遅い——しかも失敗が完全なデプロイサイクルの後にだけ表面化する場合は特にそうです。
そこで私は、そのマイクロサービス自身の中だけにスコープされたハーネスを組み込みました:
- GitHub MCP — GHAパイプラインの実行を確認し、失敗したステップの出力を読み取り、ブランチを作成し、修正をコミットする
- AWS MCP — ECSクラスター、サービスの状態、タスクの健全性を調査する
- Cloudwatch — ECSサービスのログを取得し、エラーをフィルタし、スタックトレースを可視化する
ループはこうなりました:GHAを確認 → ECSを確認 → ログを読み取る → 問題を特定する → コードを修正する → コミットしてプッシュする → 次のデプロイを監視する → もう一度ログを確認する。エラーがなくなりサービスが安定するまで繰り返します。
手作業のSSHはありません。コンソール間のタブ切り替えもありません。ハーネスは反復をまたいでデバッグの全コンテキストを保持します——何がすでに試されたかを知っていて——そしてループを綺麗になるまで締め続けます。
これは意図的に狭いスコープです。1つのサービス、1つの環境、3つのMCPサーバ。ただ、それでもこのシンプルな形だけで、デバッグの行ったり来たりに必要な数時間を節約でき、長いトラブルシューティングセッションでステートを追跡するための認知的負荷を取り除けました。
これが、実践としてのハーネスエンジニアリングの入口です。まずは1つのサービス、1つのループ、いくつかの明確に定義されたスキルから始めましょう。このパターンはそこから拡張できます。
完全な技術設計(コード編集、マルチサービスのトポロジ、デプロイのゲートを含むより包括的なビジョン)は、この文章の最後にある付録に記載しています。
難しい問題:AIは全体像を持っていない
私の単一サービスのハーネスは、スコープ内ではうまく機能しました。しかしその経験によって、次の問題が明確になりました。
本番環境の実システムでは、マイクロサービスが完全に独立することはありません。私が関わったどのサービスにも、上流の呼び出し元、下流の依存関係、そして周辺のエコシステムがあります——PostgreSQL、Redis、SQS、Lambdaワーカー、その他のマイクロサービスなど。これらは、サービスコードがまったく問題なくても、あなたのサービスを失敗させ得ます。
私はこのパターンを数えきれないほど見てきました。症状はサービスAで現れます。みんなサービスAをデバッグします。数時間後に誰かが、2時間前からサービスBがSQSキューから消費しなくなっていたことに気づきます。それがサービスAのキュー深度を急増させ、コードバグに見えるメモリ圧迫を引き起こしていました。根本原因は3ホップ先でした。
1つのサービスしか知らないハーネスは、ジュニアエンジニアとまったく同じことをします。実際の根本原因が別の場所にあるのに、症状だけを自信満々に直してしまうのです。
全体像を得るには、ハーネスがトポロジを知る必要があります——何が上流/下流に存在し、どんなエコシステムのコンポーネントがあり、そしてそれぞれを確認するためにどのスキルを使うべきか。何かを診断する前に、依存関係のグラフ全体を並列に走査し、すべてのノードからの発見を蓄積し、それからようやく根本原因を推論する必要があります。
その走査には次が含まれるかもしれません:
- GitHubおよびGHA — デプロイ自体が問題を引き起こしたのか?
- 複数サービスにまたがるECSタスク — 上流が不健康になっているものはないか?
- サービス境界を越えたCloudwatchログ — エラーが最初に現れた場所はどこか?
- PostgreSQL — コネクションプールの枯渇、遅いクエリ、ロックの競合
- Redis — メモリ圧迫、エビクションポリシーの変更、接続拒否
- SQS — キュー深度、デッドレターキューのサイズ、コンシューマラグ
- Lambda — スロットリング、コールドスタートの嵐、下流リトライのカスケード
これは、ページが飛んできたときにシニアエンジニアが本能的にやることです。失敗しているサービスを最初に開くのではなく、それにつながるあらゆるものの頭の中の地図を開いて、可能性を潰していきます。ハーネスにも同じ「直感」が必要ですが、それには地図を明示的に渡さなければなりません。
その地図を作り、システムが進化していく中で正確さを保ち、何を含めるべきかを理解すること——それは技術的な問題ではありません。判断の問題です。そしてそれはハーネスではなく、完全にエンジニア側の責任です。
人間が維持すべき境界
もう一つ、経験から直接導かれる制約があります。
私が作ったハーネスは、低い環境(lower environments)で、機能ブランチ上でのみ動作します。GHAを確認し、ECSを調査し、ログを読み取り、修正案を出して適用します。しかし、mainにマージすることはありません。生産環境(production)には一切触れません。修正が効くことに納得したら、デバッグ履歴をすべて添付したPRを作成して停止します。
人間がそれを読み、差分をレビューし、次へ進めるかどうかを判断します。
これは単なる安全性のルールではありません。AIの判断が現在どこで破綻しているかについて、実際の状況を反映しています。このハーネスは、定義された範囲内での反復に非常に優れています。状態を保持し、物事を体系的に試し、疲れません。しかし、生産上の意思決定を難しくする要素──今週他のチームが何をデプロイしているか、コンプライアンスレビューが保留になっているかどうか、金曜の深夜3時における影響範囲(ブラスト半径)がどれくらいになるのか、何か問題が起きたときにビジネスがロールバックを吸収できるか──といったことへの認識がありません。
そうした判断には、コードベースの外側に存在する文脈が必要です。その文脈は人とともにあります。
機械が反復を行います。人間が昇格(プロモーション)の意思決定をします。この役割分担は正しい設計です。エンジニアリングで後から解消すべき一時的な制約ではありません。
コーディングは安い。エンジニアリングは安くない。
ここで、あなたに最も残したいのはこの点です。
最初のシンプルなハーネス──GH MCP、AWS MCP、Cloudwatch、ECSログ──を組み上げたときに印象に残ったのは、どれだけのコードを書いたかではありません。どれだけの考えることが、それでも私に必要だったかでした。
スキルのセットアップ自体は簡単でした。しかし、ループに「何をチェックさせるべきか」、その「順序」、そして「終了条件」を決めるには、サービスを深く理解する必要がありました。Cloudwatchのエラーが根本原因ではないかもしれないこと、ECSタスクの再起動が上流側で何かが起きている“兆候”かもしれないこと──それらはハーネスからは得られませんでした。分散システムのデバッグを長年やってきた中で得たものです。
そして、スコープが1つのサービスから、マイクロサービスのエコシステム全体へと広がるにつれて、そのギャップは大きくなります。ハーネスはより強力になりますが、それを設計し、制約し、その結果を解釈するために必要な判断は、減るのではなく、より要求が厳しくなります。
AIはほとんどのコーディング作業を置き換えます。ですが、エンジニアリングの判断は置き換えません。
インフラをシステム全体として理解すること──失敗がどのように伝播するか、実際のブラスト半径がどこにあるか、トポロジが実際にはどうなっているのか(ドキュメントに書かれていることではなく)──そうした知識が希少な資源になりつつあります。構文でもありません。定型文(ボイラープレート)でもありません。アルゴリズムですらありません。
この時代に活躍するエンジニアは、適切に設計されたハーネスに、明確に定義された問題を渡せる人たちです。ハーネスが何をするのかを観察し、その確信が理解を追い越していないかを、正確に見抜ける人たちです。コードを書くよりも難しいスキルです。そして、自動化するのはさらに難しい。
付録:マイクロサービスのデバッグ・ハーネスの技術設計
スキル
| スキル | MCP / ツール | 目的 |
|---|---|---|
| GitHubスキル | GitHub MCP | ブランチ管理、PR作成、GHAパイプライン監視 |
| AWSスキル | AWS MCP | ECSクラスター、サービス、タスクの健全性確認 |
| Cloudwatchスキル | AWS MCP | ログ取得、エラーフィルタリング、スタックトレース解析 |
| PostgreSQLスキル | Postgres MCP | 遅いクエリの分析、コネクションプールの状態、スキーマ検証 |
| SQSスキル | AWS MCP | キューの深さ、DLQサイズ、コンシューマの遅延 |
| Redisスキル | AWS MCP | メモリ使用量、エビクション率、接続数 |
| Lambdaスキル | AWS MCP | エラー率、スロットル回数、所要時間(duration)、コールドスタート |
| HTTP健全性スキル | HTTPツール | 上流および下流サービスの健全性エンドポイント |
| コードリーダースキル | GitHub MCP | エラーに関連するソースファイルを取得 |
| コードエディタースキル | ファイル編集 + GitHub MCP | 修正をソースコードに適用 |
| コミット/プッシュスキル | GitHub MCP | 変更をフィーチャーブランチ上でバージョン管理 |
| GHAウォッチャースキル | GHA MCP | パイプライン実行をポーリングし、失敗ログを読み取る |
| デプロイ待機スキル | AWS MCP | ロールアウト後のECSタスクの安定化を待つ |
| 負荷テストスキル | HTTP / Playwright | 低い環境に対して負荷とUIクリックフローをトリガー |
実行フロー
メインオーケストレーター(健全になるまでループ)
│
├── フェーズ1:全体トポロジのスイープ(並列)
│ ├── 上流のヘルスチェック
│ ├── 自分側:ECSタスク、Cloudwatchエラー、GHAデプロイ状況
│ └── 下流:Postgres、Redis、SQS、Lambda、HTTP健全性
│
├── 推論:モデルが統合された所見を読み取り、根本原因を特定
│ └── 決定:インフラ修正 OR コード修正
│
├── アクション
│ ├── インフラ修正:AWSスキル → ECSタスク定義を更新、環境変数を更新
│ └── コード修正:ソースを読み取る → 編集 → コミット → push → GHAを監視 → ECSを待つ
│
├── 検証フェーズ
│ ├── ECSタスクは安定している?
│ ├── Cloudwatch:エラー率が閾値以下?
│ └── Postgres:ブロッキングクエリがない?
│
├── テストフェーズ
│ └── 負荷テスト + 低い環境に対するUIテスト
│ ├── 合格 → デバッグ要約付きでPRを開く → 完了
│ └── 不合格 → 所見をデバッグ文脈に追記 → ループに戻る
│
└── エスカレーション条件
└── 反復回数が > N → 所見を提示、PRを開く、人間のために停止
共有デバッグ文脈オブジェクト
各反復で完全な記録を追記することで、モデルが既に失敗した修正を繰り返さないようにします:
{
"service": "payments-api",
"iteration": 3,
"history": [
{
"iteration": 1,
"diagnosis": "OOMKilled - exit code 137",
"action": "infra fix - increased ECS memory to 2048",
"result": "fail - still OOMKilled at 2048"
},
{
"iteration": 2,
"diagnosis": "memory leak in batch processor",
"action": "code fix - reduced batch size 1000 → 100",
"commit": "a3f9c12",
"gha": "pass",
"result": "fail - new error:
サービス・トポロジマップ
{
"service": "payments-api",
"upstream": [
{"name": "api-gateway", "type": "http", "skill": "http-health"},
{"name": "frontend-app", "type": "http", "skill": "http-health"}
],
"downstream": [
{"name": "postgresql", "type": "db", "skill": "postgres"},
{"name": "redis", "type": "cache", "skill": "aws-elasticache"},
{"name": "sqs-payments", "type": "queue", "skill": "aws-sqs"},
{"name": "lambda-worker", "type": "compute", "skill": "aws-lambda"},
{"name": "notification-svc", "type": "http", "skill": "http-health"}
]
}
ヒューマン・ゲート
| ゲート | 条件 |
|---|---|
| PRレビューとマージ | 常に — harnessがPRを開き、人間が承認 |
| 本番環境へのデプロイ | 常に — 人間が主導 |
| DBスキーマの変更 | harnessが進行する前に明示的な承認を要求 |
| 反復(イテレーション)のエスカレーション | harnessが進捗なしでN回を超えた場合 |
Rex Zhenは、クラウドインフラストラクチャー&AI/MLを専門とするシニア・サイト・リライアビリティ・エンジニアです。クラウドアーキテクチャ、SRE、そしてエンジニアリングにおけるAIの役割の進化について詳しくは、LinkedInで彼をフォローしてください。



