AIに見積CSVを読ませるとき、先に見るべきなのは金額でしょうか。それとも単位でしょうか。
僕は単位から止めます。金額がきれいに並んでいても、「単位:千円」の一行を落とすと、レビュー結果はもっともらしいまま1000倍ずれます。数字を読めるモデルほど、この事故は気づきにくいです。
9月3日にOpenAIが公開した導入事例では、LegoraがGPT-6 Astraで財務諸表41件を数分でレビューしたと紹介されていました。こういう速さが現実になるほど、入力側の小さな前提を人が残しておく価値は上がります。Legoraの導入事例を読んで、提案前の見積CSVで使っている小さな検査を整理しました。
今朝、サンプルCSVを3つ通したら、2つに警告が出ました。一つは「単位:千円」と書いた表の4行目に2,000円が混ざっていました。もう一つは単位の記載がありませんでした。見落としやすいのに、相手へ出た後は説明が面倒なやつです。ここ地味に効きます。
先に止めるのは、単位なしと単位混在
この検査で見るのは二つだけです。
- CSV内に
単位:千円のような宣言があるか - 宣言した単位と違う、
2,000円のような金額表記が混ざっていないか
金額そのものの正しさまでは判定しません。1,200が正しいかどうかは、案件の一次情報がないと機械では決められないからです。その代わり、読む人もツールも判断できない状態を先に浮かび上がらせます。
例えば、売上見込みを千円で集計する表に、返金だけ円で貼り付けてしまうことがあります。合計欄は数式で整って見えても、元の桁が違えば意味がありません。レビューに回す前なら、その行だけ元ファイルを確認して直せます。
この順番で止めます。
標準ライブラリだけで確認するPython
inputフォルダにCSVを置き、次のスクリプトをcheck_units.pyとして保存します。UTF-8とUTF-8 BOM付きCSVを対象にしています。外部ライブラリは使いません。
import csv
import re
import sys
from pathlib import Path
UNIT_RE = re.compile(r"単位\s*[::]\s*(億円|百万円|千円|万円|円)")
AMOUNT_RE = re.compile(
r"(?<![0-90-9])[-+]?[0-90-9][0-90-9,,]*(?:[..][0-90-9]+)?\s*(億円|百万円|千円|万円|円)"
)
def inspect_rows(name, rows):
declarations = []
amount_units = []
for row_no, row in enumerate(rows, start=1):
text = " | ".join(str(cell).strip() for cell in row)
declarations.extend((row_no, m.group(1)) for m in UNIT_RE.finditer(text))
amount_units.extend(
(row_no, m.group(1), m.group(0))
for m in AMOUNT_RE.finditer(text)
)
units = sorted({unit for _, unit in declarations})
if not units:
print(f"[WARN] {name}: 単位の宣言がありません")
return 1
if len(units) > 1:
detail = ", ".join(f"{unit}({row_no}行目)" for row_no, unit in declarations)
print(f"[WARN] {name}: 単位の宣言が複数あります: {detail}")
return 1
declared = units[0]
conflicts = [
(row_no, unit, value)
for row_no, unit, value in amount_units
if unit != declared
]
if conflicts:
detail = ", ".join(f"{row_no}行目={value}" for row_no, _, value in conflicts)
print(f"[WARN] {name}: 宣言は{declared}ですが、別単位の金額があります: {detail}")
return 1
print(f"[OK] {name}: 単位={declared}")
return 0
def inspect_file(path):
with path.open(encoding="utf-8-sig", newline="") as f:
return inspect_rows(path.name, csv.reader(f))
def main():
root = Path(sys.argv[1] if len(sys.argv) > 1 else "input")
if not root.is_dir():
raise SystemExit(f"ディレクトリがありません: {root}")
files = sorted(root.glob("*.csv"))
if not files:
raise SystemExit(f"CSVがありません: {root}")
warnings = sum(inspect_file(path) for path in files)
print(f"\n確認が必要なCSV: {warnings}件")
return 1 if warnings else 0
if __name__ == "__main__":
raise SystemExit(main())
実行はこれだけです。
python3 check_units.py input
検証には、次の3パターンを使いました。Python 3.14.6で実行しています。
[WARN] forecast.csv: 宣言は千円ですが、別単位の金額があります: 4行目=2,000円
[WARN] budget.csv: 単位の宣言がありません
[OK] plan.csv: 単位=百万円
確認が必要なCSV: 2件
警告が1件でもあれば終了コードは1になります。ローカルで見るだけなら表示を確認すれば十分ですし、提案資料を作る前のバッチに入れるなら、1で止めればいい。人が直すべきファイルだけに絞れます。
なぜAIレビューの前に置くのか
単位は表の文脈です。CSVにすると、Excelのシート名、セルの色、見出しの結合といった手がかりが落ちます。AIへ渡す時点で単位の一行まで残っていなければ、「売上1200」と「売上1200千円」を区別する材料がありません。
だから、プロンプトに「単位を確認して」と足すだけでは足りません。単位なしのファイルを渡さない運用にした方が再現できます。レビュー結果が速く返るほど、入力の欠けに気づくタイミングは減ります。
このスクリプトは、複数通貨の正当性や、¥2,000のような表記までは扱いません。そこまで一度に拾おうとすると、普通のメモや日付まで金額扱いして警告だらけになります。まずは見積・予算・売上見込みで使う5単位に狭めています。例外が多い帳票は、正規表現を増やす前にCSVを分けた方が保守しやすいです。
見積レビューで守る順番
AIに渡す資料が増えるほど、レビューの強さより入口の整備で差がつきます。単位なしと単位混在を先に止めれば、レビュー担当は本当に見たい金額の根拠へ時間を使えます。
僕なら、このチェックを見積CSVの出力直後に置きます。通ったファイルだけを要約や比較に回す。派手ではありませんが、商談の数字を扱うなら、この一手の方がモデルを替えるより先です。
