What building Shippy taught us about building agents

What building Shippy taught us about building agents

构建 Shippy 的经验教训:我们从构建 AI Agent 中学到了什么

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 是一个专为高风险决策场景打造的海事 AI Agent,在这些场景中,错误的回答会产生现实影响。本文将介绍其背后的架构,以及我们将这些经验应用到 Ai2 其他环境平台中的心得。

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. Shippy 正在回答关于加纳专属经济区(EEZ)的实时查询。其回复展示了工作过程:边界来源、数据截止日期、查询时间戳,以及指向 Skylight 地图的深度链接,以便分析师核实每一个数据。

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. 为海洋保护等高风险操作领域构建 AI Agent,首要问题是可靠性。对于海事分析师而言,一个错误的答案可能导致巡逻船偏离航向数英里,浪费本已捉襟见肘的宝贵资源,甚至使人员陷入危险。因此,当 Skylight 团队着手构建用于实时海事态势感知的 AI——Shippy 时,真正的难点不在于模型本身,而在于构建一个我们能够信任的系统:它必须准确、严守边界,并能胜任各种任务。此外,我们还必须根据 Skylight 的实时数据(随着卫星和船舶信号不断更新,而非静态快照)来验证这一切。

Agent anatomy: skills, soul, and config

Agent 的解剖结构:技能、灵魂与配置

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 这样的 Agent 看作由三部分组成:灵魂、技能和配置。灵魂是定义 Shippy 人设并设定行为边界的系统提示词(System Prompt)。技能则告诉 Shippy 如何处理特定类型的请求。灵魂与技能共同被封装进一个 Docker 镜像中——这是一个版本化、可部署的制品,定义了 Shippy 的本质。配置则涵盖了其他所有内容:运行哪种 Agent 框架(Shippy 使用的是开源框架 OpenClaw)、使用哪种大语言模型(目前 Shippy 依赖 Claude Opus 4.6)以及运行时设置。API 密钥等机密信息在运行时注入;更换模型或框架只需修改配置,无需重新构建。

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 的技能遵循与 Claude Code 和 Codex 等编程工具相同的 Agent 技能规范——即带有结构化元数据(frontmatter)的纯 Markdown 文件。这使得每一项技能都易于理解、版本化且便于修订。

Shippy currently includes skills for: Shippy 目前包含以下技能:

  • Querying the Skylight API for Events (the vessel behaviors Skylight surfaces, like fishing or transshipment between two vessels) and vessel data
  • 查询 Skylight API 以获取事件(Skylight 识别的船舶行为,如捕鱼或两船间的转运)及船舶数据
  • Looking up Exclusive Economic Zones (EEZ) and Marine Protected Area (MPA) boundaries
  • 查询专属经济区(EEZ)和海洋保护区(MPA)边界
  • Interpreting vessel track data, the position and movement signals ships broadcast, building on the activity classifications Skylight’s models, including Atlantes, already produce
  • 解读船舶轨迹数据(船舶广播的位置和移动信号),并基于 Skylight 模型(包括 Atlantes)已生成的活动分类进行分析
  • Generating interactive map links that let an analyst jump from a Shippy in-chat answer to an exact location on the Skylight map
  • 生成交互式地图链接,让分析师能从 Shippy 的聊天回复直接跳转到 Skylight 地图上的精确位置

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. 例如,Skylight API 查询技能编码了回答特定区域问题的完整工作流。当分析师或用户询问“显示上个月巴拿马专属经济区内的捕鱼活动”时,该技能的指令会引导 Shippy 首先通过 Skylight 的区域 API 将“巴拿马专属经济区”解析为边界多边形,而不是猜测或硬编码坐标;随后在几何范围内查询捕鱼事件,将结果格式化并附带指向 Skylight 地图的深度链接,同时标注从 Global Fishing Watch 或 TMT 等 Skylight 合作伙伴处获取的船舶元数据。

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. 向 Shippy 提出的一个问题可以同时调用多项技能。“是否有船舶在科伊瓦山脉(Cordillera de Coiba)海洋保护区附近作业?”这个问题需要调用 Skylight 的数据查询技能、合作伙伴 ProtectedSeas 的海洋保护区边界数据库,以及用于解读船舶行为的轨迹技能。所有这些都在单次对话轮次中完成。

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. 灵魂定义了 Shippy 能做什么和不能做什么。它不会对船舶是否违法做出法律裁定——这是人类而非 Agent 的职责。它也不会在数据支持范围之外进行推测。这些边界在系统提示词中是明确的,而非隐含在微调中,这使得它们可审计且易于修订。

Deterministic tools for a nondeterministic agent

为非确定性 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. Agent 是非确定性的。你无法控制模型决定做什么,但你可以让它所使用的工具变得可预测。为此,Shippy 通过一个专门构建的 CLI(命令行界面)与 Skylight 通信,而不是直接发出原始 API 调用。我们的 API 拥有数十种输入类型、嵌套过滤对象、分页游标和复杂的几何输入。在早期原型中,我们让 Shippy 从零开始构建 API 调用,结果产生了一连串隐蔽的 Bug:分页格式错误导致结果丢失、几何编码错误,以及因误解过滤器类型而导致查询看起来正确但返回数据错误的情况。

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. Skylight CLI 将这种复杂性简化为一个可预测的接口。Shippy 只需发出一条命令——例如带有类型化过滤标志的 skylight events search——CLI 就会处理身份验证、分页和结构化输出。该 CLI 还具备自文档化功能:详尽的 --help 文本和详细的错误信息为 Agent(及人类开发者)提供了足够的上下文,使其无需猜测即可从错误中恢复。其输出始终写入本地 JSON 文件,而不是通过 Shell 管道传输。早期,大数据集会触及管道缓冲区限制或导致 jq 等下游工具崩溃。写入磁盘规避了这两个问题,并允许 Agent 在后续步骤中以编程方式访问查询结果。

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. CLI 的底层是一个标准化的 API:多种资源类型(Skylight 事件、船舶、区域、卫星图像、船舶轨迹等)均可通过“搜索(search)”和“聚合(aggregate)”这一对通用操作进行访问。API 的输入和输出被定义为带有字段级描述的类型化模式。这种分层架构——类型化 API、确定性 CLI 以及引用 CLI 命令的 Agent 技能——意味着 Shippy 的每个组件都可以独立测试。