ここが、AI ビルダーに誰も教えない真実だ。
彼らのほとんどはデモを作っているだけだ
本当に作るべきものは
プロダクションレベルの AI エージェント
TLDR; 読むのが面倒なら、このリンクをエージェントに渡して質問してみてください:➡️https://github.com/codejunkie99/agentic-harness
これがすべての始まりとなったツイートだ
問題は、ほとんどの AI エンジニアが、エージェントに本気で取り組もうと決めたときに、実際に何を作ればいいのか明確なアイデアを持っていないことだ。
ある者は、マルチエージェントのデモが YouTube で綺麗に見えるからという理由で LangChain に手を出し、次の 2 週間を Python の相互運用性と非同期ランタイムの不一致と格闘して過ごし、結局すべてを破棄する。
ある者は、ゼロからカスタムオーケストレーション層(ループ、セッションストア、コンテキストアセンブラ)を構築しようと試み、インフラがタイムラインを食いつぶしたため、実際のエージェントを完成させることができない。
またある者は、Hello World の Webhook サンプルをコピーし、JSON レスポンスが返ってきたのを見て、システムを理解したと思い込み、セッションが 10 分を超えた最初の実行、リモートサンドボックスがタスク中にダウンしたとき、またはコンパクションが設定されていない状態でコンテキストウィンドウが満杯になったときに、すぐに壊れるものを出荷する。
結果はたいてい同じだ:配管工事ばかり多く、プロダクションエージェントはなく、プロダクションエージェントのランタイムが実際にどのようなものかというメンタルモデルもない。
2026 年に本物のエージェントを構築して出荷することが目標なら、6 つのフレームワークを学ぶ必要はない。
1 つのランタイムを深く理解し、ハンドラからデプロイメントまでプロダクションエージェントを自分で管理できるようになる必要がある。
つまり、以下の方法を学ぶ必要がある:
- 3 層アーキテクチャを配線し、ハンドラロジックがエージェントコードに触れることなくプロバイダの切り替えやターゲットの変更に対応できるようにする
- セッションとタスクを正しく使用し、長時間のジョブが自身のコンテキストを汚染しないようにする
- ロールとスキルを記述し、何も再コンパイルせずにモデルの動作を形成する
- コンパクションを設定し、2 時間実行されるセッションが 1 時間目から幻覚を起こし始めないようにする
- HttpSessionEnv をリモートサンドボックスに向け、バイナリはローカルで実行しながら実行は Linux 上で行う
- 適切なビルドターゲット(ネイティブ、Node、Cloudflare)を選択し、それらの間でエージェントロジックを書き換える必要がないようにする
- コネクタを生成し、アダプタを手書きする代わりに、実際の負荷下でその違いがなぜ重要かを理解する
このガイドは、実際の agentic-harness コードベース、それを使って実際のエージェントを構築し壊した 6 週間の経験、そしてデバッグに最も時間がかかった障害モードから構築された、完全な技術ウォークスルーである。
この記事は 4,000 語以上あり、リポジトリとドキュメントから直接引用している。二次情報の要約やデモレベルの例ではない。
しかし、その真の価値は、すべてのセクションに動作するコードスニペット、その決定がなされた理由の明確な説明、そしてそれをスキップした場合に直面する正確な障害モードが含まれていることにある。
そうすれば、読み終える頃には、最初のハンドラからサンドボックス、無人で実行する CI ジョブまで、プロダクションエージェントをエンドツーエンドで管理できるようになる。
この理解を構築するには、コードベースでの 6 週間以上の日々の作業が必要だった。そのほとんどは、実際の条件下で壊れる前に正しく見えたものをデバッグすることだった。
では、始めよう。⬇️
プロジェクトの形状
2 つのクレート。1 つのバイナリ。すべての実行ターゲットは設定の選択であり、書き直しではない。
- SDK は任意の Rust プロジェクトに取り込めるライブラリである。CLI がそれをラップする。エージェントは
use agentic_harness::prelude::*;で始まる Rust バイナリである。 cargo buildがパイプライン全体である。バンドラもトランスパイルステップも、ターゲットマシン上の言語ランタイムもない。1 つの自己完結型実行可能ファイルと manifest.json だけである。
すべてを駆動した設計制約:同じエージェントバイナリが、インタラクティブモードでラップトップ上で、新しいリポジトリをクローンする GitHub Actions ジョブ内で、HTTP 経由のリモート E2B サンドボックスに対して、そして Cloudflare Worker 境界上で、それらの間で 1 行のエージェントロジックも変更せずに実行できること。
このコードベースのすべての決定は、その制約を尊重するために存在する。
3 つの層とそれぞれが存在する理由
メンタルモデルは 3 つの同心円である。それぞれの境界がどこにあるかを知ることは、このガイドの他の何よりもデバッグ時間を節約してくれる。
Rust コードは外側の円である。
- ハンドラを書く。ハンドラは AgentContext を受け取る。セッションを呼び出す。セッションはモデルを呼び出し、ファイルを読み書きし、シェルコマンドを実行し、タスクを生成し、MCP サーバに接続する。
- HTTP クライアントに直接触れることは決してない。モデルのレスポンスを直接パースすることもない。SDK が両方を処理する。
ハーネスは中間の円である。
- エージェントレジストリを管理し、URL パスによる ID をルーティングし、呼び出し間のセッション永続化、セッションが大きくなったときのコンテキストコンパクション、ロールとスキルの発見、モデル選択の優先順位、およびプロバイダニュートラルな ModelClient トレイトを処理する。
- これにより、ハンドラコードに触れることなく、Anthropic を OpenAI に、ローカルの Ollama インスタンスに交換できる。
- ハーネスは、エージェントロジックをプロバイダやターゲット間で再利用可能にするものである。
- また、プロダクションで壊れるすべてのもの(セッション状態、コンテキストオーバーフロー、プロバイダ障害、同時リクエストの順序付け)が処理される場所でもある。
実行ターゲットは内側の円である。
- ローカルファイルシステム。CI チェックアウト。Daytona または E2B を指す HttpSessionEnv。Cloudflare Worker 境界。
- ハーネスはどれを使用しているかを気にしない。ハンドラも気にしない。
session.shell()とsession.write()を呼び出し、ハーネスはそれらを基礎となるターゲットが必要とするものに変換する。 - この分離がすべてのポイントである。E2B が新しい API バージョンをリリースしたら、エージェントロジックではなくコネクタを更新する。
- Anthropic が claude-opus-4-7 を出荷したら、ハンドラではなく runtime.json を更新する。中間の円がすべての変更を吸収するため、外側の円はクリーンなままである。
ランタイム設定:モデル層を制御するファイル
1 つのハンドラを書く前に、ワークスペースに runtime.json が必要である。
これを .agentic-harness/config.json またはワークスペースルートに agentic-harness.json として配置する。load_workspace_context() が自動的にそれを拾う。
実行時のモデル選択は次の優先順位に従う:
- PromptOptions::model(...):呼び出しごとのオーバーライド
- 選択されたロールのモデルメタデータ:ロールごとのデフォルト
- ランタイム設定の defaultModel:ワークスペースのデフォルト
理解すべきこと:モデル ID は使用する前に登録する必要がある。openaiCompatibleModels は、ハーネスが組み込みの chat-completions クライアントを配線するために使用するリストである。モデルがそのリストにない場合、セッション途中での混乱した失敗ではなく、起動時に明確なエラーが発生する。
OpenAI 互換ゲートウェイの場合、設定は同じように見える。baseUrl をゲートウェイに向ける:
- runtime.json にリテラルの API キーを決して書かない。
apiKeyEnvを使用し、実際のキーは環境変数に保持する。 - ハーネスはリクエスト時に環境変数を読み取る。起動時ではない。つまり、サーバを再起動せずにキーをローテーションできる。
エージェント ID は URL パスであり、レジストリルックアップではない
これが私を驚かせた最初の設計決定である。今では正しいと思う。
エージェント ID システムはない。レジストリキーもない。自分で生成する UUID もない。エージェントの ID は POST /agents/<name>/<id> である。
- ハーネスはその URL の背後でセッション状態のすべてのブックキーピングを処理する。
- これが機能する理由:すべてのシステムのすべての呼び出し元は、コンテキストから意味のある ID を構築する方法をすでに知っている。PR 番号、実行 ID、タスク名と組み合わせたタイムスタンプ、ユーザーハンドルなど。
- セッション作成エンドポイントは必要ない。セッション ID を別途保存する必要もない。URL がセッションである。
Rust 側のエージェントハンドラは ctx.id() を呼び出して、呼び出し元が提供した ID を取得する:
セッション:ステートフルな実行コンテキスト
セッションは会話スレッド以上のものである。エージェント呼び出しの完全な実行コンテキストである。
以下を保持する:
- モデルとのメッセージ履歴
- ワークスペースファイルアクセス(読み取り、書き込み、編集、grep、glob、stat、readdir)
- cwd と env 制御付きのシェル実行
- ツール登録(MCP サーバ、カスタムツール)
- 割り当てられたロールとそのシステムプロンプトオーバーレイ
- コンパクションバジェットと履歴ウォーターマーク
セッションは、意味のある任意の ID で ctx.session_with_id() を呼び出すことで取得する:
- 同じ ID を使用すると、セッションは HTTP 呼び出し間で永続化される。同じエージェントエンドポイントを同じセッション ID で 3 回呼び出すと、モデルは 3 つの交換すべてを 1 つの連続した会話として認識する。
- 履歴は自動的に蓄積される。自分で管理する必要はない。
- これにより、状態を自分で管理することなく、マルチステップワークフローが可能になる。
session.prompt()を呼び出し続ければ、ハーネスが残りを処理する。
プロンプトと一緒に大量のコンテキストを渡す必要がある場合は、ファイルを読み込んでインラインでフォーマットする:
セッションはトークンカウントを管理し、会話の途中で誤ってコンテキストウィンドウをオーバーフローしないようにする。バジェットに近づくと、コンパクションが作動する。詳細は後のセクションで。
タスク:親をクリーンに保つフォーカスされた子セッション
- これは、初日に理解しておけばよかったと願うプリミティブである。長時間のジョブで一貫性を保つエージェントと、途中で幻覚を起こし始めるエージェントの違いである。
- タスクは 1 回限りの子セッションである。新しい履歴。共有ワークスペース。結果を親に返す。親の履歴はタスクの中間推論を一切見ない。
- リサーチタスクは分離されて実行される。その推論チェーン全体。
- モデルがコードについて行ったすべての中間観察、「待って、このファイルも確認しよう」といったものも、タスク内に留まる。
- 親セッションは 1 つのクリーンなサマリーを取得する。それだけを見る。これが実際に重要な理由:長時間実行されるセッション内で直接探索的分析を実行すると、履歴は中間ツール呼び出し、部分的な回答、もはや関連性のない事柄についてのモデルの推論で満たされる。
- モデルは不適切なタイミングでそのノイズにアンカーする。コンパクションが最終的に作動し、実際に必要なコンテキストを失う。タスクはその外科的な修正である。
ルール:サブ問題に明確な成果物があり、それを完了するために親の会話履歴を必要としない場合は、タスクにする。「タスクにする」基準は思っているより低い。
コードベース全体にわたる並行分析の場合:カートグラファーパターン。タスクをファンアウトして結果を収集する:
各タスクはクリーンである。各タスクは正確に 1 つのディレクトリに焦点を当てている。親セッションは結果を収集し、最終ドキュメントを書き込む。
12 のモジュールがある場合、12 のフォーカスされたタスクを実行し、それぞれが他のタスクからのバゲージゼロで開始する。
ロールとスキル:再コンパイルせずに動作を形成する
- ロールは
.agentic-harness/roles/に存在する。スキルは.agents/skills/に存在する。両方ともハーネス起動時に自動検出される。 - ロールは呼び出しにスコープされたシステムプロンプトオーバーレイである。呼び出し時に適用され、その後破棄される。メッセージ履歴に永続化されない。呼び出し間で蓄積されない。
優先順位チェーン:呼び出しロール > セッションロール > エージェントロール > ロールなし。
- モデルフロントマターはオプションだが便利である。特定のロールを特定のモデルにルーティングできる。
- 説明者ロールは速度とコストのために claude-sonnet-4-6 で実行される。セキュリティ監査役は深さのために claude-opus-4-7 で実行される。これをロールファイルで一度設定し、その後は二度と考えない。
- スキルは、セッションの開始時にモデルが読み取る動作記述ファイルである。
.agents/skills/内の Markdown ファイルである。ハーネスが自動的にそれらを見つける。どこにも登録する必要はない。
実用的な使用法:コードベースと一緒にスキルライブラリを置き、作業方法を記述する。コミットメッセージ形式、推奨ライブラリ、マイグレーション命名規則、API 設計パターン、テスト要件など。
モデルはすべてのセッションの前にこれを読み取る。Markdown を編集する。動作は次の実行で更新される。再コンパイルは不要。
モデルはこれを読み取る。あなたの規則に一致するコミットを書く。毎セッションで思い出させる必要はない。1 つのファイルを維持する。
コーディングエージェントループの詳細
コーディングエージェントループは、CLI が構築された主要なユースケースである。また、誤って設定すると最も多くのことがうまくいかなくなる場所でもある。
重要なすべてのオプションを含む完全なコマンド:
各フラグの機能とその重要性:
--workspace .はルートを設定する。すべてのファイル操作はここにサンドボックス化される。エージェントはこのパスの外側を読み書きできない。ハーネスレベルで強制される。モデルが自己制限することを信頼するのではない。--llm autoはランタイム設定の defaultModel からモデルを選択する。深い推論が必要な複雑なタスクには--llm anthropic/claude-opus-4-7、より高速な反復には--llm anthropic/claude-sonnet-4-6を使用する。--deny-pathはハードブロックである。プレフィックススタイルで一致するため、--deny-path config/はconfig/以下のすべてをカバーする。最初の実行前にワークスペースを監査し、秘密鍵やプロダクション設定を保持するすべてのパスを列挙する。.envだけではない。--approve-dependenciesは、人間の承認ステップなしで Cargo.toml の変更を許可する。新しいクレートが追加されるたびに確認したい場合は、これを省略する。--commitはすべての変更を自動的にステージし、成功した実行の最後に指定したメッセージでコミットする。このフラグがない場合、変更はステージされていない修正として残り、確認できる。--prはコミットからプルリクエストを開く。実行前にクリーンな git 状態と、detached HEAD ではなく実際のブランチが必要である。
ループ自体:Inspect → Brief → LLM + Tools → Edit + Test → Commit · PR。
- inspect:ワークスペース構造を読み取り、スキルとロールをロードし、プロンプトに最も関連する可能性が高いファイルを特定する。
- コードに触れる前に、理解を coding-brief.md に書き込む。
- brief:モデルが計画にコミットする。実行中に
.agentic-harness/runs/<id>/coding-brief.mdを読み取って、何を決定したかを確認できる。 - ブリーフが間違っているように見えたら、実行を強制終了する。エージェントに悪い計画を実行させるよりも、より明確なプロンプトで再起動する方がコストが低い。
- LLM + tools:編集-テストループ。モデルが変更を加え、テストスイートを実行し、出力を読み取り、さらに変更を加える。テストが合格するか、反復制限に達するか、タスクが完了したと判断するまで反復する。
commit · PR:ステージ、コミット、プッシュ、差分を添付して PR を開く。
すべての実行は、.agentic-harness/runs/<id>/ に 6 つのアーティファクトを書き込む:
- coding-brief.md:エージェントがコードを書く前にコミットした計画
- summary.md:何が行われ、何が試され、なぜそうしたかについての人間が読める説明
- run.json:構造化メタデータ:使用されたモデル、総期間、入出力トークン数、反復回数、最終終了ステータス
- events.jsonl:すべてのツール呼び出しを順番に、完全な入力と出力とともに。何が間違っていたかをデバッグするため
- diff.patch:すべてのファイル変更の完全な差分
- checks.json:成功または失敗を決定した最終テストと lint の結果
覚えておくべきヒント
- これらを一時的な出力ではなく、構造化ログとして扱う。再現可能である必要があるタスクについては、実行アーティファクトをリポジトリにコミットする。
- run.json だけ(2KB)で、モデル、トークンコスト、成功したかどうかがわかる。events.jsonl は、悪い実行をデバッグする必要があるときに、エージェントが何をどの順序で行ったかを正確に示す。
CI の場合、パターンは次のとおり:
HttpSessionEnv:バイナリをローカルで実行し、リモートで実行する
- これは、完全に理解するのに最も時間がかかった機能である。今ではインフラに触れるほとんどすべてのタスクで使用している。
- エージェントバイナリはマシン上または CI 内で実行される。ファイルシステムとシェル操作はリモートサンドボックス内で実行される。
- エージェントは自分がどの環境にいるかを知らず、気にしない。
use agentic_harness::HttpSessionEnv;
ワイヤプロトコルは HTTP 上の JSON である。すべての操作:
- exec
- read
- write
- edit
- grep
- glob
- stat
- readdir
- mkdir
- rm
には定義されたリクエスト/レスポンス形状がある。
このプロトコルを実装する任意のサンドボックスが HttpSessionEnv ターゲットとして機能する。
名前付きサンドボックスを配線するには:
組み込みコネクタは、Vercel Sandbox、Daytona、E2B の認証とライフサイクルのボイラープレートを処理する:
- 私がこれを使用する具体的なユースケース:クリーンな Linux 環境で CI 障害を再現すること。
- エージェントは正確な失敗コミットハッシュでリポジトリをクローンし、正確な失敗テストコマンドを実行し、完全な出力を読み取り、障害を診断し、レポートを書き込む。
- 私はレポートを読む。ローカルマシンには触れていない。セッションが終了するとサンドボックスは破棄される。
誰も警告しないパフォーマンスの問題:HttpSessionEnv 上のすべてのシェル呼び出しはネットワークラウンドトリップである。タイトなループ(編集、テスト、出力確認、編集)は、レイテンシを急速に蓄積する。
ローカルで 5 秒かかる 40 回の反復ループは、各反復が 3 つの別々のシェル呼び出しを行う場合、リモートサンドボックスに対して数分かかる。
修正:シェル作業をスクリプトにバッチ化する。
反復ごとに 1 回の呼び出し。スクリプトを 1 回書き、繰り返し実行する。40 回の反復ループでのレイテンシの差は現実的である。
ビルドターゲット:同じコードベース、3 つのデプロイメント形状
ネイティブがデフォルトである。1 つのバイナリ。1 つのマニフェスト。ターゲットマシンには他に何もない。ネイティブ Linux バイナリを実行できる任意の場所で実行される。
Node は、Node エントリポイントを必要とするホスティングプラットフォーム向けである。ビルドは、ネイティブ Rust バイナリを子プロセスとして起動し、HTTP をプロキシする server.mjs を生成する。エージェントロジックは依然として Rust として実行される。Node 層は 30 行の HTTP シムである。
Cloudflare はエッジデプロイメント向けである。
- ビルドは Worker 境界ファイルを生成し、Worker 互換アプリアダプタをリンクする。
- ハンドラは WASM JSON ABI を介して WASM にコンパイルされる。
- Durable Object バインディングは Cloudflare KV を介してセッション永続化を処理する。
Cloudflare に関する重要な制約:Worker は長時間実行されるシェルコマンドをサポートしていない。実際のファイルシステムもない。
cargo やビルドツールもサポートしていない。--target cloudflare は、Webhook 処理、ルートメタデータ、小さな制御エンドポイント、Durable Object ルーティングのためのものであり、コーディング作業のためではない。
cargo test を実行する必要があるものについては、ネイティブプロセスまたはリモートサンドボックスに委任する。
実用的な決定マトリックス:
- エージェントを他のサービスが呼び出す API として出荷する → nginx または管理プラットフォームの背後にあるネイティブ
- Railway、Render、または Node を期待するプラットフォームでホスティングする → node
- Webhook 取り込み、軽量ルーティング、Durable Object 状態管理 → cloudflare
- それ以外 → ネイティブ
スキーマガイド出力:モデルレスポンスからの型付き Rust 構造体
モデルに JSON を返すように依頼し、それが実際に行われることを期待するのは半分の解決策である。
ハーネスがそれを抽出、検証、そして Rust 構造体にデシリアライズすることが完全な解決策である。
モデルは、同じレスポンス内で型付きペイロードとともに推論散文を返すことができる。ハーネスは ---RESULT_START--- と ---RESULT_END--- マーカー間の結果ブロックを抽出する。Rust 構造体が得られる。モデル出力からハンドラロジックへのコンパイル時型安全性。
スキーマは 2 つのことを行う:モデルにどのような形状を生成すべきかを伝え、ハーネスにデシリアライゼーション前に検証するための何かを与える。
モデルがスキーマに一致しないものを返した場合、3 つの呼び出しサイト後で欠落フィールドにアクセスしたときにパニックになる代わりに、PromptError::SchemaValidationFailed が発生する。
MCP ツール:サンドボックスの外側に到達する
エージェントがファイルとシェルを超えた機能を必要とする場合、connect_mcp が脱出ハッチである。
エージェントは MCP サーバの完全なツールセットを取得する。記述するツール定義はない。説明はサーバから来る。モデルはそれらの説明に基づいてどのツールをいつ呼び出すかを決定する。
1 つのセッションに複数の MCP サーバを配線できる:
- モデルは説明に基づいてツールを呼び出す。「sentry を検索」のような曖昧な説明は、一貫性なく呼び出される。
- 「エラー、インシデント、またはプロダクション問題に関する質問に答える前にこれを呼び出す」という説明は、確実に呼び出される。
- MCP サーバを制御している場合は、規範的な説明を書く:何を返すかだけでなく、いつ呼び出すべきかをモデルに伝える。
コネクタ:アダプタを書く代わりに生成する
慣れない API に対してアダプタコードを手書きする代わりに、コネクタレシピをコーディングエージェントにパイプする:
- コネクタレシピは、サンドボックス API とそれが満たす必要がある SessionEnv コントラクトの構造化された記述である。
- コーディングエージェントがそれを読み取り、Rust アダプタモジュールを書き、認証を処理し、プロバイダライフサイクルをラップし、HttpSessionEnv として公開する。
- 差分を確認する。マージする。アダプタはプロジェクト内に存在する。今やあなたのコードである。
私はこれを使用して Daytona を約 20 分で配線した。完全なレビューサイクルを含めて。エージェントは最初のパスで認証ヘッダー形式を正しく取得した。
Daytona のドキュメントに対してゼロからアダプタを書くには、午後の大半と、リフレッシュトークンフローに関する少なくとも 2 つの誤った仮定が必要だっただろう。
コネクタが生成されると:
自動コンパクション:コンテキストを失わずに長時間セッションを処理する
長時間実行されるセッションは履歴を蓄積する。
最終的にモデルのコンテキストウィンドウをオーバーフローする。
ハーネスはこれを自動的に処理するが、正しく設定する必要がある。さもないと、まさに不適切なタイミングでコンテキストを失うことになる。
context_window_tokens はセッションの総バジェットである。
reserve_tokensはモデルのレスポンスのために確保するものである。履歴の実効制限はcontext_window_tokens - reserve_tokensである。keep_recent_messagesは、コンパクションに関係なく常にそのまま保持される末尾のメッセージ数である。
履歴がバジェットを超えると、ハーネスはモデルにシステムプロンプトと保持された末尾の間のすべてを要約するように依頼する。
その要約が中間セクションを置き換える。末尾メッセージはそのまま残る。コンパクト化されたセッションは小さくなり、次の呼び出しはバジェット内に収まる。
トレードオフは現実的である:要約は精度を失う。50 メッセージ前に行われた特定の決定:「axum のミドルウェアモデルで動作する PKCE サポートを持つ唯一のライブラリだから authlib を選んだ」は、要約では「認証に authlib を選んだ」として生き残るかもしれない。
その精度がセッション後半の決定にとって重要な場合は、明示的に保存する:
- 決定をファイルに書き込む。ファイルはコンパクションを生き残る。モデルは必要に応じてそれらを読み戻すことができる。ワークスペースが保持するなら、履歴がすべてを運ぶ必要はない。
agentic-harness doctorを実行して、モデルの実際の報告されたコンテキストウィンドウを確認する。context_window_tokensをその値の 80〜90% に設定する。- トークンカウンターはモデル側で完全に正確ではなく、99% で座っているときに 1 つの大きなファイル読み取りがあなたを超えさせる可能性がある。
注意すべき点
- セッション履歴の汚染
- 問題:長時間セッション内での探索的分析は、後のプロンプトを探索フェーズからのノイズで汚染する
- 修正:タスクを使用する。タスク履歴は親に触れない。「タスクにする」基準は思っているより低い
- ロール優先順位の驚き
- 問題:呼び出しレベルのロールがセッションロールを覆い隠す。モデルが期待とは異なる動作をし、理由がわからない
- 修正:セッションロールは ID を設定する。呼び出しロールは焦点を絞る。それらは層になる — 呼び出しロールは追加するものであり、キャンセルすべきではない
--deny-pathのギャップ
- 問題:
.envを拒否する。しかし、秘密鍵は.env.localとconfig/staging.yamlにも存在する。エージェントがそのうちの 1 つを読み取る - 修正:ファイル名ではなくプレフィックスを拒否する。
--deny-path config/はその下のすべてをカバーする
- CI での detached HEAD
- 問題:エージェントが編集し、テストが合格し、コミットが失敗する — コミットするブランチがないため
- 修正:ハーネスを呼び出す前に
git checkout -b agent-run-$RUN_IDを実行する
- タイトループでの HttpSessionEnv レイテンシ
- 問題:各 3 つのシェル呼び出しでの 40 回の反復は、純粋なネットワークレイテンシの数分である
- 修正:すべてを 1 回の呼び出しで行う
agent-check.shを書く。反復ごとに 1 回の呼び出し
- コンテキストバジェットの過小評価
- 問題:コンパクションがタスク途中で作動する。モデルは計画を失い、要約から即興で対応し始める
- 修正:
agentic-harness doctorを実行して実際のウィンドウを取得する。バジェットをその 80〜90% に設定する
- ハンドラ登録後にランタイム設定が読み込まれる
- --llm auto が実行間で変化する
- 問題: defaultModel が更新される。6 ヶ月離れた 2 回の実行は比較できない。最初の実行を再現できない。
- 修正: 再現性が必要なものについては、runtime.json でモデルを固定する。
- 実行アーティファクトの削除
- 問題: gitignore ルールで runs/ を削除する設定にする。3 週間後に回帰の再現が必要になったとき、すべて消えている。
- 修正: 再現が必要なタスクについては、実行アーティファクトをコミットする。run.json は 2KB。残しておく。
違うやり方をするなら
- 何かに手を付ける前に、agentic-harness ガイドを読む。
- ハンドラロジックを書く前に、セッションレベルのテストを書く。
- サブ成果物があるものはすべてタスクを使う。
- 最初の本番実行からモデルを固定する。
- 決定事項はセッション履歴ではなくファイルに保存する。
- リモートサンドボックスを使う場合は、最初からシェル操作をバッチ化する。
結論
ほとんどのエージェントフレームワークは API 呼び出しのラッパーに過ぎない。これはランタイムだ。
ラッパーは「モデルに応答させる」ことを解決する。ランタイムは「エージェントを本番環境にデプロイし、モデルが変わっても、サンドボックスが変わっても、コードベースが変わっても、セッションが 2 時間実行されてコンテキストウィンドウがあふれても、動作し続けるようにする」ことを解決する。
3 層アーキテクチャ
- あなたのコード
- ハーネス
- 実行ターゲット
これによってそれが可能になる。あなたはハンドラを書く。ハーネスが運用上の複雑さをすべて吸収する。実行ターゲットは設定の選択肢だ。
変わらないもの:ハンドラロジック、セッション構造、タスクパターン、ロール定義、スキルファイル。変わるもの:モデル、プロバイダ、サンドボックスベンダー、デプロイターゲット。
アーキテクチャは、変わるものが変わらないものに決して触れないように設計されている。
それが賭けだ。正しい賭けだ。
この記事を読んで、私がどのようにエージェントや一般的なもののために構築しているかを探求していただけたなら幸いです ❣️
免責事項
この記事は著者が調査・執筆し、Minimax-M2.7 が編集しました。サムネイルは Pinterest から取得しました。
Harrison Chase 「メモリはオープンであるべき!」 —
https://x.com/hwchase17/status/2046308913939919232Harrison
Chase :「あなたのハーネス、あなたのメモリ」 —
https://www.langchain.com/blog/your-harness-your-memory
Vivek Trivedi :「エージェントハーネスの解剖学」 —
https://www.langchain.com/blog/the-anatomy-of-an-agent-harness





