近年LLMの進化が著しく、ローカルでLLMを動かしても、わざわざRAGを構築せずともプロンプトへの直接入力で十分実用的なテキスト処理ができるようになりました。
今回は、実務でよくある**「各種ドキュメント(Word/PDFなど)を読み込み、ローカルLLMで要約・項目抽出して、Excelの決まったフォーマットに書き込む」**という処理を完全ローカル環境で構築してみたのでご紹介します。
💡 完成イメージ
(※ここに、読み込ませたWordと、出力されたExcelの比較スクショを貼ると読者に伝わりやすいです)
環境紹介
| 項目 | 内容 |
|---|---|
| OS | Windows11 |
| LLM | Llama 3.1 (Ollama経由) |
| Python | 3.11 |
システム構成と重要なポイント
安定して実務に耐えうるシステムにするため、構成としては以下のフローを採用しました。
💡 最も重要なポイント
LLMに「いきなりExcelファイルを作らせる・書かせる」のではなく、**「一度JSONなどの構造化データに変換してから、Python側でExcelに入れる」**ことです。これが処理を安定させる最大のコツです。
おすすめ構成ツール
| 目的 | ツール | 備考 |
|---|---|---|
| ローカルLLM実行 | Ollama | JSON Schemaによる構造化出力に強く扱いやすい |
| Word読込 | python-docx | |
| PDF読込 | PyMuPDF | レイアウトが崩れることがあるため複雑な帳票は注意 |
| Excel書込 | openpyxl | Office Open XML形式の読み書きの定番 |
| 処理制御 | Python | 全体のフローを制御 |
まず作るべき最小構成
例として、Wordファイルを要約してExcelのセルに入れる最小構成のコードを紹介します。
1. インストールとモデル準備
必要なPythonライブラリをインストールします。
pip install python-docx openpyxl ollama
Ollama側でモデルを用意します。日本語に強いモデルを選ぶのがおすすめです。
ollama pull llama3.1
2. Pythonコード実装(抽出→要約→書込)
from docx import Document
from openpyxl import load_workbook
import ollama
import json
# Wordファイルからテキスト抽出
def read_docx(path):
doc = Document(path)
return "\n".join([p.text for p in doc.paragraphs if p.text.strip()])
# ローカルLLMで要約・構造化
def summarize_with_llm(text):
prompt = f"""
以下の文書を読み取り、Excelに入力しやすいようにJSONで出力してください。
※重要: Markdownのバッククォート(```json)は使用せず、必ず{{}}から始まる純粋なJSON文字列のみを出力してください。
出力形式:
{{
"title": "文書タイトル",
"summary": "要約",
"important_points": "重要ポイント",
"action_items": "対応事項"
}}
文書:
{text}
"""
response = ollama.chat(
model="llama3.1",
messages=[
{"role": "user", "content": prompt}
],
format="json"
)
return json.loads(response["message"]["content"])
# Excelへ書き込み
def write_to_excel(excel_path, output_path, data):
wb = load_workbook(excel_path)
ws = wb.active
# テンプレートの指定セルにデータをマッピング
ws["B1"] = data.get("title", "")
ws["B2"] = data.get("summary", "")
ws["B3"] = data.get("important_points", "")
ws["B4"] = data.get("action_items", "")
wb.save(output_path)
if __name__ == "__main__":
text = read_docx("input.docx")
data = summarize_with_llm(text)
write_to_excel("template.xlsx", "output.xlsx", data)
実務で失敗しないための設計方針
LLMを使った自動化では、「LLMにどこまで任せるか」の線引きが重要です。
:::note warn
❌ 悪い例(LLMに任せすぎ)
「このWordを読んで、Excelにいい感じに入れておいて」
👉 LLMの出力フォーマットが毎回ブレてしまい、システムとして成立しません。
:::
:::note info
⭕ 良い例(役割分担)
- LLMには「必要な項目だけJSONで返して」と指示する。(文書名、要約、対応事項など)
- Excel側では、人間が事前にテンプレートを作り「B2=文書名、B3=要約...」と固定しておく。
Excelテンプレートの作成
あらかじめ template.xlsx として以下のようなフォーマットを用意しておきます。LLMに直接Excelの構造を考えさせるより、**「Excelテンプレートは人間が決める、中身のテキストだけLLMに作らせる」**のが最も安全です。
| セル | 項目名 | 中身(PythonがJSONから転記) |
|---|---|---|
| A1 | 文書タイトル | [B1セルに入力] |
| A2 | 100字要約 | [B2セルに入力] |
| A3 | 詳細要約 | [B3セルに入力] |
| A4 | 重要ポイント | [B4セルに入力] |
| A5 | 対応事項 | [B5セルに入力] |
| A6 | 担当者 | [B6セルに入力] |
PDFやExcelも読み込みたい場合
拡張子に応じてテキスト抽出の処理を分岐させれば、様々なファイルに対応可能です。
PDFの読み込み (PyMuPDF)
pip install pymupdf
import fitz
def read_pdf(path):
doc = fitz.open(path)
texts = []
for page in doc:
texts.append(page.get_text())
return "\n".join(texts)
Excelの読み込み (openpyxl)
from openpyxl import load_workbook
def read_excel(path):
wb = load_workbook(path, data_only=True)
ws = wb.active
rows = []
for row in ws.iter_rows(values_only=True):
rows.append("\t".join([str(cell) if cell is not None else "" for cell in row]))
return "\n".join(rows)
処理の分岐例
def read_document(path):
if path.endswith(".docx"):
return read_docx(path)
elif path.endswith(".pdf"):
return read_pdf(path)
elif path.endswith(".xlsx"):
return read_excel(path)
else:
raise ValueError("未対応のファイル形式です")
ローカルLLMで運用する場合の注意点
一番の注意点は 長い文書を一度に入れないこと です。
ローカルLLM(特にVRAMが限られた環境)はコンテキスト長に制限があります。長大なドキュメントを処理する場合は、以下のような「2段階処理」にすると安定します。
- 分割要約: ページや章ごとに要約させる
- 統合要約: 各要約をつなぎ合わせ、再度LLMにかけて最終的なJSONを出力させる
まとめ
DifyやAnythingLLMなどのノーコードツールも便利ですが、**「Excelの指定セルに正確に入力する」**など細かい制御が必要な実務においては、今回のような Ollama + Python + 各種ライブラリ の構成が最も確実でカスタマイズ性が高いです。
- Word / PDF / ExcelをPythonで読む
- ローカルLLMに「JSONで返せ」と指示する
- JSONのキーとExcelセルを対応させる
- openpyxl でExcelテンプレートに書き込む
この一連のフローを作ってしまえば、どんなフォーマットの文書が来ても同じExcel帳票に綺麗に流し込めるようになります。ローカル環境での業務自動化を検討している方は、ぜひ試してみてください。