2
1

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 Workersを使って最小構成のLINE AI Botを実装 ~wranglerも使ってみた~

Last updated at Posted at 2025-12-22

image.jpeg

はじめに

本記事ではCloudflare Workersを使ったサーバーレス構成で、AIが自動でチャットの返信をする最小構成のLINE AI Botについて実装手順を紹介します。

想定読者

  • LINE BotにAIを組み込みたい人
  • Cloudflare Workersを触ったことがある人

全体構成

今回、以下の構成でAI LINE Botを実装しました。

LINE Messaging API(Webhook)
   ↓
Cloudflare Workers
   ↓
LLM API(OpenAI / Geminiなど)
   ↓
LINEへ返信

実装手順

LINEアカウントとCloudflare Workersの設定、実装したコードについて紹介します。

実装の前提条件

  • LLMのAPIキー取得済み
  • LINE公式アカウント作成済み
  • Cloudflareアカウント作成済み
  • Wranglerインストール済み

今回の動作環境

  • Gemini 2.5 Flash 使用
  • Wrangler バージョン 4.56.0

LINE公式アカウントの作成手順については、@frozencatpisces さんの記事などをご参照ください。自分のLINEアカウントから作成した公式アカウントの追加まで行っておくとスムーズです。
📝 LINE: 公式アカウント入門(1) - 公式アカウントを作成してみる

WindowsにWranglerをインストールする手順については、@meadas さんの記事を参考にさせていただきました。
📝 ローカルからCloudflareのWorkersに接続する環境を作る手順

LINE Official Account Manager の設定

LINE公式アカウントが外部システム(今回だとCloudflare Workers)と連携するためには、チャネルの作成が必要になります。チャネルが所属するプロバイダーも必要になるため、この2つを作成します。

image.png
出典:【図解あり】LINE APIを使うなら知っておきたい!プロバイダーと認証プロバイダーの違いを解説
 

設定手順

image.png

  • 「設定」>「Messaging API」で「Messaging APIを利用する」をクリック

image.png

  • 任意の名前でプロバイダーを作成

image.png

  • 「Messaging API」のチャネルを作成

image.png

  • チャネルが作成できたら、「Channel secret」 をメモしておく

image.png

「Webhook URL」には、後ほどデプロイするCloudflare WorkerのURLを入力します。

  • LINE Developers にアクセスして、「作成したプロバイダー」>「Messaging API設定」>「チャネルアクセストークン」の「発行」をクリック

image.png

  • 「チャネルアクセストークン」 をメモしておく

Cloudflareの設定

LINEの設定が一通り完了したので、CloudflareでWorkerを作成します。今回、Cloudflareの設定は基本的にCLIツールのWranglerによって行います。

プロジェクトの作成

以下のコマンドを実行してプロジェクトを作成します。

 npx wrangler init ai-chatbot

プロジェクトのカテゴリーなど質問されるため、適宜回答を選択します。今回は以下の設定で作成しました。

項目
category Hello World example
type Worker Only
lang JavaScript
deploy no

これでプロジェクトのテンプレートが作成されるため、以下のようにコードを変更していきます。

  • wrangler.toml の作成
  • wrangler.jsonc の削除
  • src/index.js の変更

wrangler.toml ではWorkerの名前やエントリポイント(src/index.js)を定義しています。

wrangler.toml コード
name = "ai-chatbot"
main = "src/index.js"
compatibility_date = "2025-12-22"
workers_dev = true

現在wrangler設定ファイルのフォーマットとして tomljson を指定できますが、今回は読みやすい toml フォーマットを使用します。デフォルトで作成される wrangler.jsonc は削除してください。

Workersにデプロイするコードが src/index.js になります。LINEのWebhookリクエストを受け付け、署名検証を行ったうえでLLMのAPIを呼び出し、その結果をLINEへ返信します。

index.js コード
// src/index.js
export default {
	async fetch(request, env, ctx) {
		const url = new URL(request.url);

		if (request.method === "POST" && url.pathname === "/webhook") {
			const bodyText = await request.text();

			// 署名検証
			const signature = request.headers.get("x-line-signature");
			const isValid = await verifyLineSignature(bodyText, signature, env.LINE_CHANNEL_SECRET);
			if (!isValid) return new Response("Invalid signature", { status: 401 });

			// イベント処理
			const body = JSON.parse(bodyText);
			const events = body.events || [];

			const processing = async () => {
				for (const ev of events) {
					if (ev.type === "message" && ev.message.type === "text") {
						await handleMessage(ev, env);
					}
				}
			};

			ctx.waitUntil(processing());

			return new Response("OK", { status: 200 });
		}

		return new Response("Bot is running!");
	}
};

// --- メイン処理 ---
async function handleMessage(event, env) {
	const userText = event.message.text;
	const replyToken = event.replyToken;

	// モデル(Gemini 2.5 Flash)を指定して呼び出し
	const aiResponse = await callGemini(userText, env.API_KEY, "gemini-2.5-flash");

	// LINEに返信
	await replyLine(replyToken, aiResponse, env.LINE_CHANNEL_ACCESS_TOKEN);
}

// --- Gemini API 呼び出し関数 ---
async function callGemini(text, apiKey, modelName) {
	try {
		const url = `https://generativelanguage.googleapis.com/v1beta/models/${modelName}:generateContent?key=${apiKey}`;
		const response = await fetch(url, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ contents: [{ parts: [{ text: text }] }] })
		});

		const data = await response.json();
		if (!response.ok) {
			console.error(`Gemini Error: ${JSON.stringify(data)}`);
			return `エラー: ${data.error?.message || "生成失敗"}`;
		}
		return data?.candidates?.[0]?.content?.parts?.[0]?.text || "応答なし";
	} catch (e) {
		return `通信エラー: ${e.message}`;
	}
}

// --- LINE Reply API ---
async function replyLine(token, text, accessToken) {
	await fetch("https://api.line.me/v2/bot/message/reply", {
		method: "POST",
		headers: {
			"Content-Type": "application/json",
			"Authorization": `Bearer ${accessToken}`
		},
		body: JSON.stringify({
			replyToken: token,
			messages: [{ type: "text", text: text }]
		})
	});
}

// --- 署名検証 ---
async function verifyLineSignature(body, signature, secret) {
	if (!signature || !secret) return false;
	const encoder = new TextEncoder();
	const key = await crypto.subtle.importKey(
		"raw", encoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]
	);
	const signatureBuffer = await crypto.subtle.sign("HMAC", key, encoder.encode(body));
	const signatureBase64 = btoa(String.fromCharCode(...new Uint8Array(signatureBuffer)));
	return signatureBase64 === signature;
}

環境変数(Secrets)の設定

以下のコマンドで環境変数を設定します。各コマンドを実行すると、環境変数にセットする値を質問されるので適宜入力してください。

npx wrangler secret put LINE_CHANNEL_ACCESS_TOKEN
npx wrangler secret put LINE_CHANNEL_SECRET
npx wrangler secret put API_KEY

wrangler コマンドは、作成したプロジェクトフォルダ(ai-chatbot)に移動してから実行してください

  • Cloudflare dashboardにアクセスし、「Compute & AI」>「Workers & Pages」から作成したWorkerを選択
  • 「Settings」タブ > workers.dev の「・・・」アイコン > 「Enable Domain」をクリック

image.png

デプロイと動作確認

デプロイの準備ができたので、以下のコマンドでデプロイを行います。

npx wrangler deploy

https://<your-worker>.workers.dev/にアクセスして、Bot is running!と表示されていればデプロイできています。

image.png

LINE Webhook URLを設定

Workersのデプロイが完了したので、LINEでメッセージを受け取ったらWorkersを呼び出せるようにWebhookの設定を行います。

  • LINE Official Account Manager で「設定」>「Messaging API」で「Webhook URL」に以下を入力する
    ※ WorkersのURLに /webhook パスを追加
https://<your-worker>.workers.dev/webhook
  • 「設定」>「応答設定」で「Webhook」を有効化

image.png

これで設定は完了です!

動作確認

LINE Botに話しかけてみます。

image.jpeg

まとめ

最小構成でLINEボットとAIを連携する実装手順をご紹介しました。この構成だと会話履歴を保持していないため、以前の会話の文脈を汲んだ回答をさせたい場合は、データベース(Cloudflare KV, D1など)との連携が必要になります。Notionと連携させる予定なので、実装したらまた記事にしたいと思います。

関連記事

APIを利用する場合は、予算アラートの設定をおすすめします

WorkerからNotion APIを実行して、Notionをデータベースとして使っている構成

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?