Shippy の教訓から学ぶエージェント構築
Hugging Face Blog は、Shippy の開発経験から得た教訓を共有し、AI エージェント構築における設計原則と実装の難易度について分析した。
キーポイント
エージェント設計の複雑性への洞察
単純なプロンプトエンジニアリングを超え、信頼性と安定性を確保するためのアーキテクチャ設計が不可欠であることを示唆している。
Shippy の開発プロセスからの教訓
実際の製品開発で遭遇した課題を通じて、エージェントの自律性制御やエラーハンドリングの実践的なアプローチを共有している。
実用化に向けた技術的課題
理論上の可能性と現場での動作安定性のギャップを埋めるための具体的な技術的対策について言及している。
重要な引用
What building Shippy taught us about building agents
Hugging Face Blog shares insights from the development of Shippy
影響分析・編集コメントを表示
影響分析
この記事は、AI エージェント分野が理論段階から実用化フェーズへ移行する過程で直面する現実的な課題を浮き彫りにしており、開発者にとって重要な指針となる。特に Hugging Face という主要プラットフォームからの実践的知見は、業界全体の標準化やベストプラクティスの確立に寄与する可能性がある。
編集コメント
Hugging Face が自社の製品開発プロセスから得た知見を共有することは、業界全体にとって非常に価値のある実践的ガイダンスとなります。特にエージェント技術が実社会で広く採用される中で、こうした失敗と成功の経験則は開発者の意思決定に大きく寄与するでしょう。
- エージェントの解剖:スキル、魂、設定
- 非決定的なエージェントのための決定論的なツール
- サンドボックス化されたホスティングと分離
- モデルではなくエージェントを検証する
- 私たちの進むべき道
Shippy は、間違った答えが現実の重大な影響を及ぼすような高リスクな意思決定のために構築された海洋 AI エージェントです。ここではそのアーキテクチャと、Ai2 の他の環境プラットフォームへ引き継いでいる教訓について解説します。
ガーナの排他的経済水域(EEZ)に関するライブクエリに答える Shippy。回答には作業の過程が示されており、境界線の出典、データの更新日、クエリのタイムスタンプ、そして分析官が数値を一つひとつ検証できるよう Skylight マップへの深いリンクが含まれています。
海洋保護のような高リスクな運用ドメインで AI エージェントを構築する際、何よりも重要なのは信頼性です。海洋分析官にとって間違った答えは、巡視船を数マイルも誤った方向へ進ませることになり、すでに逼迫している貴重なリソースを浪費し、最悪の場合、人員の危険にさらす結果につながります。
そこで Skylight チームがリアルタイムの海洋ドメイン認識のための AI である Shippy を構築しようとした際、真の難所はモデルそのものではありませんでした。重要だったのは、正しく動作し、自身の限界を遵守し、多様なタスクにわたって耐えうるシステムを構築することです。そして、新しい衛星や船舶の信号が到着するたびに継続的に更新される Skylight のライブデータに対して、すべてを検証する必要がありました。これは単なる静止したスナップショットではなく、常に動き続ける生きたデータなのです。
エージェントの解剖学:スキル、ソウル、設定
Shippy のようなエージェントを構成する要素は、大きく分けて三つです。ソウル(Soul)、スキル(Skills)、そして設定(Config)です。
ソウルとは、Shippy の人格を定義し、行動の境界線を引くシステムプロンプトのことです。一方、スキルは、特定の種類のリクエストに対して Shippy がどのように対応すべきかを指示するものです。このソウルとスキルは、Docker イメージとして一体化されます。これはバージョン管理されたデプロイ可能なアーティファクトであり、Shippy が「何者であるか」を定義するものです。
残りのすべてが設定の領域です。ここでは、どのエージェントハネス(Shippy の場合はオープンソースフレームワークの OpenClaw)を実行するか、どの大規模言語モデル(LLM)を使用するか(現在は Claude Opus 4.6)、そしてランタイムの設定を指定します。API キーのような機密情報は実行時に注入されます。モデルやハネスの差し替えは、再構築ではなく設定の変更で済みます。
Shippy のスキルは、Claude Code や Codex などのコーディングツールと同じ agent-skills spec に従っています。これは構造化されたフロントマターを持つプレーンな Markdown ファイルです。これにより、各スキルが理解しやすく、バージョン管理され、修正も容易になっています。
現在 Shippy が備えているスキルは以下の通りです:
- Skylight API をクエリしてイベント(Skylight が検出する漁業や船舶間のトランスシップメントなどの船の行動)および船舶データを取得する
- 排他的経済水域(EEZ)と海洋保護区(MPA)の境界情報を検索する
- 船舶がブロードキャストする位置情報や移動信号である vessel track データを解釈する。これは、Atlantes などの Skylight のモデルが既に生成している活動分類に基づいています
- シッピーのチャット回答から、スカイライトマップ上の正確な場所へジャンプできるインタラクティブな地図リンクを生成する
例えば、「スカイライト API 照会スキル」は、特定エリアに関する質問に答えるための一連の流れをコード化しています。アナリストやユーザーが「先月のパナマ排他的経済水域(EEZ)での漁業活動を示してほしい」と尋ねると、このスキルの指示に従ってシッピーはまず、スカイライトの地域 API を通じて「パナマ EEZ」を境界ポリゴンとして特定します。座標を推測したりハードコードしたりするのではなくです。その後、その領域内で漁事象(Fishing Events)を検索し、結果をスカイライトマップへの深いリンク付きで整形して表示します。また、Global Fishing Watch や TMT などのパートナー企業から取得した船舶メタデータも併せて付与されます。
シッピーに投げかけられた一つの質問が、複数のスキルに同時に接続されることもあります。「コイバ山脈海洋保護区(MPA)付近で操業している船舶はありますか?」という問いには、データの照会にはスカイライトのスキルを、海洋保護区の境界情報にはパートナーである ProtectedSeas のデータベースを、そして船舶の行動解析には船舶軌跡スキルを活用します。これらすべてが、単一の対話ターン内で完結します。
「ソウル(核となる部分)」は、シッピーが行うことと行わないことを定義しています。船舶が法律違反をしているかどうかという法的判断を下すことはしません。それはエージェントではなく人間が決めるべきことです。また、データで裏付けられない推測を行うこともありません。これらの境界線はシステムプロンプトに明示的に記されており、微調整(ファインチューニング)に依存した暗黙的なルールではありません。そのため、監査が可能で、修正も容易です。
非決定論的なエージェントのための決定論的ツール
エージェントは非決定論的です。モデルが何を判断するかを完全に制御することはできませんが、モデルが頼るツール自体の挙動を予測可能にすることは可能です。
そのために Shippy は、API を直接呼び出すのではなく、専用 CLI を通じて Skylight と「対話」します。
当社の API には数十種類の入力タイプやネストされたフィルタオブジェクト、ページネーションカーソル、複雑な幾何学入力が存在します。初期のプロトタイプでは Shippy に API コールをゼロから構築させましたが、その結果、微妙なバグが次々と発生しました。具体的には、ページネーションの形式不備による結果の欠落、幾何学情報のエンコードエラー、フィルタタイプの誤解によって正しく見えるクエリが間違ったデータを返すといった問題です。
Skylight CLI はこうした複雑さを予測可能なインターフェースに集約します。Shippy は単一のコマンド(skylight events search with typed filter flags)を発行するだけで、認証処理、ページネーション管理、構造化された出力はすべて CLI が担当します。また、この CLI は自己文書化機能も備えています。詳細な --help 説明やエラーメッセージが充実しているため、エージェントも人間開発者も推測に頼らず、ミスを即座に修正して回復できます。
出力結果は常にローカルの JSON ファイルとして保存されます。シェルを介してパイプラインで流す方式では、初期段階において大量の結果セットがパイプバッファの制限に達したり、jq などの後続ツールを破損させたりする問題が発生しました。ディスクへの書き込みによりこれらの問題は回避でき、エージェントは後のステップでもプログラムを通じてクエリ結果にアクセスできるようになります。
CLI の下層には、標準化された API が用意されています。Skylight Events、船舶、地域、衛星画像、船舶の軌跡など、複数のリソースタイプが、検索と集計という共通の操作ペアを通じてアクセス可能です。API の入力と出力は、フィールドごとの説明を付与した型付きスキーマとして定義されています。
このように、型付き API、決定論的な CLI、そして CLI コマンドを参照するエージェントスキルという 3 つの層が積み重なっていることで、Shippy の各コンポーネントは独立してテストできます。API には専用のテストスイートが存在し、CLI は人間またはエージェントによって実行可能です。また、エージェントスキルは、基盤となる処理(プラムビング)を担う CLI コマンドを参照するため、Skylight API を利用するたびに Shippy がゼロから仕組みを作り直す必要がありません。各層が次の層で起こりうるミスを狭めることで、システム全体の信頼性が高まります。
隔離されたホスティング環境と分離
Skylight は、70 カ国以上にある数百の政府機関や NGO にサービスを提供しています。フィリピンの水産監視官には、その Skylight アカウントに限定された「関心領域(Areas of Interest)」、「船舶監視リスト」、「アラート設定」が用意されています。彼らが Shippy に質問した際、エージェントからの API 呼び出しは必ず該当者のデータのみを返す必要がありますし、会話履歴が他者に閲覧されることは絶対にあってはいけません。
Shippy の利用者は、それぞれ個別の一時セッション内でシステムと対話します。この仕組みを大規模かつ確実に運用することは、本プロジェクトにおける最も重要なエンジニアリング課題の一つでした。
そこで開発したのが「Mothership」と呼ぶエージェントホスティングプラットフォームです。これは、各ユーザーセッションごとに専用の Kubernetes デプロイメントを即時割り当てる仕組みです。ユーザーが会話を開始すると、システムはエージェントのランタイム、スキルセット、そして Skylight CLI をパッケージ化した一連のポッド(Pod)を起動します。この時点で、ユーザー固有の Skylight JWT が注入され、エージェントからの API 呼び出しは、そのユーザーのデータ範囲に限定されます。
マルチステップ分析中にエージェントが作成するファイルも、あくまでそのセッション内にのみ存在し、他のユーザーと共有されることはありません。サンドボックス内では、エージェントはコードの記述・実行、依存関係のインストール、データセットの取得、そして複雑な分析処理を自由に行えます。ネットワークレベルでも制限がかけられており、必要なサービス以外へのアクセスはブロックされます。
エージェントの評価:モデル単体ではない
既存のベンチマークは、一般向けの AI を静的な質問に対して評価する傾向があります。しかし、それでは実務ワークフローに組み込まれたエージェントの振る舞い——ツール選択、生データへの照会、結果に基づくアクション、そしていつ停止すべきかの判断——を捉えることはできません。
そこで私たちは、Shippy の実際の動作原理に基づいた独自の評価システムを構築しました。これはモデルだけでなく、スキルやサンドボックス環境を含めた「エージェント全体」を対象に、生データを用いて総合的にスコアリングする仕組みです。
評価フレームワークでは、専門家がシナリオと評価基準を作成し、各タスクに適用する指標を選択して重み付けを行います。これにより、各タスクは本当に重要な要素に基づいて採点されます。例えば、「釣りイベントに関する問い合わせ」の場合、データの正確性が最も重視され、次に境界の解決や時間範囲が重要視され、情報源の明記や回答スタイルは相対的に軽視されます。
また、専門家は個々の回答を「正解」「不正解」として注釈付けし、評価者(ジャッジ)が採点するための正解基準を提供します。これにより、評価プロセスに客観的な根拠が与えられます。
パイプラインの仕組みはシンプルです。自然言語のプロンプトがサンドボックス内を処理され、LLM による評価者が各基準に対して 0 から 1 のスコアを付け、その回答が基準を満たしたか否かの理由を文章で説明します。最終的に、重み付けされた集計値が固定の合格ラインと比較され、合格・不合格が判定されます。以下の図はその様子を示しています。
*当社のパイプラインにおける単一タスクの評価方法。自然言語のプロンプトがサンドボックスを通過し、LLM 評価者が各基準にスコアと根拠となる文章を付与します。重み付けされた集計値は固定の閾値と比較され、合格か不合格かが決定されます。*
タスクの実行は、オープンソースの評価フレームワークである Harbor を通じて行われます。私たちは、テスト対象の正確なバージョンで実際の Shippy セッションを起動し、ユーザーが直面するのと同じ実データに対して評価を行う Harbor プラグインを開発しました。
このスイートは特定のバージョン化された Shippy ビルドに対して並列実行され、タイムスタンプ付きの結果ファイルと、前回の実行に対するスコア変動を示すレポートを生成します。スキル、モデル、あるいは基盤となるデータに変更が生じた際は常に再実行を行い、評価基準で後退したバージョンの Shippy がエンドユーザーに届くことを防いでいます。
Shippy は、データ検索やガードレール(安全装置)タスクにおいて一貫して高いスコアを記録しています。具体的には、軍事情報に関するリクエストを適切に拒否し、ユーザーデータの分離を維持し、出典の明記も正確に行っています。
最新のテスト結果で最も明確に見られたのは、以下の 3 つのパターンです。まず、パトロール計画タスクにおいて、Shippy が意思決定支援ではなく戦術的な推奨へと踏み越えてしまったケース。次に、境界線の簡略化が原因でイベントを見逃してしまった幾何学的に敏感なクエリ。そして最後に、存在しない CLI コマンドをエージェントがでっち上げてしまった事例です。
これらすべての課題は、次のスキル改善ラウンドに向けた具体的な指針となっています。
*Skylight 内で実行される Shippy の評価スイート:各シナリオは加重された基準で採点され、判定の根拠も表示されるため、失敗した際に修正すべき特定の行動を特定できます。*
今後の展望
Shippy は現在、ロールイングベース(順次)で初期採用者に公開されており、ストレステストを通じて、エージェントが回答に苦戦する質問や、強化が必要なガードレールを見つけることを求めています。今後取り組む主な機能は以下の通りです。
- エージェントによる UI 制御。現在の Shippy は地図へのリンクを返すだけですが、今後は Skylight の地図そのものを操作できるようになります。地域への移動、フィルターの適用、時間範囲の調整などが可能です。
- モデルルーティング。すべての質問に最先端モデルが必要とは限りません。単純な照会には軽量で高速なモデルを割り当て、複雑な調査にはフルスペックのモデルを使用する仕組みを導入しています。
- スレッド間メモリ。現在の Shippy はスレッド内での会話履歴は保持しますが、スレッドを超えた文脈の共有はできません。今後は、分析官の管轄区域や好む情報源といった永続的な事実を記憶し、自動的に適用する機能を構築中です。これにより、「今週の漁業活動を表示」といった指示に対し、毎回分析官の排他的経済水域(EEZ)を再指定する必要がなくなります。
Shippy への取り組みは、Ai2 内における他のエージェント開発にもすでに影響を与えています。特に野生生物保護プラットフォーム「EarthRanger」や、地球観測ツール群のオープンスイート「OlmoEarth」においてその考え方が即座に反映されています。Mothership は汎用性を備え、他エージェントをホストすることを前提に設計されているため、現在は海運分野への適用が最優先ですが、これが唯一の領域になるとは考えていません。
*Shippy は Ai2 の Skylight チームによって開発されました。Skylight は 70 カ国以上の 300 以上のパートナー機関で利用されている、無料の海洋ドメイン・アウェアネスプラットフォームです。*
原文を表示
- Agent anatomy: skills, soul, and config
- Deterministic tools for a nondeterministic agent
- Sandboxed hosting and isolation
- Evaluating an agent, not a model
- Where we're headed
*Shippy is a maritime AI agent built for high-stakes decisions, where the wrong answer has real impacts. Here's the architecture behind it—and the lessons we're carrying into Ai2's other environmental platforms.*
*Shippy answering a live query about Ghana's EEZ. The response shows its work: the boundary source, the data cutoff, the query timestamp, and a deep link back to the Skylight map so the analyst can verify every number.*
Building an AI agent for a high-stakes operational domain like protecting the ocean is, above all, a problem of reliability. For a maritime analyst, a wrong answer could send a patrol vessel miles in the wrong direction, costing significant resources that are already stretched thin and potentially putting personnel in harm's way.
So when the Skylight team set out to build Shippy, our AI for real-time maritime domain awareness, the real work wasn't the model. It was building a system we could trust to be correct, to stay within its limits, and to hold up across a wide range of tasks. And we had to verify all of it against Skylight's live data, updated continuously as new satellite and vessel signals arrive—not a static snapshot.
Agent anatomy: skills, soul, and config
We think of an agent like Shippy as three things: a soul, skills, and config.
The soul is the system prompt that frames Shippy's persona and sets behavioral boundaries. Skills tell Shippy how to handle specific kinds of requests. Together, the soul and skills are baked into a Docker image—a versioned, deployable artifact that defines what Shippy *is*. Config covers everything else: which agent harness to run (in Shippy’s case, OpenClaw, an open-source agent framework), which LLM to use (currently, Shippy relies on Claude Opus 4.6), and runtime settings. Secrets like API keys are injected at runtime; swapping the model or the harness is a config change, not a rebuild.
Shippy’s skills follow the same agent-skills spec used by coding tools like Claude Code and Codex—plain markdown files with structured frontmatter. This keeps each skill comprehensible, versioned, and easy to revise. Shippy currently includes skills for:
- Querying the Skylight API for Events (the vessel behaviors Skylight surfaces, like fishing or transshipment between two vessels) and vessel data
- Looking up Exclusive Economic Zones (EEZ) and Marine Protected Area (MPA) boundaries
- Interpreting vessel track data, the position and movement signals ships broadcast, building on the activity classifications Skylight's models, including Atlantes, already produce
- Generating interactive map links that let an analyst jump from a Shippy in-chat answer to an exact location on the Skylight map
For example, the Skylight API query skill encodes the full workflow for answering a question about a specific area. When an analyst or user asks, "show me fishing activity in Panama's EEZ last month," the skill's instructions direct Shippy to first resolve "Panama EEZ" to a boundary polygon through Skylight's regions API instead of guessing or hard-coding coordinates, then query Fishing Events within that geometry, format the results with deep links back to the Skylight map, and attribute any vessel metadata drawn from Skylight partners like Global Fishing Watch or TMT.
A single question posed to Shippy can hook into several skills at once. "Are there vessels operating near the Cordillera de Coiba MPA?" draws on the Skylight skill for data query, our partner ProtectedSeas’ database for MPA boundary context, and the vessel track skill for interpreting vessel behavior. All of this happens in a single dialogue turn.
The soul defines what Shippy will and won't do. It won't make legal determinations about whether a vessel is breaking the law—that is a determination for people, not an agent. It also won't speculate beyond what the data supports. These boundaries are explicit in the system prompt, not implicit in fine-tuning, which makes them auditable and easy to revise.
Deterministic tools for a nondeterministic agent
Agents are nondeterministic. You can't control what the model decides to do, but you can make the tools it reaches for predictable. To that end, Shippy 'talks' to Skylight through a purpose-built CLI that calls the API, rather than issuing raw calls itself.
Our API has dozens of input types, nested filter objects, pagination cursors, and complex geometry inputs. In early prototypes, we let Shippy construct API calls from scratch. It produced a steady stream of subtle bugs: malformed pagination that silently dropped results, geometry encoding errors, and correct-looking queries that returned wrong data because of a misunderstood filter type.
The Skylight CLI collapses that complexity into a predictable interface. Shippy issues a single command – skylight events search with typed filter flags – and the CLI handles authentication, pagination, and structured output. The CLI is also self-documenting: extensive --help text and detailed error messages give the agent (and human developers) enough context to recover from mistakes without guessing. Its output is always written to a local JSON file rather than piped through the shell. Early on, large result sets would hit pipe buffer limits or break downstream tools like jq. Writing to disk sidesteps both problems and lets the agent programmatically access query results across subsequent steps.
Underneath the CLI is a standardized API: multiple resource types – Skylight Events, vessels, regions, satellite imagery, vessel tracks, and more – accessible through a common pair of operations, search and aggregate. The APIs' inputs and outputs are defined as typed schemas with field-level descriptions.
This layering – typed API, deterministic CLI, and agent skills that reference the CLI's commands – means that each of Shippy's components can be tested independently. The API has its own test suite. The CLI can be exercised by a human or an agent. And the agent skills reference CLI commands that handle the plumbing so that Shippy doesn't have to reinvent the wheel every time it hits the Skylight API. Each layer narrows what the next layer can get wrong.
Sandboxed hosting and isolation
Skylight serves hundreds of government agencies and NGOs across over 70 countries. A fisheries officer in the Philippines has Areas of Interest, vessel watchlists, and alert configurations that are scoped to their Skylight account. When they ask Shippy a question, the agent's API calls need to return their data, and their conversation history must never be visible to anyone else.
Every user talks to Shippy inside their own ephemeral, isolated session, and making that work reliably at scale was one of the most significant engineering efforts behind the project. We built Mothership, an agent hosting platform that provisions a dedicated Kubernetes deployment for each user session. When a user opens a conversation, the system spins up a set of pods packaging the agent runtime, its skills, and the Skylight CLI. The user's Skylight JWT is injected at provision time so the agent's API calls are scoped to that user's data.
Files the agent writes during a multi-step analysis exist only within that session and are never shared across users. Inside the sandbox, the agent can write and run code, install dependencies, pull in datasets, and work through multi-step analyses. At the network level, the sandbox is restricted to only the services it needs.
Evaluating an agent, not a model
Most benchmarks rank general-purpose AI on static questions. They don't capture how an agent behaves once it's wired into a real workflow: how it selects tools, queries live data, acts on results, and knows where to stop. So we built our own eval system around how Shippy works, scoring the whole agent – model, skills, and sandbox together – against live data.
In our eval framework, subject-matter experts write scenarios and rubrics, choosing which criteria apply to each task and setting the weights, so every task is graded on what actually matters for it. A fishing-events query, for instance, weights data accuracy most heavily, with boundary resolution and timeframe next, and source attribution and response style carrying less. They also annotate individual responses as correct or incorrect, giving the judge ground truth to score against. Subject-matter experts additionally annotate individual responses as correct or incorrect, giving the judge ground truth to score against.
The pipeline is straightforward: a natural-language prompt runs through the sandbox, an LLM judge grades each criterion from 0 to 1 and explains in writing why the response did or didn't meet it, and the weighted aggregate is checked against a fixed pass threshold, as the diagram below shows.
*How a single task is scored in our pipeline. A natural-language prompt runs through the sandbox, an LLM judge grades each rubric criterion with written reasoning, and the weighted aggregate resolves to a pass or fail against a fixed threshold.*
Tasks are executed through Harbor, an open evaluation framework. We wrote a Harbor plugin that spins up a real Shippy session on the exact version being tested, against the same real data a user would encounter. The suite runs in parallel against a specific versioned Shippy build, producing a timestamped results file and a report of score changes against the previous run. We rerun the suite whenever the skills, model, or underlying data change, and a version of Shippy that regresses on our eval criteria doesn't reach end users.
Shippy scores consistently across data retrieval and guardrail tasks, correctly refusing military intelligence requests, maintaining user data isolation, and attributing sources accurately. In our latest run, the clearest patterns were patrol-planning tasks where Shippy overstepped into tactical recommendations rather than decision support, geometry-sensitive queries where boundary simplification caused missed Events, and one case where the agent invented a CLI command that didn't exist. Each of these directly informs our next round of skill improvements.
*Shippy's eval suite running inside Skylight: each scenario is scored on weighted criteria, with the judge's reasoning visible so a failure points to a specific behavior to fix.*
Where we're headed
We're opening Shippy to early adopters on a rolling basis and inviting them to stress-test it—to find the questions the agent answers poorly and guardrails that may need tightening. Here’s what we're building next:
- Agent-driven UI control. Shippy returns map links today; next it will drive the Skylight map itself, moving to a region, applying filters, and adjusting time ranges.
- Model routing. Not every question needs a frontier model, so we're routing simple lookups to smaller, faster ones and saving the full-weight model for complex investigations.
- Cross-thread memory. Conversation history persists within a thread, but context doesn't carry across threads. We're building memory so Shippy carries persistent facts (e.g., an analyst's jurisdiction, preferred sources) and applies them automatically. So, "Show me fishing activity this week" won't mean re-specifying an analyst's EEZ each time.
Our work on Shippy is already shaping how we think about agents elsewhere at Ai2—most immediately EarthRanger, our wildlife-conservation platform, and OlmoEarth, our open suite of Earth observation tools. Mothership was built to be general and to host other agents, so while maritime is the first domain we're applying it to, we don't expect it to be the last.
*Shippy is built by the Skylight team at Ai2. Skylight is a free maritime domain awareness platform used by 300+ partners across 70 countries.*
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み