「領収書を出す締切が書いてある資料は、どのファイルだったか」。ファイル名を思い出せず、同じフォルダを何度も開き直すことがあります。一方、請求番号を知っているときには、意味が似た別の請求書では困ります。
anygrepは、こうしたフォルダ内の資料探しをターミナルから行うローカルAI検索ツールです。自然な言葉で探す検索に加え、請求番号などがそのまま含まれるファイルを優先します。初回公開版のv0.1.0は、日本時間2026年10月12日23時44分にリリースされました。
ふくふくでは翌13日朝、公開されたv0.1.0をMacに入れ、架空の日本語資料だけで試しました。締切の資料と請求番号は意図したファイルが先頭に出ました。それと同じくらい実用上大切だったのは、索引を更新しなければ古い締切が表示され、PDFやExcelの中には最初から検索対象にならないものがあることです。この記事では、その確かめ方まで紹介します。
意味を探すモデルを、フォルダ検索の道具にした
anygrepの公式READMEによると、内部ではEmbeddingGemma 2のint8 ONNX版をCPUで動かし、ローカルに検索用の索引を作ります。GPUやクラウド検索APIのキーは不要です。質問への回答文を生成する道具ではなく、関連するファイルと該当箇所を探す道具です。
ふくふくではすでにEmbeddingGemma 2の日本語検索と画像検索を検証しています。今回の対象は、そのモデルを使って日々のファイルを扱う操作です。フォルダを索引に登録し、内容の変更を反映し、似たコピーをまとめ、番号が分かるときに意図した資料を見つけられるかを見ました。
検索は正規表現ではなく、初期設定では関連するファイルを最大10件返します。関連が弱い結果は隠されるため、いつも10件出るわけではありません。画面の説明やヘルプは英語ですが、日本語の検索文と日本語の本文を使えました。コマンド操作に慣れた経理・総務の担当者や、社内資料を整理する開発者に向いています。
導入条件と、最初に必要な容量
公式の導入説明では、Python 3.10以降と、Linux・Windows・macOS 13以降が対象です。作者の動作確認はLinux、CIではWindowsとApple siliconのMacも検査しています。Intel MacのPython 3.14には依存するONNX Runtimeの配布ファイルがないため、Python 3.13以前を使う案内があります。Windows on ARMではPython 3.11以降が必要です。
アプリ本体はMITライセンスです。モデルは別途取得されるEmbeddingGemma 2のONNX変換版で、GoogleのモデルカードにはApache 2.0の表示とGemma Prohibited Use Policyへの参照があります。本体の利用料や検索APIへの従量課金はありません。
初回には、テキスト用のモデルとトークナイザーで約350MBをダウンロードします。画像を索引に入れる場合は約200MBが追加されます。今回のテキストとPDFの検証では、画像用の追加モデルは取得しませんでした。モデルの取得後は、ANYGREP_OFFLINE=1を指定して追加ダウンロードを止めた状態で動かせます。
検証環境はmacOS 27.0のApple silicon、Python 3.12.10、anygrep 0.1.0、ONNX Runtime 1.23.2です。モデルの固定リビジョンはdaa72c51243991dfcaf9f9137d2c573d8f7790c0。既存の業務資料は読ませず、索引とモデルの保存先も検証用のフォルダに分けました。なお索引には抽出した本文も保存されるため、元資料だけでなく索引の保存先も適切に管理する必要があります。
日本語の意味検索と、請求番号の検索を分けて試す
用意したのは、経費精算、請求番号が1桁違う2件のメモ、VPN手順とそのコピー、会議室案内、PDFなどです。初回に検索可能になったのはテキスト6件と、文字情報を持つPDF1件でした。いずれもこの記事のために作った架空の内容です。
意味で探す例では、検索文を「領収書を出す締切」にしました。1位はexpense.mdで、「10月分の締切は2026年10月20日」と書かれた経費精算のメモが返りました。検索文全体が本文にあるわけではなく、結果のexactはfalseでした。
一方、INV-2026-1042で検索すると、同じ番号のinvoice-target.mdが1位、1桁違うINV-2026-1043のinvoice-near.mdが2位になりました。同じ番号の結果にはexact: trueが付き、別番号の結果はfalseでした。
完全一致の公式仕様は、入力した3文字以上の検索文が本文やファイル名にそのまま含まれる場合に優先する仕組みです。短い英単語や多くの資料に現れる一般語には例外があるため、「どんな単語でも一致すれば必ず優先」とは捉えないほうがよいでしょう。番号が分かるときは番号をそのまま入れる、分からないときは目的を文章で入れる、という使い分けができます。
| 架空資料での操作 | 今回の観測 |
|---|---|
| 「領収書を出す締切」 | 経費精算メモが1位、exact: false |
INV-2026-1042 | 同じ請求番号が1位、exact: true |
| 「顧客へ送る資料の確認」 | 納品手順PDFの1ページ目が1位 |
VPN、通常の検索 | 同じ本文の2ファイルを1件にまとめて表示 |
VPN、--no-collapse付き | 2ファイルを別々の結果として表示 |
VPNのコピーは、JSON出力では代表の結果にsimilarとして紐付きました。複製したファイルばかりで検索結果が埋まるのを抑えられます。逆に、全コピーの保存場所を調べたいときは--no-collapseを使います。まとまるのは検索結果であり、元ファイルが削除されたり統合されたりするわけではありません。
これらは少数の架空資料での観測です。一般的な検索精度や、大量の日本語文書での正解率は測っていません。表示される類似度も、内容が正しい確率ではありません。
締切を変更しても、索引を更新しなければ古いまま
今回、expense.mdの締切を10月20日から10月25日に書き換え、その直後に--no-index付きで検索しました。返ってきたのは、まだ「10月20日」と書かれた古い本文でした。
--no-indexは、保存済みの索引をそのまま読む指定です。元のファイルを変更しただけでは、その索引は新しくなりません。次にanygrep indexを実行すると「1 updated」と表示され、同じ検索で「10月25日」が返りました。内容に変更のない再索引では、新規・更新はともに0でした。
通常の検索コマンドは、検索前に新規・変更ファイルを索引へ反映します。ただし、スクリプトなど端末への対話出力がない実行では、初期設定の約30秒の索引作成予算に収まるかで動作が変わります。大量のファイルを扱うなら、先にanygrep index 対象フォルダを実行して、完了を確認してから検索する運用が分かりやすいです。
追加・削除・名前の変更も試しました。新しい返品メモを1件加え、別番号の請求メモを1件削除し、会議室のファイル名を変更すると、結果は「2 new、2 removed」でした。名前の変更も、新しいファイルの索引作成として処理されたためです。
その後、会議室ファイルの名前と内容は変えず、同じ検索対象フォルダ内の別のサブフォルダへ移すと、「1 moved」で既存の索引が再利用されました。v0.1.0の実装では、テキストやPDFの埋め込みにファイル名も使うため、内容が同じでも名前が変わる場合は同じ扱いになりません。フォルダ整理のあとに件数が増減しても、ただちに重複や読み取り失敗と決めつけず、操作内容と照らして確認できます。
PDFなら何でも読めるわけではない
今回の納品手順PDFは、ページから文字を抽出できるPDFです。「顧客へ送る資料の確認」で検索すると、その1ページ目が先頭に返りました。
同時に入れた画像だけのスキャンPDFは、anygrep status --problemsで「no text layer」と表示され、検索可能なPDFには入りませんでした。Excelの.xlsxも非対応で、初回の索引作成時に「skipped 1 document (.xlsx)」と通知されました。スキャンPDFのスキップ件数と、非対応Officeファイルの通知は別枠です。
対応形式の説明では、PDFは文字層を読み取り、OCRは行いません。Word、Excel、PowerPointも現時点では非対応です。画像そのものの検索機能はありますが、スキャンPDFを自動的にOCRして請求番号まで読める機能とは異なります。今回、独立した画像ファイルの検索精度は検証していません。
検索結果に出ない資料については、質問の言い回しを工夫する前に、対応形式か、文字を抽出できるか、除外対象になっていないかを確かめる必要があります。隠しファイルや.anygrepignoreなどの除外ルールも有効です。検証用の除外メモと隠しメモは索引に入りませんでした。
架空資料で同じ操作を再現する
日本語の架空資料と検証スクリプトをダウンロードする。ZIPには元の資料、今回の観測ログ、検算用スクリプトを入れています。モデルやanygrep本体は含みません。
ZIPを展開したフォルダで、Pythonの仮想環境を作ってv0.1.0をインストールします。次はmacOS・Linux向けの例です。Windowsの起動方法は同梱READMEに記載しました。
python3 -m venv .venvsource .venv/bin/activatepython -m pip install 'anygrep==0.1.0'python run_lab.py --fixtures fixtures --work lab-run --model-dir models初回はモデルを取得するため、インターネット接続が必要です。スクリプトはfixturesを新しいlab-run/corpusへコピーし、そのコピーだけを更新・移動・削除します。既存のlab-runがあると停止するため、もう一度試す場合は別の新しい作業名を指定します。索引もlab-run/dataに分かれます。
全手順が終わるとlab-run/observed.jsonに実際の結果が残ります。今回の保存済みログだけを読む場合は、モデルを動かさずに検算できます。
python verify_results.py observed.jsonまずこの小さな資料群で、自分が探したい文書の種類と検索の仕方が合うかを確認すると判断しやすくなります。請求番号がある資料、日本語で目的を説明して探す資料、そもそも検索対象に入らない資料を分けて見れば、導入後の「あるはずなのに見つからない」にも対処しやすくなります。