SaaS型AIツールの導入は手軽ですが、情報システム部門やDX推進の現場からは「機密データを通せない」「カスタマイズ性に限界がある」という声が頻繁に上がります。
セキュリティの壁を越え、自社固有のナレッジを真に活用するためには、AI基盤の内製化が不可欠です。本記事では、LangChainを用いた自社専用RAG(検索拡張生成)の構築手順を、Pythonコードを交えてステップバイステップで紐解きます。
AI内製化の目的と「自社専用RAG」の全体像
なぜSaaSではなく内製化なのか
SaaS型AIサービスは進化を続けていますが、エンタープライズの要件を完全に満たすとは限りません。特に機密性の高い社内文書や顧客データを扱う場合、外部サーバへのデータ送信は大きなガバナンスリスクを伴います。
また、業務特有のドメイン知識をAIに反映させる際、既存のSaaSではプロンプトの文字数制限や検索アルゴリズムのブラックボックス化が障壁となります。AI基盤を内製化することで、データフローを完全にコントロール下に置き、要件に応じた柔軟なアーキテクチャ設計が可能になります。
本ガイドで構築する技術スタックの構成
本ガイドでは、実践的かつ拡張性の高い技術スタックを採用します。
- LangChain: LLMアプリケーション開発のデファクトスタンダード。
- ChromaDB: 軽量でローカル環境でも動作するオープンソースのベクトルデータベース。
- FastAPI: 高速でモダンなPython向けWebフレームワーク。
これらを組み合わせることで、特定のクラウドベンダーに依存しすぎない、セキュアで独立した自社専用LLM基盤を構築します。最新のライブラリ仕様や詳細な利用条件については、各公式サイトを適宜参照してください。
ステップ1:再現性を確保する開発環境のセットアップ
開発を始める前に、チーム全体で再現可能な環境を構築することが重要です。ライブラリのバージョン競合を防ぎ、安全な開発基盤を整えます。
Poetryによる依存関係の管理
Pythonプロジェクトでは、依存関係の管理がプロジェクトの寿命を左右します。ここでは、シンプルかつ強力なパッケージ管理ツールであるPoetryを使用します。
# プロジェクトの初期化
poetry new internal-rag-system
cd internal-rag-system
# 必要なパッケージのインストール
poetry add langchain langchain-openai chromadb fastapi uvicorn python-dotenv
poetry add unstructured pdf2image pypdf # ドキュメント読み込み用
これにより、pyproject.tomlとpoetry.lockが生成され、どの開発者のPCでも同じ環境が即座に構築できるようになります。
環境変数の設定(.env)
APIキーやデータベースのパスなど、ソースコードに直接記述すべきでない機密情報は、環境変数として分離します。プロジェクトのルートディレクトリに.envファイルを作成します。
OPENAI_API_KEY="sk-..."
CHROMA_DB_DIR="./chroma_storage"
.envファイルは必ず.gitignoreに追加し、GitHubなどのバージョン管理システムに誤ってコミットされないよう対策を講じてください。認証情報の流出は、内製化プロジェクトにおいて最も避けるべきリスクの一つです。
ステップ2:ドキュメントの読み込みとベクトル化の実装
RAGの心臓部となるのは、自社のナレッジベースです。PDFや社内Wikiのテキストを、AIが検索しやすい形に加工するプロセスを実装します。
DirectoryLoaderによる一括読み込み
社内には様々な形式のドキュメントが散在しています。LangChainのDirectoryLoaderを使用すると、特定のディレクトリ内のファイルを一括で読み込むことができます。
from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
# PDFファイルが格納されたディレクトリを指定
loader = DirectoryLoader('./docs', glob="**/*.pdf", loader_cls=PyPDFLoader)
documents = loader.load()
print(f"読み込んだドキュメント数: {len(documents)}")
運用フェーズでは、ファイルサーバや社内ポータルから定期的にドキュメントを取得するバッチ処理と連携させることで、常に最新の情報をAIに提供できます。
RecursiveCharacterTextSplitterによるチャンク分割
読み込んだドキュメントをそのままLLMに渡すと、トークン数制限を超過してしまいます。そこで、意味のまとまりを維持したままテキストを適切なサイズ(チャンク)に分割します。
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
length_function=len,
is_separator_regex=False,
)
chunks = text_splitter.split_documents(documents)
chunk_overlap(重複部分)を設けることで、文脈が途切れて検索精度が低下するのを防ぎます。この分割サイズの最適化は、回答の品質を左右する重要なチューニングポイントです。
ステップ3:ベクトルデータベースChromaDBへの格納と検索
分割したテキストチャンクをベクトル化(数値化)し、高速に検索できるデータベースに保存します。ここでは、インフラ構築のオーバーヘッドが少ないChromaDBを採用します。
永続化ストレージの作成
ローカルディスクにデータを永続化することで、サーバ再起動時にもインデックスを再構築する手間を省きます。
import os
from dotenv import load_dotenv
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
load_dotenv()
# 埋め込みモデルの初期化
embeddings = OpenAIEmbeddings()
# ChromaDBへの格納と永続化
persist_directory = os.getenv("CHROMA_DB_DIR", "./chroma_storage")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory=persist_directory
)
このコードを実行すると、指定したディレクトリにベクトルデータが保存されます。自社環境内にデータが留まるため、外部への情報漏洩リスクを最小限に抑えることができます。
類似度検索(Similarity Search)の実行
ユーザーからの質問に対して、ベクトルデータベースから関連性の高いチャンクを抽出します。
query = "社内のリモートワーク規定について教えてください。"
# 関連性の高い上位4件(K=4)を取得
docs = vectorstore.similarity_search(query, k=4)
for i, doc in enumerate(docs):
print(f"--- 検索結果 {i+1} ---")
print(doc.page_content)
この検索精度(リトリーバル精度)が、RAGシステム全体の性能を決定づけます。K値の調整や、検索アルゴリズムの変更など、運用を通じた継続的な検証が求められます。
ステップ4:LangChainによる回答生成チェーンの構築
検索した根拠データとLLMを連携させ、ユーザーにとって自然な回答を生成するロジックを組み立てます。
RetrievalQAチェーンの実装
LangChainの強力な機能の一つであるChainを用いて、検索から回答生成までの一連のパイプラインを簡潔に記述します。
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
# LLMの初期化(温度パラメータを低く設定し、事実に基づいた回答を促す)
llm = ChatOpenAI(temperature=0)
# QAチェーンの構築
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(search_kwargs={"k": 4}),
return_source_documents=True
)
response = qa_chain.invoke({"query": query})
print("回答:", response["result"])
return_source_documents=Trueとすることで、回答の根拠となったドキュメントも同時に取得できます。これにより、ユーザーは情報源を確認でき、AIに対する信頼性が向上します。
プロンプトテンプレートのカスタマイズ
社内専用AIとして適切な振る舞いをするよう、システムプロンプトを設計します。ハルシネーション(もっともらしい嘘)を防ぐための明確な指示を与えます。
from langchain_core.prompts import PromptTemplate
prompt_template = """
あなたは優秀な社内アシスタントです。
以下のコンテキスト情報のみを使用して、質問に答えてください。
コンテキストに答えが含まれていない場合は、推測で答えず「提供された情報からは回答できません」と答えてください。
コンテキスト:
{context}
質問: {question}
回答:
"""
PROMPT = PromptTemplate(
template=prompt_template, input_variables=["context", "question"]
)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(),
chain_type_kwargs={"prompt": PROMPT}
)
プロンプトエンジニアリングは、システムの堅牢性を高めるための重要な防波堤となります。
ステップ5:FastAPIによる社内向けAPIサーバの公開
構築したAIロジックを、社内のチャットツール(SlackやTeams)や既存の業務システムから利用できるようにAPI化します。
APIエンドポイントの作成
FastAPIを用いると、非常に少ないコード行数で高性能なWeb APIを立ち上げることができます。
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI(title="社内AIアシスタントAPI")
class QueryRequest(BaseModel):
query: str
class QueryResponse(BaseModel):
answer: str
sources: list[str]
@app.post("/ask", response_model=QueryResponse)
async def ask_question(request: QueryRequest):
try:
# 非同期処理でQAチェーンを呼び出す
result = qa_chain.invoke({"query": request.query})
# 情報源の抽出
sources = [doc.metadata.get("source", "Unknown") for doc in result["source_documents"]]
return QueryResponse(
answer=result["result"],
sources=list(set(sources))
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
エラーハンドリングとロギング
実運用環境では、予期せぬエラーやAPIのタイムアウトへの対策が不可欠です。上記コードでは基本的なtry-except構文を用いていますが、実際にはPython標準のloggingモジュールを活用し、エラーの詳細なスタックトレースをファイルや監視システムに出力する仕組みを整えるべきです。これにより、運用開始後のトラブルシューティングが格段にスムーズになります。
まとめと次のステップ:精度向上に向けたベストプラクティス
本記事では、SaaSの制約から脱却し、PythonとLangChainを活用して自社専用のRAG基盤を構築するまでのロードマップを解説しました。しかし、システムが動いた時点はゴールではなく、スタート地点に過ぎません。
ハイブリッド検索への拡張
ベクトル検索(セマンティック検索)は意味の類似性を捉えるのには優れていますが、特定の型番や専門用語の検索には弱いという特性があります。実運用に耐えうる精度を出すためには、BM25などのキーワード検索アルゴリズムを組み合わせた「ハイブリッド検索」の導入を検討することが効果的です。
評価パイプラインの導入検討
AIの回答精度を主観的に評価するのではなく、定量的に測定する仕組みが必要です。RAGAS(RAG Assessment)などの評価フレームワークを導入し、回答の正確性や文脈の関連性をスコア化するパイプラインを構築することで、継続的な改善サイクルを回すことができます。
自社専用のAI基盤を構築することは、データガバナンスを確保しつつ、組織の知的生産性を飛躍的に高める戦略的な投資です。まずは手元の環境でプロトタイプを立ち上げ、小さな成功体験を積み重ねながら、本格的な内製化への道を歩み始めてはいかがでしょうか。さらに深い検討を進める際は、関連するアーキテクチャ設計や組織づくりの記事も参考に、自社に最適なアプローチを探求してください。
コメント