Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Prevent Hallucinated Bot Commands: Build an LLM Tool Loop for Telegram in Node.js

2026年10月27日に「Dev.to」が公開したITニュース「Prevent Hallucinated Bot Commands: Build an LLM Tool Loop for Telegram in Node.js」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

LLM搭載Telegramボットで直接指示を実行させると、ハルシネーションや情報漏洩のリスクがある。これを防ぐには、Node.jsで「関数呼び出し(ツール利用)」を実装する。LLMは意図をJSONで出力し、アプリがローカルコードを実行、その結果を元にLLMが最終応答を生成する。厳密なスキーマ定義とループ制御が重要だ。

ITニュース解説

大規模言語モデル(LLM)の発展は、チャットボット開発に大きな可能性をもたらした。特にTelegramのようなメッセージングプラットフォームでLLMを搭載したボットを開発する際、単なる質問応答だけでなく、「注文状況の確認」や「レストランの予約」といった具体的なアクションをボットに実行させたいと考えるのは自然な流れである。しかし、この種の機能を素朴な方法で実装すると、予期せぬ問題に直面することが多い。

開発者が最初に試みがちなのは、ユーザーのメッセージをLLMに直接渡し、LLMが生成したテキストをそのままボットの返答として送り返す方法である。このアプローチは一般的な質問応答には有効だが、具体的なアクションを伴う指示、例えば「注文番号9482の状況を教えて」といった要求に対しては、うまく機能しない。

主な問題点は、LLMが「幻覚(Hallucination)」を起こすことにある。これは、LLMがもっともらしいが架空の情報や、ユーザーが指定していないパラメータをでっち上げてしまう現象を指す。例えば、注文IDが不明な場合でも、LLMが適当なIDを生成し、誤ったデータベースクエリを引き起こす可能性がある。

また、開発者がLLMにJSON形式で特定の情報を返すよう指示しても、LLMは常にその指示に厳密に従うとは限らない。JSONブロックをMarkdown形式で囲んだり、不要な会話文を付加したり、あるいは解析不能な形式で出力したりすることが頻繁に発生する。このような不正確な出力は、ボットのプログラムがLLMの応答を解析する際にエラーを発生させ、機能不全を招く。

さらに深刻なのは、システムに関する機密情報(データベースの構造、APIキー、ボットトークンなど)をLLMのシステムプロンプトに直接含めてしまうリスクである。これは、悪意のあるユーザーが「プロンプトインジェクション」という手法を使い、LLMからこれらの機密情報を引き出す可能性があり、ボットのセキュリティを著しく損なう。

これらの課題を解決し、信頼性の高いトランザクションボット、つまり具体的な操作を正確に実行できるボットを構築するためには、「厳密な関数呼び出し(Tool Use / Function Calling)」という設計パターンを導入する必要がある。このパターンでは、LLMはアクションを直接実行せず、機密情報にアクセスすることもない。LLMは、ユーザーの意図を「何をすべきか」という構造化されたデータ(JSON形式)として出力する役割に徹する。

この構造化された意図を受け取ったNode.jsアプリケーションが、その意図に基づいてローカルに実装された実際のコードを実行する。例えば、データベースから情報を取得したり、外部のAPIを呼び出したりする処理だ。その実行結果は再びLLMにフィードバックされ、LLMはこの結果を元に、最終的にユーザーにとって自然で分かりやすい返答を生成し、Telegramユーザーに送り返す。

この仕組みの最初のステップは、ボットが実行できる具体的な「ツール」(関数)を明確なスキーマとして定義することにある。このスキーマは、LLMに「私にはこのような機能があり、この機能を使うには、このような情報(パラメータ)が必要です」と教えるための設計図である。

例えば、「注文状況を取得する get_order」というツールと、「テーブルを予約する create_booking」というツールを定義する。get_order ツールには「注文ID」が必須の文字列として、create_booking ツールには「ゲスト名」「人数」「予約時間」が必須のパラメータとして詳細に記述される。このように必須フィールドをスキーマで指定することで、もしユーザーが「注文は?」とだけ尋ね、注文IDを伝えなかった場合、LLMは勝手にIDを生成するのではなく、「注文IDを教えてください」とユーザーに確認を促すようになる。

ツール定義において最も重要なことは、データベース接続情報やAPIキーのような機密情報を決して含めてはならないという点である。LLMはあくまで関数の引数のみを受け取り、実際の処理はNode.jsアプリケーション内部で行われるため、機密情報がLLMを介して外部に漏洩する心配はない。

安全なツール実行ループの具体的な流れは以下の通りである。

  1. 最初の呼び出し: ユーザーからのメッセージと、ボットが利用可能なツール(関数)の定義をLLMに送る。
  2. ツール呼び出しの確認: LLMがユーザーの意図を解釈し、特定のツールを呼び出す必要があると判断した場合、そのツールの名前と必要な引数を構造化された形式で出力する。LLMはこの時点で最終返答の生成を一時停止する。
  3. ローカルでの関数実行: Node.jsアプリケーションは、LLMが要求したツール呼び出しを受け取り、指定された引数を用いて、自ら実装したローカル関数を実行する。
  4. 結果のフィードバック: ローカル関数の実行結果(例えば、注文の詳細情報)を、再びLLMに「ツールからの応答」として送り返す。
  5. 最終応答の生成: LLMはツールからの応答を受け取り、それを踏まえて、ユーザーにとって自然で分かりやすい最終的なテキストを生成する。このテキストがTelegramユーザーに返答として送られる。

このような多段階の会話ループを構築することで、LLMの幻覚や出力形式の不安定さに依存せず、かつ機密情報を安全に保ちながら、信頼性の高いボットを実現できる。

しかし、この仕組みを本番環境で運用する際には、いくつかの注意点がある。 一つは「ループの深さのガードレール」だ。LLMがツール呼び出しを無限に繰り返すことを防ぐため、一回のユーザーとのやり取りにおけるツール実行の最大回数を設定し、超過した場合は処理を中断する。 次に、「メッセージ長の制限」である。Telegramのメッセージには文字数制限があるため、データベースから大量のデータが取得された場合、Node.js側でデータを適切に切り詰める必要がある。また、LLMが生成した最終応答が長すぎる場合も、分割して送信する工夫が必要だ。 さらに、「非同期処理とタイムアウト」も考慮すべき点だ。LLMへの問い合わせやデータベースクエリは時間を要するため、TelegramのWebhookの応答時間制限を超過する可能性がある。これを避けるため、即座に「入力中」などのステータスを返したり、時間のかかる処理はバックグラウンドジョブに回したりする対策が求められる。 最後に、「入力のサニタイズ」は極めて重要である。LLMが生成した引数も、ユーザー入力に基づいているため、常に信頼できないデータとして扱うべきだ。これらの引数をSQLクエリなどに渡す前に、必ず型検証と適切なエスケープ処理を行い、セキュリティリスクを防ぐ必要がある。

このように、LLMを活用したTelegramボットで安定した機能を実現するには、LLMの能力だけに頼るのではなく、厳密なツール定義、安全な実行ループ、そして本番運用を見据えた堅牢な設計が不可欠である。

関連コンテンツ

関連IT用語

関連ITニュース