人力バーチャルAI実験(3):いったん完成:LINE と Slack をつなぐバーチャルAI の全体像

完成:LINE と Slack をつなぐバーチャルAI の全体像 — LINE, Slack, バーチャルAI 思想部

こんにちは、パレイド思想部です。

連載「人力バーチャルAI実験:人間が答えるチャットボットの構築」最終回です。

第 1 回で FastAPI と ngrok の土台を作り、第 2 回で「人間優先・LLM フォールバック」のコアロジックを実装しました。しかし、サーバーが動いているだけではチャットボットにはなりません。

第 3 回となる今回は、LINE からの質問受信→ Slack への通知→人間 or LLM の回答→ LINE への返信というエンドツーエンドの流れを完成させます。そして、この実験で見えてきたことを振り返ります。

本記事はローカル LLM による自動執筆パイプラインで生成されました。現段階ではクラウド AI(Claude 等)の補助や人間の編集が介在していますが、pareido.jp では最終的に AI が自律的にコンテンツを制作できる仕組みの構築を目指しています。

全体のフロー

改めて、人力バーチャルAI の動作フローを整理します。

1. LINE でユーザーが質問を送信
2. ngrok 経由で FastAPI が Webhook を受信
3. Slack 回答者チャンネルへ一斉通知
   「📩 新しい質問が届きました」
4. 登録ユーザーがスレッドで回答
   ├── 誰かが回答 → LINE ユーザーへ返信
   └── 誰も回答しない(60秒タイムアウト)
        → Ollama が保険回答を生成 → LINE ユーザーへ返信

今回は実験のため、FastAPI は PC や Mac などの端末上で構築し、ngrok でリクエストを受け取ります。 本格稼働には、VPS 等で実装し、Ollama 部分も API キーでクラウドの大型LLMサービスで実装すると実用性が上がるでしょう。

実装:LINE Webhook の受信

LINE からメッセージが届いた瞬間を捉え、前回実装した handle_question へつなぎます。

from fastapi import FastAPI, Request
import os

app = FastAPI()

@app.post("/webhook/line")
async def line_webhook(request: Request):
    body = await request.json()

    for event in body.get("events", []):
        if event.get("type") == "message":
            user_id = event["source"]["userId"]
            text = event["message"]["text"]

            # 人間優先の応答ロジックをトリガー
            await handle_question(user_id, text)

    return {"status": "ok"}

ここで重要なのは、handle_questionawait で呼び出している点です。FastAPI の非同期処理により、複数の LINE ユーザーからの質問を並列に扱えます。

実装:Slack 側の双方向通信

回答者への通知

質問が届いたら、Slack の専用チャンネルへ通知します。回答者はスレッド返信で回答する運用にしています。

from slack_sdk.web.async_client import AsyncWebClient

slack_client = AsyncWebClient(token=os.getenv("SLACK_BOT_TOKEN"))
RESPONDER_CHANNEL = "#virtual-ai-questions"

async def post_question_to_slack(query: str, user_id: str) -> str:
    """Slack へ質問を投稿し、メッセージの ts(タイムスタンプ)を返す。"""
    result = await slack_client.chat_postMessage(
        channel=RESPONDER_CHANNEL,
        text=f"📩 新しい質問が届きました:\n> {query}\n\nスレッドで回答してください。"
    )
    return result["ts"]  # スレッドの親メッセージ ID

回答の受け取り

Slack 側で人間が回答を投稿したら、そのイベントを受け取って LINE へ返します。

@app.post("/slack/webhook")
async def slack_webhook(request: Request):
    body = await request.json()

    # Slack Events API の URL 検証(初回のみ)
    if body.get("type") == "url_verification":
        return {"challenge": body["challenge"]}

    event = body.get("event", {})

    # スレッド返信かつ Bot 自身の投稿でない場合のみ処理
    if (event.get("type") == "message"
            and event.get("thread_ts")
            and not event.get("bot_id")):

        answer = event["text"]
        thread_ts = event["thread_ts"]

        # スレッドに紐づく LINE ユーザーを DB から特定
        task = find_task_by_thread(thread_ts)

        if task and not task.answered:
            # まだ回答されていなければ、LINE へ返信
            await send_line_message(task.user_id, answer)
            task.answered = True
            save_task(task)

    return {"status": "ok"}

ここで重要なのは task.answered フラグです。人間が回答する前に LLM がフォールバック回答を送っている可能性があるため、二重送信を防ぐ必要があります。DB 上でこのフラグを原子的に更新することで、競合状態(Race Condition)を回避します。

運用の設定:ngrok と Webhook

コードが完成したら、LINE と Slack の管理画面で Webhook URL を設定します。

ここは手続きが複雑でつまづきやすいポイントのため、詳細を別記事でも用意しました。

LINE Developers コンソール

  1. Webhook URL: https://<ngrok-domain>.ngrok.io/webhook/line
  2. イベント設定: 「メッセージイベント」を有効にする

Slack アプリ設定

  1. Event Subscriptions: https://<ngrok-domain>.ngrok.io/slack/webhook
  2. Subscribe to bot events: message.channels を追加

ngrok の注意点

ngrok は再起動するたびに URL が変わります。開発中は毎回 Webhook URL を貼り直す必要がありますが、固定ドメイン機能を使えば一度の設定で済みます。

実験を振り返って

3 回にわたって「バーチャルAI」を構築してきました。最後に、この実験で見えてきたことを整理します。

うまくいったこと

  • 技術的にはシンプル: FastAPI + asyncio + Slack API + Ollama という組み合わせで、人間優先・LLM フォールバックの仕組みは意外とすっきり実装できました。
  • 回答の質: 人間が答えた場合、文脈を踏まえた丁寧な回答になりやすい。LLM にありがちな「それっぽいが微妙にズレた回答」が出にくいのは大きなメリットです。

課題として残ったこと

  • 応答率の壁: 登録ユーザーが忙しいと、タイムアウトが頻発します。結果として LLM ばかりが答える時間帯が生まれ、「バーチャルAI」というより「普通のチャットボット」に近くなり良さが薄れます。
  • タイムアウト値のジレンマ: 短くすると LLM の出番が増え、長くするとユーザーを待たせます。「60 秒」は一つの目安ですが、最適値は運用データを見ながら探る必要があります。
  • スケーラビリティ: 質問が増えた場合、人間の回答者を増やすのは AI のスケールアップほど簡単ではありません。

また、最大の課題は、登録ユーザーが回答したいと思うモチベーションや、質問ユーザーがそもそもこのサービスを使う意義をデザインできるかです。最初こそ物珍しさで興味を持ち、実際に最初のやり取りは楽しんでもらえますが、続ければすぐに飽きてしまうでしょう。

現時点は実験段階ですが、本サービスや社会実験に進むには、この点が大きな課題です。

「人間がAIの代わりになるか」への答え

なる。ただし実現にはハードルあり。

答える人がいて、答える人数余裕があるときには、人間の回答は LLM を超えます。しかし、24 時間 365 日の安定稼働という点では、やはり LLM にはかないません。LLM を「保険」として組み込んだこのアーキテクチャには一定の柔軟性がありますが、十分な人数が控えていなければ単なるLLMとの雑談になってしまいます。

人間の知恵を主役に据えつつ、AI がそれを支える。その逆ではなく。今後 AI がさらに進化しても、この発想は一つの選択肢として残り続けるのではないでしょうか。

まとめ

全 3 回で、バーチャルAI チャットシステムを一通り構築しました。

  • 第 1 回: FastAPI、.envngrok で開発基盤を構築
  • 第 2 回: 人間優先・LLM フォールバックのコアロジックを asyncio で実装
  • 第 3 回: LINE と Slack の双方向通信を完成させ、エンドツーエンドのフローを実現

LINE で質問を送ると、Slack の回答者チャンネルに通知が飛び、答えられる人が答える。誰も答えなければ LLM が保険で回答する——「人間がAIの代わりに答える」バーチャルAI の実験は、仕組みの実証でひとまず一区切りです。

このシステムは小さな実験ですが、「AI にすべてを任せる」以外の選択肢を技術的に示せたと思います。興味を持った方は、ぜひ自分の環境でも試してみてください。

タイトルとURLをコピーしました