今回は、ドキュメントをローカルLLMに要約からの書き込みをさせてみました。ぜひご参考に。
近年LLMの成長もありローカルでもLLM使うとわざわざRAG作らなくてもある程度利用できるようになりましたね。実践をしてみようと思い取り組みました。
環境紹介
| セル | 内容 |
|---|---|
| OS | Windows11 |
| LLM | Gemma4 |
| python | 3.11 |
構成
安定させるため、構成としては 「文書読込 → ローカルLLMで要約・抽出 → JSON化 → Excelへ書き込み」
特に重要なのは、LLMにいきなりExcelへ書かせるのではなく、一度JSONなどの構造化データに変換してからExcelに入れる ことです。
⸻
全体構成
Word / PDF / Excel / txt
↓
Pythonでテキスト抽出
↓
ローカルLLMで要約・項目抽出
↓
JSON形式で出力
↓
PythonでExcelの指定セルに入力
ローカルLLMは Ollama が扱いやすいです。OllamaはJSON Schemaによる構造化出力に対応しているため、文書から決まった項目を抜き出す用途に向いています。
⸻
おすすめ構成
目的 ツール
ローカルLLM実行 Ollama
Word読込 python-docx
PDF読込 PyMuPDF
Excel書込 openpyxl
処理制御 Python
Excelへの書き込みは openpyxl が定番です。.xlsx / .xlsm などのOffice Open XML形式を読み書きできます。
PDFはPyMuPDFでテキスト抽出できますが、PDFはレイアウト順が崩れることがあるため、表や複雑な帳票は注意が必要です。
⸻
まず作るべき最小構成
例として、Wordファイルを要約してExcelのセルに入れるならこうです。
- インストール
pip install python-docx openpyxl ollama
Ollama側でモデルを用意します。
ollama pull llama3.1
日本語文書が多いなら、可能なら日本語に強いモデルを選ぶとよいです。
⸻
- Wordを読んで、LLMで要約し、Excelへ書く例
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で出力してください。
出力形式:
{{
"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["A1"] = "タイトル"
ws["B1"] = data.get("title", "")
ws["A2"] = "要約"
ws["B2"] = data.get("summary", "")
ws["A3"] = "重要ポイント"
ws["B3"] = data.get("important_points", "")
ws["A4"] = "対応事項"
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)
⸻
実務ではこの形が一番安定します
悪い例
このWordを読んでExcelにいい感じに入れて
これはLLMの出力が毎回ぶれます。
良い例
以下の項目だけJSONで返してください。
- 文書名
- 要約
- 対応事項
- 締切
- 担当者
そしてExcel側では、
B2 = 文書名
B3 = 要約
B4 = 対応事項
B5 = 締切
B6 = 担当者
のように固定します。
⸻
Excelテンプレートを作っておくと楽です
たとえば template.xlsx を用意しておきます。
| セル | 内容 |
|---|---|
| A1 | 文書名 |
| B1 | LLMが入力 |
| A2 | 要約 |
| B2 | LLMが入力 |
| A3 | 重要ポイント |
| B3 | LLMが入力 |
| A4 | 対応事項 |
| B4 | LLMが入力 |
| A5 | 担当者 |
| B5 | LLMが入力 |
| A6 | 期限 |
| B6 | LLMが入力 |
LLMに直接Excelの構造を考えさせるより、Excelテンプレートは人間が決める、中身だけLLMに作らせる のが安全です。
⸻
PDFやExcelも読みたい場合
pip install pymupdf
```
```python
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を読みたい場合
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)
⸻
処理フローの完成形
documents/
├─ report1.docx
├─ report2.pdf
├─ meeting.xlsx
template.xlsx
main.py
output.xlsx
Python側で拡張子を見て処理を分けます。
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はメモリやコンテキスト長に制限があります。長い文書は、
- ページごとに要約
- 各要約をさらに統合
- 最終結果をExcelへ入力
という2段階処理にすると安定します。
長文書
↓
分割要約
↓
統合要約
↓
JSON化
↓
Excel書込
⸻
おすすめの設計
個人的には、最初はこの構成がよいです。
Ollama + Python + openpyxl + python-docx + PyMuPDF
理由は、完全ローカルで動かせて、Excelへの書き込みも細かく制御できるからです。
ノーコード寄りにしたい場合は、
Dify / AnythingLLM / Open WebUI + Ollama
も候補になりますが、Excelの指定セルに正確に入力する なら、最終的にはPythonを挟む方が確実です。
⸻
実務向けの結論
最も安定する作り方はこれです。
① Word / PDF / ExcelをPythonで読む
② ローカルLLMに「JSONで返せ」と指示する
③ JSONのキーとExcelセルを対応させる
④ openpyxlでExcelテンプレートに書き込む
最初に作るなら、以下のようなExcelテンプレートを固定するのがおすすめです。
項目 セル
文書タイトル B1
100字要約 B2
詳細要約 B3
重要ポイント B4
対応事項 B5
担当者 B6
期限 B7
リスク B8
備考 B9
この形にしておくと、WordでもPDFでもExcelでも、同じExcel帳票に流し込めます。