FastAPIとPineconeでRAG!信頼性の高い栄養チャットボット構築ガイド
信頼できるAI栄養アシスタントの構築方法を紹介。科学データのベクトル化、Pineconeのセマンティック検索設定、FastAPIバックエンドのデプロイを解説。科学的根拠に基づく正確な回答を実現します。
このページの内容
「赤身肉は体に悪い?」「ヴィーガン蛋白質の最佳源は?」情報過多の時代において、nutritionに関する明確で信頼できる回答を得ることは、驚くほど難しいことです。矛盾するブログ投稿、古くなったアドバイス、科学的な裏付けを欠いたアルゴリズム主導のコンテンツに常常に出会います。開発者にとって、この混乱は興味深い技術的課題を提示しています:正確で証拠に基づいた栄養ガイダンスを提供するツールを構築することは可能でしょうか?
これがこのプロジェクトショーの目的です。科学的論文の信頼できる知識ベースのみに基づいて栄養質問に回答する、智能AIアシスタント「NutriRAG」チャットボットを構築します。
以下、最新の強力なAIスタックを使用します:
- FastAPI:高性能で使いやすいAPIバックエンド
- Pinecone:超高速類似性検索用の管理ベクトルデータベース
- Sentence-Transformers:科学的テキストを意味のあるベクトル埋め込みに変換
- OpenAIやローカルモデルなどの大規模言語モデル(LLM):人間らしい回答を生成
本記事では、データの準備からライブAPIエンドポイントの展開まで、全プロセスを解説します。検索拡張生成(RAG)の背後にある中心概念を学び、自分の Specialized チャットボットを構築するための実践的なスキルを習得できます。
問題の理解
標準的なLLMは、広範なインターネットデータで訓練されています。非常に博識ですが、ユースケースには2つの主要な制限があります:
- ハルシネーション(幻覚):健康関連のトピックでは危険な、自信を持って虚偽の事実を生成したり、古くなった情報を提示したりすることがあります。
- 特異性の欠如:その知識は一般的なものです。最近の同僚審査済み栄養科学論文精心に選択されたセットでは訓練されていません。
RAGアーキテクチャはこの問題を解決します。LLMに単に質問する代わりに、まず信頼できる知識ベースから関連情報を検索し、その情報をコンテキストとしてLLMに渡します。これにより、モデルは提供されたソースに基づいて回答を生成し、正確性が劇的に向上し、応答の生成に使用された正確なドキュメントを引用することが可能になります。
私たちのアプローチは検証可能、** Specialized**、信頼できるため、より優れています。
前提条件
ikuti하려면、以下が必要です:
- Python 3.8以上:Pythonの最新バージョンがインストールされていることを確認
- Pineconeアカウント:Pinecone.ioで無料層アカウントにサインアップし、APIキーを取得
- LLM APIキー:OpenAIなどのプロバイダーからのAPIキー、またはアクセス可能なローカルLLM
- PythonとAPIの熟悉度:PythonプログラミングとREST API概念の基本知識が役立ちます
- 精选ドキュメント:栄養に関する科学的論文または信頼できるテキストのコレクション(例:
.txtまたは.pdf形式)。このプロジェクトでは、PubMedなどのソースからの要旨を保存することから始められます
まず、プロジェクト環境をセットアップしましょう。新しいプロジェクトディレクトリと仮想環境を作成します:
mkdir nutritrag-project
cd nutritrag-project
python -m venv venv
source venv/bin/activate # Windowsでは `venv\Scripts\activate`
次に、必要なライブラリを含むrequirements.txtファイルを作成します。
# requirements.txt
fastapi
uvicorn[standard]
pinecone-client
sentence_transformers
python-dotenv
langchain
langchain-openai
pipを使用してインストールします:
pip install -r requirements.txt
最後に、APIキーを安全に保存するための.envファイルを作成します。
# .env
PINECONE_API_KEY="YOUR_PINECONE_API_KEY"
OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
ステップ1:データ準備と埋め込み
何をしているか
any RAGシステムの第一步は、知识库的準備です。これには,营养記事を読み込み,管理可能なチャンクに分割し,これらのチャンクをベクトル埋め込みに変換することが含まれます。埋め込みとは、テキストのセマンティックな意味を捉える数値表現であり、ベクトルを比較することで類似したテキストを見つけることができます。
実装
このステップでは、ingest.pyというスクリプトを作成します。科学的記事をdata/という名前のディレクトリに保存していることを前提とします。
# ingest.py
import os
from dotenv import load_dotenv
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import DirectoryLoader
from langchain_community.embeddings import HuggingFaceEmbeddings
from pinecone import Pinecone, ServerlessSpec
# 環境変数を読み込む
load_dotenv()
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
PINECONE_INDEX_NAME = "nutritrag"
def ingest_data():
"""Pineconeにドキュメントを読み込み、チャンク化し、埋め込み、保存する。"""
# 1. dataディレクトリからドキュメントを読み込む
loader = DirectoryLoader('data/', glob="**/*.txt", show_progress=True)
documents = loader.load()
print(f"{len(documents)}個のドキュメントを読み込みました。")
# 2. ドキュメントをより小さなピースにチャンク化
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
docs = text_splitter.split_documents(documents)
print(f"{len(docs)}個のチャンクに分割しました。")
# 3. 埋め込みを作成
embeddings_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
print("埋め込みモデルを読み込みました。")
# 4. Pineconeを初期化し、インデックスを作成
pc = Pinecone(api_key=PINECONE_API_KEY)
if PINECONE_INDEX_NAME not in pc.list_indexes().names():
pc.create_index(
name=PINECONE_INDEX_NAME,
dimension=384, # all-MiniLM-L6-v2の次元数
metric='cosine',
spec=ServerlessSpec(
cloud='aws',
region='us-east-1'
)
)
print(f"Pineconeインデックス '{PINECONE_INDEX_NAME}' を作成しました。")
index = pc.Index(PINECONE_INDEX_NAME)
# 5. バッチでPineconeに埋め込みをアップサート
batch_size = 100
for i in range(0, len(docs), batch_size):
batch = docs[i:i+batch_size]
ids = [f"doc_{i+j}" for j in range(len(batch))]
texts = [doc.page_content for doc in batch]
embeds = embeddings_model.embed_documents(texts)
metadata = [doc.metadata for doc in batch]
# アップサート用のベクトルを準備
vectors_to_upsert = []
for doc_id, embed, meta in zip(ids, embeds, metadata):
vectors_to_upsert.append({
"id": doc_id,
"values": embed,
"metadata": { "text": texts[ids.index(doc_id)], **meta }
})
index.upsert(vectors=vectors_to_upsert)
print(f"バッチ {i//batch_size + 1} をアップサートしました")
print("データ取込が完了しました。")
if __name__ == "__main__":
ingest_data()
動作の仕組み
- 読み込み:LangChainの
DirectoryLoaderを使用して、dataフォルダからすべての.txtファイルを読み込みます。 - チャンク化:
RecursiveCharacterTextSplitterを使用して、大きなドキュメントを小さく、セマンティックに一貫性のあるチャンクに分割します。これにより、埋め込みが集中し関連性のあるものになります。 - 埋め込み:Sentence-Transformersからの
all-MiniLM-L6-v2モデルを使用します。これは、性能とサイズのバランスで人気の選択肢です。各テキストチャンクを384次元のベクトルに変換します。 - 保存:Pineconeクライアントを初期化し、存在しない場合は新しいインデックスを作成し、チャンクの埋め込みとメタデータを
upsert(アップロード/更新)します。生成ステップのためにメタデータに元のテキストを保存することが重要です。
これを実行するには、ターミナルからスクリプトを実行するだけです:
python ingest.py
ステップ2:FastAPIバックエンドの構築
何をしているか
теперь наш知識がPineconeにあるので、それを照会するためのAPIが必要です。FastAPIアプリケーションを作成し、ユーザーの質問を受け取り、Pineconeから関連するコンテキストを取得し、LLMを使用して回答を生成する単一のエンドポイント/askを作成します。
実装
main.pyという名前のファイルを作成します。
# main.py
import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from dotenv import load_dotenv
from pinecone import Pinecone
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain_pinecone import PineconeVectorStore
# 環境変数を読み込む
load_dotenv()
# APIキーと設定を初期化
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
PINECONE_INDEX_NAME = "nutritrag"
# FastAPIアプリを初期化
app = FastAPI(
title="NutriRAG API",
description="科学的論文に基づいた栄養質問用のAPI。",
version="1.0.0",
)
# リクエストボディのPydanticモデル
class QueryRequest(BaseModel):
question: str
# 埋め込みモデルとLLMを初期化
embeddings_model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
llm = ChatOpenAI(api_key=OPENAI_API_KEY, model_name='gpt-3.5-turbo', temperature=0.0)
# Pineconeベクトルストアを初期化
vectorstore = PineconeVectorStore.from_existing_index(
index_name=PINECONE_INDEX_NAME,
embedding=embeddings_model
)
# RetrievalQAチェーンを作成
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(),
return_source_documents=True
)
@app.post("/ask")
async def ask_question(request: QueryRequest):
"""
栄養質問を受け取り、Pineconeから関連するコンテキストを取得し、
LLMを使用して回答を生成します。
"""
if not request.question:
raise HTTPException(status_code=400, detail="質問は必須です。")
try:
response = qa_chain.invoke({"query": request.question})
answer = response.get("result", "回答が見つかりません。")
source_documents = response.get("source_documents", [])
sources = []
if source_documents:
sources = [
{"source": doc.metadata.get("source", "不明"), "text": doc.page_content}
for doc in source_documents
]
return {"answer": answer, "sources": sources}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/")
def read_root():
return {"message": "NutriRAG APIへようこそ。テストするには/docsエンドポイントを使用してください。"}
動作の仕組み
- FastAPIのセットアップ:標準的なFastAPIアプリケーションを作成します。
- Pydanticモデル:
QueryRequestは、着信POSTリクエストに予想されるJSON構造を定義し、データ検証を確実にします。 - 初期化:埋め込みモデルとLLMを読み込みます。LangChainの
PineconeVectorStoreも初期化し、これはPineconeインデックスへのブリッジとして機能します。 - RetrievalQAチェーン:これはRAGロジックのコアです。LangChainの
RetrievalQAチェーンは以下のプロセスを自動化します:- ユーザーの
queryを取得します。 retriever(Pineconeベクトルストア)を使用して、最も関連するドキュメントを見つけます。- これらのドキュメントをクエリと一緒にLLMのコンテキストに「 stuffs(詰め込み)」ます。
- 最終回答を生成します。
- ユーザーの
- エンドポイントロジック:
/askエンドポイントはqa_chainを起動し、回答とソースドキュメントを含むように応答をフォーマットし、JSONとして返します。
すべてをまとめる
APIサーバーを実行するには、uvicornを使用します:
uvicorn main:app --reload
Uvicornはローカルサーバーを起動します,通常はhttp://127.0.0.1:8000です。
APIのテスト
FastAPIは自動的な対話型ドキュメントを提供します。ブラウザを開き、**http://127.0.0.1:8000/docs**に移動します。Swagger UIが表示され、そこで直接/askエンドポイントをテストできます。
/askエンドポイントをクリックして展開します。- 「Try it out」をクリックします。
- リクエストボディに、ドキュメントに関連する質問を入力します,例如:
json { "question": "オメガ3脂肪酸は認知機能にどのような影響を与えますか?" } - 「Execute」をクリックします。
LLM生成の回答と、それを作成するために使用されたソーステキストチャンクのリストを含むJSON応答を受け取るはずです。
パフォーマンスの考慮事項
- 埋め込みモデル:埋め込みモデルの選択は、速度、コスト、正確性の間のトレードオフです。
all-MiniLM-L6-v2は開始点に最適ですが、より大きなモデルの方が検索品質が向上する可能性があります。 - バッチ処理:大量のデータを取り込むときは、常連バッチで処理してアップサートし、接続を圧倒したり、APIレートの制限に達したりすることを避けます。
ingest.pyスクリプトはこれを行います。 - LLMレイテンシー:生成ステップは往往最も低速です。ユーザー体験を向上させるために、より小さく高速なLLMを使用するか、応答をストリーミングすることを検討してください。
セキュリティのベストプラクティス
- 環境変数:APIキーをソースコードにハードコードしないでください。ローカル開発には
.envファイルを使用し、本番環境では環境変数を使用してください。 - 入力検証:FastAPIのPydantic統合は基本的な入力検証を処理し、多くの一般的なインジェクションスタイルの攻撃から保護します。
- 認証:本番アプリケーションでは、OAuth2やAPIキーなどの認証メカニズムでAPIエンドポイントを保護し、アクセスを制御してください。
結論
完全な検索拡張生成システムを構築しました!このプロジェクトは、選択された知識ベースに基づいて回答を裏付ける Specialized で信頼できるチャットボットを作成する方法をデモしています。FastAPIの性能、Pineconeの効率的なベクトル検索、LLMの生成力を組み合わせることで、nutritionなどの重要な領域での誤情報と戦うための強力なツールを作成しました。
ここから、以下を選択してプロジェクトを拡張できます:
- ReactやStreamlitなどのフレームワークでフロントエンドインターフェースを構築
- 異なるチャンク化戦略と埋め込みモデルを экспериメント
- 会話履歴を追加して、よりステートフルなチャットボット体験を создайте
リソース
- FastAPIドキュメント:https://fastapi.tiangolo.com/
- Pineconeドキュメント:https://docs.pinecone.io/
- LangChain Pythonドキュメント:https://python.langchain.com/
- Sentence-Transformersライブラリ:https://www.sbert.net/
クイックリファレンス
| 側面 | 主な情報 |
|---|---|
| トピック | 開発 |
| 関連性 | 患者教育と意識向上 |
| 行動 | 医療提供者にご相談ください |
| 頻度 | ケアチームのおすすめに応じて |
| 証拠 | 現在の臨床ガイドラインに基づく |
よくある質問
Q: これが自分に該当する怎么看? A: 個人的な病歴と家族歴を医療提供者とdiscussし、個々のリスク要因を評価し、適切な次のステップを決定してください。
Q: 医師に何年就ますか? A: 良い質問には:「私の結果はどういう意味ですか?」「私のオプションは何ですか?」「どんなライフスタイルの変更が有帮助ですか?」「いつフォローアップすべきですか?」
Q: 帮助できるライフスタイルの変更はありますか? A: ほとんどの健康状態は、基本的な対策から恩恵を受けます:バランスの 取れた栄養、定期的な運動(週150分以上)、質の睡眠(7〜9時間)、ストレス管理、および禁煙。
医療免責事項
本文は教育目的のみを目的としており、医学的アドバイスを提供しません。健康、治療、またはケアに関する決定する前に、常に資格のある医療提供者にconsultationしてください。個人の状況是不同的ため、1人に適切なことがもう1人に適切なとは限りません。
医学的緊急事態が発生した場合は、直ちに911(または現地の緊急番号)に電話してください。