---
title: "Kobako：讓 Agent 安全的操作 Rails"
date: 2026-05-20T00:00:00+08:00
publishDate: 2026-05-20T00:00:00+08:00
lastmod: 2026-05-18T21:26:49+08:00
tags: ["LLM","AI","經驗","Ruby","Harness Engineering","Rails"]
toc: true
permalink: "https://blog.aotoki.me/posts/2026/05/20/kobako-ruby-sandbox-for-ai/"
language: "zh-tw"
---



今年 [RubyKaigi 2026](https://rubykaigi.org/2026/) 時，剛好在跟朋友聊 Harness Engineering 提到 Sandbox 的部分，覺得 Ruby 語言目前還沒有比較完善的解決方案，剛好第二天晚上的 Code Party 被分配到 [druby](https://github.com/ruby/drb)（Ruby 語言內建的分散式系統）組別，讓我有了靈感，讓 [Kobako](https://github.com/elct9620/kobako) 被設計出來。

<!--more-->

## 沙盒選擇：為什麼是 WebAssembly{#sandbox}

要打造 AI Agent 可以運行的環境有很多路線，像是虛擬機器（Virtual Machine）、容器技術、WebAssembly 都可以實現。

> 目前有哪些路線，可以讀 [Agent Sandbox 沙箱架構: 論兩種設計模式與七種隔離方式](https://blog.aihao.tw/2026/04/20/agent-sandbox-landscape/)這篇文章的整理

選擇哪一種技術，就會影響到後續技術發展的路線，以及可以做的事情，在搜集現有的解決方案跟技術後，最終只能走自己開發。

舉例來說，Shopify 有 [mruby-engine](https://github.com/Shopify/mruby-engine) 的技術，這是相當理想的選項之一，但是這個做法只能保證 Host（宿主）跟客體（Guest）不是直接互通的，如果運行的 Ruby 腳本針對記憶體或是一些攻擊，都很容易打穿，給 Agent 使用強度還是稍嫌不足。

如果選虛擬機器或者容器技術，最大的困難是對環境的要求相對嚴苛，這種嚴苛對小專案或者開發都會有不少限制，所以最後 Kobako 選擇 WebAssembly 的路線，有類似虛擬機器的 WASI 標準，跟直接跑 mruby 來說，犧牲一些啟動、運行速度，換到更好的隔離性還算是划算。

後來 Shopify 也有投資元在 [wasmtime](https://github.com/bytecodealliance/wasmtime-rb) 讓 [ruby.wasm](https://github.com/ruby/ruby.wasm) 可以替代原本 Shopify 的腳本功能，也因此 ruby.wasm 也是我考量的選項之一，但最終因為 ruby.wasm 本身的限制，讓我走向不同的路線。

## WASI 的限制與 Kobako 的取捨{#wasi}

WASI 全名是 WebAssembly System Interface，簡單來看，是一種讓我們在 WebAssembly 環境中獲得類似 UNIX 介面的架構，像是 ruby.wasm 就是使用 Preview 1 版本的標準，並且正在測試 Preview 2 的標準。

然而，這個介面設計的非常的差，以 Preview 1 來說，除了有 Stdin / Stdout / Stderr 等介面，以及類似 VFS（Virtual File System）的機制外，基本上沒什麼能做的事情，也不支援 I/O 之類的行為，這也造成 Kobako 在評估是否要用 ruby.wasm 當基底時，只能放棄這條路線。

> 即使 ruby.wasm 能用，也不一定是好的選項，因為本身需要載入 20 MB 左右的 Ruby 環境，加上啟動時間可能還比容器技術慢

目前 WASI 有 Preview 1 ~ Preview 3 個不同版本，後面要建置跟編譯也有不同類型的麻煩，最後 Kobako 選比較穩定和普及的 Preview 1 標準來實作，跟 ruby.wasm 的差異在於額外的 ABI（Application Binary Interface）來實現一個 In-Memory RPC 的溝通，讓 Sandbox 中的 Ruby 腳本能夠呼叫 Host 提供的方法。

這也是沒有選擇 ruby.wasm 的主要原因，如果想增加 ABI 就必須完整編譯 ruby.wasm 背後的開發成本跟困難度會極大上升，但是 mruby 設計給嵌入式系統的特性反而就很適合。

在今年 RubyKaigi 也有 [Uzumibi: Reinventing mruby for the Edges](https://rubykaigi.org/2026/presentations/udzura.html) 這樣的主題，剛好呼應 Kobako 想要實現 Cloudflare 針對 MCP 問題所提出的 [Code Mode](https://blog.cloudflare.com/code-mode/) 想法，同樣是從 Edge 環境運行為出發點，mruby 的規模也剛很好適合。

## RPC：讓 Sandbox 與 Host 溝通{#rpc}

Kobako 受到 druby 啟發的地方，就是 druby 巧妙的運用 Ruby 語言特性來實現 RPC 機制，以下是 Kobako 實際使用的範例。

```ruby
User = Data.define(:name)

sandbox = Kobako::Sandbox.new
sandbox.define(:App).bind(:User, User.new(name: "Aotoki"))

sandbox.run(<<~RUBY)
  "Hello, #{App::User.name}"
RUBY
# => "Hello, Aotoki"
```

在 Sandbox 中，要怎麼知道 Host 端提供了 `App::User` 而且有 `#name` 這個方法呢？

Kobako 在每次 `Sandbox#run` 的時候，都會自動注入像這樣的程式碼：

```ruby
class App::User < Kobako::RPC::Client; end
# ...
```

然後，就沒有然後，我們的 Sandbox 環境就能自然地知道 `#name` 可以呼叫，這是因為 Ruby 語言天生支援這樣的實作，因此 `Kobako::RPC::Client` 實現了這樣的行為

```ruby
class Kobako::RPC::Client
  def method_missing(name, *args, &block)
    __kobako_rpc_call__(name, *args)
  end
end
```

這個 `__kobako_rpc_call__` 是利用 Rust 所定義的 ABI，負責將 Method Call 轉到 WebAssembly 外面，等外面回覆後再轉發回 WebAssembly。透過這個機制，就能在隔離性跟可擴充性之間達到平衡。

套用到 Rails 的情境，原本要整合 AI 需要重新設計跟定義工具，但是原本就有做不錯的 Service Object 封裝跟權限控管，就只需要利用 [RBS](https://github.com/ruby/rbs) 向 AI 說明介面定義，讓 Agent 自動轉寫操作的腳本即可。

```ruby
sandbox = Kobako::Sandbox.new
ns = sandbox.define(:Merchant)
ns.bind(:Product, ProductManagementService.new(actor: current_user))
# - ProductManagementService#where
# - ProductManagementService#update
# - ...

# Agent Tool
def execute_code(code)
  sandbox.run(code)
end

# Merchant::Product.where(name: "%macOS%")
# => [#<Product id=1>, #<Product id=2>]
```

這也是 Cloudflare 為什麼需要用他們的 Cloudflare Worker 底層技術，改造出 Code Mode 的使用方式，因為這樣可以很快的把大量 API 整合進去，但不需要提供大量的工具。

Cloudflare Code Mode 提供一個值得思考的選擇，利用 LLM 本身的程式能力來解決問題，Kobako 則從 Ruby 生態系提取經驗，讓這種整合更加無縫。Kobako 專案目前也有 [examples/codemode](https://github.com/elct9620/kobako/tree/main/examples/codemode) 的範例，可以使用 OpenAI 相容的 API 或者本地 Ollama / LMStudio 搭配 Gemma 4 體驗 KeyValue Store + WebFetch 的功能，有興趣的可以嘗試看看。
