『その仕事、AIに任せた後は? あなたの脳を整える、焙煎士の診断ガイド』
PR

AIエージェントの状態管理|外部ファイルを使ったステートレス設計

社会人の勉強

[!NOTE]
この記事の要約

  • 結論: AIエージェントの実行プロセス(推論)に状態を抱え込ませず、タスクの進捗・ルール・知識を「外部ファイル(Markdown/CSV/JSON等)」に切り出して管理することが、途中で停止しても再開しやすくなる高信頼な自動化システムを構築するための重要な設計原則です。
  • 解決する悩み: 「会話が長くなるとAIが最初の指示を忘れる」「途中でエラー停止したとき、どこまで進んだか分からなくなる」「外部ファイル化とステートレス設計の違いが曖昧」
  • 3つのポイント:
    1. 「AIエージェントで区別したい4つの情報」(会話履歴・コンテキスト・メモリ・状態)の概念整理
    2. rule.md / knowledge.md / tasks.csv / state.md による「4つの外部管理ファイル」構成
    3. 途中再開の実装パターンと、複数エージェント運用時の「ファイル競合・排他制御」対策

AIエージェントに複数ステップにわたる複雑な仕事を任せていると、

「作業が進むにつれて、最初に指示したルールや条件を無視し始める」
「途中で通信エラーが起きた際、どこまで完了したのか分からず最初からやり直す羽目になる」
「特定モデルのセッションに依存してしまい、モデル変更や改善のハードルが高くなる」

といった課題に直面することがあります。

これらの問題の根本原因は、**「AIエージェントの推論プロセスやチャットセッションの中に、タスクの状態やルールを抱え込ませていること」**にあります。

本記事では、AIエージェントの「処理」と「状態」を分離し、進捗やルールを外部ファイルで管理する設計手法を解説します。

[!IMPORTANT]
用語の整理と設計のポイント
厳密には、「外部ファイルに状態を保存すること」そのものがステートレス設計を意味するわけではありません。
重要なのは、AIモデルやエージェントの実行プロセス自身にセッション状態を持ち越させず、必要な状態やルールを外部ストレージから明示的に受け渡して処理を完結させる構造(ステートレスな推論フロー)を作ることです。


  1. 1. AIエージェントで区別したい4つの情報(記憶・コンテキストとの違い)
    1. AIエージェントが扱う4つの情報と役割
  2. 2. ステートレス設計とは何か?
  3. 3. なぜAIの会話履歴だけに状態を依存すると問題なのか?
    1. ① 指示の埋没とルールの希薄化
    2. ② エラー発生時の復旧(再試行)が困難
    3. ③ 特定セッションへの依存と移行コストの増大
  4. 4. AIエージェントの状態を外部ファイルで管理する「4つの要素」
    1. 1. rule.md — ルール(規範の定義)
    2. 2. knowledge.md — 知識(参照データの固定)
    3. 3. tasks.csv — タスク(工程の一覧と順序)
    4. 4. state.md — 進捗状態(動的チェックポイント)
  5. 5. 実際のブログ自動化で使った状態管理
  6. 6. AIエージェントを途中から再開する仕組み
  7. 7. 外部ファイルによる状態管理のメリット
  8. 8. 実装における注意点と限界
    1. ① コンテキスト増大時のRAG・DB移行
    2. ② プロンプトキャッシュの検討
    3. ③ 複数エージェント運用時の「ファイル競合(Race Condition)」
    4. ④ 状態ファイルの更新主体(プログラム側で責務を持つ)
  9. 9. ステートレス設計とセッション依存設計の比較まとめ
  10. 10. よくある質問(FAQ)
    1. Q1. ステートレス設計にすると、AIは過去の情報を一切使えなくなりますか?
    2. Q2. 状態管理のファイル形式はJSONとMarkdownのどちらが良いですか?
    3. Q3. LangGraphやCrewAIなどのフレームワークを使う場合も同じ考え方ですか?
  11. 11. まとめ:AIと状態管理の役割を明確に分ける

1. AIエージェントで区別したい4つの情報(記憶・コンテキストとの違い)

AI活用において「記憶」という言葉は曖昧に使われがちです。エージェントをシステムとして設計する際は、まず扱う情報の種類を明確に切り分ける必要があります。

AIエージェントが扱う4つの情報と役割

概念役割・定義典型的なライフサイクルと特徴
会話履歴(History)これまでの対話やツール実行の記録ログ現在のセッションで利用される対話ログ。保存方式によっては外部ストレージへ永続化可能
コンテキスト(Context)1回の推論処理に渡される全情報1回の推論に入力される情報。次回の推論で自動的に引き継がれるとは限らず、必要に応じて履歴・メモリ・外部から再構成する
メモリ(Memory)過去の経験・ユーザーの好み・判断など、将来の処理でも再利用する情報タスクやセッションを跨いで長期的に参照・更新されるナレッジ
状態(State)「現在どのタスクを実行中か」「何が完了したか」という進捗タスクの実行中に動的に更新され、中断・再開のチェックポイントとなる進行状況

これら4つの情報を保存・永続化する基盤として、ローカルファイル(Markdown/JSON/CSV)、データベース(SQLite/PostgreSQL)、ベクトルDB、オブジェクトストレージ などを適材適所で利用します。

このように、「今どこまで進んでいるか」という**タスクの進行状態(State)**をエージェントの実行プロセスから分離し、明示的な外部ストレージで管理することが安定運用の第一歩です。


2. ステートレス設計とは何か?

システム設計における「ステートレス(Stateless)」とは、処理を行うサーバーや実行プロセスが、前回のリクエストに依存する内部状態(セッション情報)を持ち越さない仕組みを指します。

身近な事務作業に例えると、その違いは以下の通りです。

【ステートフル(頭の中に記憶)】
作業者が「頭の中の記憶」だけを頼りに作業を進める
➔ 席を外したり担当者(AIモデル)が交代すると、文脈が失われて復旧できない

【ステートレス(机の上の書類で管理)】
机の上に「指示書」「タスク表」「進捗メモ」が置かれている
➔ 作業者は指示書とメモを見て1工程だけ処理し、結果を書類に記録して席を立つ
➔ 別の作業者が来ても、書類を見れば直前の状態から何事もなく再開できる
【ステートレスなエージェント実行サイクル】
1. 起動:外部から「指示書(ルール)」と「進捗メモ(状態)」を読み込む
   ↓
2. 実行:未完了のタスクを1つだけ推論・実行する
   ↓
3. 永続化:成果物をファイルに出力し、「進捗メモ」を更新する
   ↓
4. 終了:エージェントの実行プロセスに状態を持ち越さず終了(リセット)

エージェントの実行プロセスに状態を持ち越さず、**「外部の状態を読み取り ➔ 1ステップ処理し ➔ 外部の状態を更新して終了する」**というサイクルを繰り返すことで、極めて堅牢なシステムが完成します。


3. なぜAIの会話履歴だけに状態を依存すると問題なのか?

チャット画面上の会話履歴(ステートフルなセッション)だけでエージェントを動かすと、実務において次の3大トラブルが発生します。

① 指示の埋没とルールの希薄化

セッションが長くなるとコンテキストが肥大化し、重要な指示が大量の情報に埋もれてしまうことで、モデルが初期に定義した「執筆ルール」や「制約条件」を適切に参照・反映できなくなる場合があります。

② エラー発生時の復旧(再試行)が困難

APIのタイムアウトやネットワーク切断でプロセスが落ちた場合、進捗が会話ログの中にしか存在しないと、「どこまで正常に完了し、どこからやり直せばいいか」の特定が困難になります。

③ 特定セッションへの依存と移行コストの増大

特定モデルの会話履歴やプロプライエタリなセッション機能への依存が強くなると、別のモデル(Claude、Gemini、ローカルLLM等)へ切り替える際の移行コストが高くなります。


4. AIエージェントの状態を外部ファイルで管理する「4つの要素」

AIをステートレスな処理エンジンとして動かすため、作業ディレクトリ内に以下の4つの役割を持つファイルを配置します。

project/
├── rule.md        # 【ルール】品質基準・トーン・禁止事項(静的)
├── knowledge.md   # 【知識】専門情報・前提データ・用語集(静的)
├── tasks.csv      # 【タスク】全工程の順序と定義(静的)
├── state.md       # 【状態】現在の進捗・完了ログ(動的更新)
└── output/        # 【成果物】各ステップで生成された実ファイル群
【4つの要素と成果物の関係】
ルール (rule.md) ──┐
知識 (knowledge.md) ─┼─➔ [AIエージェント (推論)] ─➔ 成果物 (output/)
タスク (tasks.csv) ──┤            │
状態 (state.md) ────┘            └─➔ 状態更新 (プログラム側で書き戻し)

1. rule.md — ルール(規範の定義)

文章のトーン&マナー、文字数制限、禁止用語など、エージェントが常に遵守すべき規範を記述します。

# 執筆ルール
- トーン:気取りのない実直な動作に基づく文体
- 禁止事項:ポエム調の表現、客観的事実に基づかない断定
- 見出し構造:H2配下にH3を正しく配置(飛び番禁止)

2. knowledge.md — 知識(参照データの固定)

作業に必要な専門情報やマニュアル、一次情報を記載します。プロンプトに直接書き込まずファイルとして切り出すことで、ハルシネーションを抑制します。

3. tasks.csv — タスク(工程の一覧と順序)

実行すべき工程をID付きで定義します。

task_id,task_name,output_file,depends_on
1,構成案作成,output/outline.md,none
2,本文執筆,output/draft.md,1
3,ファクトチェック,output/fact_check.md,2
4,最終校正,output/final_article.md,3

4. state.md — 進捗状態(動的チェックポイント)

エージェントが1工程を終えるたびに更新される状態管理ファイルです。

# 現在の進捗状態
- 最終更新日時: 2026-08-23 06:15
- 現在の工程: 3_ファクトチェック
- 完了したタスク:
  - [x] 1_構成案作成 (output/outline.md)
  - [x] 2_本文執筆 (output/draft.md)
- 未完了のタスク:
  - [ ] 3_ファクトチェック
  - [ ] 4_最終校正

この「AIの外側で環境と状態を整えて出力を厳格に制御する」という思想は、**ハーネスエンジニアリング(Harness Engineering)**の実践そのものです。


5. 実際のブログ自動化で使った状態管理

私自身がブログ記事の執筆やコンテンツ作成を自動化するにあたり、以前はチャット上で「まず構成を作って、良ければ本文を書いて、最後に推敲して」と連続指示を出していました。

しかし、途中で前段の工程を飛ばして本文を書き始めたり、APIエラーで停止した際に最初から全工程をやり直す羽目になり、トークンと時間を浪費しました。

そこで、処理の流れを以下のように外部ファイルを用いた状態管理の実装イメージへと切り替えました。

[!NOTE]
※以下は状態管理の考え方を示す簡略化した実装イメージ(Python)です。call_llm()get_next_task() などは、利用するLLMやAPI(OpenAI / Anthropic / Google 等)の仕様に合わせて実装します。
※ここではプログラムから扱いやすいよう state.json を使用しています。人間が直接エディタで確認・編集する運用では state.md として管理する方法もあります。

# 外部ファイルを使った状態管理の実装イメージ(Python)
import json
from pathlib import Path

def run_agent_step():
    # 1. 外部ファイルから「状態」と「ルール」をロード
    state_file = Path("state.json")
    state = json.loads(state_file.read_text(encoding="utf-8"))
    rules = Path("rule.md").read_text(encoding="utf-8")
    
    current_task = state.get("current_task")
    if not current_task:
        print("すべてのタスクが完了しています。")
        return

    # 2. 単一ステップの処理を実行
    # (この例では、前回の実行状態を外部から明示的に渡す)
    print(f"Executing: {current_task}")
    result = call_llm(rule=rules, task=current_task)
    
    # 3. 成果物の保存と、外部状態(state.json)の更新
    Path(f"output/{current_task}.md").write_text(result, encoding="utf-8")
    state["completed_tasks"].append(current_task)
    state["current_task"] = get_next_task(current_task)
    state_file.write_text(json.dumps(state, indent=2, ensure_ascii=False))

if __name__ == "__main__":
    run_agent_step()

この構成にしたことで、工程飛ばしのミスが解消され、途中で停止しても直前の工程から安全に再開できる再現性と安定性が格段に向上しました。


6. AIエージェントを途中から再開する仕組み

外部ファイルで状態を管理する最大の強みは、「途中再開(Resumption)」が極めて低コストになる点です。

sequenceDiagram
    autonumber
    actor User as 開発者 / システム
    participant State as state.md (外部状態)
    participant Agent as AIエージェント (ステートレス推論)
    participant Out as output/ (成果物)

    User->>Agent: 実行コマンド発行
    Agent->>State: state.md を読み込み未完了タスクを特定
    Agent->>Out: 前段の成果物(draft.md等)を参照
    Note over Agent: 単一タスク(ファクトチェック)を実行
    Agent->>Out: 結果(fact_check.md)を書き出し
    Agent->>State: state.md に「完了」を追記
    Agent-->>User: 1ステップ完了(プロセス終了)

通信切断やプログラムのクラッシュが発生しても、次回起動時にエージェントは state.md を読むだけで「未完了のタスク」を即座に認識し、前段の成果物を読み込んで作業を継続できます。過去の会話履歴をすべて再送信して文脈を学習させ直す必要はありません。


7. 外部ファイルによる状態管理のメリット

  1. エラー停止からの安全なリカバリー
    クラッシュしても、最後に正常終了したチェックポイントから1ステップ単位で復旧しやすくなります。
  2. AIモデルの移行がスムーズになる
    ルールや状態が外部ファイルとして独立しているため、会話履歴に依存した設計よりも、モデル変更やステップ別の使い分け(構成は高性能モデル、校正は高速モデル等)が容易になります。
  3. 人間による確認(Human-in-the-Loop)を挟みやすい
    「構成案が出力された時点で一度止まり、人間がファイルをチェック・加筆してから次へ進む」というワークフローを自然に構築できます。
  4. 透明性とデバッグ性の確保
    各ステップの入力ルール・進捗・成果物がすべてローカルファイルやGitログとして残るため、なぜその出力になったのかの追跡・検証が容易です。

8. 実装における注意点と限界

外部ファイルによる状態管理を導入する際は、以下の実務的な課題への対策が必要です。

① コンテキスト増大時のRAG・DB移行

参照すべきナレッジ(knowledge.md)の分量が数万文字を超えて肥大化した場合、テキストファイルを丸ごとプロンプトに流し込む方式はトークン上限やコスト面で限界を迎えます。情報量が増大した段階で、SQLiteや**ベクトル検索(RAG)**へ移行し、関連する断片のみを動的に取得して渡す設計へ進化させる必要があります。

② プロンプトキャッシュの検討

長い固定ルール(rule.md 等)を毎回APIに送信する場合、利用するモデルやAPIが提供する**プロンプトキャッシュ(Prompt Caching)**を検討すると、入力コストや遅延を抑えられる場合があります。静的な指示をプロンプトの先頭に固定し、動的な状態情報を末尾に置く構造が有効です。

③ 複数エージェント運用時の「ファイル競合(Race Condition)」

複数のエージェントやプロセスが同時に動作する場合、同一の state.md に対して同時に読み書きを行うと、状態の上書きや先祖返り(競合)が発生するリスクがあります。

【ファイル競合の発生例】
Agent A ➔ state.md を読む(工程2完了と認識)
Agent B ➔ state.md を読む(工程2完了と認識)
Agent A ➔ 工程3を実行し、state.md を更新
Agent B ➔ 古い状態を元に工程4を実行し、Agent Aの更新を上書き(データ破損)

対策:

  • 単一エージェントの場合はシンプルなファイルロック(fcntl 等)を導入する。
  • 複数エージェントが並行処理を行う場合は、状態管理のバックエンドをファイルからSQLiteRedisなどのトランザクション対応ストレージへ移行する。

④ 状態ファイルの更新主体(プログラム側で責務を持つ)

state.md の更新をAIの自由なテキスト出力に完全に委ねると、フォーマット崩れや誤認が発生する可能性があります。状態の更新ロジック自体はPythonなどの決定論的なプログラム側で制御し、AIには処理結果(テキストや分析)の生成のみを担当させる責務分離が最も安全です。

【推奨される責務分離】
AI(推論)      ➔ 判断・テキスト生成を担当
プログラム     ➔ ファイル保存・状態(state.md)の更新を担当
外部ストレージ ➔ データの永続化を担当

9. ステートレス設計とセッション依存設計の比較まとめ

比較項目セッション依存の設計外部状態管理を中心とした設計
状態の保存先セッション / セッションストアなど外部ファイル / DBなど
耐障害性保存方式・実装に依存チェックポイントを設計しやすい
モデル切替セッション機能への依存があると移行コストが高くなるモデルから状態を分離しやすい
設計の複雑さ低〜中
適した用途会話中心の処理・短〜中規模のワークフロー複数工程の自動化・長時間の処理

10. よくある質問(FAQ)

Q1. ステートレス設計にすると、AIは過去の情報を一切使えなくなりますか?

いいえ、使えなくなるわけではありません。
ステートレス設計は「永続的な情報を持たない」という意味ではなく、「処理主体の内部メモリと、永続化された状態を分離する」という設計思想です。必要な過去ログや前提知識は外部ストレージに保存しておき、推論時に必要な情報だけを明示的に取得してプロンプトへ渡すことで、高精度な文脈処理と安定性を両立できます。

Q2. 状態管理のファイル形式はJSONとMarkdownのどちらが良いですか?

用途によって使い分けるのがベストです。人間がObsidianやVS Codeで直接目視・追記したい場合は「Markdown」、プログラムで厳密にパース・制御したい場合は「JSON」や「SQLite」が適しています。

Q3. LangGraphやCrewAIなどのフレームワークを使う場合も同じ考え方ですか?

基本的な考え方は共通しています。AIエージェント向けのフレームワークには、実行途中の状態を保存して再開するための仕組みを備えたものがあります。
ただし、状態の保存方法やチェックポイントの扱いはフレームワークごとに異なるため、実装時には各フレームワークの仕様を確認する必要があります。


11. まとめ:AIと状態管理の役割を明確に分ける

AIエージェントを活用した自動化を成功させる鍵は、**「AIの記憶力に頼らない環境設計」**です。

  1. AIは「与えられた入力を処理する計算エンジン」としてステートレスに扱う
  2. タスクの進捗・ルール・前提知識はすべて「外部ファイル」に切り出す
  3. 状態の更新はプログラム側で制御し、中断・再開が可能な疎結合システムを作る

まずは、AIに毎回チャットで指示しているルールを rule.md という1つのファイルに切り出し、実行時に「このファイルを読んで作業してください」と指示する第一歩から、堅牢な状態管理を始めてみてください。


タイトルとURLをコピーしました