case_615 士業・専門業務

月次の予実突合をClaude Codeで仕組み化する実装パターン

月次の予実突合をClaude Codeで仕組み化する実装パターン

会計ソフトの試算表CSVと部門別予算表の月次突合をClaude Codeで仕組み化する実装を解説。勘定科目名の揺らぎを吸収するマッピング表運用、乖離の閾値アラート、経営会議向けサマリー生成のコード例つき。

結論:月次の予実突合は、Excelの手作業でVLOOKUPを組み直す仕事ではなく「会計ソフトの試算表CSV・部門別予算表・勘定科目マッピング表」の3点を入力にした突合パイプラインとして、Claude Codeで構築できます。突合ロジックと乖離判定の閾値は決定的なコードに固定し、AIに任せるのは科目名の揺らぎ検出・マッピング表の更新候補提案・経営会議向けサマリーの文章化までです。

  • 要点1:予実突合が毎月終わらない最大の原因は計算ではなく「名寄せ」——会計ソフト側の勘定科目・補助科目と予算表側の管理科目が1対1に対応しておらず、しかも期中に増減する。ここをマッピング表として外部ファイル化するのが実装の核になる
  • 要点2:突合そのものは足し算と引き算であり、AIに計算させる必要はない。乖離率の算出・閾値判定はPythonの決定的なコードに固定し、Claude Codeには「未知の科目名が現れたときの対応候補の提案」と「乖離理由の下書き」だけを任せる
  • 要点3:成果物を「経営会議向けの1枚サマリー」まで含めて設計すると、突合が単なる検算作業から意思決定の材料づくりに変わる。乖離の羅列ではなく、閾値超過の部門×科目だけを理由記入欄つきで出す

対象読者:経理・経営企画部門とAI活用を進める開発者・PM。毎月の予実突合をExcelで手作業している会社

今日やること:自社の予算表と会計ソフトの試算表を並べ、科目名が「文字列として完全一致しない」ペアがいくつあるか数えてみる。それがそのまま自動化の設計難度になります

先に断っておくと、本記事は複数の支援経験をもとに一般化した実装パターン解説です。登場する数値や工数はいずれも想定モデルケースの目安で、特定企業の実測値ではありません。効果は予算管理の粒度・科目数・部門数によって大きく変わります。

バックオフィスのAI活用支援で経理・経営企画の方と話していると、「予実の突合そのものより、毎月ちょっとずつ形が変わることがつらい」という声をよく聞きます。新しい部門ができる、会計ソフト側で補助科目が増える、予算表の科目名が担当者の引き継ぎで微妙に書き換わる——どれも単体では小さな変化ですが、Excelの参照式は完全一致の世界で生きているので、その都度どこかの行が「#N/A」になり、数字を出す前にまず表の修理から始まる。月次の締めから経営会議までの限られた日数の中で、この修理作業が毎月発生するわけです。

この記事では、予実突合を「毎月組み直すExcel」から「マッピング表を育てながら回すパイプライン」に置き換える実装を、コードと運用の両面から解説します。給与計算の検算入金消込の差異分類と同じ「判定はコードに固定し、AIは正規化と整理を担う」パターンの予実版です。

なぜ予実突合は毎月終わらないのか——科目名の揺らぎという正体

予実突合の計算自体は、部門×科目ごとに「実績−予算」と「実績÷予算」を出すだけです。四則演算しかありません。それなのに毎月半日から数日かかるのは、計算の前段にある突き合わせの準備が自動化されていないからです。典型的には次の3つの揺らぎが原因になります。

揺らぎの種類 具体例 Excelで起きること
科目名の表記揺れ 「地代家賃」と「地代・家賃」、「広告宣伝費」と「広告費」、全角半角・スペース混在 VLOOKUPが完全一致で外れて#N/Aになる
粒度の不一致 会計側は「旅費交通費」1本、予算側は「出張旅費」「通勤交通費」に分割(またはその逆) 1対1で引けず、手動で合算セルを作る
期中の増減 新部門の追加、補助科目の新設、使われなくなった科目の残置 先月のシートをコピーすると新科目が漏れ、合計が合わない

重要なのは、この3つはどれも「今月直せば終わり」ではなく毎月発生し続けることです。組織と勘定科目は生き物なので、揺らぎを一度きりのデータクレンジングで解決しようとすると、翌月また同じ作業が待っています。だから実装の核心は、揺らぎを吸収する対応表——勘定科目マッピング表——をコードの外のファイルとして持ち、毎月少しずつ育てる設計にすることです。

実装の全体像——正規化・マッピング・突合・レポートの4層

パイプラインは4層に分けます。層を分ける理由は、揺らぎが発生する場所(正規化・マッピング)と、絶対に揺らいではいけない場所(突合・閾値判定)を分離するためです。

  1. 正規化層 — 会計ソフトから出力した部門別試算表CSVと、Excelの予算表を、同じ列構造の中間データ(部門・科目・金額)に変換する。全角半角・空白・記号の統一もここで行う
  2. マッピング層 — 勘定科目マッピング表(YAMLまたはCSV)を使って、会計側の科目名を予算側の管理科目に名寄せする。未知の科目が現れたら止まるのがこの層の最重要仕様
  3. 突合層 — 部門×管理科目ごとに予算・実績・差額・達成率を計算し、閾値を超えた乖離にフラグを立てる。ここは決定的なPythonコードのみで、AIは介在させない
  4. レポート層 — 全件の突合結果CSVと、閾値超過だけを抜き出した経営会議向けサマリー(Markdown)を出力する。乖離理由の下書きはClaude Codeに任せてよいが、必ず「下書き」として人間が確定させる

Claude Codeの使いどころは2つです。1つ目は、この4層のコード自体を対話しながら書かせること。自社のCSVレイアウトを見せて「この形式を読み込むパーサを書いて」と指示すれば、初期構築は大きく短縮できます。2つ目は、毎月の運用で未知の科目が現れたときに、マッピング表の更新候補を提案させること。この2つ目が、予実突合ならではの使い方になります。

実装コード例1:試算表CSVと予算表を正規化する

まず入力を揃えます。会計ソフトの部門別試算表エクスポートは製品によって列構成が異なるため、ここでは「部門・勘定科目・金額の3列に落とせればよい」という方針だけをコードに固定します。自社のレイアウトへの適合は、実際のCSVをClaude Codeに見せて調整するのが早いです。

# normalize.py — 試算表CSVと予算表を共通形式に正規化する
import pandas as pd
import unicodedata
import re

def clean_name(s: str) -> str:
    """科目名・部門名の表記を統一する(NFKC正規化+空白・中黒除去)"""
    s = unicodedata.normalize("NFKC", str(s))
    s = re.sub(r"[s・・]", "", s)
    return s.strip()

def load_actual(path: str) -> pd.DataFrame:
    """会計ソフトの部門別試算表CSV → (部門, 科目, 実績額)"""
    df = pd.read_csv(path, encoding="utf-8-sig")
    df = df.rename(columns={"部門名": "dept", "勘定科目": "account", "当月残高": "amount"})
    df["dept"] = df["dept"].map(clean_name)
    df["account"] = df["account"].map(clean_name)
    df["amount"] = (
        df["amount"].astype(str).str.replace(",", "").str.replace("△", "-")
    ).astype(int)
    return df[["dept", "account", "amount"]]

def load_budget(path: str, month: str) -> pd.DataFrame:
    """予算表Excel → (部門, 管理科目, 予算額)。monthは '2026-07' 形式"""
    df = pd.read_excel(path, sheet_name="月次予算")
    df = df.rename(columns={"部門": "dept", "管理科目": "mgmt_account", month: "budget"})
    df["dept"] = df["dept"].map(clean_name)
    df["mgmt_account"] = df["mgmt_account"].map(clean_name)
    return df[["dept", "mgmt_account", "budget"]].dropna(subset=["budget"])

ポイントはclean_name()を実績側・予算側の両方に必ず通すことです。NFKC正規化で全角英数と半角カナが揃い、空白と中黒の除去で「地代・家賃」と「地代家賃」が同じ文字列になります。この機械的な正規化だけで、表記揺れの相当部分は消えます。それでも残る「広告費と広告宣伝費」のような語彙レベルの揺らぎが、次のマッピング層の仕事です。

実装コード例2:勘定科目マッピング表——揺らぎを吸収する運用

マッピング表は、会計側の勘定科目(複数可)を予算側の管理科目1つに対応づける表です。コードに埋め込まず、経理担当者が直接編集できるYAMLファイルとして持ちます。

# account_mapping.yaml — 会計科目 → 管理科目の対応表
# 経理担当者がレビュー・編集する。コードには埋め込まない
人件費:
  - 給料手当
  - 賞与
  - 法定福利費
  - 福利厚生費
広告宣伝費:
  - 広告宣伝費
  - 広告費        # 2026-05 補助科目新設に伴い追加
  - 販売促進費
地代家賃:
  - 地代家賃
旅費交通費:
  - 旅費交通費
  - 出張旅費      # 予算側が分割管理をやめた2026-04以降はこちらに集約

このマッピングを適用するコードで最も重要なのは、対応が見つからない科目を黙って捨てないことです。未知の科目はエラーとして列挙し、処理を止めます。

# mapping.py — マッピング適用。未知科目は止める
import yaml
import pandas as pd

def load_mapping(path: str) -> dict:
    """YAML → {会計科目: 管理科目} の逆引き辞書"""
    with open(path, encoding="utf-8") as f:
        raw = yaml.safe_load(f)
    reverse = {}
    for mgmt, accounts in raw.items():
        for acc in accounts:
            if acc in reverse:
                raise ValueError(f"科目 '{acc}' が複数の管理科目に登録されています")
            reverse[acc] = mgmt
    return reverse

def apply_mapping(actual: pd.DataFrame, mapping: dict) -> pd.DataFrame:
    actual = actual.copy()
    actual["mgmt_account"] = actual["account"].map(mapping)
    unknown = sorted(actual.loc[actual["mgmt_account"].isna(), "account"].unique())
    if unknown:
        raise SystemExit(
            "【未知の科目】マッピング表にない科目が見つかりました。n"
            + "n".join(f"  - {u}" for u in unknown)
            + "naccount_mapping.yaml に対応を追加してから再実行してください。"
        )
    return actual.groupby(["dept", "mgmt_account"], as_index=False)["amount"].sum()

「未知科目で止まる」仕様は、一見すると自動化に逆行するようですが、これが揺らぎ対応の生命線です。黙って除外すれば合計が静かにずれ、勝手に推測で名寄せすれば誤った科目に金額が乗ります。どちらも、突合結果への信頼を失う壊れ方です。止まった時にやることを機械的にするために、Claude Codeへ次のように依頼して更新候補を提案させます。

> 予実突合パイプラインが未知の科目「販促物制作費」で停止した。
> account_mapping.yaml を読み、既存の管理科目のうちどれに追加すべきか、
> 科目の意味の近さを理由つきで3候補提案して。
> ただしYAMLの編集はまだしないこと。私が判断してから指示する。

提案はあくまで候補であり、確定するのは経理担当者です。「AIが提案し、人が確定し、確定結果はファイルに残る」というループを回すと、マッピング表は月を追うごとに揺らぎに強くなり、停止の頻度は自然に下がっていきます。

実装コード例3:部門別の予実突合と乖離の閾値アラート

名寄せが済めば、突合は単純なマージです。閾値判定もここで行います。

# reconcile.py — 予実突合と閾値フラグ
import pandas as pd

# 閾値は経営会議の運用に合わせて調整する(例:乖離率10%かつ乖離額50万円以上)
RATE_THRESHOLD = 0.10
AMOUNT_THRESHOLD = 500_000

def reconcile(actual_mapped: pd.DataFrame, budget: pd.DataFrame) -> pd.DataFrame:
    df = budget.merge(actual_mapped, on=["dept", "mgmt_account"], how="outer")
    df["budget"] = df["budget"].fillna(0).astype(int)
    df["amount"] = df["amount"].fillna(0).astype(int)
    df["diff"] = df["amount"] - df["budget"]
    df["rate"] = df.apply(
        lambda r: r["diff"] / r["budget"] if r["budget"] != 0 else float("inf"),
        axis=1,
    )
    df["alert"] = df.apply(
        lambda r: abs(r["rate"]) >= RATE_THRESHOLD
        and abs(r["diff"]) >= AMOUNT_THRESHOLD,
        axis=1,
    )
    return df.sort_values(["alert", "diff"], ascending=[False, False])

閾値を「乖離率」と「乖離額」の二段構えにしているのは、片方だけだとノイズが出るからです。率だけで見ると予算1万円の科目の数千円のずれが上位に並び、額だけで見ると予算規模の大きい人件費が毎月常連になります。「率も額も超えたものだけ」を経営会議に上げると、議論すべき乖離に絞れます。how="outer"でマージしているのも意図的で、予算にだけある科目(未消化)と実績にだけある科目(予算外支出)の両方を漏らさず拾うためです。

実装コード例4:経営会議向け1枚サマリーの生成

突合結果の全件CSVは経理の検証用に保存しつつ、経営会議にはアラート行だけを抜き出した1枚サマリーを出します。フォーマットはMarkdownにしておくと、そのまま議事システムや社内Wikiに貼れます。

# report.py — 閾値超過だけの1枚サマリー(Markdown)
def to_summary_md(df, month: str) -> str:
    alerts = df[df["alert"]]
    lines = [
        f"# {month} 予実サマリー(乖離率10%かつ乖離額50万円以上)",
        "",
        f"- 突合対象: {len(df)} 行(部門×管理科目) / アラート: {len(alerts)} 件",
        "",
        "| 部門 | 管理科目 | 予算 | 実績 | 乖離額 | 乖離率 | 理由(記入欄) |",
        "|---|---|---:|---:|---:|---:|---|",
    ]
    for _, r in alerts.iterrows():
        rate = "予算外" if r["budget"] == 0 else f"{r['rate']:+.1%}"
        lines.append(
            f"| {r['dept']} | {r['mgmt_account']} | {r['budget']:,} "
            f"| {r['amount']:,} | {r['diff']:+,} | {rate} |  |"
        )
    return "n".join(lines)

「理由(記入欄)」を空欄で出すのがこの帳票の設計思想です。乖離理由の一次下書きはClaude Codeに書かせることもできますが(例:「広告宣伝費の超過は販促物制作費の予算外計上によるもの、とCSVの補助科目から推定される」)、外部報告や意思決定に使う理由説明は必ず担当者が事実確認して確定させてください。AIの推定はあくまで調査の出発点です。

Claude Codeへの指示プロンプト集——構築と月次運用で使う5つ

実際の構築・運用で使う指示の型を5つ挙げます。いずれも「判定コードは触らせない」「編集の前に提案で止める」が共通の作法です。

1. 初期構築——自社CSVへの適合

> このフォルダの sample_trial_balance.csv は当社の会計ソフトが出力した
> 部門別試算表です。normalize.py の load_actual() をこのレイアウトに
> 合わせて修正して。列名は実ファイルのヘッダーを読んで確認すること。

2. マッピング表の初期生成

> 実績側の科目一覧(accounts_actual.txt)と予算側の管理科目一覧
> (accounts_budget.txt)を読み、account_mapping.yaml の初期案を作って。
> 確信が持てない対応には「# 要確認」コメントを付けること。

3. 月次運用——未知科目の対応候補提案

> パイプラインが未知の科目で停止した。エラーメッセージの科目ごとに、
> 既存の管理科目への追加候補を理由つきで提案して。YAMLはまだ編集しない。

4. 乖離理由の下書き

> summary_2026-07.md のアラート5件について、試算表CSVの補助科目と
> 摘要列から乖離理由の下書きを書いて。推定であることを明記し、
> 断定表現は使わないこと。

5. 回帰テスト——ロジック変更時の検算

> 閾値を変更したので、先月の入力データで再実行し、前回の
> summary_2026-06.md との差分を一覧にして。アラートの増減が
> 閾値変更で説明できるか確認したい。

プロジェクト直下のCLAUDE.mdに「reconcile.pyの判定ロジックは指示なしに変更しない」「未知科目は必ず停止」といった運用ルールを書いておくと、毎回の指示が短くなり、意図しない書き換えも防げます(Claude Code公式ドキュメント: Memory)。

運用の3フェーズ——最初の2か月は「マッピング表を育てる」

Phase 1(1〜2か月目):並走期。従来のExcel突合と並行してパイプラインを回し、両者の合計が一致することを確認します。この期間の主目的は突合の置き換えではなく、未知科目エラーを潰しながらマッピング表を実態に追いつかせることです。最初の月は停止が何度も起きますが、それは設計どおりの挙動です。

Phase 2(3〜4か月目):切り替え期。合計一致が2か月続いたらパイプラインを正とし、Excel側は検証用に残します。閾値をこの時期に調整します。アラートが多すぎて会議で流し読みされるなら閾値を上げ、拾うべき乖離が漏れたら下げる——閾値は一度で決まらない前提で運用します。

Phase 3(5か月目以降):拡張期。月次が安定してから、四半期累計・年度着地見込みへの拡張や、電子帳簿保存法対応のデータ保存など周辺の月次業務との連携を検討します。工数の目安として、想定モデルケース(10部門×30管理科目程度)では、半日〜1日かかっていた突合作業がパイプライン実行と結果確認で1時間前後に収まることが多い、という感触ですが、これは科目の揺らぎの多さに大きく左右されます。

【要注意】よくある失敗パターンと回避策

❌ 失敗1:科目の名寄せをAIの推測に任せて自動続行する
「似た科目名を自動でマッチさせて」と指示すると、一見それらしく動きますが、誤った名寄せは金額が科目間で静かに付け替わるだけなので、合計チェックでは検出できません。
⭕ 回避策:名寄せの確定は必ずマッピング表ファイル経由にする。AIの役割は「候補の提案」まで。未知科目では停止し、人がYAMLを更新してから再実行する。

❌ 失敗2:予算表のセル構造をそのままパースしようとする
結合セル・小計行・注記が混ざった「人が見るための予算表」を直接読むコードは、翌月の体裁変更で壊れます。
⭕ 回避策:予算表に「部門・管理科目・月別金額」だけのデータシートを1枚追加し、パイプラインはそのシートだけを読む。見た目用の表はデータシートから参照式で作る。

❌ 失敗3:乖離アラートの閾値を最初から凝りすぎる
科目別に個別閾値を設定し始めると、閾値表自体が第二のマッピング表になり、メンテナンス対象が増えます。
⭕ 回避策:まず「率10%かつ額50万円」のような全社一律の二段閾値で始め、運用しながら例外が本当に必要な科目だけ個別化する。

❌ 失敗4:経理の実務担当者がYAMLを触れない構成にする
マッピング表の更新のたびに開発者を経由する構成だと、更新が滞り、パイプラインが止まったまま放置されて「結局Excelに戻る」結末になりがちです。
⭕ 回避策:マッピング表はコメント付きのYAMLまたはCSVにし、編集手順を1枚のREADMEにまとめて経理チームに渡す。編集ミスは読み込み時のバリデーション(重複科目チェック等)で検出する。

よくある質問

Q. 会計ソフトの予実管理機能があるのに、なぜ外部で突合するのですか?

会計ソフト内の予実機能は、予算を勘定科目の粒度でソフトに登録できる場合には十分機能します。外部突合が必要になるのは、予算が管理会計の粒度(事業部別・プロジェクト別・独自の管理科目)で作られていて、財務会計の科目体系と一致しない場合です。多くの会社では予算はExcelで組まれており、その粒度の変換こそが毎月の手作業の正体なので、変換を仕組みにする本記事のアプローチが効きます。

Q. Excelのパワークエリでも同じことができるのでは?

正規化とマージだけならパワークエリでも実現できます。差が出るのは揺らぎ対応です。未知科目での停止・更新候補の提案・乖離理由の下書きといった「例外処理の半自動化」は、Claude Codeのような対話型の環境が向いています。すでにパワークエリ資産がある場合は、名寄せ層だけを本記事の方式に置き換える構成も現実的です。

Q. 毎月の実行は自動化できますか?

突合パイプライン自体は通常のPythonスクリプトなので、タスクスケジューラやCIで定期実行できます。Claude Codeをヘッドレスモードで組み込み、未知科目発生時の候補提案までを自動でレポートに含める構成も可能です(Claude Code公式ドキュメント: Headless mode)。ただし、マッピング表の確定とアラートへの理由記入は人の判断として残すことを推奨します。

Q. 予算の期中修正(補正予算)にはどう対応しますか?

予算表のデータシートに「当初予算」と「修正予算」の列を分けて持ち、突合はパラメータでどちらを基準にするか選べるようにしておくのが簡単です。経営会議で「当初比」と「修正比」のどちらを見るかは会社の管理方針によるので、両方出せる形にしておくと切り替えの議論に耐えられます。

Q. 導入にはどれくらいの期間がかかりますか?

想定モデルケース(10部門×30管理科目程度、会計ソフト1系統)で、初期構築に1〜2週間、並走期間を含めた切り替え完了まで3〜4か月が目安です。最大の変数は科目の揺らぎの多さと予算表の構造で、コードを書く時間より「この科目はどの管理科目に載せるべきか」という管理会計上の判断を確定させる時間のほうが長くなる傾向があります。

まとめ:今日から始める3つのアクション

  1. 今日やること:予算表と試算表を並べ、科目名が完全一致しないペアを数える。10個未満ならマッピング表は小さく済み、初月から効果が出やすい構成です
  2. 今週中:予算表に「部門・管理科目・月別金額」だけのデータシートを追加する。パイプラインを書く前でも、この1枚があるだけでVLOOKUPの張り直しが減ります
  3. 今月中:先月分の試算表CSVでマッピング表の初期案をClaude Codeに作らせ、経理担当者がレビューする。要確認コメントの数が、自社の揺らぎの実態を教えてくれます

予実突合は、給与検算入金消込の差異分類月次決算の残高照合と同じ「毎月やる突合系業務」の一員です。判定はコードに固定し、揺らぎの吸収に人とAIの協働ループを置く——このパターンを1つ組めば、他の月次業務にもそのまま横展開できます。


著者:佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援。著書『AIエージェント仕事術』(SBクリエイティブ)。

参考・出典

ご質問・ご相談は お問い合わせフォーム からお気軽にどうぞ。

関連記事: 夏季休暇の問い合わせメール一次対応をClaude Codeで仕組み化する

Next Step

この事例を、自社の業務に置き換える。

対象業務、利用データ、評価基準、社内展開の順番まで整理すると、AI開発ツール導入の失敗を減らせます。

導入を相談する

チームで学ぶなら: Claude Code 法人研修(2日間ハンズオン) / 1人で習得するなら: 個別指導(週1マンツーマン)