1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflare を使い倒す Agents SDK 編 (1/2 調査編)

1
Last updated at Posted at 2025-12-24

この記事は、DeepL 翻訳による翻訳が含まれています。
筆者による翻訳検証を行っていますが、不正確な場合もあります。

こんにちは、@toreis です。

Cloudflare には Agents SDK といった面白そうな名前をした製品があります。
多分 AI Agent を作るために生まれたんだと思いますが、肝心の中身がわかりません。

そこで、この記事ではユースケースが思いつくことを目標として仕組みを調べてまとめてみます。

AI Agent ってなんやねん

そもそも Agent ってなんなんでしょう。

Cloudflare によれば

An agent is an AI system that can autonomously execute tasks by making decisions about tool usage and process flow. Unlike traditional automation that follows predefined paths, agents can dynamically adapt their approach based on context and intermediate results. Agents are also distinct from co-pilots (e.g. traditional chat applications) in that they can fully automate a task, as opposed to simply augmenting and extending human input.

エージェントとは、ツールの使用方法やプロセスフローに関する意思決定を行い、自律的にタスクを実行できるAIシステムである。事前に定義された経路に従う従来の自動化とは異なり、エージェントは状況や中間結果に基づいてアプローチを動的に適応させることができる。また、エージェントはコパイロット(例:従来のチャットアプリケーション)とも異なり、単に人間の入力を補完・拡張するのではなく、タスクを完全に自動化できる点が特徴である。

とのことで、今まではショッピングしたかったら自分で某ゾン開いて検索して…ってやっていたのが、Agent だと自動的に調べて購入処理までやってくれる、ってことですね。

ChatGPT のように、おしゃべりしながらなにかを決めるのも体験ではありますが、時間かけてられんと。

よりわかりやすい事例もあります。

「この Issue に対応したいから、実装してプルリク開いて」って話をしたときに、生成 AI は「もちろん!どのリポジトリのどれを実装しますか?」って聞いてきます。

でも Agent なら、「もちろん!① 該当の Issue を探して ② 実装して ③ プルリク投げます」と、全部やってくれます。やり取りがいりません。

いつもの LLM なら、文章のラリーでした。(一世代前の ChatGPT みたいな…)

自分で考えてツールを呼び出して処理を行ってくれる Agent、触ってみたいですね。
エージェントって響きがいいですね。

Agents ってどうやって動いてるねん

これを読んでいきます。

Agents SDK の大黒柱とも言える Agent クラスの実装についてです。

Agent Class の大本を辿っていくと、Durable Objects がいます。
君 Containers にもいなかった?

ですが、実装を見ると Server って別物がいます。

Durable Objects ちゃうやんって話ですが、大丈夫です。
Durable Objects 依存なので

ということで、まずは Durable Objects ってなんやねんをしていきます。

Layer 0: Durable Object ってなんやねん

Agents SDK に関わる範囲だけを見るので、詳しくは語りません。

Durable Object はクラスなので、コンストラクタを備えています。
しかし、このコンストラクタは直接呼び出すことはありません。代わりに、DurableObjectNamespace を使います。

というのも、コンストラクタを呼び出さなくても勝手にインスタンスを作ってくれるようですが、実装までは掴めませんでした…

さて、Durable Object で公開されている関数は、RPC として触ることができます。
Durable Object のインスタンスが動ける状態でなくとも、呼び出しが動作するようにWorkers Runtime がコンストラクタを呼び出します。

Durable Object は fetch も実装できます。
これは主に Response を返すのに使われ、特に Durable Object との WebSocket を確立するために使われます。

さらには、alarm と呼ばれる「スケジュールして発火したら動作させる」ということもできるようです。

定時実行といえば Cron も実装できますが、alarm は Durable Object ごとに設定できるため、1 Worker に 3 つしか設定できない Cron に対して、alarm は実質無制限に設定できるのがポイントです。

Durable Object の this.ctx には DurableObjectState と呼ばれる変なプロパティが入っています。

この中に詰まっている this.ctx.storage は、 DurableObjectStorage と呼ばれる Durable Object のデータ永続化周りを同期的にいい感じにしてくれる関数が実装されています。

また、this.ctx.env には Workers にくっついている Bindings が詰まっており、D1 や R2 にもこのプロパティ経由でアクセスできます。

Layer 1: Partykit Server

Partykit…?と思ったら、そういうサービスがあるみたいです。

2024 年に Cloudflare に Join した企業で、AI Agent や マルチプレイヤーアプリ向けに設計されたサービス?ライブラリ?のようです。(公式は deployment platform って書いてるけど)

どうやら WebSocket を触る、つまり双方向通信に強いライブラリのようで、Durable Objects の独特な記法を意識せずともリアルタイムで双方向の処理が必要なロジックを書けるって感じですね。

ref:

Now that you have seen what Durable Objects come with out-of-the-box, what PartyKit ↗'s Server (package partyserver) implements will be clearer. It is an opinionated DurableObject wrapper that improves DX by hiding away Durable Object primitives in favor of more developer friendly callbacks.

An important note is that Server does NOT persist to the Durable Object storage, so you will not see extra storage operations by using it.

公式には、Durable Object の複雑さをラップして開発体験を良くしたものだよ、という感じですかね。
また、Durable Object ストレージに永続化処理を行わない、というのも気になります。

まず、partyserver は URL を見て Durable Object を返すという機能を持っています。

URL 別で処理を分けたいとき (例えば id によって Durable Objects を変更したいとき) には重宝する機能ですね。

onStart が公開されていて、これを実装すると Durable Object が起こされたときに実行する処理を指定することもできるようです。

他にも、WebSocket や HTTP リクエストが来たときにはそれぞれ onConnect、onRequest でハンドラを実装することができます。

WebSocket では、ブロードキャストしたり、Durable Object にもとから実装されている onMessage, onClose, onError も引き続き公開されているので、実装できます。やったぁ!

Durable Object では、指定に id が必要です。これは getIdByName で取得できるのですが、Durable Object の中では Name は取得できません。
「いや Name 取れへんのかい!」ってことで、partyserver では name が取れるようになっていますが、これはどうやら完璧ではないそうです。
真理はこちら

Layer 2: Agent

本丸です!大本命の Agent を見ていきましょう。

RPC と WebSocket は Durable Object でも見てきましたが、なんとメールも送受信できる改造っぷりです。

まず気になるのは this.state の存在です。

this.state は状態のことですが、自動的に保存されます。
「Durable Object じゃん」と思いましたが、どうやら this.state を世界に散らばっている Durable Object で共有できるみたいです。

例えば、公式から以下のコードを拝借しました。

class MyAgent extends Agent<Env, { count: number }> {
  initialState = { count: 0 };

  increment() {
    this.setState({ count: this.state.count + 1 });
  }

  onStateUpdate(state, source) {
    console.log("State updated:", state);
  }
}

このとき、increment を呼べば、全世界で this.state が更新されるというのです。
便利すぎんか?

また、同期 API である this.ctx.storage.sql をテンプレートタグにした this.sql があるようです。
正直理解できていませんが、公式によれば以下のような書き方ができるようです。

class MyAgent extends Agent {
  onStart() {
    this.sql`
      CREATE TABLE IF NOT EXISTS users (
        id TEXT PRIMARY KEY,
        name TEXT
      )
    `;

    const userId = "1";
    const userName = "Alice";
    this.sql`INSERT INTO users (id, name) VALUES (${userId}, ${userName})`;

    const users = this.sql<{ id: string; name: string }>`
      SELECT * FROM users WHERE id = ${userId}
    `;
    console.log(users); // [{ id: "1", name: "Alice" }]
  }
}

this.sql から始まる見たことない文。
MDN にありました。これなのかはともかく。

Agent クラスに実装した関数は、WebSocket 経由で RPC を実装することで、クライアントでもエージェントのメソッドを直接呼び出せるようです。
デバッグにちょうど良いのかも。

this.queue 系についても注目です。
これは読んで時の如くキューで、重たい処理をぶん投げたりするのに役立ちます。

呼び出し方もお手軽。

class MyAgent extends Agent {
  async onConnect() {
    // Queue a task to be executed later
    await this.queue("processTask", { userId: "123" });
  }

  async processTask(payload: { userId: string }, queueItem: QueueItem) {
    console.log("Processing task for user:", payload.userId);
  }
}

処理が正常に終わったら自動的にデキュー (キューから外すこと) をしてくれるのもいいですね。

this.schedule 系は Agent によってめっちゃ進化したと思います。

元々 Durable Object は 1 つのアラームしか設定できませんでしたが、SQL で管理することで 1 つのアラームでどうにかする術を身に着けたようです。

特定の日時でも特定の秒数後でも Cron 表記でも使えるってのは個人的にアツいです。
アラーム使いたいから、で Agent にするか…。

さて、エージェントと言ったら MCP ですよね。

クライアントにバッチリ対応しています。
ちなみにサーバー側もバッチリです。

class MyAgent extends Agent {
  async onConnect() {
    // Add an MCP server
    await this.addMcpServer(
      "GitHub",
      "https://mcp.example.com/sse",
      "https://my-worker.example.workers.dev", // callback host for OAuth
      "agents" // routing prefix
    );
  }
}

実装も簡単そうでなによりですね。

この章の最初に、メールも行けるって話をしました。

Cloudflare の Email Routing を使えばできます!

メールを受信したら、自動返信する Worker くらいならすぐに作れます。

ここに Agent をつけて、例えば予定を引っ張り出して Calendar MCP に投げて…とかもできるのではないでしょうか。

結構アツいですよね。

あとは実行コンテキストは getCurrentAgent から引っ張ってこれたり、

なにかエラーを起こしたら発火する onError は WebSocket エラーとサーバーエラーの両方がキャッチ出来たり、

Agent をすべて吹き飛ばす destroy が実装されていたり、

partyserver の「URL から直接 Durable Object」が「URL から直接 Agent」になっていたりします。

おわりに

Agent の中身がどうなっているかについて調べてみました。いかがでしたでしょうか。

Agents SDK は Chat Agent 用に AIChatAgent クラスを持っていたりするので、こういったものを使ってチャットエージェントとかが作れると面白そうですよね。

Durable Objects としても優秀なので、いつか間違った使い方をしてみたいと思います。

個人的には Durable Objects の謎が深まりました。
またの機会に調べてみようと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?