「プロジェクトに置いた PDF が、今日になったら参照されなくなった」——Claude Projects を日常的に使っていると、こうした挙動に出会うことがあります。エラーメッセージも出ず、Claude が淡々と「該当する内容は見当たりません」と返してくる。この沈黙が、いちばん厄介です。
原因が見えないまま、同じ質問を言い換えて何度も投げる。そのうちに時間だけが溶けていく。個人開発の手を止めてこれをやっている時間が、いちばんもったいない。私自身、複数サイトの運用資料を Projects に置いて回している関係で、この溶け方を何度も経験しました。
そこで途中から方針を変えました。アップロードしてから「読んでくれない」と気づくのではなく、置く前に機械で診断する。この記事は、その切り分けの手順と、実際に使っている診断スクリプトをまとめたものです。
症状の置き場所は三層のどこか
最初にやることは、原因を三つの層のどこかに落とすことです。層が決まれば、打つ手はほぼ一つに絞れます。
| 層 | 典型的な症状 | 切り分けの合図 |
|---|---|---|
| インデックス | アップロード直後だけ「該当なし」 | 数分待つと直る |
| ファイル | 何時間経っても認識されない | 特定のファイルだけ症状が出る |
| 指示 | 検索はされるが回答に反映されない | 「ナレッジを引用して」と言うと出てくる |
三層目の「指示」が原因のとき、ファイルをいくら作り直しても直りません。逆にスキャン PDF が原因のとき、カスタム指示をどれだけ磨いても無駄です。ここを取り違えると、丸一日が消えます。
まず疑うのは「ファイル」ではなく「インデックス更新」
Claude Projects のナレッジは、アップロードした瞬間に使えるわけではありません。内部的にチャンク化(文書をベクトル検索可能な単位に分割)→ 埋め込み生成 → インデックス反映、という段階を踏みます。
私の体感では、テキスト主体の PDF(30 ページ以下)なら数十秒で反映されますが、画像の多い資料や 100 ページを超えるドキュメントでは、5〜10 分かかることもあります。
症状: アップロード直後に質問しても「該当なし」と返ってくる
5 分待ってから、新しい会話を立ち上げて再度質問してみてください。同じ会話の中では、最初に「該当なし」と判定されたコンテキストを引きずる傾向があります。ここで会話を変えずに粘るのが、いちばんよくある遠回りです。
症状: 数時間経っても認識されない
インデックスの問題ではありません。ファイル側です。次に進みます。
目視では分からない — テキストレイヤーを機械で判定する
ファイル側の原因で最も多いのが、スキャン PDF(画像 PDF) です。Word から書き出した PDF はテキストレイヤーを持ちますが、紙の書類をスキャンした PDF は「画像」として扱われます。Claude Projects のナレッジ検索は OCR を経由しないため、スキャン PDF はそもそも検索対象になりません。
昔ながらの確認方法は、PDF を開いて文字を選択できるかどうかです。ただ、これには落とし穴があります。先頭数ページだけテキストレイヤーがあり、後半がスキャン画像という混在 PDF が、実務ではよくあるからです。表紙で文字が選択できたので大丈夫だと判断して、実は本文が丸ごと検索対象外だった——これを一度やりました。
そこで、目視をやめて機械に判定させます。
from pypdf import PdfReader
TEXT_PAGE_MIN = 50 # 1ページを「テキストあり」と見なす最小文字数
SAMPLE_PAGES = 5 # 先頭から何ページ調べるか
def text_ratio(path):
"""先頭数ページのうち、テキストを抽出できたページの割合を返す"""
pages = PdfReader(path).pages[:SAMPLE_PAGES]
if not pages:
return 0.0
filled = sum(
1 for p in pages
if len((p.extract_text() or "").strip()) >= TEXT_PAGE_MIN
)
return filled / len(pages)
r = text_ratio("report.pdf")
print(f"text_ratio={r:.2f}")text_ratio が 0 ならスキャン PDF、1.0 ならテキスト PDF。手元で試したところ、テキスト PDF は 1 ページあたり 1,700 文字前後が抽出でき、スキャン PDF は 0 文字でした。判定は明確に割れます。
閾値を 50 文字に置いているのには理由があります。ページ番号やヘッダーだけが抽出できる「実質空」のページが、10 文字前後を返してくるからです。ここを 1 文字にすると、スキャン PDF を取りこぼします。
そして 0 と 1.0 のあいだが出たときが、先ほどの混在 PDF です。0.4 のような値が返ってきたら、その資料は半分が検索対象外だと考えてください。
ナレッジ候補をまとめて診断する
一つずつ調べるのは続きません。プロジェクトに入れる予定のフォルダを、まとめて診断するようにしました。
PDF のテキストレイヤーに加えて、実務で刺さった残り二つ——ファイルサイズと文字コード——も同時に見ます。
import sys, pathlib
import chardet
from pypdf import PdfReader
MAX_MB = 20.0 # 上限に対する実務上の安全圏
TEXT_PAGE_MIN = 50
SAMPLE_PAGES = 5
def check_pdf(path):
try:
pages = PdfReader(path).pages[:SAMPLE_PAGES]
except Exception as e:
return f"READ_ERROR ({e.__class__.__name__}) — 暗号化の可能性"
if not pages:
return "EMPTY"
filled = sum(
1 for p in pages
if len((p.extract_text() or "").strip()) >= TEXT_PAGE_MIN
)
ratio = filled / len(pages)
if ratio == 0:
return "SCANNED — OCR が必要(検索対象になりません)"
if ratio < 0.5:
return f"PARTIAL — 先頭{len(pages)}頁中{filled}頁のみテキストあり"
return "OK"
def check_text(path):
raw = pathlib.Path(path).read_bytes()
enc = (chardet.detect(raw)["encoding"] or "").lower()
if enc.replace("-", "") not in ("utf8", "ascii"):
return f"ENCODING — {enc} 検出。UTF-8 に変換してください"
return "OK"
for path in sorted(pathlib.Path(sys.argv[1]).iterdir()):
if path.suffix.lower() not in (".pdf", ".txt", ".md"):
continue
mb = path.stat().st_size / 1024 / 1024
if mb > MAX_MB:
verdict = f"TOO_LARGE — {mb:.1f} MB。章ごとに分割を"
elif path.suffix.lower() == ".pdf":
verdict = check_pdf(path)
else:
verdict = check_text(path)
print(f"{path.name:12} {mb:6.2f} MB {verdict}")python audit.py ./knowledge のように実行すると、こう返ってきます。
ok.txt 0.00 MB OK
scan.pdf 0.00 MB SCANNED — OCR が必要(検索対象になりません)
sjis.txt 0.00 MB ENCODING — shift_jis 検出。UTF-8 に変換してください
text.pdf 0.00 MB OK
このスクリプトは pypdf と chardet だけで動きます。それぞれの判定に補足を書いておきます。
サイズ: 1 ファイルあたりの上限そのものより手前に、処理が不安定になる領域があります。上限に近いファイルは、章ごとに分割してアップロードし直すほうが確実です。上限の具体的な数値は改定されるため、Claude の公式ヘルプで最新を確認してください。
文字コード: 見落としやすいのがこれです。Mac で作った日本語 docx を Windows で編集して再保存した、というファイルでは、テキスト抽出の段階で文字化けが起きます。Claude 側は「文字化けした文字列」を素直にインデックスするので、検索しても当然引っかかりません。プレーンテキスト(.txt, UTF-8)に貼り直すと症状が消えます。返答そのものが化ける場合は原因が別のところにあるので、返答が途中で止まる・文字化けする場合の対処のほうを見てください。
暗号化: 「印刷不可」「コピー不可」のセキュリティが付いた PDF は、テキスト抽出が阻害されます。上のスクリプトでは READ_ERROR として現れます。パスワードを解除してアップロードし直してください。
「ファイルが消える」「数が合わない」場合
「昨日 8 個アップロードしたのに、今日見たら 6 個しかない」というケース。原因は次のいずれかであることがほとんどです。
原因 A: プロジェクトのストレージ上限超過
プロジェクト全体のナレッジ容量には上限があります。超えると、新しいファイルのアップロードは成功したように見えても、古いファイルが内部的に優先度を下げられ、検索対象から外れることがあります。すでに別の形でまとめ直した素材を削除して、容量に余裕を作ってください。
原因 B: 別アカウント・別ワークスペースでログインしていた
社用と個人用を併用している方に多い症状です。ブラウザのキャッシュやセッション切れで、知らないうちに別アカウントに切り替わっているケースを何度も見ました。アカウント名を確認してから入り直してください。
原因 C: プロジェクトがアーカイブされている
明示的にアーカイブした覚えがなくても、長期間アクセスしていないプロジェクトは一覧から外れることがあります。「アーカイブ済み」フィルタを確認してみてください。
認識されているのに「使ってくれない」場合
ファイルはアップロード済み、診断も OK、それでも Claude が回答にナレッジを反映しない。これは三層目、指示の問題です。
Claude Projects にはプロジェクト単位のカスタム指示があります。この指示が「常に簡潔に答えてください」のように書かれていると、ナレッジの参照が後回しになることがあります。Claude は明示されない限り、内部知識(学習済みの知識)と外部知識(ナレッジ)の優先順位を保守的に判断する傾向があるためです。
私が運用資料用に使っているプロジェクトでは、カスタム指示の冒頭に必ずこの一文を置いています。
回答する前に、必ずプロジェクトナレッジ内のドキュメントを検索してください。
ナレッジに該当する記述がある場合、そちらを最優先して引用してください。
これを入れるだけで、ナレッジへの参照率が体感で大きく変わります。切り分けの目安として、「ナレッジを引用して答えてください」と手で付け足したときだけ正しく答えるなら、原因は指示です。ファイルではありません。カスタム指示の組み立て方そのものは、Claude Projects カスタム指示の書き方に別途まとめています。
それでも直らない時
ここまで試して改善しない場合、次の順で当たってください。
- 新規プロジェクトを作り、ナレッジだけ移行する — プロジェクトの内部状態が壊れていることが稀にあります。新しい器に移すと解決することがあります。
- 長く続いた会話ではなく、新規会話で試す — コンテキスト窓が圧迫されていると、ナレッジ検索の精度が落ちます。
- ブラウザを変えて検証する — 拡張機能(特に広告ブロッカー)がファイルアップロードと競合するケースがあります。シークレットモードで再現するか確かめてください。
- サポートに連絡する前に再現手順を記録する — どのファイル、どんな質問、何時に試したか。診断スクリプトの出力を添えると、話がかなり早く進みます。
次のアクション
まずは診断スクリプトを、これからプロジェクトに入れる予定のフォルダに一度かけてみてください。私の場合、SCANNED と ENCODING の二つで、認識されない症状のほとんどが説明できました。
そして症状が出たときは、質問を言い換える前に三層のどこかを決める。インデックスなら待つ、ファイルなら診断する、指示ならカスタム指示に一文足す。この順番を持っているだけで、午後が丸ごと消えることはなくなります。
お読みいただきありがとうございました。