コーディングハーネスの構築に必要なすべての要素、エージェントループ、計画、サブエージェント、サンドボックス、メモリ、チェックポイントについて、段階的に解説します。
自分でコーディングエージェントを構築したことがある方なら、この流れをご存知でしょう。モデルにファイル操作用のツールとシェルを接続し、実際のコードベースを対象に動かすと、十数回のツール呼び出しで破綻します。
間違ったファイルを読み込み、途中で目標を見失い、もう必要のない出力でコンテキストを埋め尽くしてしまいます。
ところが、同じタスクを Claude Code に通すと、きれいに完了します。手っ取り早い結論としては、Anthropic が単により優れたモデルを持っているというものですが、その結論では実際の作業が行われている場所を見逃しています。
違いはハーネスにあります。ハーネスとは、モデルの周りに配置される通常のコードであり、計画、ツール実行、メモリ、安全性を処理します。モデルは次のステップを決定するだけです。
フルにハーネス化されたエージェントを図に描くと、次のようになります。

GIF
この図は一見複雑に見えますが、4 つのグループに分けられます。
- メモリ は、作業中のコンテキストと、セッションを超えて学習した事実をモデルに提供します。
- スキル は、エージェントがどのように動作すべきか、つまり従うべき手順、制約、ヒューリスティックをエンコードします。
- プロトコル は、エージェントをユーザー、ツール、他のエージェントに接続します。
- ハーネスコア は、サブエージェントのオーケストレーション、サンドボックス、評価器、承認ループ、可観測性、コンテキスト圧縮によって、これらすべてを統合します。
Anthropic はこの分割を、脳と手として説明しています。モデルは各アクションを選択する脳であり、ハーネスはそれを実行し、実行を軌道に乗せ続ける手です。
つまり、あなたのエージェントと Claude Code の差はモデルではなく、モデルを取り巻く仕組みにあります。
Claude Code は現在本番環境で最も有能なハーネスの 1 つであり、その図にあるレイヤーのうち、驚くほど少ないセットから構築されています。その仕組みのうちどれだけを自分で構築する必要があるかを確認するために、エージェントをオーケストレーションするためのオープンソースフレームワークである CrewAI で再構築しました。
予想以上に多くの部分が組み込み機能にマッピングされ、そうでない部分にこそ、実際のエンジニアリングが存在します。
レイヤーごとに構築していきましょう。まずコアループから始め、計画、サブエージェント、サンドボックス、メモリを積み重ねていきます。各ステップで、フレームワークの範囲と、あなたの作業が始まる場所を明確にします。
Claude Code のハーネスの仕組み
Claude Code の中心には、シンプルなエージェントループがあります。メッセージを送信すると、モデルが次に何をするかを決定し、直接応答するか、ツールを要求します。ツールを要求した場合、ツールが実行され、その結果が会話に戻され、モデルが再度決定します。
このプロセスは、モデルがそれ以上ツールを呼び出さずに最終回答を返すまで繰り返されます。
そのループの中で、モデルはファイルの読み取り、コードの編集、シェルコマンドの実行、テストの実行を行います。これらは別々のモードではありません。同じループ内の異なるツール呼び出しにすぎません。
ただし、ループだけでは信頼性の高いコーディングエージェントには不十分です。Claude Code は、その周りに計画、ファイルツール、サブエージェント、メモリ、および権限とサンドボックスシステムを追加します。これらのレイヤーはループを置き換えるのではなく、実際の作業に耐えるだけの安全性と信頼性を提供します。

これが、私たちが再構築するアーキテクチャです。まずコアループ、次に各レイヤーを重ね、各レイヤーを処理する CrewAI の機能にマッピングします。
コアエージェントループ
ループは、タスクが完了するまで同じシーケンスを実行します。
- モデルにタスクの実行を依頼します。
- モデルが直接応答するか、1 つ以上のツールを要求します。
- ツールが要求された場合は、それらを実行し、結果をモデルに返します。
- 更新された会話で繰り返します。
- モデルがツールを要求せずに応答した場合、タスクは完了です。

1while True:2 reply = model(messages, tools)3 calls = [b for b in reply if b.type == "tool_use"]4 if not calls: # plain text, no tool call: the job is done5 return reply.text6 messages += [reply, run_all(calls)]
各ツール呼び出しは 1 つのステップを完了し、モデルに新しい情報を提供し、次の決定にフィードされます。簡単な質問であれば 1 回の反復で終了するかもしれませんが、複雑なバグの修正や大規模なコードベースのリファクタリングでは、モデルが最終回答を生成するのに十分な情報を得るまでに数十回の反復が必要になることがあります。
CrewAI は、エージェントを作成するとすぐにこの実行ループを自動的に提供します。自分で while ループを実装する必要はなく、エージェントを定義してタスクを割り当てるだけです。
最初のエージェントの構築
簡単なバグ修正エージェントを作成しましょう。
1from crewai import LLM, Agent, Crew, Task23bug_fixer = Agent(4 role="Bug Fixer",5 goal="Find and describe the fix for the reported bug in the codebase.",6 backstory="You read directories and files to build an accurate picture of the code.",7 llm="claude-sonnet-4-6",8)910task = Task(11 description="Find the fix for {objective}.",12 expected_output="A short description of the fix and which file it belongs in.",13)1415result = Crew(agents=[bug_fixer], tasks=[task]).kickoff(16 inputs={"objective": "the overdraft bug in account.py"}17)
ここで理解すべき 3 つの概念があります。
- Agent は、役割、目標、LLM、ツールを通じて、誰が作業を行うかを定義します。
- Task は割り当てを記述します。
- Crew はエージェントとタスクをまとめます。kickoff() を呼び出すと、上記と同じ実行ループが実行されます。基盤となるモデルが Anthropic、OpenAI、Google、その他であっても同様です。
エージェントへのツールの付与
ツールは、テキストを生成するだけのモデルが実際にコードベースで作業できるようにするものです。ファイルの読み取り、書き込み、シェルコマンドの実行、外部 API の呼び出しを行います。
CrewAI には、ファイルシステムツールが標準で用意されています。
- FileReadTool はファイルを読み取ります。
- DirectoryReadTool はディレクトリを一覧表示します。
- FileWriterTool はファイルを書き込みます。
1from crewai_tools import DirectoryReadTool, FileReadTool, FileWriterTool23read_file = FileReadTool()4write_file = FileWriterTool()5list_dir = DirectoryReadTool()67filesystem_tools = [read_file, write_file, list_dir]
これらは外部メモリとしても機能します。大規模な検索結果をモデルのコンテキストウィンドウに保持する代わりに、エージェントはそれをファイルに書き込み、ファイル名だけを保持し、必要なときに読み戻すことができます。
これにより、コンテキストウィンドウが小さく保たれ、モデルがより集中できるようになります。これは Anthropic がコンテキストエンジニアリングと呼んでいるものです。

組み込みツールは一般的なワークフローのみをカバーします。より特殊なニーズには、@tool デコレータを使用して Python 関数をツールとして公開します。
docstring は説明書として機能し、ツールの機能、使用タイミング、期待される入力についてモデルに指示します。
1from crewai.tools import tool2import subprocess34@tool("run_tests")5def run_tests(path: str = "tests/") -> str:6 """Run the pytest suite at the given path and return the result."""7 result = subprocess.run(8 ["pytest", path, "-q"], capture_output=True, text=True, timeout=1209 )10 output = result.stdout + result.stderr11 return output[-4000:] if len(output) > 4000 else output
長時間実行タスクの計画
タスクが複雑になるにつれて、単純な実行ループでは元の目標を見失い始めます。十分なツール呼び出し、ファイル読み取り、中間結果の後、コンテキストが埋まり、目標はその後に続くすべてのものに押し流されてしまいます。
この緩やかな劣化は、コンテキスト腐敗と呼ばれています。
計画はこれに直接対処します。エージェントは作業を開始する前に段階的な計画を構築し、実行中はその計画をコンテキストに保持します。
計画は作業を実行するわけではありません。これは、モデルを元の目標に結び付けるためのロードマップであり、Claude Code の ToDo リストと同じ役割を果たします。

CrewAI では、これをクルーレベルで planning=True と設定することで追加します。実行前に計画を生成し、タスクの進行中も利用できるようにします。
1from crewai import Crew, LLM23crew = Crew(4 agents=self.agents,5 tasks=self.tasks,6 planning=True,7 planning_llm=LLM(model="gpt-4o-mini"),8)
注: デフォルトでは、CrewAI は計画に gpt-4o-mini を使用します。このステップには任意の LLM を自由に選択できます。
個々のエージェントは、reasoning=True を使用して自身の作業について推論することもできます。
1from crewai import Agent23bug_fixer = Agent(4 role="Bug Fixer",5 goal="Find and describe the fix for the reported bug in the codebase.",6 backstory="You read directories and files to build an accurate picture of the code.",7 tools=[FileReadTool()],8 reasoning=True,9 max_reasoning_attempts=3 # Optional: Set a maximum number of reasoning attempts10)
計画と推論は異なる問題を解決します。計画はタスク全体の高レベルのロードマップを構築するのに対し、推論は 1 つのエージェントが行動する前に自身のアプローチを検討する時間を与えます。
推論が有効な場合、エージェントは次のことを行います。
- タスクを熟考し、実行計画を草案します。
- 計画の準備ができているかどうかを評価します。
- 必要に応じて計画を洗練し、満足するか max_reasoning_attempts に達するまで繰り返します。
- 最終化された推論計画を実行前にタスクに注入します。

これらを組み合わせることで、エージェントは長時間実行タスクに集中し続け、元の目標からの逸脱を減らします。
サブエージェントによる委任
計画によってエージェントの集中力は維持されますが、モデルが保持しなければならない情報量は減りません。大規模なコードベースでは、適切に計画されたタスクでも 1 つのコンテキストウィンドウを超える可能性があります。
1 つのバグを見つけるために数十のファイルを読む必要があるかもしれませんが、メインエージェントがそれらすべてをメモリに保持する必要はありません。
サブエージェントは、委任によってこの問題を解決します。メインエージェントは特定のタスクをヘルパーエージェントに任せ、ヘルパーエージェントは自身のコンテキストで作業し、短いサマリーを返します。メインエージェントは結論のみを参照し、中間ステップは参照しません。

CrewAI は、階層的ワークフローを通じてこれをサポートします。マネージャーエージェントが専門エージェントに委任し、それらの結果を統合します。
先ほどのセットアップでは、1 つのバグ修正エージェントがすべての重労働を行っていました。ここでは、作業を 1 人のマネージャーと 3 人の専門家に分割しましょう。
- Codebase Explorer はコードを探索し、リポジトリをマッピングします。
- Software Engineer は要求された変更を実装します。
- Test Runner はサンドボックスでテストを実行し、合格/不合格を報告します。
- Engineering Lead は 3 人の専門家を監督します。

1from crewai import Crew, Agent, Task, Process23explorer = Agent(4 role="Codebase Explorer",5 goal="Map the repository and surface the files relevant to the task.",6 backstory="You read directories and files to build a picture of the code.",7 tools=[read_file, list_dir],8 llm=llm,9) # Same for other two specialist agents1011manager = Agent(12 role="Engineering Lead",13 goal="Break the request into steps and delegate each to the right specialist.",14 backstory="You decide who does what, review tests, finish once change is done.",15 llm=llm,16 allow_delegation=True,17)1819crew = Crew(20 agents=[explorer, coder, tester],21 tasks=[task],22 manager_agent=manager,23 process=Process.hierarchical,24)
注意すべき点として、allow_delegation はデフォルトで無効になっているため、マネージャーで明示的に有効にする必要があります。
サンドボックス: エージェント実行の保護
シェルアクセス権を持つエージェントは破壊的なコマンドを実行する可能性があり、モデルに何かをしないように指示することは保護策にはなりません。
実際の保護は 2 つのレイヤーから得られます。
- 機密性の高いアクションに対して承認を必要とする権限システム。
- 承認されたコマンドでもホストマシンに影響を与えないように実行を分離するサンドボックス。
Anthropic も同じアプローチを使用しています。コード実行をサンドボックスに移動することで、ユーザーがアクションを承認する必要がある頻度を減らしながら、ホストシステムを保護します。

CrewAI でのサンドボックス化
ホストマシンではなくサンドボックス内でコードを実行することは、この 2 番目のレイヤーを適用します。この設定では、コードは E2B 内で実行されます。E2B はセッションごとに新しい VM を起動し、セッション終了後に破棄します。
シェルコマンドと Python は、その分離された環境内で完全に実行されます。

1from crewai_tools import E2BExecTool, E2BPythonTool2sandbox_tools = [E2BExecTool(), E2BPythonTool()] # run tests / run code
ヒューマンインザループの承認
Task に human_input=True を設定すると、クルーは回答を生成した後で一時停止します。出力を確認し、承認するか、別の反復のために送り返します。
そのタスクの実行に達すると、CrewAI は標準入力からフィードバックを待ちます。
1from crewai import Task23task = Task(4 description=(5 "In the working directory ./workspace, {objective}. "6 "Explore the code first, make the change, then run the tests and report."7 ),8 expected_output="A summary of the files changed and the final test output.",9 human_input=True,10)
クルーがターミナルではなく Web アプリやチャットインターフェースの背後で動作している場合、CrewAI の Webhook ベースのヒューマンインザループシステムが同じレビューステップを処理します。
メモリとチェックポイント
デフォルトでは、エージェントは実行が終了するとすべてを忘れます。翌日戻って同じプロジェクトの別のバグを修正しようとすると、ゼロから始まります。
エージェントが実行間で情報を引き継ぐことを可能にする 2 つのメカニズムがあり、それぞれ異なる目的を果たします。
- チェックポイント は、実行中にエージェントの状態を保存します。これにより、中断後に再開したり、別のパスに沿って同じポイントから続行したりできます。
- 永続メモリ は、個別の会話にわたって事実を保存します。たとえば、「最後に必ずコードをフォーマットしてから終了する」といったプロジェクトの好みなどです。

CrewAI のメモリ
CrewAI は、個別の短期、長期、エンティティ、外部メモリタイプではなく、統一された Memory インターフェースを提供します。保存時には、LLM を使用して重要な詳細を特定し、整理し、後で取得可能にします。
クルーに memory=True を設定すると、実行間でメモリが保持されます。各タスクの後、CrewAI は出力から有用な事実を抽出して保存し、将来の実行では関連するメモリを取得してタスクプロンプトに追加します。

1from crewai import Crew23crew = Crew(4 agents=[explorer, coder, tester],5 tasks=[task],6 memory=True,7)
クルー内のすべてのエージェントは、そのメモリを共有します。ただし、エージェントに独自のメモリが与えられている場合は除きます。
CrewAI のチェックポイント
チェックポイントは、エージェントの進行状況のスナップショットです。設定、タスク状態、メモリ、中間結果、入力、実行履歴が含まれます。
デフォルトでは、CrewAI はタスクが終了するたびにチェックポイントを作成します。これにより、ワークフローが中断された場合にそのポイントから再開できます。
チェックポイントは、2 つの組み込みストアのいずれかに保存できます。
- JsonProvider は各チェックポイントを個別の JSON ファイルとして保存します。手動で読み取り、検査するのが簡単です。
- SqliteProvider はすべてのチェックポイントを 1 つの SQLite データベースに保存します。頻繁なチェックポイントや大規模なワークロードに対してより適しています。

1from crewai import Crew23crew = Crew(4 agents=[explorer, coder, tester],5 tasks=[task],6 checkpoint=True,7)
Crew、Flow、Agent はすべて checkpoint 引数を受け入れ、子は独自の値を設定しない限り親から継承します。
すべてをまとめる
以下は、実行ループ、ツール、計画、サブエージェント、サンドボックス、メモリが連携して動作する、1 つのタスクに対する完全なハーネスです。
1from crewai import Agent, Crew, LLM, Process, Task2from crewai.tools import tool3from crewai_tools import (DirectoryReadTool, FileReadTool, FileWriterTool,4E2BExecTool, E2BPythonTool)56llm = LLM(model="anthropic/claude-sonnet-4.6")78list_dir = DirectoryReadTool(directory="./workspace")9filesystem_tools = [FileReadTool(), FileWriterTool(), list_dir]10sandbox_tools = [exec_tool, E2BPythonTool()]1112@tool("run_tests")13def run_tests(path: str = "tests/") -> str:14 """Sync ./workspace into the sandbox, then run pytest there."""15 return E2BExecTool().run(command=sync_and_test_command(path))1617explorer = Agent(role="Codebase Explorer", goal="Map repo, surface relevant files.",18 tools=[read_file, list_dir], llm=llm)19coder = Agent(role="Software Engineer", goal="Implement requested change.",20 tools=filesystem_tools, reasoning=True, llm=llm)21tester = Agent(role="Test Runner", goal="Run tests in sandbox, report pass/fail.",22 tools=sandbox_tools + [read_file] + [run_tests], llm=llm)23manager = Agent(role="Engineering Lead", goal="Delegate steps, finish once tests pass.",24 allow_delegation=True, llm=llm)2526task = Task(27 description="In ./workspace, {objective}. Explore, edit, test, report.",28 expected_output="Summary of changes and test output.", human_input=True,29)30crew = Crew(31 agents=[explorer, coder, tester], tasks=[task],32 manager_agent=manager, process=Process.hierarchical,33 planning=True, memory=True, checkpoint=True,34)35result = crew.kickoff(inputs={"objective": "fix failing tests in account.py"})
エージェントハーネスは、成功を自動的にチェックできる場合に最も評価が容易です。テストスイートはエージェントに具体的な目標を与えるため、計画、編集、テスト、合格するまで繰り返すことができます。
そこで、このハーネスを小さなコードベースでテストしました。BankAccount クラスに 2 つの実際のバグと 5 つのテストがあり、そのうち 3 つが失敗していました。ルールは、実装のみを修正し、テストは修正しないことでした。
これは、Anthropic が内部でコーディングエージェントを評価する方法を反映しています。公開されている例の 1 つでは、Claude が claude.ai インターフェースのクローンを、大規模な失敗テストスイートに対して再構築しています。
ここでは、ハーネスによってプロジェクトが 3 つ失敗、2 つ成功から、すべて 5 つ成功に変わりました。実装のみのルールにより、失敗テストを編集または削除するショートカットは封じられました。

依然としてあなたの仕事である部分
システムの一部の要素は、フレームワークが自動的に構築してくれるものではありません。
- プロンプト。 各エージェントの動作は、役割、目標、バックストーリーから決まります。これらを適切に設定するには、テストと反復が必要であり、設定フラグで代用できるものではありません。
- 実行環境。 サンドボックス(E2B または自己管理 VM)は、セットアップして接続する必要があります。
- ツールの選択。 各エージェントにどのツールを与えるか、どのエージェントが何にアクセスできるかは、フレームワークが決定しない設計上の判断です。
ハーネス自体にもコストがかかります。計画、サブエージェント、ループはすべて API 呼び出しを追加するため、複雑なエージェント設定は、単一のモデル呼び出しで直接解決できたタスクよりも高価になる可能性があります。
また、長期的な制限も念頭に置く価値があります。モデルが改善されるにつれて、一部の足場は不要になります。現在ハーネスに組み込まれているものの一部は、今日のモデルの制限に対する回避策であり、永続的な要件ではないからです。
Anthropic は当初、コンテキストリセットを使用して Claude Sonnet 4.5 がタスクを早期に終了するのを防いでいましたが、より高性能な Claude Opus 4.5 では不要になりました。

まとめ
以上が全体像です。コーディングエージェントの能力は主にハーネスにあり、オーケストレーションフレームワークは、想像以上に多くのハーネス部分を提供してくれます。
ループ、計画、委任、サンドボックス、メモリはすべて設定として提供され、プロンプト、実行環境、ツールの選択はあなたの責任として残ります。
このハーネスを自分のコードベースで実行したい場合は、CrewAI のドキュメントでここで使用したすべての機能がカバーされており、フレームワークは完全にオープンソースです。
お読みいただきありがとうございます!
それでは、よいコーディングを! :)





