【個人開発】NotionもDBも一元管理!GPT-4×FastAPIで作る「ドキュメント管理AI」の裏側
はじめに
エンジニアの皆さんは 「ドキュメントが散らばりすぎて探せない問題」 に悩まされていませんか?
・仕様書は Notionにある
・技術メモはローカルの Markdownにある
・実際のデータは PostgreSQLに入っている
・顧客データは CSVで管理している
これらを横断して検索し、分析までしてくれるAIアシスタントがいれば便利だと思い、 「Tech Doc Assistant」 というアプリを開発しました。
今回は、 FastAPI+LangChain+GPT-4 を用いて、複数のデータソース(Notion,DB,Markdown)を統合的に扱うRAG(Retrieval Augmented Generation)システムを構築した際の技術的な知見を共有します。
開発したアプリ:Tech Doc Assistant
デモサイト: https://tech-doc-assistant.vercel.app
主な機能
- Markdownドキュメント管理: 基本的なドキュメント管理機能
- Notion連携: Notionのページを自動で取り込み、検索対象にする
- 高度なAI検索 (RAG): 単なるキーワード検索ではなく、文脈を理解した回答
- データ分析: DBやCSVからデータを読み込み、Pandas/AIで分析・可視化
- チャンク分析: 長文ドキュメントを意味のまとまりで分割し、検索精度を向上

技術スタックとアーキテクチャ
開発効率とパフォーマンスを両立させるため、以下の構築を採用しました。特にバックエンドはPythonの豊富なAIエコシステムを活用するためにFastAPIを選択しています。
Backend(Pyhton)
・ Framework:FastAPI(非同期処理と型安全性)
・ LLM Orchestration:LangChain,LangGraph
・ Vector DB:Pinecone(高速なベクトル検索)
・ Data Analysis:Pandas,Numpy,Plotly(データ処理と可視化)
・ Database:PostgreSQL(psycopg2-binary,SQLAlchemy)
・ External API:Notion Client
Frontend
・ Framework:Next.js(App Router)
・ Platform:Vercel
Infrastructure/CI/CD
・ CI/CD:Github Action
・ Environment:Docker(開発環境)
実装ポイント
バックエンドのディレクトリ構造は、「機能(Service)」ごとに責務を明確に分離しました。これにより、RAGのロジックや外部連携の改修が容易になっています。
backend/
├── main.py # エントリーポイント
├── models.py # Pydantic/DBモデル
├── services/ # ビジネスロジックの中核
│ ├── chunking.py # テキスト分割ロジック
│ ├── notion_service.py # Notion連携
│ ├── data_analysis.py # データ分析・可視化
│ ├── qa.py # 質問応答(RAG)
│ ├── search.py # ベクトル検索
│ └── database_connector.py
└── tests/ # Pytestによるテスト
特に工夫した3つの技術ポイントを紹介します。
1. RAGの精度を高める「チャンク分析」
RAGにおいて最も重要なのは 「ドキュメントをどう分割(Chunking)するか」 です。単に文字数で区切るだけでは、文脈が分断され、AIが正しく回答できません。
今回はlangchain-text-splittersを活用しつつ、Markdownのヘッダー構造を意識した分割処理を実装しました。
from langchain_text_splitters import MarkdownHeaderTextSplitter, RecursiveCharacterTextSplitter
def intelligent_chunking(text: str):
# Markdownのヘッダーベースで分割し、コンテキストを保持
headers_to_split_on = [
("#", "Header 1"),
("##", "Header 2"),
("###", "Header 3"),
]
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
md_header_splits = markdown_splitter.split_text(text)
# さらにトークン数で微調整する処理を追加
# ... (RecursiveCharacterTextSplitterなどで再分割)
return chunks
これにより、「どのセクションに書かれている情報か」というメタデータを保持したままベクトル化できるため、検索精度が大幅に向上しました。
2. Notion APIとの連携
ドキュメントの多くはNotionにあるため、notion-clientを使用して同期機能を実装しました。Notionデータは「ブロック」という単位で管理されており、そのままではLLMに扱いにくいため、以下のような変換パイプラインを構築しました。
- Notion APIでページ内の全ブロックを取得
- ブロックタイプ(Paragraph,Heading,Codeなど)に応じてMarkdownテキストに変換
- 変換したテキストを前述の
chunking.pyに渡してベクトル化
3. 自然言語によるデータ分析
「先月の売上推移はどうだった?」といった質問に対し、テキストで返すだけでなく、グラフで可視化する機能を実装しました。
ユーザーの自然言語クエリを、LangChainを用いてPandasのクエリ(またはSQL)に変換し、実行結果をPlotlyのグラフオブジェクトとして生成しています。
import pandas as pd
import plotly.express as px
def analyze_data_and_plot(df: pd.DataFrame, query: str):
# LLMがデータフレームのカラム構造を理解し、
# 適切な分析コードを生成・実行するフロー
# ...
# Plotlyで可視化
fig = px.bar(df, x='date', y='sales', title='Monthly Sales')
return fig.to_json()
開発での苦労と解決策
依存ライブラリの管理
langchain,numpy,pandas,pydanticなど、依存関係が複雑になりがちなライブラリを多数使用しています。特に、pydanticのv1/v2の互換性や、numpyのバージョン依存には注意が必要でした。requirements.txtを細かく管理し、Docker環境でビルドを安定させることに注力しました。
レスポンス速度の課題
これに対しては以下の対策を行いました。
・ FastAPIのasync/awaitを徹底する
・ Pineconeへのクエリを並列化する
・ フロントエンドではストリーミングレスポンスを活用する
まとめ・今後の展望
FastAPIとLangChainを組み合わせることで、「ドキュメント管理」×「データ分析」 という2つの領域を統合したアプリを個人開発レベルでも構築できました。
今後は以下の機能拡張を考えています。
- Slack/Teams連携 :チャットツールから直接botに質問
- ローカルLLM対応 :機密性の高いデータ向けにOllamaなどでローカルモデルを選択可能に
- マルチモーダル対応 :図表や画像を含めたドキュメント理解
もし「RAGアプリを作りたい」「ドキュメント管理に役立てたい」という方がいれば、ぜひ参考にしてみてください!
Discussion