Cloudflare Workers AIエージェントの構築は、単純なAIプロンプトから自律的なワークフローへと移行するための次のステップです。AIエージェントとして知られるこれらのシステムは、大規模言語モデル(LLM)を使用して外部ツールを呼び出し、意思決定を行い、タスクを自律的に実行します。従来、エージェントの実行には高スペックなサーバーが必要でしたが、このチュートリアルでは、Cloudflare WorkersとLangChain.js を使用してサーバーレスAIエージェントを構築し、ホストする方法を実演します。

TL;DR

  • AIエージェントの理解:エージェントはLLMを使用して意思決定を行い、外部API(ツール)を呼び出してユーザーの質問を自律的に解決します。
  • エッジでのLangChain.jsの活用:LangChain.jsは、Cloudflare Workersの軽量なV8ランタイムと完全に互換性があります。
  • カスタムツールの作成:データの取得、データベースの読み取り、またはWorkerのfetchハンドラーからのロジックの実行を行うカスタムツールを作成します。
  • サーバーレスバインディングの利用:SQL状態メモリにはCloudflare D1、セッションキャッシュにはKVをエージェントに接続します。
  • ガードレールとタイムアウトの適用:無限実行ループを防ぎ、トークンAPIのコストを制御します。

AIエージェントとは?

通常のチャットボットは、単純なリクエスト・レスポンスのループです。プロンプトを送信すると、モデルがテキストを返します。これに対し、Cloudflare Workers AIエージェントは自律的に動作します。エージェントの目標を定義し、一連の「ツール」(APIの呼び出し、データベースの検索、算術計算などを行うカスタムJavaScript関数)を提供します。モデルはどのツールを呼び出すべきかを判断し、ツールの出力を検査し、リクエストが解決するまでループ処理を行います。このエージェント型ロジックは、複雑なカスタマーサポート、バックグラウンド自動化、データベース管理に非常に適しています。基本的なエッジAPIのセットアップの詳細については、Cloudflare Workersを使用したサーバーレスAPIの構築 のガイドを参照してください。

前提条件

開始する前に、以下の準備ができていることを確認してください。

  • Workersが有効化されたCloudflareアカウント(無料プランで十分です)。
  • Node.js 18以降およびWrangler CLI(npm install -g wrangler)。
  • OpenAI APIキー、またはLangChain.jsがサポートする別のプロバイダーの資格情報。
  • JavaScriptのPromiseとWorkersのfetchハンドラーに関する基本的な知識。

必要なLangChainパッケージをインストールします。Workersは圧縮されたバンドルサイズ制限を適用するため、フレームワーク全体をインポートするのではなく、個別にインポートしてください。

 1{
 2  "dependencies": {
 3    "@langchain/openai": "^0.3.0",
 4    "@langchain/core": "^0.3.0",
 5    "langchain": "^0.3.0"
 6  },
 7  "devDependencies": {
 8    "wrangler": "^3.0.0"
 9  }
10}

LangChain.jsのWorkersへの統合

LangChainは、LLMアプリケーションを構築するための人気のあるフレームワークです。JavaScriptバージョン(LangChain.js)はウェブ標準APIを使用して設計されているため、Cloudflareの軽量なV8ランタイムと完全に互換性があります。

まず、Workerのfetchハンドラー内でエージェントを初期化します。

 1import { ChatOpenAI } from "@langchain/openai";
 2import { initializeAgentExecutorWithOptions } from "langchain/agents";
 3import { DynamicTool } from "@langchain/core/tools";
 4
 5export default {
 6  async fetch(request, env) {
 7    // 1. Define custom tools for the agent
 8    const databaseTool = new DynamicTool({
 9      name: "DatabaseQuery",
10      description: "Queries the customer database for billing status.",
11      func: async (input) => {
12        // Query database (e.g. Cloudflare D1)
13        return `Customer ${input} billing status is Active.`;
14      }
15    });
16
17    const tools = [databaseTool];
18
19    // 2. Initialize the reasoning model
20    const model = new ChatOpenAI({ 
21      apiKey: env.OPENAI_API_KEY,
22      modelName: "gpt-4o-mini"
23    });
24
25    // 3. Create the executor
26    const executor = await initializeAgentExecutorWithOptions(tools, model, {
27      agentType: "openai-functions",
28    });
29
30    // 4. Run the query
31    const result = await executor.call({ input: "Check status for Customer 101" });
32    return Response.json(result);
33  }
34};

このセットアップは完全にエッジで動作し、ユーザーの近くで実行され、コールドスタートはほぼゼロです。OpenAIを呼び出す代わりにサーバーレスのローカルモデルを設定したい場合は、Cloudflare Workers AIチュートリアル を参照してください。

Workerプロジェクトの構成

LangChain.jsはいくつかのNode.js組み込みモジュールに依存しているため、nodejs_compatフラグを有効にするまでWorkerはコンパイルされません。wrangler.tomlで、ツールが使用するバインディングとともに設定します。

1name = "ai-agent-worker"
2main = "src/index.js"
3compatibility_date = "2024-09-23"
4compatibility_flags = ["nodejs_compat"]
5
6[[d1_databases]]
7binding = "DB"
8database_name = "agent-memory"
9database_id = "<your-database-id>"

APIキーをコードに直接書き込まないでください。代わりに暗号化されたシークレットとして保存します。

1npx wrangler secret put OPENAI_API_KEY

ローカル開発の場合は、ソース管理でキーが公開されるのを防ぐため、同じ値を.dev.varsファイル(.gitignoreに追加)に配置し、wrangler devが読み取れるようにします。

状態管理とエージェントメモリ

サーバーレスのWorkersはリクエスト間でステートレスであるため、会話履歴を保存するためのメモリシステムをエージェントに提供する必要があります。

エージェントをCloudflare D1などのサーバーレスSQLデータベースに接続できます。エージェントはリクエストを受信すると、D1にクエリを実行して以前のメッセージスレッドを取得し、それを思考モデルに渡し、新しい応答をデータベースに保存します。リレーションテーブルの作成方法については、Cloudflare D1エッジデータベースのセットアップ を参照してください。

実用上、最小限のメッセージストアには、スレッドを読み込むヘルパーと、新しい会話を追加するヘルパーの2つが必要です。CREATE TABLE messages (id INTEGER PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);でテーブルを作成し、接続します。

 1async function loadHistory(db, sessionId) {
 2  const { results } = await db
 3    .prepare(
 4      "SELECT role, content FROM messages WHERE session_id = ? ORDER BY created_at ASC"
 5    )
 6    .bind(sessionId)
 7    .all();
 8  return results ?? [];
 9}
10
11async function saveMessage(db, sessionId, role, content) {
12  await db
13    .prepare("INSERT INTO messages (session_id, role, content) VALUES (?, ?, ?)")
14    .bind(sessionId, role, content)
15    .run();
16}

各リクエストの開始時に履歴を読み込み、事前コンテキストとしてモデルに渡し、応答を返す前にユーザー入力とエージェントの最終回答の両方を保存します。永続性が重要でない存続期間の短いセッションの場合は、Cloudflare KVの方がD1よりも安価な選択肢になります。

本番環境におけるガードレールとコスト管理

エージェントはループ(思考 → ツールの実行 → 思考)で実行されるため、定義が不十分なエージェントは無限ループに入り、APIの請求額が急速に膨らむ可能性があります。

  • 最大反復回数の設定:エージェントが実行できるループの最大数を制限します(例:最大5回に制限)。
  • タイムアウトの構成:Cloudflare WorkersはCPU実行制限を強制します。リクエストのキャンセルを防ぐために、ツールが迅速に処理されるようにします。
  • レート制限の導入:レート制限を適用して、トークンの悪用からエッジエンドポイントを保護します。

コードでは、エグゼキューターのオプションで最初の2つのガードレールを明示します。

1const executor = await initializeAgentExecutorWithOptions(tools, model, {
2  agentType: "openai-functions",
3  maxIterations: 5,
4  earlyStoppingMethod: "generate",
5  verbose: false,
6});

maxIterationsを設定すると、モデルが最終回答を生成していない場合でも、5回の思考サイクル後にループが停止し、リクエストあたりの最悪のトークン消費量を制限できます。

コンテキスト管理の詳細については、OpenAI APIチャットボットの構築 のガイドを参照してください。

よくある落とし穴とトラブルシューティング

最初のデプロイメントの多くは、いくつかの予測可能な原因で失敗します。以下の表は、発生しやすいエラーとその原因、修正方法を示しています。

現象考えられる原因修正方法
ビルド時にCannot find module 'node:async_hooks'が発生するnodejs_compatフラグが不足しているcompatibility_flags = ["nodejs_compat"]と最近のcompatibility_dateを追加する
デプロイ時にバンドルサイズ制限を超えるバレルインポートがフレームワーク全体を読み込んでいる特定のサブパス(@langchain/openai)からインポートし、未使用のツールを削除する
OPENAI_API_KEY is not definedシークレットが未設定、またはローカルに.dev.varsがないwrangler secret putを実行し、wrangler dev用の.dev.varsにキーを追加する
高負荷時にリクエストがタイムアウトするツールの処理が遅い、またはループの暴走maxIterationsを下げ、各ツールのfunc内にタイムアウト処理を追加する
エージェントが使用すべきツールを無視するツールのdescriptionが曖昧モデルがいつ呼び出すべきかを正確に示すように説明文を書き直す

注目すべき点が2つあります。第一に、Workersは実時間とCPU時間を分離しています。LLMやデータベースの応答を待つ時間はCPU時間ではなくI/Oとしてカウントされるため、長いモデル呼び出しだけでCPU制限に達することはほとんどありませんが、ループ内での複雑なJSONパースは達する可能性があります。第二に、エージェントの決定の質は、ツールの説明方法に大きく依存します。各descriptionフィールドをプロンプトとして扱い、期待する入力を具体的に指定しないと、モデルが誤ったツールを呼び出す原因になります。

テストと本番環境へのデプロイ

リリースする前にローカルランタイムで開発を行います。wrangler devは、Cloudflareが本番環境で使用しているものと同じWorkerdエンジンでWorkerを実行するため、動作はエッジとほぼ一致します。

1npx wrangler dev      # local iteration with hot reload
2npx wrangler deploy   # publish to the edge

本番環境に移行したら、エージェントの思考ループを把握する必要があります。ツール呼び出しとエラーがキャプチャされるようにオブザーバビリティを有効にし、ログをリアルタイムでストリーミングします。

1[observability]
2enabled = true

npx wrangler tailを使用して、リクエストをリアルタイムで監視します。ログ記録に加え、本番エージェントを健全に保つためのいくつかの習慣があります。データベースに接触するツールに届く前にユーザー入力を検証してクレンジングすること、モデルが反復制限を超えた場合は生の内部エラーを表示するのではなく適切な代替メッセージを返すこと、悪意のあるユーザーによる高額な請求を防ぐためにセッションごとのトークン使用量を監視することなどです。高スループットのワークロードの場合は、ループ全体の終了を待つのではなく、生成された出力をユーザーが順次確認できるように、応答をストリーミングすることを検討してください。

主なポイント

  • AIエージェントは思考モデルを使用して、複雑なクエリを解決するために呼び出すべきカスタムツールを決定します。
  • LangChain.jsは、Cloudflare Workersの軽量なV8アイソレートランタイム内で効率的に動作します。
  • カスタムツールは、データベース、API、またはファイルに接続するJavaScript関数として定義します。
  • Cloudflare D1サーバーレスSQLを使用して、ステートレスなリクエスト間でエージェントメモリを維持します。
  • ループ反復制限とリクエストタイムアウトを実装して、APIコストを制御し、実行クラッシュを防ぎます。

AIワークフローの拡張

本番環境に対応したAIエージェントの構築には、サーバーレスアーキテクチャ、データベースエンジニアリング、およびプロンプト設計に関する専門知識が必要です。Mecanikは、プロフェッショナルなAI導入サービス と、Web開発者の採用 ページを通じた専任エンジニアの提供を行っています。私たちは、業務を自動化し、きれいに拡張できる、高速で安全なエージェントシステムを構築します。次の構築について、今すぐお問い合わせください。

よくある質問(FAQ)

AIチャットボットとAIエージェントの違いは何ですか? AIチャットボットは、プロンプトに対してテキストの回答のみを返します。AIエージェントは自律的であり、リクエストを評価し、タスクを完了するためにループ内で実行する外部API(ツール)を決定します。

Cloudflare WorkersでLangChainを実行できますか? はい。LangChain.jsはウェブ標準APIを使用して設計されているため、完全なNode.jsを実行しないCloudflare WorkersのV8エンジンと完全に互換性があります。

AIエージェントにデータベースへのアクセス権を与えるにはどうすればよいですか? データベースクエリをLangChainのカスタムツール内にラップします。エージェントがデータベース情報を必要と判断すると、クエリを実行するツール関数を呼び出します。

AIエージェントが無限ループに陥るのを防ぐにはどうすればよいですか? エージェントエグゼキューターで最大反復回数(例:maxIterations: 5)を設定し、ツール関数に厳格なタイムアウトを実装します。

AIエージェントに最適なホスティングは何ですか? Cloudflare Workersのようなサーバーレスエッジホスティングは、グローバルな分散、ほぼゼロのコールドスタートを提供し、D1やR2などのデータベースと直接バインドできるため、理想的です。