AIもくもく会 / suiP  ·  ローカルLLM実践

特許PDFを丸ごと検索する
ローカルRAGを組む

PyPDFで特許文書を読み込み、Ollamaのローカルモデルで意味ベクトル化。ネットに出さずに「似た特許」を引き当て、質問に答えるところまでを、手元のMacで動かした記録です。

PyPDF Ollama nomic-embed-text 768d deepseek-r1:8b Qdrant / pickle 全ローカル オフライン
データの流れ / pipeline
IN特許PDF.pdf
01テキスト抽出PyPDF
02埋め込み768次元ベクトル
03ベクトル格納pickle / Qdrant
04類似検索コサイン類似度
OUT回答生成deepseek-r1
§1

成果物の構成

patent_rag_lite.py416行 · 本命 Qdrant不要の軽量版。pickleベースのローカルベクトルストアで完結する
patent_rag_system.py553行 Qdrantを使うフル版。本番・大規模向け
patent_rag_demo.py189行 対話的に試すためのデモスクリプト
docker-compose-qdrant.ymlyaml QdrantをDockerで立てる設定(REST 6333 / gRPC 6334)
patent_rag_venv/venv 依存を隔離するPython仮想環境
patent_vectors.pklstore 埋め込みベクトルの永続化ファイル
§2

組み上げるまでの5ステップ

設計から動作確認まで。途中でつまずいた2つの壁と、その回避も含めて。

01

設計 — フル版から作る

まずQdrant前提のフル版・Docker設定・デモの4ファイルを生成。理想形を先に置いた。

02

環境確認 — Qdrantが立たない

Ollamaは稼働中。しかしDocker未導入で docker: command not found。Qdrantを諦めず、pickleで代替するLite版へ方針転換した。

docker not found → Lite版を新設
03

依存導入 — macOSの保護に阻まれる

externally-managed-environment でpipが拒否。仮想環境を切って解決。

externally-managed → python3 -m venv
04

埋め込みモデルを用意

nomic-embed-text をpull。テキストを768次元ベクトルに変換する準備が整った。

05

動作テスト — 全コンポーネント緑

PyPDF・Ollama・埋め込み・LLM・ベクトルストアの全てが接続確認済み。検索まで一気通貫で動いた。

§3

検索精度テスト

言い換えのクエリでも、意味の近い特許を引けるか。3問で確かめた。

「電池の寿命を延ばす」 1位 → 劣化抑制制御装置
0.724
「充電を速くする方法」 1位 → 急速充電制御装置
0.825
「発熱を抑える仕組み」 1位 → バッテリー冷却装置
0.871

// スコア = コサイン類似度。0.7以上で実用域。言い換えたクエリでも狙った特許が1位に来ている。

§4

使い方

patent_rag_lite.py
# 仮想環境を有効化
$ source ~/Downloads/patent_rag_venv/bin/activate

# PDFをインデックス(単体 / ディレクトリ一括)
$ python3 patent_rag_lite.py index /path/to/patent.pdf
$ python3 patent_rag_lite.py index /path/to/pdf_directory/

# 類似特許を検索
$ python3 patent_rag_lite.py search "リチウムイオン電池の急速充電"

# 質問応答(RAG)
$ python3 patent_rag_lite.py ask "この技術の特徴は何ですか?"

# PDF分析 / インデックス情報
$ python3 patent_rag_lite.py analyze /path/to/patent.pdf
$ python3 patent_rag_lite.py info
§5

技術ポイント

EXTRACT

PyPDFで特許PDFから本文テキストを抽出。純Python実装で依存が軽い。

EMBED

nomic-embed-textで文章を768次元に。意味の近さを数値で扱えるようにする。

SEARCH

コサイン類似度でベクトル間の角度を比較し、意味的に近い文書を順位付け。

GENERATE

deepseek-r1:8bが検索結果を根拠に自然言語で回答。ハルシネーションを抑える。

PERSIST

ベクトルはpickleでローカル保存。Qdrant導入時はそのままフル版へ移行可能。

OFFLINE

抽出・埋め込み・生成すべてが手元で完結。機密特許を外部に出さない。

なぜローカルにこだわるか

先行技術調査で扱う出願前の情報は、外部APIに投げた瞬間にリスクになる。抽出も埋め込みも生成もすべて手元で回るこの構成なら、機密性を保ったまま「似た特許」を横断的に探せる。

二次電池・パワー半導体のように出願が密集する領域ほど、この横断検索が効いてくる。Lite版で回し、量が増えたらそのままQdrantのフル版へ——という増築のしやすさも設計の狙い。

この検索の土台にある話

ここでは埋め込みを部品として使った。なぜ距離を測ると意味の近さが出るのか——その前提のほうを、Word2Vec 以前の認知科学の側から立ち上げた教材が別にある。概念を多次元空間の点として置き、カテゴリーを凸領域として扱い、類似度を距離の単調減少関数と読む。二次電池やパワー半導体のように言い回しが割れる領域で横断検索が効くのは、「二つの典型例の中間も同じカテゴリーに属する」という性質そのものに乗っているから。

概念の幾何学 — 意味が空間の中に形を持つということ