2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

知財のあれこれをPythonとローカルLLMで何とかする

2
Last updated at Posted at 2025-09-26

ローカルLLMに先行文献を調査させる

今回のテーマは「大量の先行文献をローカルLLMに入力して、全文を精査させる」です。
まず以下のような状況を想定してください。(よくある光景では)

上司「特許調査データベースを使って先行文献調査して。全文精査してね。」

部下「承知しました。(2~30件くらいかな。。。)」

3.png

部下「データベースで検索して。。。」

部下「1000件もある。。。」

1.png

先行文献調査は特許出願、無効調査における非常に重要な業務ですが、何しろ調査対象の文献数が多いことは実務担当者の共通の悩みです。手順の最初では特許データベースを使ってキーワードや特許分類で絞り込みますが、それでも数百件から数千件になることがあり、それからは文献を目視確認することになります。要約や請求項だけならともかく全文を隅々まで確認しようとすると膨大な時間がかかります。
そこで今回は担当者に代わってローカルLLMが文献全体を隅々まで確認するプログラムを作成したいと思います。
今回のプログラムで実現しようとしていることを以下のイラストで示します。
スクリーンショット 2025-09-23 231408.png

全体の仕組みについて

全体の仕組みについては前回の記事(以下にリンクを張ります)と同じなのでそちらを参照ください。

用意すべき機材

最低限の動作環境はメモリ16GB以上のPCとします(32GB以上を推奨)。

ローカルLLM実行環境「ollama」をインストールして起動する

ローカルLLMを使用するため、「ollama」をインストールします。
ollamaのホームページからインストーラをダウンロードしてインストールし、今回利用するLLMをダウンロードすることで利用可能となります。今回はLLMとしてグーグル製のモデル「gemma3:12b」を使用します。
インストール後ollamaが起動していることを確認(タスクバー右下のインジケータ、「▲」ボタンを押して以下のアイコンが表示されている)してください。
スクリーンショット 2025-07-21 111535.png
起動していないようであればスタートメニューからollamaを実行ください。
ollamaが起動していたらgemma3:12bをダウンロードします。コマンドプロンプト(「windows」キー+"S"→”cmd”→「コマンドプロンプト」を実行)から「ollama pull gemma3:12b」を入力してダウンロードします。完了したら確認のためコマンドプロンプトから「ollama list」を入力します。「gemma3:12b」が表示されればダウンロード成功です。

全体の処理の流れ

以下のような順序で実行します。
1.複数PDF全文を読み込んでcsvファイルを作成する(program1)
2.csvファイルを一定の文字数で切り分けてxlsxファイルを作成する(program2)
3.xlsxファイルを読み出してローカルLLMに入力しレポートを記録する(program3)

流れを以下に図示します。
スクリーンショット 2025-09-27 070328.png
プログラムが正常に終了するとローカルLLMの回答は出力ファイル「query_modified.xlsx」のB列に記入されます。
今回もcopilot,geminiに助けてもらって以下のサンプルプログラムを作成しました。

1.複数PDF全文を読み込んでcsvファイルを作成する

調査対象の複数の文献をまずPDFでダウンロードして指定フォルダ(ここではC:\tempにしています)に保存しておいて下さい。
以下のprogram1を使ってまずPDFからいったんcsv型式でコピペします。csvにするのは、csvにはExcelのような1セルの文字数制限がないため全文を取り込めるからです。

program1.py
import os
import csv
import fitz  # PyMuPDF

# PDFファイルが保存されているフォルダのパスを指定
pdf_folder = r"C:\temp"
output_csv = "query.csv"

# CSVファイルを作成
with open(output_csv, mode='w', newline='', encoding='utf-8') as csv_file:
    writer = csv.writer(csv_file)
    writer.writerow(["特許番号", "全文"])  # ヘッダー行

    # フォルダ内のPDFファイルを処理
    for filename in os.listdir(pdf_folder):
        if filename.lower().endswith(".pdf"):
            pdf_path = os.path.join(pdf_folder, filename)
            try:
                doc = fitz.open(pdf_path)
                text = ""
                for page in doc:
                    text += page.get_text()
                doc.close()
                writer.writerow([filename, text.strip()])
            except Exception as e:
                print(f"エラー({filename}): {e}")
                writer.writerow([filename, "読み取りエラー"])

(プログラムについて)

・プログラムを実行する前にまずpdfファイルをアクセスするためのライブラリをダウンロードします(pip install PyMuPDF)。
・変数pdf_folderで指定するフォルダに調査対象のPDFファイルを保存し、program1を実行すると調査対象文献のファイル名(PDFファイル名=特許番号としています)と全文を含むquery.csvが生成されます。
・query.csvの内容を確認する際はCassava.exeなどのcsv編集ソフトが便利です。

2.csvファイルを一定の文字数で切り分けてxlsxファイルを作成する

ローカルLLMにプロンプトとして一度に入力可能な文字数に上限があることから、CSVファイルを一定の文字数で切り分けてローカルLLMの1回処理する文字数だけを1セル内に収めるようにします。Excelのセル内文字列制限(最大文字数32,767文字)もありますので、1セル内に収まるようにCSVファイルの全文を加工し、query.xlsxを作成します。
1セル内の文字数は30,000文字とし、全文を最初にC列に記入して30,000文字を超える部分はD列、さらに超える場合はE列・・・というように順次右方向のセルに記入していくようにします。なおLLMの回答の記入セルとしてB列は空けてあります。
プログラムを実行するにはpythonのライブラリ「pandas」「openpyxl」のインストール(pip install pandas openpyxl)が必要です。

program2.py
import pandas as pd
import openpyxl

# 文字数制限の指定(例:30000)
CHRLMT = 30000

# CSVファイルの読み込み
df = pd.read_csv('query.csv', encoding='utf-8')

# Excelファイルの準備
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Sheet1"

# 🔹 タイトル行(列名)を1行目に記入
ws.cell(row=1, column=1, value="特許番号")
ws.cell(row=1, column=2, value="LLM回答")
ws.cell(row=1, column=3, value="全文")

# 🔹 データ行の処理(2行目から開始)
for idx, row in df.iterrows():
    excel_row = idx + 2  # データは2行目から

    # A列のコピー(ファイル名)
    ws.cell(row=excel_row, column=1, value=row.iloc[0])

    # B列の文字列取得(テキスト内容)
    text = str(row.iloc[1])
    col = 2  # B列から開始

    while len(text) > CHRLMT:
        chunk = text[:CHRLMT]
        marker_pos = chunk.rfind('')

        if marker_pos > 0:
            chunk = chunk[:marker_pos]
            remainder = text[marker_pos:]
        else:
            remainder = text[CHRLMT:]
            
        #分割済み文字列はc列より右
        ws.cell(row=excel_row, column=col +1 , value=chunk)
        col += 1
        text = remainder

    ws.cell(row=excel_row, column=col + 1, value=text)

# 保存
wb.save('query.xlsx')
print("処理が完了しました。query.xlsx に保存されました。")

(プログラムについて)

・変数CHRLMTで1セル内に収める文字数を30,000に設定しています。今回ローカルLLMとしてgemma3:12bを使うことでプロンプト文字数が30,000でも処理可能です。
・別のローカルLLMでは一度に入力可能なプロンプトの文字数上限が4,000文字だったり8,000文字だったりしますので、別のローカルLLMを使用する場合は種類に応じてプロンプト文字数上限に合わせて変数CHRLMTの文字数設定を変える必要があります。
・テキストを切り分けるときに文章の途中で切れたりしないよう、段落記号の「【」の直前を切り分けの境界にするように指定してます。

3.xlsxファイルを読み出してローカルLLMに入力しレポートを記録する

Program2を実行しquery.xlsxが生成できましたので、以下のプログラム(program3)を使ってローカルLLMに処理を実行させます。
ollamaが起動していることを確認して以下のprogram3を実行してください。
プログラムを実行するにはpythonのライブラリ「openpyxl」「requests」のインストール(pip install openpyxl requests)が必要です。

program3.py
import openpyxl
import requests

# Ollamaの設定
OLLAMA_BASE_URL = "http://localhost:11434"
MODEL_NAME = "gemma3:12b"

TEMPERATURE = 0.5 #揺らぎ設定(0:確定的~1:揺らぎの最高値)
with open('prompt.txt', 'r', encoding='utf-8') as file:
    SYSPR = file.read()

# コンテキスト長の設定を追加
CONTEXT_LENGTH = 32000

# Excelファイルの読み込み
wb = openpyxl.load_workbook("query.xlsx")
ws = wb["Sheet1"]

#C列より右のすべての列について、文字列があるセルだけを処理する
for row in range(2, ws.max_row + 1):
    for col in range(3, ws.max_column + 1):  # C列から右方向へ順次処理
        cell = ws.cell(row=row, column=col)
        prompt = cell.value

        if isinstance(prompt, str) and prompt.strip():  # 文字列があるセルのみ処理
            response = requests.post(f"{OLLAMA_BASE_URL}/api/generate", json={
                "model": MODEL_NAME,
                "prompt": prompt,
                "temperature": TEMPERATURE,
                "system": SYSPR,
                "stream": False,
                "options": {
                    "num_ctx": CONTEXT_LENGTH
                }
            })
            output = response.json().get("response", "")
            print(f"row: {row}, col: {col}")
            res = ws.cell(row=row, column=2).value or "" # B列を読み出し
            ws.cell(row=row, column=2).value = res + output + "\n" # B列にLLM回答を追加書き込み

wb.save("query_modified.xlsx")

(プログラムについて)

・program3の実行に先立ちLLMへの指示プロンプトをファイル名「prompt.txt」のテキストファイルに保存します。指示プロンプトは「(技術特徴)に関する記載個所を探し、記載が有れば説明して。」といった文面になります。指示プロンプトの文字数は後にも説明しますが上限2000文字としています。
・program3を実行するとquery_modified.xlsxが新たに生成されます。このファイルのA列に示される特許番号(=ファイル名)に対応するB列にローカルLLMからの回答が記入されています。
・全文が複数セルに分割されている場合、複数セルに対する回答を結合(文末につなげていく)してB列の1セル内に収めています。
・指示プロンプトの文字数(上限2000文字)を足しても処理できるよう、CONTEXT_LENGTH = 32000として1セルの文字数(program2のCHRLMTの値30000)より多めに設定しています。
・requests.post(f"{OLLAMA_BASE_URL}/api/generate・・「api/generate」と記述することで各セルは独立して処理され、以前に処理したセルに対する処理履歴は残りませんので、他の特許の内容が回答に影響するようなことはありません。
・うまく動作しない場合や反応が遅すぎて正常に動作しているかわからない場合は、プロンプトの文字数を減らすとうまくいくかもしれません(program2の「CHRLMT」とprogram3の「CONTEXT_LENGTH」の設定値を小さくする」)

サンプル文献およびプログラムの実行結果

サンプル文献(特開2005-122271)の全文から、技術特徴「指スライド・ジェスチャーでアイコン操作し、画面ロックの解除を行う」を探索させたいとします。
まず以下のリンクからサンプル文献の全文PDFをダウンロードしてフォルダ(C:\temp)に保存ます。
(今回のサンプルにはiPhoneの画面アンロック特許で有名な特許5457679の審査引例を利用させて頂きました)

特開2005-122271:J-platpatのリンク

次にLLMへの指示プロンプトとして、以下の文字列をファイル名「prompt.txt」のテキストファイルで保存します。

「指スライド・ジェスチャーでアイコン操作し、画面ロックの解除を行う」に関する記載個所を探し、記載が有れば説明して。

最後にProgram1、Program2、Program3の順に実行します。
サンプルでの実行結果がquery_modified.xlsxのB列に記入されます。結果は以下のようになりました。

(サンプル実行結果)
この特許文献を精査した結果以下の箇所に指スライドジェスチャーによるアイコン操作と関連する記述が見つかりました

*   **特許請求の範囲 :** 操作検知部...接触場所と接触時間を検知可能で且つ接触場所と接触時間の組み合わせによる複数種類の操作タイプをそれぞれ弁別して検知可能という記述から指の動き接触場所と長さを検知して異なる操作を識別できる機能があることがわかります
*   **特許請求の範囲 :** 操作設定登録情報を記憶可能な記憶部という記述から操作タイプとアイコンとの関連付けがデータとして保存されていることがわかります
*   **発明の実施の形態:** 図10はユーザが各アイコンの配置設定を任意に設定変更カスタマイズした待受画面の表示例を示す。」という記述からユーザーがアイコンの配置や操作方法を自由に設定できることがわかります
*   **発明の実施の形態:** 図16はユーザが各アイコンの設定変更と操作エリアの機能設定変更の際の全体の流れのフローチャートを示す。」という記述からフローチャートで具体的に操作手順が示されています

これらの記述からこの携帯型電子装置では指の動きを検知するタッチパッドとそれを基にアイコン操作や機能実行を行う仕組みが組み込まれていることがわかりますユーザーは指スライドやジェスチャーを用いてアイコンの配置や操作方法をカスタマイズすることも可能です
はいご指示通り特許文献中の記載個所を探し関連する内容を説明します

**関連箇所:**

*   **【0097】~【0099】:** ショートカットキーアイコンの設定プロセス全体の説明ユーザによる機能選択操作エリア選択新規操作設定テーブルへの仮登録などが説明されています
*   **【0100】~【0102】:** ユーザによる操作エリアの選択がない場合の終了指示への対応について説明
*   **【0112】~【0113】:** 項目選択操作設定フローチャートの際操作エリアの選択がない場合の終了指示への対応について説明
*   **【0125】~【0126】:** キーロック処理のフローチャートの説明

**説明:**

これらの箇所は携帯電話端末における**画面ロック解除アイコン操作及びショートカットキー設定**に関連する機能の動作フローを説明しています

具体的には以下の要素について記述があります

*   **ユーザインターフェース:** ユーザは画面上のアイコンを通じて様々な機能を選択し操作できます
*   **操作エリア:** 各機能は画面上の特定の領域操作エリアに割り当てられています
*   **ショートカットキー設定:** ユーザはこれらの操作エリアと機能を任意に設定できます
*   **終了指示:** ユーザが操作を中断したい場合特定の操作クリアキーや終了キーの押下などによって終了指示を送ることができます
*   **デフォルト設定:** 操作エリアや機能の割り当てが特定のデフォルト設定に初期化されることもあります
*   **利き手設定:** ユーザの利き手に合わせてアイコンの配置や操作エリアの割り当てを自動的に変更する機能も搭載されています

**特に指スライドジェスチャーによるアイコン操作に関しては**

*   **ステップS85:** ユーザがタッチパッド上の操作エリアを選択する際触覚フィードバックや点滅マークなどで操作エリアを視覚的に示唆している
*   **ステップS102:** 操作エリアの選択プロセスにおいてユーザのタッチ操作を検出し対応する機能を実行する

これらの説明から指スライドやジェスチャー操作が携帯電話端末の画面ロック解除やアイコン操作の中核的な手段として利用されていることがわかります

最後に

・調査対象の文献が大量になるとB列の回答を読むのも一苦労するので、その場合はB列全部をコピペしてGeminiかCopilotに要約してもらうのも一つの手かと思います。
・注意すべき点としては、一般的なスペックのPCでローカルLLMを動かすとそれなりに処理時間がかかります。今回の例ではメモリ32G、GPU無しのごく普通のデスクトップPCで、30,000文字弱のセル1つを処理するのに20~30分かかりました。(メモリ16GのノートPCで1セル2時間かかりました)
・ソフトウエア特許の分野でざっくりみたところ全文で30,000文字以下が全体件数の約8割を占めていましたので、全体の概ね8割は1セルに収まる文字数となります。8割の文献を1件30分でレポートを作成してくれると考えれば(しかも昼夜問わず作業し、かかるのは電気代だけ)驚くべき生産性ですが、更なる効率化を追求するのであれば、GPUを備えた高性能PC導入を検討すべきではと思います。(VRAM16GのGPUで3~4倍速程度かと。)
今回の記事が何らかの助けになれば幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?