はじめに
本記事は、生成AIの良回答を 育てる ための 専門チャット検索機能 を作った話 の Part2 です。
なお、本記事の記載内容は、構成要素 と 処理フロー を設計として整理するにとどめ、実装コードの記載はしておりません。
理由はコードはライブラリのバージョンや実行環境で陳腐化しやすい一方、設計は新たな実装時にも再利用しやすいためです。
本記事で説明すること
- サーバー起動 と 検索 を以下の内容を中心に、
緩く説明 ※1します。- コンポーネント図
- サーバー起動時の処理フロー
- 質問から回答までの処理フロー
- RAGアプリとして見た場合の構成要素との対応
- 用語解説
- まとめ
※1. 要するに 本機能 の構成要素は サーバー起動 と 検索 だけではない、ということです。(笑)
コンポーネント図
補足説明
Compute Engine 上の構成
VMインスタンス に配置される 本機能 は、以下のレイヤで構成されます。
| レイヤ | 目的 |
|---|---|
| Guest OS (Debian) | ブートディスクのソースイメージとして指定する Guest OS(Debian) です。 |
| Nginx | 本機能 の フロントエンド を配置します。 |
| Docker Container (chat-search-app) | 本機能 の バックエンド を配置します。 |
レイヤ毎の構成
Nginx
WebUI
- インデックスHTML
| コンポーネント | 目的 |
|---|---|
| Search | 検索UI です。以下の 検索条件 を実装します。 - カテゴリ。 - サジェスト。 - 質問。 - 前提。 - 要件。 - 依頼。 |
| 回答 | 回答UI です。 質問に対する コーパスから回答 または Gemini API 連携 結果を表示します。 |
- メンテナンス中HTML
| コンポーネント | 目的 |
|---|---|
| メンテナンス中HTML |
ONNXモデル をロード中(準備中)、または ワーカースレッド 準備中に 本機能 にアクセスした場合当該HTMLを表示して、メンテナンス中 である旨をクライアントに知らせます。 メンテナンス中 とした理由は、準備中となる要因がデプロイ処理(メンテナンス)であるためです。 |
Docker Container (chat-search-app)
ExpressApp (Node.js + Express)
エンドポイント
- サーバー
| コンポーネント | 目的 |
|---|---|
| サーバー | 初期化(Top-level処理) サーバー起動 |
- API
| コンポーネント | 目的 |
|---|---|
| API | WebUIからのリクエストをもとに コーパス を検索対象として サービス を呼び出します。検索結果をもとに ルーティング判定 を呼び出して 判定結果 を取得します。 判定結果 をもとに回答(コーパスから回答 または Gemini API 連携)を WebUI に返却します。 |
サービス
ビジネスロジックを担当する層です。
| コンポーネント | 目的 |
|---|---|
| サービス | サービスとして以下の機能を実装します。 ・設定ファイルアクセスサービス ・カテゴリ別ナレッジベースアクセスサービス ・代表クエリアクセスサービス ・コーパスアクセスサービス ・評価レポートアクセスサービス ・検索サービス 1. BM25検索。 2. ベクトル検索。 3. RRF統合。 |
リポジトリ
データアクセスを担当する層です。
| コンポーネント | 目的 |
|---|---|
| リポジトリ | リポジトリとして以下の機能を実装します。 - 設定ファイル の読み込み。- カテゴリ別ナレッジベース の読み込み。- 代表クエリ の読み込み。- コーパス の 読み込み と 書き込み。- 評価レポート の書き込み。 |
ワーカースレッド
| コンポーネント | 目的 |
|---|---|
| ワーカークライアント | ベクトル検索 から呼び出され、ワーカー に 推論 を委譲します。 |
| ワーカー | ワーカークライアントからの POSTメッセージ受信 をトリガーに、推論 を呼び出します。 |
推論
| コンポーネント | 目的 |
|---|---|
エンベディング |
質問に対する ベクトル値 を取得します。 |
ルーティング
| コンポーネント | 目的 |
|---|---|
| ルーティング判定 | RRF統合スコアから コーパスから回答 または Gemini API 連携 を判定して判定結果を返却します。 |
CLIツール
運用スクリプト
| コンポーネント | 目的 |
|---|---|
コーパス作成スクリプト |
カテゴリ別ナレッジベース を読み込みトークナイズ(分かち書き) と ベクトル値 を埋め込んだ コーパス を出力します。 |
保守スクリプト
| コンポーネント | 目的 |
|---|---|
評価レポート作成スクリプト |
代表クエリ と コーパス に対する BM25検索 と ベクトル検索 の結果を RRF で統合し得られた RRF統合スコア の最小値を 推奨しきい値 として 評価レポート に出力します。 |
Guest OS (Debian)
スクリプト
導入
| コンポーネント | 目的 |
|---|---|
ディレクトリ構成構築スクリプト |
本機能 の ディレクトリ構成の構築 と設定ファイル のテンプレートを出力します。 |
運用
| コンポーネント | 目的 |
|---|---|
カテゴリ別ナレッジベース作成スクリプト |
カテゴリ別ナレッジベース のテンプレートを Markdown で出力します。 |
デプロイ処理スクリプト |
Compute Engine 上で動作する Docker Container のデプロイを自動化します。 |
環境変数
| コンポーネント | 目的 |
|---|---|
.envファイル |
APIキーを格納します。 |
データモデル
Part1 の データモデル を参照してください。
AIモデル
Part1 の AIモデル を参照してください。
サーバー起動時の処理フロー
補足説明
この処理フローは、Docker Container 内で Node.js プロセスが起動され Express がポート 3000 を listen する状態になるまでを表しており
大きく以下の 4 フェーズに分かれます。
- フェーズ1: Top-level処理
- フェーズ2: 初期データの読み込み と Gemini API クライアント生成
- フェーズ3: EagerLoad
- フェーズ4: サーバー起動
フェーズ1: Top-level処理
-
dotenvライブラリにより環境変数の内容を取得します。dotenv.config() -
プロキシ環境下でのクライアントIPアドレス取得を有効化します。
app.set("trust proxy", 1) -
ミドルウェア適用
-
morgan
- HTTP リクエストロギング用のミドルウェア morgan を組込みます。
-
express.json()
- JSON ボディパーサーミドルウェアの組込みを組込みます。
-
-
APIエンドポイント登録呼び出し
- API側の初期処理
- ミドルウェア適用
- limiter ミドルウェアを 検索API に設定します。
-
express-rate-limitにより 1分間に10回までのリクエスト を許可します。設定内容は以下の通りです。- ウィンドウ: 1分間
- 最大リクエスト数: 10回
-
- ミドルウェア readiness判定を 検索API に設定します。
- readiness判定とは
ONNXモデルや ワーカースレッド が準備できていない場合、検索API を受け付けない仕組みです。
- readiness判定とは
- limiter ミドルウェアを 検索API に設定します。
- ミドルウェア適用
- API側の初期処理
フェーズ2: 初期データの読み込み と Gemini API クライアント生成
- 初期データの読み込み
設定ファイルコーパス代表クエリ
- Gemini API クライアント生成
- Google が提供している Node.js/TypeScript 向けの公式 Gen AI SDK (@google/genai パッケージ) を使用します。
フェーズ3: EagerLoad
-
EagerLoadを非同期に実行 ※1
※1.
EagerLoad の処理内容は 検索サービス と同じです。
検索サービス の詳細は「質問から回答までの処理フロー」の フェーズ2: 検索サービス(BM25検索・ベクトル検索・RRF統合)呼び出し を参照してください。
技術的制約
- リソース制約
- e2-micro インスタンスは CPU/メモリ が限られています。
- e2-micro(2個の vCPU, 1 GBメモリ) + Swap領域 4 GB
- このため、
ONNXモデルを使用した パイプラインロード と推論に大きな負荷が掛かり処理速度に影響を与えます。 -
EagerLoadを実行することにより、初回リクエスト時の待ち時間を短縮しています。
- e2-micro インスタンスは CPU/メモリ が限られています。
フェーズ4: サーバー起動
- 3000番ポートで HTTP リクエストのリスニングを開始します。
質問から回答までの処理フロー
補足説明
この処理フローは、利用者 が WebUI から検索を実行した際に、
ExpressApp上でどのように処理が進み、コーパスから回答 または Gemini API 連携 により回答が返却されるまでを
API を中心に表しており、大きく以下の 4 フェーズに分かれます。
- フェーズ1: リクエストパラメータ取得
- フェーズ2: サービス(BM25検索・ベクトル検索・RRF統合)呼び出し
- フェーズ3: ルーティング判定(コーパスから回答 または Gemini API 連携)呼び出し
- フェーズ4: 結果作成とレスポンス返却
フェーズ1: リクエストパラメータ取得
- 以下のリクエストパラメータを取得します。
- カテゴリ。
- 質問。
- 前提。
- 要件。
- 依頼。
フェーズ2: 検索サービス(BM25検索・ベクトル検索・RRF統合)呼び出し
検索は Precision@5 を指標として、BM25検索 と ベクトル検索 を実行し
BM25関連度スコア と コサイン類似度スコア を RRF により統合して最終スコアの順位付けをします。
1. BM25検索
-
BM25関連度スコア算出
- カテゴリで絞り込んだ
コーパスと質問の BM25関連度スコア を算出します。
- カテゴリで絞り込んだ
-
BM25関連度スコア 降順ソート
- 算出した BM25関連度スコア を降順にソートし、上位5件 を抽出して返却します。
2. ベクトル検索
- ワーカースレッド
- ワーカークライアント から ワーカー を呼び出します。
- ワーカー から
推論を呼び出します。-
推論- 量子化された
ONNXモデルをxenova/transformersによって パイプラインロード し パイプラインインスタンス を取得します。 - 取得した パイプラインインスタンス によって、質問に対する
ベクトル値を取得します。-
onnxruntime-nodeによって質問を量子化されたONNXモデルに入力します。 - 量子化された
ONNXモデルがエンベディングを実行して質問に対するベクトル値を取得します。
-
- 量子化された
-
-
コサイン類似度スコア 算出
- カテゴリで絞り込んだ
コーパスと質問のベクトル値で コサイン類似度スコア を算出します。
- カテゴリで絞り込んだ
-
コサイン類似度スコア降順ソート
- 算出した コサイン類似度スコア を降順にソートし、上位5件 を抽出して返却します。
3. RRF統合
- BM25関連度スコア と コサイン類似度スコア を RRF で統合し、RRF統合スコア を算出します。
- 算出した RRF統合スコア を降順にソートし、上位5件 を抽出して返却します。
フェーズ3: ルーティング判定(コーパスから回答 または Gemini API 連携)呼び出し
- 1位の RRF統合スコア と
設定ファイルのしきい値を比較し、以下の判定結果を返却します。- 1位の RRF統合スコア が しきい値以上
- コーパスから回答
- 1位の RRF統合スコア が しきい値未満
- Gemini API 連携
- 1位の RRF統合スコア が しきい値以上
フェーズ4: 結果作成とレスポンス返却
コーパスから回答
- コーパスから回答 を作成して API から WebUI にレスポンスを返却します。
Gemini API 連携
- Gemini API 連携 を実行、連携結果から回答を作成して API から WebUI にレスポンスを返却します。
RAGアプリとして見た場合の 構成要素 との対応
本機能、一般的なRAG構成に当てはめると次のようになります。
| RAGの要素 | 本機能での構成要素 | 設計上の意味 |
|---|---|---|
| Knowledge Source | カテゴリ別ナレッジベース |
外部知識のもとになるデータです。 |
| Index | コーパス |
検索しやすい形に構造化した外部知識です。 BM25検索用情報とベクトル検索用情報を、あらかじめ埋め込みます。 |
| Retriever | サービス |
外部知識を検索するための仕組みです。 本機能ではBM25検索、ベクトル検索、RRF統合で外部知識を取得します。 |
| Embedder | 推論 |
質問や外部知識の埋め込み ベクトル値 を取得する ONNXモデル です。 |
| Orchestrator | API + サービス + ルーティング判定 |
システム全体のデータの流れを制御するコントローラです。 検索、判定、生成AIフォールバックを制御します。 |
| Generator | Gemini API |
質問が外部知識にない場合、生成AIで回答生成を行います。 |
| UI | WebUI |
利用者の質問入力と回答表示を担当します。 |
用語解説
| 用語 | 役割と意味 |
|---|---|
| RAG | Retrieval-Augmented Generation の略です。 生成AIに直接すべてを答えさせるのではなく 検索で取得した外部知識を根拠として回答生成に利用するシステムです。 |
コーパス |
検索対象として整形された文書です。 本機能ではカテゴリ別ナレッジベースを検索用JSONに変換したものを指し カテゴリ別ナレッジベースの回答を トークナイズ(分かち書き) した結果および ベクトル値 を埋め込みます。 |
EagerLoad |
処理時間を抑える目的のため 関連データをあらかじめ読み込む方式です。 |
| readiness判定 | アプリケーションがリクエストを受け付けられる状態かを示すことです。 本機能では ONNXモデル のロード状態、ワーカースレッド の状態を見て システム利用可能/システム利用不可 を判定します。 |
| Precision@5 | 上位5件の検索結果のうち、正解がどれだけ含まれているかを表す評価指標です。 |
トークナイズ(分かち書き) |
文書を意味のある単位(単語・形態素)に分割します。 例: 質問が "DAO 設計 JPA SQL" の場合 "dao", "設計", "jpa", "sql" に分割。 BM25検索の入力パラメータになります。 |
| BM25検索 | キーワード一致に強い検索方式です。 トークンの出現頻度と文書長をもとに関連度を算出します。 |
| BM25関連度 | 本機能においては、「質問の トークナイズ(分かち書き)」と「コーパス に含まれる トークナイズ(分かち書き)」を比較し質問のトークンがどの程度一致しているかを数値化します。 |
| ベクトル検索 | 本機能においては、質問に対する ベクトル値 と コーパス 内の各 ベクトル値 を比較し意味の近さで検索する方式です。 表現が違っても意味が近い文書を拾いやすくします。 |
| コサイン類似度 (Cosine Similarity) | 本機能においては、「質問に対する ベクトル値」と「コーパス に埋め込まれる ベクトル値」の 向き(意味) がどの程度近いかを数値化します。 向き(意味) が近いほど、質問と コーパス の意味が近いと判断します。 |
| RRF統合 | Reciprocal Rank Fusion の略です。 BM25検索結果 と ベクトル検索結果 を順位ベースで統合し 検索方式ごとの偏りを抑え順位付けする方式です。 |
推奨しきい値 |
本機能においては、コーパスから回答 するか Gemini API 連携 するかを判定する 境界値 です。 |
| ワーカースレッド | Node.jsでCPU負荷の高い処理をメインスレッドから分離して実行する仕組みです。 |
推論 |
本機能においては、onnxruntime-node によって文書を ONNXモデル に入力し、ベクトル値 を取得することです。 |
AIモデル |
本機能における AIモデル とは「文書を ベクトル値 に変換」する「学習環境から 変換・出力 された 学習済みモデル」を指します。学習済みモデル とは、文書を意味的な数値列 (ベクトル値)に変換するシステムです。意味的な数値列 (ベクトル値)とは意味が近い文書ほど近くに配置されるように数値化されたデータを指します。 |
| 学習環境 |
AIモデル に学習データを与え、新しい AIモデル を作成するための実行環境です。 |
ONNXモデル |
Open Neural Network Exchange の略です。AIモデル を ONNXという共通形式 で 変換・出力 したものです。本機能では ONNXモデル を 推論 のために使用します。 |
エンベディング |
文書を ベクトル値 に変換する処理で、ベクトル検索の入力パラメータになります。本機能では文書の ベクトル値 を取得するために- @xenova/transformers (ライブラリ) - model_quantized.onnx (ONNX形式の量子化モデル) を使って 日本語 を含む多言語文書をベクトル検索用の ベクトル値 に変換しています。 |
| @xenova/transformers |
ONNXモデル で 推論 を実行するためのコントローラーで、以下を実行します。- 文書のトークナイズ(単語ID化)。 - onnxruntime-node 呼び出し。 - ONNXモデル が出力したトークンごとの ベクトル値 を平均化して文書に対する384次元ベクトル(384個の数値)を出力します。 |
| onnxruntime-node |
ONNXモデル を Node.js 環境 からネイティブ実行する 推論エンジン です。 |
| 量子化モデル | 精度の低下を最小限に抑えて、INT8などの 重みパラメータの精度を縮小・離散化 する技術を用いて軽量化した AIモデル です。メリットはメモリ消費量が少なく、ファイルサイズも小さいので高速に 推論 することが可能となります。推論精度は非量子化モデルに比べ、95% 〜 99%(実用上ほぼ同等) です。 |
| 非量子化モデル | 高精度(FP32)な重みパラメータを持つ精度の高い AIモデル です。メリットは推論精度が高く、モデル本来の性能を 100%(基準値として) 発揮できることです。 |
まとめ
Part2 では、専門チャット検索機能の現在の構成を、コードではなく設計として整理しました。
Part3 では、ホスティング環境 とした理由と、コンポーネント図 とした理由を、課題一覧 の 課題No.1 プラットフォームの選定 と紐付けて 説明 します。


