大量のマニュアルをGeminiに読み込ませて質問応答するシステム
Gemini APIを使って、大量のマニュアルを事前に読み込ませ、それについての質問に回答するシステムを作った。
前回はシンプルなチャットだった。今回は、特定の情報を大量に読み込ませて、その情報に基づいて回答する。マニュアルが長文でも、Geminiは理解して答えてくれる。
作ったもの
Gemini APIと大量のコンテキストを組み合わせたQAシステムだ。
HTMLファイル全体(約1000行以上のマニュアル)を読み込み、プロンプトに付加してGeminiに送る。ユーザーの質問に対して、マニュアルの内容を参照しながら回答する。
マニュアルはdoc/index_ja.htmlに格納されている。Geminiは長文のコンテキストを扱えるので、マニュアル全文を送っても問題ない。
マニュアルを読み込む仕組み
マニュアルをプロンプトに付加する処理は意外とシンプルだ。
async function loadManualText() {
const res = await fetch('doc/index_ja.html');
const text = await res.text();
// HTMLタグを除去
const plainText = text.replace(/<[^>]+>/g, '');
return plainText;
}
HTMLファイルをfetch()で取得し、HTMLタグを正規表現で除去する。プレーンテキストだけを抽出して、Geminiに送る。
最初はHTMLタグをそのまま送っていた。一度つまずいた。
タグが大量に含まれると、トークン数が無駄に増える。マニュアルの本文だけを抽出した方が効率的だ。
タグを除去した結果、トークン数が約30%削減できた。これで、より多くのマニュアルを読み込ませることができる。
プロンプトの工夫
マニュアル全文を読み込ませるため、プロンプトの構成を工夫した。
const manualText = await loadManualText();
const prompt = `【アプリのマニュアル全文】\n${manualText}\n\n【質問】\n${input}`;
マニュアル部分と質問部分を明確に区別している。Geminiが「どこがマニュアルで、どこが質問か」を正確に理解できる。
最初は単純に「マニュアル:〜 質問:〜」という形式だった。あいまいだった。
「【アプリのマニュアル全文】」と明示的に書いたら、Geminiの回答精度が上がった。これだ。
JSON形式でのアクション判定
Geminiの回答に、特定のアクション(プログラムA、B、Cの実行)を含められるようにした。
// Geminiの回答テキスト(aiText)からJSONを抽出
// chatHistory: チャット履歴の配列
// programA(), programB(), programC(): 各プログラムの実行関数(詳細は省略)
// executed: アクションが実行されたかどうかのフラグ
let match = aiText.match(/\{[\s\S]*?\}/);
if (match) {
try {
const obj = JSON.parse(match[0]);
if (obj.action === "A") {
const res = programA();
chatHistory.push({ role: 'system', text: `[A実行結果] ${res}` });
executed = true;
} else if (obj.action === "B") {
const res = programB();
chatHistory.push({ role: 'system', text: `[B実行結果] ${res}` });
executed = true;
} else if (obj.action === "C") {
const res = programC();
chatHistory.push({ role: 'system', text: `[C実行結果] ${res}` });
executed = true;
}
} catch (e) { }
}
Geminiの回答からJSONを抽出し、actionフィールドを見てアクションを判定する。該当するプログラムを実行し、結果をチャット履歴に表示する。
これで、Geminiがマニュアルを理解して、適切なプログラムを実行できる。ユーザーは「プログラムAを実行して」と言えば、Geminiが判断して実行してくれる。
トークン数の管理
マニュアルが大量にあると、トークン数が問題になる。
Gemini 1.5 Proは入力トークン上限が約100万トークン。十分な容量がある。ただし、トークン数が多いと処理時間が長くなる。
簡易的なトークン数計算(文字数÷4)を実装した。厳密にはcountTokens APIを使うべきだが、概算でも十分だ。
ユーザーが入力するたびにトークン数を表示し、上限を超えないようにチェックしている。
試行錯誤の記録
最初はマニュアルを読み込まずに、Geminiに直接質問していた。当然、答えられない。
Geminiは事前学習データしか知らないから、特定のアプリのマニュアルについては答えられない。
次に、マニュアルの一部だけを読み込ませた。不完全だった。
ユーザーが「プログラムCの使い方は?」と聞いても、プログラムCの説明がマニュアルの後半にあると、Geminiは答えられない。
マニュアル全文を読み込ませたら、すべての質問に答えられるようになった。ヨシ。
実際に試した質問
「プログラムAの起動方法を教えて」と聞いた。Geminiはマニュアルの該当箇所を参照して、起動手順を詳しく説明してくれた。正確で分かりやすい。
「プログラムBとCの違いは?」と聞いた。Geminiは両者の機能を比較して、使い分けのアドバイスまでくれた。マニュアルにはない視点で説明してくれる。意外だった。
「エラーが出た時の対処法は?」と聞いた。マニュアルのトラブルシューティングセクションを引用しながら、具体的な解決策を提示してくれた。
全体の流れ
マニュアルを読み込み、ユーザーの質問と組み合わせてGeminiに送信。Geminiが回答を生成し、必要に応じてアクションを実行する。
使ってみて
大量のマニュアルをGeminiに読み込ませて質問応答するシステムを作った。
ポイントは以下の3つ:
- HTMLマニュアル全文を取得し、HTMLタグを除去してトークン数を削減
- プロンプトでマニュアル部分と質問部分を明確に区別
- JSON形式でアクション判定し、対応する関数を実行
Gemini 1.5 Proの長文コンテキスト処理能力を活用できた。マニュアルが長くても、的確に回答してくれる。
同じようなQAシステムを作りたい方の参考になれば嬉しいです。
まとめ
今回は、Gemini APIで大量のマニュアルを読み込ませるQAシステムを作った。
ポイントは以下の4つ:
- HTMLマニュアル全文を取得し、タグを除去(トークン数約30%削減)
- プロンプトで【マニュアル全文】と【質問】を明確に区別
- JSON形式でアクション判定(A、B、C)
- Gemini 1.5 Proの入力トークン上限約100万を活用
マニュアル全文を読み込ませることで、すべての質問に答えられるシステムができた。Geminiの長文処理能力の高さを実感した。
さらに深く学ぶには
この記事で興味を持った方におすすめのリンク:
自分の関連記事:
最後まで読んでくださり、ありがとうございました。