実は逆です。Office資料をMarkdownへ変換しやすくなるほど、要約前の確認は省けません。
8月5日にFirecrawlが公開したanydocは、Office資料をMarkdownへ変換できるRust製ライブラリです。提案書、旧版の見積書、顧客から届いたExcelを同じ入口で扱えるのは、営業企画では助かります。
ただ、変換結果がMarkdownになっていることと、要約に必要な情報が残っていることは別です。表の金額、納期、検収条件のどれかが落ちても、生成された要約は妙に自然な文章で返ります。自然だから見落とす。ここが厄介でした。
僕なら、変換直後に「この資料で絶対に落としてはいけない語」を機械的に確認してから、要約やCRM登録へ流します。Markdown を信用する前に、今回の検査を一段挟みます。
変換の成否と、業務で使えるかは別に見る
anydocのREADMEには、変換できなかった画像だけのPDFや暗号化ファイルをエラーとして扱う説明があります。まずこのエラーを記録して、変換できたファイルだけを次へ進めます。
その次に見るのが内容です。たとえば提案書なら、顧客名、見積金額、納期。料金表なら表そのもの。全部を人が読み返すのではなく、資料ごとに最低限の条件をJSONへ置きます。
文字数だけでは足りません。巻末の免責事項で文字数を満たしても、本文の金額が消えていれば困るからです。見出し数とMarkdown表の数も見ます。要約前の足切りとしては十分に効きます。
先に検査条件を書く
checks.json はこんな形です。必須語は、要約結果に欲しい語ではなく、元資料から消えたら困る語にします。
[
{
"file": "proposal.md",
"min_chars": 80,
"min_headings": 2,
"min_tables": 1,
"required": ["北関東物流", "1280000円", "2026年9月30日"]
}
]
金額を「1280000円」と決め打ちにするのは、正式版の見積書を取り込むときだけです。毎月更新される料金表なら、見積金額 のような見出しを必須語にして、金額の妥当性は別の処理で確かめます。ここを一つの万能ルールにしない方が、後から困りません。
Markdownを止めるPython
標準ライブラリだけで動きます。変換済みのMarkdownとJSONを置き、次のコードを check_markdown.py として保存します。
import argparse
import json
import re
import sys
from pathlib import Path
def count_tables(markdown: str) -> int:
return sum(
1
for line in markdown.splitlines()
if re.match(r"^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$", line)
)
def inspect(item: dict) -> list[str]:
path = Path(item["file"])
if not path.is_file():
return ["Markdownファイルが見つかりません"]
markdown = path.read_text(encoding="utf-8")
compact = re.sub(r"\s+", "", markdown)
headings = len(re.findall(r"(?m)^#{1,6}\s+", markdown))
tables = count_tables(markdown)
errors = []
min_chars = item.get("min_chars", 1)
min_headings = item.get("min_headings", 0)
min_tables = item.get("min_tables", 0)
if len(compact) < min_chars:
errors.append(f"文字数不足: {len(compact)} < {min_chars}")
if headings < min_headings:
errors.append(f"見出し不足: {headings} < {min_headings}")
if tables < min_tables:
errors.append(f"表不足: {tables} < {min_tables}")
for word in item.get("required", []):
if word not in markdown:
errors.append(f"必須語がありません: {word}")
return errors
parser = argparse.ArgumentParser()
parser.add_argument("manifest", help="変換後Markdownの検査条件JSON")
args = parser.parse_args()
items = json.loads(Path(args.manifest).read_text(encoding="utf-8"))
failed = False
for item in items:
errors = inspect(item)
name = item["file"]
if errors:
failed = True
print(f"NG {name}")
print("\n".join(f" - {error}" for error in errors))
else:
print(f"OK {name}")
sys.exit(1 if failed else 0)
実行はこれだけです。
python3 check_markdown.py checks.json
手元のサンプルでは、こう出ました。
OK proposal.md
checks.json に存在しない 検収条件 を一語足すと、終了コードは1になり、出力はこう変わります。
NG proposal.md
- 必須語がありません: 検収条件
この時点では要約APIを呼びません。元のdocxかPDFを開いて、変換に失敗したのか、そもそも資料に書かれていないのかを確認します。昨日、必須語を一つ足しただけでこのNGが出たとき、変換結果を目で斜め読みする運用よりずっと安心できました。ここ地味に効きます。
表があるから正しい、ではない
このコードは表の罫線を数えるだけです。セル結合で列がずれた、数式の表示値だけが入った、といった内容までは判定しません。
金額や日付を自動で使うなら、検査に通ったMarkdownをCSVやJSONへ抜き出し、元ファイルの該当セルと突き合わせる工程を分けます。全部を一つのスクリプトへ詰めると、ルール変更のたびに壊れます。提案書の受付では必須語と見出し、料金表では列名と行数、という具合に小さく増やす方が現場では続きます。
現場では変換の後ろに置く
資料変換が速くなった分、AIに渡すファイルは増えます。そこで必要なのは、変換ツールを増やすことより、止める場所を決めることです。
この検査を通ったMarkdownだけを要約やCRM登録へ渡せば、欠けた資料をもっともらしい文章にしてしまう事故を減らせます。まずは失うと困る語を三つだけ書く。営業企画の自動化では、その三つを先に守る方が、プロンプトを長くするより成果につながります。