0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIに仕事を奪われる不安から始めるハーネス作成入門 第14回 AIエージェント実行ログをMarkdownとJSONで残す

0
Posted at

連載: AIに仕事を奪われる不安から始めるハーネス作成入門
第14回前回(第13回): AIハーネスにログ設計が必要な理由

はじめに:ログ項目は決めた、次は実装

前回(第13回)で、AIハーネスに必要なログ項目表を設計しました。今回は、それを実際のファイルとして残すためのMarkdownテンプレートとJSONスキーマを作成します。

「何を記録するかは決めたけど、実際にどうファイルに書き出せばいいのか」という疑問に、具体的なコード例とともに答えるのが本記事の目的です。

MarkdownとJSONを併用する理由

ログの保存形式にはMarkdownとJSONを併用するアプローチを提案します。それぞれの役割は次の通りです。

形式 主な用途 対象者
Markdown 手動レビュー、共有、報告 人間(開発者・管理者)
JSON 自動集計、検索、ダッシュボード プログラム(分析スクリプト)

SE業務でたとえると、Markdownは「障害報告書」、JSONは「ログDBのレコード」に相当します。同じ実行データを異なるビューで見られるようにすることで、運用の柔軟性が大きく向上します。

Markdownログテンプレート(成果物①)

以下が、AIエージェント実行ログのMarkdownテンプレートです。

# AIエージェント実行ログ

## 基本情報

| 項目 | 値 |
|---|---|
| 実行ID | exec_20240101_001 |
| 開始時刻 | 2024-01-01T10:00:00+09:00 |
| 終了時刻 | 2024-01-01T10:00:15+09:00 |
| ステータス | success |
| モデル | gpt-4o |
| トークン数(入力) | 450 |
| トークン数(出力) | 320 |

## プロンプト

以下の要件でコードレビューを実施してください。
- セキュリティ観点でのチェック
- パフォーマンスの懸念点指摘

## コンテキスト(RAG取得)

- ソース: coding_guidelines_v2.md
- 関連度: 0.85

## モデル応答

(応答内容)

## ツール呼び出し

なし

## 備考

特記事項なし

テンプレートの設計ポイント

  1. 基本情報を表形式でまとめる: 一覧性を確保
  2. プロンプトと応答を分離: 入出力の対応を明確に
  3. コンテキスト情報を含める: RAGで何を参照したかの追跡性
  4. ツール呼び出しを記録: MCPツールの利用履歴

JSONスキーマ(成果物②)

以下が、同じ実行データをJSONで表現したスキーマです。

{
  "execution_id": "exec_20240101_001",
  "timestamp": {
    "start": "2024-01-01T10:00:00+09:00",
    "end": "2024-01-01T10:00:15+09:00"
  },
  "status": "success",
  "model": {
    "name": "gpt-4o",
    "version": "2024-01-01"
  },
  "tokens": {
    "input": 450,
    "output": 320,
    "total": 770
  },
  "prompt": "以下の要件でコードレビューを実施...",
  "context": [
    {
      "source": "coding_guidelines_v2.md",
      "relevance_score": 0.85
    }
  ],
  "response": "モデルの応答内容...",
  "tool_calls": [],
  "metadata": {
    "trigger": "manual",
    "user_id": "developer_01",
    "environment": "development"
  }
}

JSONスキーマの設計ポイント

  1. フラットよりネスト構造: timestamp.starttimestamp.end のように関連項目をグルーピング
  2. 配列で可変長データに対応: contexttool_calls は配列で複数件に対応
  3. metadataで拡張性を確保: 後から項目を追加しやすい設計

Python実装例:ログ出力ユーティリティ

以下に、MarkdownとJSONの両方を出力するPythonコード例を示します。

import json
from datetime import datetime
from pathlib import Path
from dataclasses import dataclass, asdict
from typing import Optional


@dataclass
class ExecutionLog:
    """AIエージェント実行ログのデータクラス"""
    execution_id: str
    start_at: str
    end_at: str
    status: str
    model_name: str
    tokens_input: int
    tokens_output: int
    prompt: str
    response: str
    tool_calls: list
    context_sources: list
    trigger: str = "manual"
    user_id: str = ""
    notes: str = ""

    def to_json(self) -> str:
        """JSON形式で出力"""
        data = {
            "execution_id": self.execution_id,
            "timestamp": {
                "start": self.start_at,
                "end": self.end_at,
            },
            "status": self.status,
            "model": {"name": self.model_name},
            "tokens": {
                "input": self.tokens_input,
                "output": self.tokens_output,
                "total": self.tokens_input + self.tokens_output,
            },
            "prompt": self.prompt,
            "response": self.response,
            "tool_calls": self.tool_calls,
            "context": self.context_sources,
            "metadata": {
                "trigger": self.trigger,
                "user_id": self.user_id,
            },
        }
        return json.dumps(data, ensure_ascii=False, indent=2)

    def to_markdown(self) -> str:
        """Markdown形式で出力"""
        total = self.tokens_input + self.tokens_output
        lines = [
            "# AIエージェント実行ログ",
            "",
            "## 基本情報",
            "",
            "| 項目 | 値 |",
            "|---|---|",
            f"| 実行ID | {self.execution_id} |",
            f"| 開始時刻 | {self.start_at} |",
            f"| 終了時刻 | {self.end_at} |",
            f"| ステータス | {self.status} |",
            f"| モデル | {self.model_name} |",
            f"| トークン数 | {total} ({self.tokens_input} + {self.tokens_output}) |",
            "",
            "## プロンプト",
            "",
            self.prompt,
            "",
            "## モデル応答",
            "",
            self.response,
            "",
            "## 備考",
            "",
            self.notes if self.notes else "特記事項なし",
        ]
        return "\n".join(lines)


def save_log(
    log: ExecutionLog,
    output_dir: str = "./logs"
) -> None:
    """MarkdownとJSONの両方を保存"""
    path = Path(output_dir)
    path.mkdir(parents=True, exist_ok=True)

    # JSON保存
    json_path = path / f"{log.execution_id}.json"
    json_path.write_text(log.to_json(), encoding="utf-8")

    # Markdown保存
    md_path = path / f"{log.execution_id}.md"
    md_path.write_text(log.to_markdown(), encoding="utf-8")

コードの設計意図

  • dataclassでデータ構造を明確化: ログ項目のスキーマを型で表現
  • to_jsonとto_markdownを分離: 用途に応じた出力形式の切り替え
  • save_logで両方同時保存: 保存漏れを防止
    このコードは、そのまま自分のプロジェクトにコピーして使うことができます。

ファイル構成の提案

ログファイルの配置について、以下の構成を提案します。

logs/
├── 2024-01/
│   ├── exec_20240101_001.json
│   ├── exec_20240101_001.md
│   ├── exec_20240101_002.json
│   └── exec_20240101_002.md
├── 2024-02/
│   └── ...
└── index.json  ← 検索用インデックス

設計の判断基準

観点 判断基準
ディレクトリ分割 月単位(ファイル数が1000件/月を超えるなら日単位)
ファイル名 実行IDをそのまま使用(一意性保証)
インデックス 集計・検索用に別途作成(大規模運用時)

MarkdownとJSONの使い分けガイド

運用シーンごとの使い分けを整理します。

シーン 使う形式 理由
障害対応中の確認 Markdown 人が素早く読める
月次コスト集計 JSON プログラムで自動化
品質トレンド分析 JSON 統計処理に適する
チームへの報告 Markdown そのまま共有可能
監査対応 両方 JSONで証跡、Markdownで説明

ログローテーションの考え方

AIエージェントのログは、従来システムのログよりもサイズが大きくなりがちです(プロンプトと応答の全文を含むため)。ローテーションの判断基準を示します。

レベル 保存期間の目安 考慮点
DEBUG(全文) 7日 ストレージコストとのバランス
INFO(要約) 90日 トレンド分析に必要な期間
WARN/ERROR 1年 監査・コンプライアンス要件

これも、従来システムのログローテーションと同じ考え方です。あなたの経験がそのまま活きます。

実装時の注意点

機密情報の取り扱い

プロンプトや応答に機密情報が含まれる場合、ログにそのまま記録するとセキュリティリスクになります。第19回で詳しく扱いますが、現時点では「機密情報をマスクしてからログに書く」という原則を意識してください。

ファイルサイズの制御

プロンプトと応答の全文を含めると、ログファイルが大きくなりがちです。INFOレベルではプロンプトの先頭200文字とトークン数のみを記録するなど、レベルに応じた情報量の制御が重要です。

SE経験者が追加できる工夫

既存のログ運用経験から、以下の工夫が考えられます。

  • アラート設定: トークン消費が閾値を超えたら通知(監視システムと同じ)
  • ダッシュボード: JSONログを集計して日次レポートを生成(BIツールの経験が活きる)
  • ログ相関分析: 複数ログを突き合わせて問題パターンを発見(障害分析のスキル)

まとめ

  • Markdownは人が読むため、JSONはプログラムが処理するために併用
  • dataclassでログスキーマを定義し、両形式に変換する実装がシンプル
  • ファイル構成、ローテーション、セキュリティは従来システムの知見をそのまま活用
  • まずは小さく始め、運用しながら拡張する

次回予告:Human-in-the-loopはどこに入れるべきか

第15回では、AIエージェントのワークフローに人間の承認ポイント(Human-in-the-loop)をどこに配置するかを設計します。

具体的には以下の内容を扱います。

  • AIエージェントの処理フローにおける承認ポイントの配置基準
  • リスクレベルに応じた承認の粒度設計
  • 今回作成したログと承認フローの連携
  • 承認フローの実装パターン

「ログで記録するだけでなく、重要な処理の前に人間がチェックする仕組みがあれば、もっと安心できるのに」という考えに答える回です。ぜひお楽しみに。


連載: AIに仕事を奪われる不安から始めるハーネス作成入門
次回(第15回): Human-in-the-loopはどこに入れるべきか

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?