REST APIの基礎知識
REST APIはクライアントとサーバー間の通信を実現するインターフェースです。Representational State Transfer APIの略称であり、特定のエンドポイントに対してHTTPリクエストを送信することで、サーバーが処理を行う仕組みです。プロジェクトではFastAPIを利用して以下の主要なHTTPメソッドを実装します。
RAGとFastAPIの融合
なぜこの組み合わせが最適なのか、その理由を探っていきます。
RAGとは何か
検索強化生成(RAG)は、大規模言語モデルが外部ナレッジベースを活用できるようにする技術です。まるで制限時間付きテストに臨む学生のように動作します。質問に対して、まず参考資料から関連情報を検索し、その情報を基に正確な回答を作成します。RAGのアーキテクチャは以下の二つの要素から構成されます:
- 検索コンポーネント:ユーザーの質問に基づき、文書群から最も関連性の高い情報を見つけ出す
- 生成コンポーネント:大規模言語モデルが取得した情報をコンテキストとして、最終的な回答を生成する
このアプローチにより、言語モデルの知識期限切れや虚偽生成といった問題を効果的に解決し、汎用モデルとプライベートデータを接続する理想的な橋渡しとなります。
FastAPIを選択する理由
FastAPIはAPI開発に特化した現代的な高パフォーマンスPythonフレームワークです。本プロジェクトにおいて以下の利点があります:
- 自動ドキュメント生成:コード記述だけでSwagger UIが生成され、ブラウザ上で直接APIテストが可能
- 型ヒントベースの検証:Pydanticモデルを利用したリクエスト検証とシリアライズ機能
- 非同期処理対応:ファイル操作やネットワークリクエストなどのI/Oバウンド処理に最適
- 高速なパフォーマンス:StarletteとPydanticの恩恵により、Node.jsやGo並みの速度を実現
実装ステップ
実際のコード実装では以下の2つの主要エンドポイントを構築します:
/process:PDFまたはTXT形式の文書を受け取り、チャンキング・ベクトル化してFAISSインデックスに格納/search:ユーザーの質問を受け取り、関連文書ブロックを検索し、言語モデルで回答を生成
環境設定
必要な準備:
- OpenAI APIキーを取得し、プロジェクトルートに
.envファイルを作成して以下を追加:OPENAI_API_KEY=your_api_key_here
- Python仮想環境を作成・有効化し、依存パッケージをインストール
requirements.txtの内容:
fastapi uvicorn[standard] python-multipart langchain langchain-community langchain-openai faiss-cpu openai pypdf python-dotenv
コマンド:pip install -r requirements.txt
コアロジック:document_processor.py
このモジュールはRAGの全プロセスをカプセル化しています:
# リクエスト間で共有されるグローバルベクトルストア
global_store: FAISS | None = None
text_encoder = OpenAIEmbeddings(model=EMBEDDING_MODEL_NAME)
def _initialize_store() -> FAISS | None:
"""既存のFAISSインデックスをディスクから読み込む"""
global global_store
if global_store is None and os.path.exists(INDEX_STORAGE_PATH):
global_store = FAISS.load_local(
INDEX_STORAGE_PATH,
text_encoder,
allow_dangerous_deserialization=True
)
return global_store
def handle_file(upload_path: str, original_name: str = "") -> int:
"""
アップロードされた文書を処理:読み込み、分割、ベクトル化、インデックス登録
処理されたチャンク数を返却
"""
global global_store
# 1. 拡張子に応じたローダー選択
if upload_path.endswith(".pdf"):
loader = PyPDFLoader(upload_path)
else:
loader = TextLoader(upload_path)
docs = loader.load()
# 全チャンクにファイル名情報を付与
source_info = original_name or os.path.basename(upload_path)
for doc in docs:
doc.metadata["source"] = source_info
# 2. テキスト分割処理
segmenter = RecursiveCharacterTextSplitter(
chunk_size=SEGMENT_SIZE,
chunk_overlap=SEGMENT_OVERLAP,
separators=["\n\n", "\n", ".", " ", ""]
)
segments = segmenter.split_documents(docs)
# 3. ベクトル埋め込みとストアへの追加
if global_store is None:
global_store = FAISS.from_documents(segments, text_encoder)
else:
global_store.add_documents(segments)
# インデックスをディスクに永続化
global_store.save_local(INDEX_STORAGE_PATH)
return len(segments)
サービス起動
ターミナルで以下のコマンドを実行:
uvicorn main:app --reload
http://127.0.0.1:8000/docsにアクセスすると、自動生成されたSwagger UIが表示され、すべてのAPIエンドポイントをテストできます。
テストプロセス
文書処理とインデックス作成(/process)
Swagger UIで/processエンドポイントを選択し、PDFファイルをアップロードして実行します。成功すると文書が正しく分割・インデックス登録されたことを示すレスポンスが返ります。faiss_indexフォルダがプロジェクトディレクトリに作成され、サービス再起動後もデータが保持されます。
インテリジェント検索(/search)
/searchエンドポイントをテストします。例えば「人工知能の応用例は?」という質問を入力し、top_k=4を設定します。実行後、システムは回答とその根拠となる文書ソースを返却します。回答はアップロードした文書内容に基づいて生成されており、信頼性を高めるために情報源が明示されています。
HTTPステータスコードの理解
API開発において、適切なHTTPステータスコードの使用は重要です。これらは簡潔なコードでクライアントにリクエスト処理結果を伝達します。
- 2xx 成功:200 OKなど、リクエストが正常に処理されたことを示す
- 4xx クライアントエラー:リクエスト側に問題がある場合。例:400 Bad Request(サポート外ファイル形式や空の質問)、422 Unprocessable Entity(Pydanticモデル不適合)
- 5xx サーバーエラー:サーバー処理中に予期せぬエラーが発生。FAISSやOpenAI呼び出し失敗時に500 Internal Server Errorを返却
適切なステータスコードの使用により、APIの堅牢性と使いやすさが向上します。
まとめと今後の改善
本記事ではFastAPIベースのRAGシステムを構築・展開しました。このシステムは以下の機能を持っています:
- PDFおよびTXT文書の受信とインデックス作成
- ユーザー質問に基づく文書からの情報検索
- 大規模言語モデルによる正確な回答生成
このプロジェクトはRAG技術の実装プロセスを示し、FastAPIがAIサービス構築においてどれだけ効率的かつ便利であるかを実証しています。
将来の最適化方向性:
- 検索戦略の改善:MMR(Maximum Marginal Relevance)など、関連性と多様性をバランスする手法の導入
- 分割戦略の最適化:文書タイプや言語ごとに最適なチャンクサイズとオーバーラップを調整
- 複合検索:BM25などのキーワード検索とベクトル検索を組み合わせてリコール率向上
- フロントエンド開発:チャットインターフェースの実装によるユーザーエクスペリエンス向上