はじめに — 前回の記事から実装へ
前回の記事では、GraphRAGの仕組みと従来RAGとの違いを解説しました。「使うほど賢くなるAI」の構造は理解した。では、実際に自分で構築して使い倒すとどうなるのか?
今回は、普段の業務やアイデアの知識を一元管理したいという動機から、OSSの組み合わせでGraphRAGプラットフォームを構築し、GitHubにも公開しました。
本稿では、構築の過程で得た知見と、実際に使ってみて分かったことをまとめます。
動機 — なぜ「個人ナレッジグラフ」なのか
ノートが散らかる問題。 エンジニアなら誰しも経験があるのではないでしょうか。
Notion、Obsidian、Google Docs、ローカルのMarkdown、Slackの自分用チャンネル…。メモを取る場所は増える一方で、「あのとき調べたことどこに書いたっけ?」と探す時間が積み重なっていきます。
結局のところ、ノートツールは書く場所は提供してくれますが、知識同士の繋がりは自分で管理しなければなりません。タグやフォルダで整理しても、時間が経てばまた散らかる。
やりたかったのは:
- 散らばったノートやドキュメントの知識を1箇所に集約する
- ドキュメントを入れたら、知識が自動で構造化される
- 「あの件とこの件って関係あったっけ?」にグラフで答えられる
- 新しい文書やメモを追加するたびに、既存の知識と自動で繋がる
前回の記事で書いた「使うほど賢くなる」を、自分自身のノート・知識管理で実現したかったのです。
技術スタック — 全てOSSの組み合わせ
| コンポーネント | 技術 | ライセンス |
|---|---|---|
| グラフDB | Neo4j Community Edition | GPLv3 |
| 埋め込みモデル | intfloat/multilingual-e5-base (768次元) | MIT |
| 埋め込みサーバー | FastAPI + sentence-transformers | Apache 2.0 |
| PDF処理 | pymupdf | AGPL |
| Office文書処理 | python-docx, openpyxl, python-pptx | MIT等 |
| LLM(エンティティ抽出) | Claude Code(Claude自体が処理) | — |
| コミュニティ検出 | Neo4j GDS (Leiden algorithm) | — |
全て公開OSSの標準的な組み合わせです。特別なプロプライエタリ技術は使っていません。
アーキテクチャ — 4層 + 動的ソースノード
前回の記事で紹介した4層構造をベースに、動的なソースノードを追加しました。
グラフスキーマ全体図
ソースノードの種類
知識の入力元に応じて、Entityのソース(出典)を分けています。
| ノード | 用途 | 例 |
|---|---|---|
| Document | ファイルからの取り込み | PDF、DOCX、PPTX等 |
| Note | CLIからの直接入力 | メモ、調査結果 |
| WebSource | Web上の情報 | URL付きの情報 |
| Conversation | 人から聞いた情報 | 会議、ヒアリング |
Neo4jはスキーマレスなので、新しいソース種類は自由に追加できます。「この知識はどこから来たか」がノードタイプで即座に判別でき、信頼度の判定にも使えます。
Claude Code Skills — APIキー不要のエンティティ抽出
今回の実装で最も工夫した点は、エンティティ抽出にClaude Code自体を使う設計です。
一般的なGraphRAG構築の課題
GraphRAG構築では、ドキュメントからエンティティ(人物、組織、技術、概念等)を抽出する工程が必要です。通常はLLM APIを呼び出しますが、API キーの管理やトークンコストが発生します。
Claude Code = Claude そのもの
Claude Code内でスキルを実行すると、Claude自体がドキュメントを読んでエンティティを抽出します。外部APIコールは不要。
/ingest の実行例
$ /ingest technical_report.pdf
# 1. チャンク分割 + 埋め込み
[config] Config(project=default, neo4j=bolt://localhost:7687)
[done] technical_report.pdf: 12 chunks (default)
# 2. Claude がエンティティを抽出(この部分はClaude Code自身が処理)
Extracting entities from document content...
Found 8 entities and 5 relationships.
# 3. Neo4jに保存
[config] Config(project=default, neo4j=bolt://localhost:7687)
[done] 8 entities, 5 relationships saved
# 4. コミュニティ再構築
[community] Running community detection...
[done] 3 communities created (Level 0: 2, Level 1: 1)
用意したスキル
| スキル | 機能 |
|---|---|
/ingest |
ファイルをナレッジグラフに投入(チャンク + エンティティ + コミュニティ) |
/visual-extract |
PDFをページ単位でPNG化し、Claudeのビジョン機能で図表・OCR含む意味情報を抽出 |
/add-knowledge |
CLIから直接知識を投入(メモ、URL、会話情報等) |
/graph-search |
ベクトル検索 + グラフトラバーサルのハイブリッド検索 |
/vector-search |
シンプルなベクトル類似度検索 |
ハイブリッド検索 — ベクトル + グラフトラバーサル
前回の記事で触れたLocal Searchを実装しました。
検索の流れ
ベクトル検索だけでは見つからない、グラフ構造を辿った多段推論が可能になります。
/graph-search の実行例
$ /graph-search "マイクロサービスアーキテクチャの選定基準"
=== Seed Entities (vector match) ===
[0.8523] Microservices (TECHNOLOGY)
Container-based architecture for independent service deployment.
[0.7891] Kubernetes (TECHNOLOGY)
Container orchestration platform.
[0.7654] Architecture Design (DOMAIN)
System design methodology and technology selection.
=== Seed Communities (vector match) ===
[0.7801] L0 Cloud Native Technologies
Members: Microservices, Kubernetes, Docker, API Gateway
[0.7532] L1 System Architecture
Members: Architecture Design, Cloud Native Technologies, ...
=== Related Entities (graph expansion) ===
Docker (TECHNOLOGY) --[runs_on]--> Microservices
API Gateway (TECHNOLOGY) --[manages]--> Microservices
Team Independence (CONCEPT) --[motivates]--> Microservices
=== Context Chunks ===
[1] architecture_report.pdf (chunk #3)
entities: Microservices, Kubernetes
"When selecting microservices architecture, team size and
service boundaries are the primary considerations..."
[2] tech_memo.md (chunk #0)
entities: Microservices, Team Independence
"Past 3 projects taught us: prioritize team proficiency
over technology novelty in architecture decisions..."
=== Provenance ===
Microservices <- architecture_report.pdf
Microservices <- tech_memo.md (Note)
Kubernetes <- architecture_report.pdf
Team Independence <- tech_memo.md (Note)
注目すべきは、ドキュメント(architecture_report.pdf)とメモ(tech_memo.md)の知識がEntityを介して自動的に結びついている点です。メモに書いた「チームの習熟度を優先」という教訓と、レポートの技術詳細が統合されて回答に反映されます。
グラフの動的更新 — ドキュメントのライフサイクルに連動
前回の記事で「使うほど賢くなる」と書きましたが、逆に「古い情報が残り続ける問題」もあります。
自動クリーンアップ
ドキュメントの追加・更新・削除時に、全層が動的に連動します。
| 操作 | Document/Chunk | Entity | Community |
|---|---|---|---|
| 追加 | 作成 | 抽出・MERGE | 再構築 |
| 更新(再ingest) | 旧削除→再作成 | 孤立Entity自動削除 | 再構築 |
| 削除 | 削除 | 孤立Entity自動削除 | 再構築 |
# auto_ingest.py より — 孤立Entity自動削除
def cleanup_orphan_entities(driver):
with driver.session() as session:
session.run("""
MATCH (e:Entity)
WHERE NOT (e)<-[:MENTIONS]-(:Chunk)
DETACH DELETE e
""")
どのChunkからもMENTIONSされなくなったEntityは自動的に削除されます。複数ドキュメントから参照されているEntityは、いずれかのChunkが残っている限り安全です。
競合検出 — 矛盾する情報への対処
複数のドキュメントが同じEntityについて異なる情報を持つ場合があります。
出典追跡(SOURCED_FROM)
EntityがどのDocumentから来たかをSOURCED_FROM関係で追跡しています。/ingestスキル実行時に、Claudeが既存Entityと新しい情報を比較し、矛盾があればユーザーに確認します。
$ /ingest quarterly_report_q2.pdf
# Entity "Acme Corp" が既にグラフに存在
Entity "Acme Corp" conflict:
Existing (from quarterly_report_q1.pdf): "Software company with 100 employees"
New (from quarterly_report_q2.pdf): "Software company that has grown to 500 employees"
Options: [keep existing / use new / merge]
> use new
[done] Updated description for Acme Corp
[done] 12 entities, 8 relationships saved
- 矛盾なし(追加情報)→ 自動マージ
- 矛盾あり(数値や事実の不一致)→ ユーザーに確認して解決
具体的なユースケース — ドキュメントだけじゃない
GraphRAGというと大量の業務文書を処理するイメージが強いですが、このプラットフォームの強みは日常のちょっとしたメモや気づきも知識として蓄積できる点です。
ドキュメントの取り込み
PDFやOffice文書を入れるだけで、テキスト抽出 → チャンク分割 → エンティティ抽出 → コミュニティ構築まで自動。/visual-extractなら図表やグラフの意味情報までClaudeのビジョン機能で読み取れます。
$ /visual-extract presentation.pdf
[render] page 1/5
[render] page 2/5
...
## Page 1
### Text Content
**Title:** Microservices Migration Plan
**Subtitle:** Q2 2026 Technical Proposal
### Diagrams & Visuals
Architecture diagram showing monolith → microservices transition.
Three services identified: Auth, Order, Notification.
### Metadata
- Slide layout with header + diagram + footer
- Company logo in top-right
[done] 5 pages processed → presentation_visual_extract.md
[done] presentation_visual_extract.md: 4 chunks ingested
[done] 6 entities, 3 relationships saved
メモや気づきの投入
$ /add-knowledge "技術選定で迷ったときは、チームの習熟度を最優先にすべき(過去3案件の教訓)"
# Claude が入力を分析し、ソースタイプを自動判定
Analyzing input... classified as: Note
Extracting entities...
[config] Config(project=default, neo4j=bolt://localhost:7687)
[created] Note node (id: a1b2c3d4...)
[done] 2 entities, 1 relationships saved
Entities saved:
- Technology Selection (CONCEPT): "Process of choosing tech stack"
- Team Proficiency (CONCEPT): "Team's skill level with a technology"
Relationship: Team Proficiency --[prioritized_in]--> Technology Selection
ふとした気づき、調べた結果、打ち合わせで聞いた話。これらは通常、メモアプリに書いて忘れ去られます。しかしナレッジグラフに入れておけば、後からドキュメントの知識と自動で繋がります。
- メモで「マイクロサービス」のEntityが作られる
- 後日、技術調査レポートをingestすると、同じ「マイクロサービス」Entityが
RELATES_TOで他の技術概念と繋がる -
/graph-search "マイクロサービス"で、メモの気づきと技術レポートの詳細情報が統合された回答が得られる
断片的なメモが、ドキュメントの知識と結びつくことで価値を持つ。 これが「使うほど賢くなる」の本質です。
情報ソースの分類
Claudeが入力内容を分析し、適切なソースタイプを自動判定します。
| 入力 | Claude の判定 | ノード |
|---|---|---|
| 普通のテキスト | Note | メモとして保存 |
| URLを含む | WebSource | 出典URL付きで保存 |
| 「〜さんから聞いた」等 | Conversation | 話者・日時付きで保存 |
出典の種類がノードタイプで分かれるため、「この知識はどこから来たか」「信頼できるソースか」が後から追跡できます。
ファイル命名規約 — バージョン管理の工夫
Neo4j Community EditionにはDocumentノードのバージョン管理機能がないため、ファイル名にバージョンや日付を含める運用で対応しています。
docs/proposal_v1.pdf # バージョンベース
docs/proposal_v2.pdf # 両方がグラフに共存
docs/report_2026-03.pdf # 日付ベース
docs/report_2026-04.pdf # 新旧が並存
各ファイルが別のDocumentノードになるため、Chunk → Document を辿れば「この情報はどのバージョンから来たか」が分かります。古いバージョンが不要になったら削除すれば、孤立Entityも自動クリーンアップされます。
セットアップ — docker compose up で即起動
$ git clone https://github.com/okikusan-public/knowledge_graph.git
$ cd knowledge_graph
$ pip install sentence-transformers neo4j requests pymupdf python-docx openpyxl python-pptx
$ docker compose up -d
# ヘルスチェック
$ curl http://localhost:8082/health
{"status":"ok"}
# Neo4j Browser: http://localhost:7474 (neo4j/changeme)
これだけでEmbeddingサーバー + Neo4j が起動します。あとはClaude Codeで:
# ドキュメントを入れる
$ /ingest report.pdf
# メモを入れる
$ /add-knowledge "今日の打ち合わせでAPI設計の方針が決まった"
# 知識を検索する
$ /graph-search "API設計の方針"
今後の展望 — スマホから知識を貯める
現状はPCのCLIからの操作ですが、将来的にはスマホからSkillsを使ってメモを取れるようにしたいと考えています。
移動中や打ち合わせの合間に思いついたこと、ふと聞いた情報。こうした「今メモしないと忘れる」瞬間は、PCの前にいるときとは限りません。スマホから /add-knowledge を叩けるようになれば、思考の断片を即座にナレッジグラフに投入でき、後からPCで入れたドキュメントの知識と自動的に結びつきます。
「書く」と「繋がる」が分離されているのがGraphRAGの強みです。メモする側は構造を意識する必要がなく、入れるだけで後から知識が繋がっていく。
まとめ
前回の記事からの進展
| 前回(概念編) | 今回(実装編) |
|---|---|
| GraphRAGの仕組みを解説 | OSSで実際に構築しGitHubに公開 |
| 4層構造の説明 | 動的ソースノード(Note/WebSource等)を追加 |
| Local/Global Searchの概念 | ハイブリッド検索を実装 |
| 「使うほど賢くなる」の理論 | 孤立Entity自動削除・競合検出を実装 |
| エンティティ抽出にはLLM API必要 | Claude Code自体が抽出(APIキー不要) |
得られた知見
- OSSの組み合わせで十分実用的なGraphRAGが作れる — Neo4j + multilingual-e5 + pymupdf + Claude Code、全て公開OSSの標準的な使い方
- Claude Code Skillsは強力 — APIキー不要でLLMの能力を活用できる。エンティティ抽出、競合検出、ビジュアル解析まで
- 「知識を貯める仕組み」は運用が命 — 自動クリーンアップ、競合検出、出典追跡がないと、グラフがゴミだらけになる
リポジトリ
MITライセンスで公開しています。フォークして使ってください。