公認会計士試験を解くAIエージェントの作り方

ー Eulerich ら(2024)論文から得られる実用的な「実装」と「知見」


近年、公認会計士をはじめとする専門職の世界でも、

  • 決算書レビュー
  • 税務申告書のドラフト作成
  • 監査調書・内部統制評価の作成
  • 社内研修・資格試験対策

といった業務に、生成AIやLLM(大規模言語モデル)を組み込む動きが一気に加速しています。

一方で、

「本当に“試験レベル”の専門問題をAIに任せて大丈夫なのか?」
「どの程度まで、人間の合格ラインに近づいているのか?」

といった疑問や不安も、実務家・受験生のあいだで根強く存在しています。

こうした問いに対して、かなり踏み込んだ形で答えようとしているのが
Eulerich ら(2024) の論文です。この研究では、ChatGPT に主要な会計資格試験(CPA / CMA / CIA / EA)の過去問を解かせ、

  • どのくらいの正答率が出るのか
  • 設定や工夫次第で、どこまで合格ラインに近づけるのか

を、段階的な実験で検証しています。

本記事では、この論文の内容をベースに、

  • 前半:ビジネスパーソン向けに「何がわかったのか」を整理
  • 後半:エンジニア向けに「どう実装すれば再現できるか」を解説

という二部構成でまとめます。

1本読み切っていただくことで、

  • 「AIが会計資格試験レベルの問題をどこまで解けるのか」
  • 「自社や自部門で、同じような評価・エージェント構成を作るには何が必要か」

の両方をイメージできることを目指しています。


1. この論文は何を明らかにしたのか?

ここで扱うのは、

Marc Eulerich et al. (2024)
“Is it all hype? ChatGPT’s performance and disruptive potential in the accounting and auditing industries”

という論文です。

一言でいうと、

「ChatGPT は主要な会計資格試験(CPA/CMA/CIA/EA)をどこまで合格ラインで解けるのか?
もし解けるとしたら、会計・監査の世界はどう変わりうるのか?」

を、本格的に検証した研究です。

1.1 対象となった4つの資格試験

論文で対象となっているのは、次の4つの資格試験です。

  • CPA(Certified Public Accountant:米国公認会計士)
    • 財務会計、監査、ビジネス法、税務などを広く含む
  • CMA(Certified Management Accountant:管理会計士)
    • 管理会計、業績管理、戦略財務
  • CIA(Certified Internal Auditor:公認内部監査人)
    • 内部監査の実務、統制、ガバナンス、ビジネス知識
  • EA(Enrolled Agent:米国税務代理人)
    • 個人・法人税務と、税務代理・手続き

いずれも、会計・監査・税務のプロフェッションにとって中核となる資格であり、

  • 財務会計
  • 管理会計
  • 内部監査
  • 税務

といった主要な領域を、ほぼ網羅的にカバーしています。

つまり、この論文は

「単なる一部のトピック」ではなく、
会計・監査のコア領域全体に対してAIの性能を測りにいっている

という点が重要です。

1.2 どんな問題を使って検証したのか?

扱っているのは、いずれも 過去問や試験対策用の4択問題(Multiple Choice Questions) です。

共通の前提として:

  • 4択の選択式のみ
  • 画像付きの問題は除外
  • 「途中式を書かせる」「長文ケーススタディ」といったワークアウト形式の問題は除外

という条件を置いています。

イメージとしては、日本の公認会計士試験でいう 短答式問題 に近い形です。
「文章+選択肢+1つの正解」というスタイルに限定することで、

  • 純粋な知識+数値計算+短い推論力 にフォーカスできる
  • モデル間の比較がやりやすい

というメリットがあります。

1.3 性能をどうやって高めていったのか?(3ステップ)

この論文の特徴は、AIの使い方を 3つのステップで“ブースト”させていく設計 にあります。

Step 1:モデルを変える(GPT-3.5 → GPT-4)

まずは一番シンプルに、

  • ChatGPT-3.5(GPT-3.5-turbo)
  • ChatGPT-4(GPT-4)

に、それぞれ同じ問題をゼロショット(追加説明なし)で解かせ、正答率を比較しました。

結果のイメージは次の通りです。

  • GPT-3.5:平均正答率 約53%
    • どの資格試験も合格ラインには届かない
  • GPT-4:平均正答率 約70%
    • CIA(内部監査)など、一部の試験では合格ラインに到達するセクションもある
    • ただし、「すべての試験・すべてのセクションで完勝」というレベルには至らない

ここから言えるのは、

モデル世代を上げるだけで、かなりの性能向上はあるが、
それだけでは全資格・全セクションを合格させるには足りない

ということです。

Step 2:few-shot(例題10問)を追加する

次に、GPT-4に対して 「例題10問+正解」 を見せてから本番問題を解かせる、という 10-shot few-shot 設定 を追加します。

  • 各試験ごとに、ランダムに10問をサンプル
  • 本番問題の前に、
    「問題文+選択肢+正解」をまとめて提示

人間でいえば、

「この試験はだいたいこういう出題の仕方・ひっかけ方をしてくる」

という “試験の流れ” を、冒頭の10問で掴ませているイメージです。

結果として、

  • GPT-4 ゼロショット:平均 約70%
  • GPT-4 + 10-shot few-shot:平均 約76%

となり、数ポイント〜十ポイント近く正答率が改善しました。

この時点で、

  • CMA・CIAの多くのセクションは合格ラインを超え
  • EAもかなり合格に近づく(ただし、まだ届かないセクションもある)

というレベルに到達します。

Step 3:ReActエージェントを導入する(Reason + Act)

最後の一押しが、ReAct(Reason + Act) と呼ばれるアプローチです。

ここでは、GPT-4に「頭の中で考える」だけでなく、

  • Thought(考えていること) を文章で書かせ、
  • 必要に応じて
    • 電卓(Calculator)
    • Web検索(Search)
      などの外部ツールを呼び出させる

という、“エージェント”としての振る舞いをさせます。

具体的には、モデルが次のような形式で出力します。

  • Thought: いま何を考えているか、次にどのような手順で解くか
  • Action: 実行するツール名(例:Calculator / None)
  • Action Input: ツールに渡す数式やキーワード
  • Observation: ツールから返ってきた結果(これはシステム側が埋め込む)
  • Answer: 最終的な回答(A/B/C/D)

この「考える」+「ツールを使う」の組み合わせによって、
計算や事実確認の精度がグッと上がる ことが示されています。

結果として、

  • GPT-4 + few-shot + ReAct:平均正答率 約85%

となり、

すべての資格試験・すべてのセクションで、合格ラインを安定的に上回る

レベルに到達します。

1.4 ここから分かること

この結果が意味するところは、とてもシンプルです。

きちんと設計された GPT-4 エージェントであれば、
会計資格試験レベルの専門問題を “合格ライン以上” で解くことが可能である。

ここから先は、

  • どう教育に組み込むか
  • 実務のどこまでを任せるか
  • どの部分を人間が判断し続けるか
  • 説明責任・モデルリスクをどう管理するか

といった、「業務設計」「ガバナンス設計」の話になってきます。

1.5 実務への示唆(教育・監査法人・事業会社)

教育・試験の世界では

  • 学生の質問対応をAIが担う「TAチャットボット」は、すでに実例が出始めています。
  • 教科書に「ChatGPTボタン」が組み込まれ、
    • 要約
    • 確認テスト
    • 演習問題の生成
      まで含めてAIが支援する未来は、かなり現実味があります。

一方で、

  • 不正利用(AIに解かせた答案をそのまま提出する 等)
  • AIに任せすぎて、本人の理解が浅いままになる

といったリスクへの対処も、同時に検討する必要があります。

監査法人・コンサルティング・事業会社では

  • 契約書レビュー
  • 経費精算のチェック
  • 税務処理のドラフト作成
  • 内部監査のサンプリング・チェックリスト作成

といった場面で、LLMベースのシステム導入が始まっています。

特に ReAct 型のエージェントを使うと、

  • ツールの利用履歴(Action)
  • 参照した資料(Observation)
  • 計算・検討の過程(Thought)

がログとして残るため、

「なぜその結論に至ったか」の説明がしやすい

という特徴があります。


この論文は、

  • 「会計士がいらなくなる」という話ではなく、
  • 「AIが合格レベルの知識を持つことを前提に、人間とどう役割を分担するか」

を考え始めるべき段階に来ていることを示している、と捉えると分かりやすいと思います。

ここまでが前半(ビジネスパーソン向け)のまとめです。
ここから先は、「自分の手元で同じような評価・エージェント構成を再現するには?」という、技術者向けの後半に入ります。


2. 公認会計士試験向けAIエージェントの設計と実装ガイド(エンジニア向け)

ここからは、論文の手法を参考にした 実装イメージ を具体的に示していきます。

ゴールは:

「公認会計士試験風の4択問題を、GPT-4系のReActエージェントで解かせる、最小限のデモ」

を作れるくらいまで、イメージとコードを落とし込むことです。

2.1 全体アーキテクチャ

シンプルに4レイヤーで考えます。

  1. Question DB(問題データ)
    • 問題文
    • 選択肢(A/B/C/D)
    • 正解
    • 試験種別・分野などのメタ情報
  2. LLMクライアント
    • OpenAIのChat APIラッパ
    • temperature = 0 で固定(再現性&正答率計測向け)
  3. ReActエージェント
    • System Promptで Thought / Action / Action Input / Answer のフォーマットを指定
    • Action に応じて電卓や検索ツールを呼ぶ
  4. 評価スクリプト
    • Zero-shot / few-shot / ReAct で同じ問題セットを解かせる
    • 正答率やログを集計

この記事では、特に 3. ReActエージェント の部分を、実際に動くコード付きで説明します。

2.2 超ミニ問題セット(questions.json)

まずは、動きを見るための2問だけの問題ファイルです。

questions.json

[
  {
    "id": "Q1",
    "exam": "DEMO",
    "section": "FIN",
    "question": "当期の売上高は100、売上総利益率は40%である。売上原価はいくらか?",
    "choices": {
      "A": "40",
      "B": "60",
      "C": "100",
      "D": "140"
    },
    "answer": "B",
    "has_image": false,
    "is_mcq": true
  },
  {
    "id": "Q2",
    "exam": "DEMO",
    "section": "TAX",
    "question": "ある商品の税込価格は110で、消費税率は10%である。税抜価格はいくらか?",
    "choices": {
      "A": "100",
      "B": "99",
      "C": "90",
      "D": "110"
    },
    "answer": "A",
    "has_image": false,
    "is_mcq": true
  }
]

実際に使うときは、ここに何百問・何千問と問題を追加していくイメージになります。

2.3 ReActエージェントのミニ実装(react_cpa_agent.py)

以下が、実際に動く最小構成のデモです。
そのまま react_cpa_agent.py という名前で保存して使えます。

import json
import os
import re
from dataclasses import dataclass
from typing import Dict, List, Literal, Optional

from openai import OpenAI

# ==========
# 設定
# ==========

# 環境変数 OPENAI_API_KEY を使用
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

# 使用するモデル(必要に応じて変更してください)
MODEL_NAME = "gpt-4.1-mini"

Choice = Literal["A", "B", "C", "D"]

# ==========
# データ定義
# ==========

@dataclass
class Question:
    id: str
    exam: str
    section: str
    question: str
    choices: Dict[Choice, str]
    answer: Choice
    has_image: bool = False
    is_mcq: bool = True

def load_questions(path: str = "questions.json") -> List[Question]:
    """questions.json を読み込んで Question のリストに変換"""
    with open(path, "r", encoding="utf-8") as f:
        raw = json.load(f)
    questions: List[Question] = []
    for item in raw:
        questions.append(
            Question(
                id=item["id"],
                exam=item.get("exam", "DEMO"),
                section=item.get("section", "GEN"),
                question=item["question"],
                choices=item["choices"],
                answer=item["answer"],
                has_image=item.get("has_image", False),
                is_mcq=item.get("is_mcq", True),
            )
        )
    return questions

# ==========
# LLM クライアント
# ==========

def call_chat(messages: List[Dict[str, str]], model: str = MODEL_NAME) -> str:
    """OpenAI Chat API を呼ぶラッパ(temperature=0 固定)"""
    resp = client.chat.completions.create(
        model=model,
        messages=messages,
        temperature=0.0,
    )
    return resp.choices[0].message.content

# ==========
# ReAct 用プロンプト
# ==========

REACT_SYSTEM_PROMPT = """
あなたは会計・監査・税務に詳しい専門家エージェントです。
次のフォーマットで思考し、必要に応じてツールを使ってください。

- Thought: 今どう考えているか、次に何をするか
- Action: 実行するツール名(Calculator / None)
- Action Input: ツールに渡す文字列(数式)
- Answer: 最終的な選択肢(A / B / C / D)

【重要事項】
- ツールが不要な場合は Action: None としてください。
- 計算が必要そうな場合は Calculator を使って、数式を Action Input に書いてください。
- 最終的には必ず "Answer: X" の形式で A/B/C/D を1文字だけ書いてください。
"""

def format_react_question(q: Question) -> str:
    """LLM に渡す問題文のフォーマット"""
    return f"""
問題:
{q.question}

選択肢:
A. {q.choices["A"]}
B. {q.choices["B"]}
C. {q.choices["C"]}
D. {q.choices["D"]}

最初の行は "Thought:" から始めてください。
"""

# ==========
# ツール実装(Calculator)
# ==========

def tool_calculator(expr: str) -> str:
    """
    数式文字列を評価する簡易電卓。
    ※ 本番用途では、より安全な数式パーサーの利用を推奨します。
    """
    try:
        # eval の builtins を無効化して最低限にする(それでも運用環境では注意)
        value = eval(expr, {"__builtins__": {}})
        return str(value)
    except Exception as e:
        return f"Error: {e}"

# ==========
# 出力パース用
# ==========

def extract_block(text: str, label: str) -> Optional[str]:
    """
    出力テキストから "label: ..." 形式の行を取り出す簡易関数。
    例: label="Action" -> "Calculator"
    """
    pattern = rf"{label}\s*:(.*)"
    m = re.search(pattern, text)
    if not m:
        return None
    return m.group(1).strip()

# ==========
# ReAct で1問解く
# ==========

def answer_with_react(
    q: Question,
    model: str = MODEL_NAME,
    max_steps: int = 5,
    verbose: bool = True,
) -> str:
    """
    ReAct で1問解く。
    戻り値は 'A'/'B'/'C'/'D' または '?'(失敗時)。
    """
    messages: List[Dict[str, str]] = [
        {"role": "system", "content": REACT_SYSTEM_PROMPT},
        {"role": "user", "content": format_react_question(q)},
    ]

    if verbose:
        print("====================================")
        print(f"Question {q.id}: {q.question}")
        print("------------------------------------")

    for step in range(max_steps):
        # 1ステップ分 LLM に聞く
        raw = call_chat(messages, model=model)

        if verbose:
            print(f"[Step {step+1}] LLM Output:")
            print(raw)
            print("------------------------------------")

        # LLM 出力そのものも会話履歴に追加
        messages.append({"role": "assistant", "content": raw})

        # Thought / Action / Action Input / Answer を抽出
        thought = extract_block(raw, "Thought")
        action = extract_block(raw, "Action")
        action_input = extract_block(raw, "Action Input")
        answer = extract_block(raw, "Answer")

        # Answer が出ていれば終了
        if answer:
            candidate = answer.strip()[-1:]  # "Answer: B" -> "B"
            if candidate in ["A", "B", "C", "D"]:
                if verbose:
                    print(f"--> 最終回答: {candidate}")
                return candidate

        # Answer がまだ無い場合、Action を処理する
        if action is None or action.lower() == "none":
            # ツール不要 → 空の Observation を返してもう1ステップ考えさせる
            messages.append({"role": "user", "content": "Observation: "})
            continue

        # Calculator ツールを実行
        if action == "Calculator":
            obs = tool_calculator(action_input or "")
        else:
            obs = f"Error: 未知のツール {action} です。Calculator または None を使用してください。"

        if verbose:
            print(f"[Tool] {action}({action_input}) -> {obs}")
            print("------------------------------------")

        # Observation を LLM に返す
        messages.append({"role": "user", "content": f"Observation: {obs}"})

    # max_steps までに Answer に到達しなかった場合
    if verbose:
        print("max_steps に達しましたが Answer が出ませんでした。")
    return "?"

# ==========
# メイン:全問を ReAct で解いてみる
# ==========

def main():
    questions = load_questions("questions.json")
    correct = 0
    total = 0

    for q in questions:
        if not q.is_mcq or q.has_image:
            continue

        pred = answer_with_react(q, verbose=True)
        total += 1
        if pred == q.answer:
            correct += 1
            result = "✔ 正解"
        else:
            result = f"✘ 不正解(正解: {q.answer})"

        print(f"結果: {result}")
        print("====================================\n")

    acc = correct / total if total else 0.0
    print(f"Summary: {correct} / {total} = {acc:.1%}")

if __name__ == "__main__":
    main()

2.4 実行方法(概要)

環境はローカル端末(Python 3.10 くらい)を想定します。

  1. ディレクトリ作成 mkdir react_cpa_agent cd react_cpa_agent
  2. questions.jsonreact_cpa_agent.py を保存
  3. ライブラリインストール pip install openai
  4. OpenAI APIキーを環境変数に設定 export OPENAI_API_KEY="sk-xxxxxxxx"
  5. 実行 python react_cpa_agent.py

ターミナル上に、

  • LLMの Thought / Action / Action Input
  • ツール呼び出し [Tool] Calculator(...) -> ...
  • 最終回答 Answer: B
  • 正誤判定・正答率

が順番に表示されるようになります。
これが「論文でいう ReAct エージェントが、公認会計士試験風の問題を解いている」最小限の姿 です。


3. ここからCPAレベル・実務レベルに近づけるには?

最後に、このミニデモをどのように発展させれば、論文に近いレベル、あるいは自社のユースケースに近いレベルになるかの方向性を整理します。

3.1 問題セットの拡張

  • 実際のCPA教材(ライセンスには注意)や社内研修問題などを用意し、
    数百〜数千問規模の4択問題集 にする
  • 試験区分(FAR / AUD / REG / BEC)やテーマ(収益認識、リース、税効果など)をメタ情報として付与

これにより、Eulerich らと同様に

  • 試験別
  • セクション別
  • テーマ別

の正答率を比較できるようになります。

3.2 few-shot(10-shot)の導入

  • セクションごとに10問ずつ、代表的な問題をサンプルとしてピックアップ
  • System Prompt の後に「例題+選択肢+正解」を列挙してから本番問題を出す構成にする

これにより、論文と同じような few-shot ブースト が再現できます。

実装イメージとしては、

  • REACT_SYSTEM_PROMPT の直後に「例題セクション」を追加
  • 例題の後に、今回解かせたい本番問題を提示

という流れになります。

3.3 ツールの強化(Calculator / DocSearch / 自社システム)

ReAct の強みは、「ツールを簡単に増やせること」です。

Calculatorの高度化

  • 割引現在価値(DCF)
  • 年金現価係数・終価係数
  • 税額計算

などに対応した、会計・ファイナンス向けライブラリ に置き換えることができます。

DocSearchツールの追加

  • EDINET/有価証券報告書
  • 会計基準・監査基準
  • 社内マニュアル

といったドキュメントを対象にした RAG検索ツール を追加し、

  • Action: DocSearch
  • Action Input: 「IFRS 第15号 変動対価」

のような形で呼び出せるようにします。

自社システムとの連携

  • 会計システムの試算表API
  • ワークフローシステムの承認履歴
  • 文書管理システム上の監査調書

などとつなげることで、
「自社固有のデータを見た上で判断するAI監査アシスタント」 に近づけることができます。

3.4 ログの活用(教育・監査証跡)

ReActで残るログは、

  • Thought(どう考えたか)
  • Action(どのツールを使ったか)
  • Action Input(何を計算/検索したか)
  • Observation(どんな情報が返ってきたか)
  • Answer(最終結論)

という、「AIの思考過程+根拠」のセットです。

これはそのまま:

  • 受験生に「模範解答+解き方」として見せる
  • 講師側が論点別のつまずきポイントを分析する
  • 実務では「AIがどの根拠資料を見て、どの計算をして、その結論に至ったか」の監査証跡として残す

といった形で活用できます。


4. まとめ

本記事では、Eulerich ら(2024)の論文を入り口に、

  • 前半:主要な会計資格試験(CPA/CMA/CIA/EA)に対する ChatGPT の性能が、
    • モデル世代の変更(GPT-3.5 → GPT-4)
    • few-shot(例題10問)
    • ReActエージェント(ツール利用)
      を組み合わせることで、合格ラインを安定的に超える水準まで到達し得る こと
  • 後半:それを自分たちの手元で再現するための
    • シンプルなアーキテクチャ設計
    • 超ミニ問題セット
    • ReActエージェントのデモ実装

をまとめました。

ポイントをあらためて整理すると:

  • AIはすでに「合格ライン近辺」の知識レベルに達しつつある
  • しかし、それだけでは実務にそのまま置き換えられるわけではなく、
    「教育設計」「業務設計」「ガバナンス設計」がセットで必要
  • 技術的には、ReAct+ツール連携により、
    「試験を解くAI」「監査調書を作るAI」「研修問題を自動生成するAI」へと展開していける

という流れになります。

\ 最新情報をチェック /

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です