公認会計士試験を解く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レイヤーで考えます。
- Question DB(問題データ)
- 問題文
- 選択肢(A/B/C/D)
- 正解
- 試験種別・分野などのメタ情報
- LLMクライアント
- OpenAIのChat APIラッパ
temperature = 0で固定(再現性&正答率計測向け)
- ReActエージェント
- System Promptで Thought / Action / Action Input / Answer のフォーマットを指定
- Action に応じて電卓や検索ツールを呼ぶ
- 評価スクリプト
- 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 くらい)を想定します。
- ディレクトリ作成
mkdir react_cpa_agent cd react_cpa_agent questions.jsonとreact_cpa_agent.pyを保存- ライブラリインストール
pip install openai - OpenAI APIキーを環境変数に設定
export OPENAI_API_KEY="sk-xxxxxxxx" - 実行
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」へと展開していける
という流れになります。

