メインコンテンツへスキップ
  1. 記事/

Gordonの構築:DockerのAIエージェント

Nuno Coração
著者
Nuno Coração
Principal Product Manager @ Docker
目次

この1年、私はGordon - DockerのAIエージェント - を開発するチームの一員として活動してきた。最近Docker Desktopを使ったことがあるなら、きっと見たことがあるだろう。サイドバーのGordonアイコンをクリックするか、ターミナルでdocker aiを実行すれば、コンテナ、イメージ、環境を理解したエージェントが現れる。質問に答えるだけでなく、実際に行動するエージェントだ。

しかし、何百万人もの開発者がコード、コンテナ、イメージ、Composeファイル、ビルド、CIパイプラインを任せられるAIエージェントを作ることは、単純ではなかった。これは、どのような決断を下し、何を間違え、何を学んだか――Gordonを構築した物語だ。

Gordon v1
#

Gordon v1は、現在私たちが持っているようなエージェント向けツールの多くが存在する前に構築された。Gordonは当初から、docs.docker.com、サポート、Docker Desktopの中で、DockerのAI体験を担ってきた。最初のエージェントループはLangGraphで書き、DockerのドキュメントにRAGシステムを組み込んでGordonが実際のコンテンツに基づいた回答を返せるようにした。また「レシピ」と呼ぶ仕組みも構築した。これはDockerfileの生成やコンテナのデバッグといった特定タスクを処理する決定論的なコードパスだ。レシピはMCPやツール呼び出しの前身と言えるが、完全にカスタム実装だった。各レシピはユーザーの意図を検出し、適切なコンテキストを収集し、動作が確認済みの一連のステップを実行する、手作りのフローだった。

リリースされ、ユーザーに使われ、多くのことを学んだ。ユーザーが実際に何を必要としているか、LLMがどこで苦労するか、そしてあらゆるエッジケースをカバーしようとしたときに決定論的フローがいかに脆いかを。当時はGPT-4o世代のモデルを使っていた。十分な能力はあったが、今あるモデルとは比べものにならない。今では最も小さなモデルであるHaikuでさえ当時を上回る性能を持ち、それはまだ1年も経っていない。

しかし、Gordon v1が本番稼働している間に、世界は急速に動いた。MCPがツール統合の標準となった。ツール呼び出しがすべての主要モデルにネイティブで実装された。エージェントフレームワークが成熟した。モデル自体が大きく進化した。自分たちが構築したものと今や可能なものとの差は広がり続けた。

そこで、v1で学んだすべてと、リリース以来登場した新しい標準やインフラを組み合わせ、Gordonを一から作り直すことにした。

基盤
#

再構築にあたって最初の問いは根本的なものだった。何の上に構築するか?

LangGraphのスタックを反復改善する選択肢もあったが、私たちはオープンソースのAIエージェントランタイムとしてdocker-agent(当初はcagentと呼んでいた)を開発していたため、自分たちのプロダクトを自分たちで使うことが理にかなっていた。

docker-agentはYAMLでエージェントを宣言的に定義する方法を提供する。モデル、指示、ツール、そしてエージェント同士の協調方法を記述できる。会話ループ、ツールのディスパッチ、コンテキストウィンドウを管理する命令型コードを書く代わりに、エージェントが何をすべきかを記述し、残りはランタイムに任せる。ほぼ全体がGoで書かれており、Docker CLIプラグインとして提供される。docker agent rundocker agent newなどのコマンドはDockerのワークフローにネイティブな感覚だ。

Gordonにとってこれはイテレーションを速くすることを意味した。システムプロンプトを変更したい? YAMLを編集すればいい。新しいツールを追加したい? ツールセットに追加する。モデルを変えたい? 1行変えるだけ。カスタムコードの再デプロイも、パイプラインの再構築も不要。エージェント定義がプロダクトそのものだ。

docker-agentで構築する最大の利点の一つはディストリビューションだ。エージェント定義はOCIアーティファクトとしてパッケージ化・共有される。これはDockerがコンテナイメージに使っているのと同じフォーマットだ。つまり、docker agent pushで新バージョンのGordonをDocker Hubにプッシュし、docker agent pullで受け取ることができる。アップデートはコードを一切再ビルドせずに即座に配信できる。なぜならエージェントループはアプリケーションに焼き込まれていなく、ランタイムの中に存在するからだ。GordonのデFINITIONはDocker Hub上のYAMLファイルにすぎない。新バージョンをプッシュすれば、すべてのDocker Desktopインストール環境がそれを取得する(実際はもう少し複雑だが、要点は伝わるだろう)。バイナリの更新も、アプリストアのレビューも、マイグレーションスクリプトも不要だ。ランタイム(docker-agent)とエージェント定義(YAML)の分離こそが、スケールで機能する仕組みを実現している。

docker-agentにはビルトインのツールセットが付属している。ファイルの読み書き用のfilesystem、コマンド実行用のshell、推論スクラッチパッド用のthink、タスク追跡用のtodo、セッション間の永続化用のmemoryだ。さらに、任意のMCPサーバーをツールとして接続できる。YAMLの中でカスタムスクリプトツールを直接定義することもできる。シェルスクリプトやAPIエンドポイントをラップして、型付き引数とともにエージェントに公開するのだ。

docker-agentを使うことで、Gordonはランタイムがすぐに提供するすべての恩恵を受けられる。マルチプロバイダーサポート(OpenAI、Anthropic、Gemini、Bedrock、Mistral、さらにDocker Model Runner経由のローカルモデル)、MCPインテグレーション、複数の検索戦略を持つビルトインRAG、サブエージェントとハンドオフによるマルチエージェントオーケストレーション、そしてOCIベースのディストリビューション。docker-agentが改善されれば、Gordonも良くなる。そして、GordonがDockerエージェントの限界を押し広げれば、ランタイム全体が改善される。

私たちはdocker-agentを使ってdocker agentを構築している。これはキャッチフレーズではなく、実際の開発方法だ。

ユーザーが本当に求めるものを理解する
#

AIエージェントを作るのは簡単だ。本当に役立つものを作るのは難しい。その違いは、ユーザーが実際に何を求めているかを理解することにある。

初期の段階で、私たちは人々がDockerをどのように使うかを分析することに多くの時間を費やした。フォーラムでどんな質問をするか。ドキュメントで何を検索するか。どこで詰まるか。Gordon v1がすでにdocs.docker.com、サポート、Docker Desktop内のAIアシスタントとして稼働していたため、二つの貴重なデータソースがあった。ドキュメントとサポートのインタラクション、そしてv1セッションからの実際のユーザーインテントデータだ。何をGordonに頼んだか、どのレシピが起動されたか、どこで成功し、どこで失敗したか。

パターンは明確だった:

  • 「なぜコンテナが起動しないのか?」 - デバッグが最も多いユースケースだ。終了コード、ログエラー、ネットワーク問題、パーミッション問題。
  • 「これをコンテナ化するにはどうすればいいか?」 - アプリを持っていて、良いDockerfileが欲しい。チュートリアルにある汎用的なものではなく、自分のプロジェクト構造を理解したものを。
  • 「DockerでXをするにはどうすればいいか?」 - コマンドを知っていれば簡単だが、知らなければドキュメントを調べなければならない日常的な操作。

この3つのカテゴリーがすべてを形作った。Gordonは偶然Dockerについて知っているだけの汎用チャットボットではない。デバッグ、構築、管理というワークフローを中心に特別に設計されたエージェントだ。すべてのツール、すべてのプロンプト、すべてのUXの決定がここから生まれる。

また、ユーザーは整理された明確な質問をしないことも学んだ。エラーメッセージを貼り付ける。原因ではなく症状を説明する。不完全なコンテキストを与える。優れたエージェントはキーワードのパターンマッチングだけでは不十分で、意図を理解し、必要に応じて明確化のための質問をし、自分で調査を行う必要がある。

エージェントの構築
#

docker-agentをランタイムとして採用し、ユーザーのニーズを明確に把握した上で、構築を開始した。その後は数週間の急速なイテレーションが続き、エージェントは過程で劇的に変化した。GordonはDocker Hub上のOCIアーティファクト(docker/gordon)として配布されており、cagent pull docker/gordon:<tag>で任意のバージョンを取得して完全なエージェント定義を読むことができる。バージョン履歴の中に、その進化が記録されている。

マルチエージェントの群れから単一エージェントへ
#

Gordon v2の最初の試みは野心的だった。9つの特化したサブエージェントを持つマルチエージェントアーキテクチャを設計した。Dockerの専門家、コーディングの専門家、デプロイの専門家、Kubernetesスペシャリスト、ネットワーキングエージェント、セキュリティエージェント、GitHub連携エージェント、DHIマイグレーション専門家、さらにNotionエージェントまで。ルートエージェントはオーケストレーターとして機能し、ユーザーのリクエストを分析して適切なスペシャリストに委任し、チーム全体のレスポンスを調整する設計だった。共有のTodoによってエージェント間でコンテキストを引き継いだ。

理論上は優雅だった。実際には遅く、予測不能だった。委任によってレイテンシーが増した。オーケストレーターが間違ったサブエージェントを選ぶことがあった。ハンドオフでコンテキストが失われた。エージェントを追加すればするほど、システム全体の動作を把握することが難しくなった。

そこで統合した。ほぼすべてを、1つの慎重に設計されたシステムプロンプトを持つ単一のルートエージェントに移した。生き残った唯一のサブエージェントはDHIマイグレーションスペシャリストだ。そのワークフローは独自のエージェント、独自のツール、独自の指示を持つのに十分なほど本当に独立しているからだ。それ以外のすべて、Docker操作、デバッグ、コンテナ化、一般的な開発サポートはルートエージェントに集約された。

結果はより速く、より予測可能で、イテレーションしやすくなった。1つのエージェント、1つのプロンプト、何かが問題になったときに調べる場所が1つ。

モデルの選択
#

モデルの選択も変化した。v2の初期ビルドはClaude Sonnet 4.5で動いていた。強力なモデルだが、Gordonが稼働するスケールではコストが高い。プロンプトとツールを洗練させていく中で、Claude Haiku 4.5でも同等の品質を得られることがわかった。より小さく、速く、安価なモデルだ。コツはより良いプロンプトに投資することだった。指示を改善するたびに、より具体的なツールの説明、より明確な動作ルール、より良い例を加えることで、SonnetとHaikuの差は私たちのユースケースでは消えていった。

Gordonは現在、ほとんどのインタラクションでHaiku 4.5で動いている。速度の差は顕著で、レスポンスはきびきびとしており、ツール呼び出しの解決が速く、会話あたりのコストが大幅に下がった。docker-agentのマルチプロバイダーサポートにより、YAMLの1行変更でモデルを切り替えられるため、新しいモデルが出るたびに常にテストしている。

プロダクト開発としてのプロンプトエンジニアリング
#

最大の驚きは、プロダクトのどれだけ多くの部分がシステムプロンプトに存在するかだった。Gordonのプロンプトは数段落の指示ではなく、アイデンティティ、コミュニケーションスタイル、ファイルアクセスのパターン、ナレッジベースの使用方法、レスポンスのサイズ感、Dockerfileのベストプラクティス、デバッグのワークフロー、安全ルールを網羅した詳細な仕様書だ。

今日の実際のGordon定義はこのようになっている:

version: "2"

models:
  brain:
    provider: anthropic
    model: claude-haiku-4-5-20251001

agents:
  root:
    model: brain
    description: Gordon - Docker Agent
    instruction: |
      You are Gordon, an AI assistant created by Docker Inc.,
      specialized in Docker and Docker-related products, tools,
      and technologies...
    sub_agents:
      - DHI migration
    toolsets:
      - type: api
        api_config:
          name: knowledge_base
          endpoint: https://ai-backend-service.docker.com/docs
          ...
      - type: filesystem
      - type: shell
      - type: fetch
      - type: todo

  DHI migration:
    model: brain
    description: Migrates a Dockerfile to use Docker Hardened Images
    toolsets:
      - type: api
        api_config:
          name: get_image_tags
          endpoint: https://ai-backend-service.docker.com/dhi
          ...
      - type: filesystem
      - type: shell

プロンプトは常にイテレーションし続けた。失敗のパターンを見つけるたびに、Gordonが過度に長くなる、間違ったツールを選ぶ、不必要な明確化の質問をする、穴埋め言葉を使うなど、それに対処するものを追加した。新しいevalを追加し、新しい指示を加えた。プロンプトは実際のユーザーインタラクションとevalの失敗から有機的に成長した。美しいコードではないが、機能する。そして実はもう、これらのプロンプトのほとんどを手作業で書いてはいない。evalの話の後に詳しく説明しよう。

ユーザーエクスペリエンス
#

AIエージェントのUXはチャットボットとは根本的に異なる。チャットボットはテキストを返す。エージェントは行動したい。コマンドを実行し、ファイルを編集し、設定を作成する。それがインタラクションの設計方法をすべて変える。

私たちが辿り着いたコアの原則: 見せてから実行する

Gordonは何をしようとしているかをまず正確に見せずに何も実行しない。シェルコマンドを実行したい? コマンドが表示される。Dockerfileを編集したい? diffが表示される。コンテナを停止したい? どれかが表示される。すべてのアクションには明示的な承認が必要だ。

これは単なる安全機能ではなく、信頼を構築するメカニズムだ。Gordonを初めて使うとき、すべてのアクションを承認する。時間が経つにつれ、Gordonが良い判断をするのを見てきたため、信頼するようになる。より素早く承認するのは、注意が薄れたからではなく、何をするかへの自信が生まれたからだ。

Gordonを2つの場所で利用できるようにした。Docker Desktop(GUI)とCLI(docker ai)だ。Desktopの体験は視覚的で、会話の横にコンテナ、イメージ、ログが表示される。CLIの体験はターミナルで生活する開発者のためのものだ。同じエージェント、同じ機能、異なるコンテキスト。

意図的に避けたこと: 自律モード。Gordonは裏で10個のことを実行しない。あなたが見ていない間に動くことはない。協調型エージェントであり、あなたの代わりではなく、あなたと一緒に働く。AIツールが監督なしにインフラに変更を加えることに開発者が正当に懐疑的な世界では、これは重要だ。

ツール: Gordonが実際にできること
#

ツールのないLLMはただのテキスト生成器だ。Gordonをエージェントたらしめているのは、行動を取る能力だ。そして適切なツールを整えることが、このプロジェクトで最も難しい部分の一つだった。

Gordonのアーキテクチャはクライアントとサーバーに分かれている。バックエンドはDockerのサーバー上にあり、クライアントはDocker Desktopにバンドルされてユーザーのマシン上で動作するCLIだ。クライアントはローカルアクセスを担当し、ファイルの読み取り、コマンドの実行、Dockerデーモンとの対話を行う。バックエンドはLLMオーケストレーションを担当する。Docker Desktop経由でGordonを使う場合、ユーザーはアクセスを制限するための作業ディレクトリを選択できる。あるいはデフォルトのディレクトリが使われる。ターミナルからdocker aiを使う場合は、現在のディレクトリで動作する。

Gordonのコアツールセットは驚くほどシンプルだ:

  • Filesystem - ユーザーの作業ディレクトリ内のファイルの読み取り、書き込み、編集、一覧表示。Gordonがプロジェクト構造を確認し、Dockerfileを読み、新しい設定を書くための仕組みだ。
  • Shell - ユーザーのターミナルでコマンドを実行する(承認付き)。これが主力だ。Shellを通じて、Gordonはdocker builddocker compose updocker scoutkubectlgitなど、ユーザーのマシンにインストールされているものなら何でも実行できる。Dockerコマンドごとに専用の統合を構築する代わりに、エージェントにシェルアクセスを与え、開発者がすでに持っているCLIツールを使わせる。
  • Fetch - ドキュメント、APIリファレンス、または質問への回答に必要なWebコンテンツのために外部URLへHTTPリクエストを送る。
  • Todo - 複雑なリクエストを分解して体系的に処理できるよう、マルチステップのタスクを追跡する。
  • Knowledge base - Dockerのドキュメントバックエンドを照会するカスタムAPIツール。v1以来、Dockerのドキュメントに独自のRAGパイプラインを構築しており、それはGordonだけでなくドキュメントアシスタントやサポートにも使われている。Gordonはこの共有インフラを通じて最新のドキュメント、ベストプラクティス、一般的なパターンにアクセスできる。
  • DHI migration - DHI互換のイメージタグを解決するAPIツールを含む独自のツールセットを持つ専用サブエージェント。DockerfileをDocker Hardened Imagesに移行する。

Gordonのパイプラインの最初のステップ、ユーザーが何を求めているかを理解し、どのツールを使うかを判断することは、LLMによるツール呼び出しを通じて行われる。シンプルに聞こえるが、最も多くの実験時間を費やした領域の一つだ。

学んだこと:

ツールの説明は想像以上に重要だ。 曖昧な1行の説明では不十分だ。LLMには各ツールをいつ使うかの例を含む詳細な説明が必要だ。より説明的なツール定義がツール選択の精度を劇的に改善することがわかった。

ツールを追加すると壊れることがある。 これは直感に反した。新しいツールを追加すると、LLMが既存のツールを正しく使わなくなることがあった。ツールセットは単なるリストではなく、意思決定空間であり、拡張するとモデルがどのツールを選ぶかについての推論が変わる。

モデルによって動作が異なる。 ツール呼び出しはプロバイダー間で標準化されていない。あるモデルでうまく機能するものが別のモデルでは失敗することがある。GPT-4に最適な説明がClaudeを混乱させる場合があり、その逆もある。プロバイダー間でテストし、時にはモデルごとに説明を調整する必要があった。

既存のナレッジインフラを活用する。 v1からDockerのドキュメントに独自のRAGパイプラインを構築し、それ以来ドキュメントアシスタント、サポート、Gordonを動かしてきた。v2ではこれを再発明する必要はなかった。GordonをAPIツール経由で同じバックエンドに接続するだけだった。何年もかけてインデックス化されたドキュメントが、本番環境でバトルテスト済みで、1回のAPI呼び出しで利用できる。

評価(Evals)
#

AIエージェントについて知っておくべきことがある。微妙な形で壊れる。若干間違った回答をするチャットボットは面倒だ。間違ったコマンドを実行するエージェントは危険だ。Evalはオプションではなく、必須だ。

docker-agentには評価機能がビルトインされている。ワークフローはセッションの記録から始まる。Gordonと通常通りやり取りし、ある会話が良いテストケースだと判断したら、evalとして保存する。各evalは、ユーザーメッセージ、期待されるツール呼び出し、評価基準をキャプチャしたJSONファイルだ。評価基準は、レスポンスが満たすべき関連性ステートメント、期待されるレスポンスサイズ、呼び出すべきツール、作成すべきファイルを含む。これらのevalは分離のためDockerコンテナ内で実行される。各evalはクリーンな環境を得るため、結果は再現性がある。

docker agent evalはフルスイートを実行し、複数の次元でスコアを付ける。ツール呼び出しの正確さ(Gordonは正しいツールを呼び出したか?)、関連性(レスポンスは実際に質問に答えているか?)、レスポンスのサイズ感、そしてサブエージェントのハンドオフ。LLMジャッジが関連性基準を評価するため、単純な文字列マッチングではなく、微妙な動作をテストできる。

これが退行を検出する方法だ。Gordonへのすべての変更、プロンプトの更新、ツールの変更、モデルの入れ替えは、リリース前にフルスイートで評価される。エージェントシステムではすべてが相互に接続されている。ツールの説明への小さな変更が予期しない動作の連鎖を引き起こすことがある。新しいモデルバージョンがリリースされたら、切り替える前にスイートを実行する。盲目的にアップグレードしない。

一つの厳しい教訓: evalのカバレッジはevalの数より重要だ。初期の頃、evalはメインのユースケースをカバーしていなかった。コアワークフロー(コンテナのデバッグ、Dockerfileの生成、Docker質問への回答)が十分に表現されていない中で、エッジケースのためにGordonを最適化していた。ほとんどのユーザーを実際に改善することなくスコアを上げていた。v1のデータから得た実際の使用パターンにevalスイートをリバランスすると、改善がユーザーの実際の体験と一致し始めた。

エージェントを使ってエージェントを改善する
#

プロンプトを手作業で書いていないという話に戻ろう。実際のところ、これはどのように機能するか。

私たちはカスタムエージェントを構築した。Claude Opus 4.6のようなより強力なモデルで動き、仕事はGordonのシステムプロンプトを改善することだ。ワークフロー: Gordonの現在のエージェント定義、失敗しているevalのセット、そして結果を与える。エージェントは失敗を分析し、プロンプトの変更を提案し、更新されたYAMLを出力する。新バージョンに対してevalスイートを実行する。スコアが改善され、退行がなければ、リリースする。

これにより緊密な改善ループが生まれる。Gordonがファイルをすぐに読む代わりに明確化の質問ばかりすると報告があった? そのためのevalを追加し、オプティマイザーエージェントに失敗を指摘させ、適切なプロンプトの変更を見つけさせる。「filesystemツールを使ってファイルを直接読むこと。ユーザーにコンテンツを貼り付けるよう頼まないこと。」のようなルールを追加するかもしれない。これはまさに、良いエージェントと苛立たしいエージェントの差を生む、具体的で実行可能な指示だ。

より強力なモデルを「教師」として使い「生徒」を改善することは意図的だ。Opusには微妙な動作上の問題を理解し、Haikuを正しい方向に導く正確な指示を作成する推論能力がある。すべてがエージェントで構成されている。

Gordon のプロンプトにある詳細な動作ルールのほとんど、禁止されているフィラーワード、ファイルアクセスのパターン、レスポンスサイジングのガイドライン、デバッグシーケンスは、人間ではなくオプティマイザーエージェントによって書かれるか洗練された。私たちは方向性を設定し、evalを通じて何が良いかを定義する。エージェントがそこへの到達方法を見つける。

次のステップ: メモリ
#

現在、Gordonはセッションをまたいでステートレスだ。すべての会話は新しく始まる。Docker Desktopを閉じると、Gordonはすべてを忘れる。プロジェクト構造、デバッグしていた問題、好みのDockerfileパターン。

メモリが次のフロンティアだ。Gordonにセッションをまたいでコンテキストを覚える能力を与える取り組みを進めている:

  • プロジェクトコンテキスト - Gordonがプロジェクト構造、Docker設定、使用するパターンを覚えておくべき
  • インタラクション履歴 - 先週問題を解決したなら、似た問題が出たときにGordonがそれを知っているべき
  • ユーザーの好み - 常にマルチステージビルドを使うなら、Gordonはデフォルトでそれを提案すべき

これは聞こえるより難しい。AIエージェントのメモリは単純に「チャット履歴を保存する」ことではない。何を覚える価値があるか、どうやって効率的に取り出すか、どうやって陳腐化を防ぐかを決めることだ。無関係なコンテキストを表面化するメモリシステムは、メモリがない場合より悪い。

docker-agentにはすでに構成要素がある。セッションをまたいでローカルデータベースに情報を永続化するmemoryツールセットがある。エージェントは作業中に事実を保存・取り出せる。パーツは揃っている。課題は自然に感じさせることだ。Gordonはプロンプトされなくても関連するメモリを表面化し、言われなくても好みを学習し、もはや関連性のないことを忘れるべきだ。Evaを構築する際に使ったスライディングウィンドウのように、でもよりスマートに。

目標はシンプルだ: Gordonは毎回すべてを再説明しなければならない見知らぬ人ではなく、あなたのプロジェクトを知るチームメンバーのように感じられるべきだ。


Gordonの構築は、私が取り組んだ中で最も挑戦的でやりがいのあるプロジェクトの一つだ。AIエージェントはまだ黎明期にある。ツールは急速に進化し、ベストプラクティスはまだ書かれている最中で、ユーザーの期待は新しいモデルリリースのたびに変化している。しかしコアの洞察は変わらない: 開発者が必要としているのは、もう一つのチャットボットではない。自分の環境を理解し、行動を取り、承認されたコマンド一つひとつを通じて信頼を勝ち取るエージェントだ。

Gordonを試したい場合は、最新のDocker DesktopにアップデートしてサイドバーのGordonアイコンを探すか、ターミナルからdocker aiを実行してほしい。

自分のエージェントを構築したい場合は、docker-agentをチェックしてほしい。オープンソースで、GordonがRunするのと同じランタイムだ。

関連記事