DeepSeek Harness: セッションログと Trajectory

最終更新:2026-08-31

すべての Agent 会話は再現不可能な旅——モデルにはランダム性があり、ツールには副作用があり、コンテキストは蓄積されます。DSH の Trajectory システムは「追記専用ログ」ですべてのステップを完全に記録し、任意の時点に遡って追跡、監査、フォーク、復元を可能にします。

💡 ヒント:Trajectory は単なるログビューアではなく——セッション管理の中核です。メインラインに影響を与えずにフォークして実験したり、任意のチェックポイントから復元して別の道を選んだりできます。

📋 前提知識07-python-sdk.md の完了、SDK の基礎に精通していること

1. 学習内容

セッションライフサイクル


2. 追記専用ログの設計

(1) なぜ追記専用なのか

従来のログシステムは変更と削除を許可しますが、Agent セッションログは不変でなければなりません——フライトデータレコーダー(ブラックボックス)のように、一度記録が書き込まれたら変更できません:

100%
graph LR
    E1[Event 1] --> E2[Event 2] --> E3[Event 3] --> E4[Event 4] --> E5[Event 5]
    E5 -.->|Append only| NEW[Event 6]
    
    style E1 fill:#e8f5e9
    style E2 fill:#e8f5e9
    style E3 fill:#e8f5e9
    style E4 fill:#e8f5e9
    style E5 fill:#e8f5e9
    style NEW fill:#fff3e0

追記専用設計の3つの原則:

原則 説明 利点
不変性 一度書き込まれたログは変更・削除不可 完全な監査証跡
順序性 イベントはタイムスタンプで厳密に順序付け 再生可能な再現
追記のみ 新しいイベントの追加のみ、削除なし 並行性の競合なし

(2) 従来ログとの比較

次元 従来ログ DSH 追記専用ログ
変更可能 ✅ 変更/削除可能 ❌ 変更不可
並行安全性 ロックが必要 本質的に安全(追記のみ)
ロールバック機能 バックアップに依存 任意の時点から復元
監査能力 改ざんの可能性あり 改ざん防止
ストレージ効率 圧縮可能 継続的に増大(定期アーカイブが必要)

(3) ログストレージ構造

TEXT 📖 参照専用
.dsh/
└── sessions/
    └── sess_abc123/
        ├── events.log          # イベントログ(追記専用)
        ├── snapshots/          # 状態スナップショット
        │   ├── snap_001.json
        │   ├── snap_002.json
        │   └── snap_003.json
        └── metadata.json       # セッションメタデータ

3. SessionEvent イベントストリーム

(1) イベントタイプ

DSH セッションのすべての操作は SessionEvent として記録されます:

TYPESCRIPT
type SessionEventType =
  | 'session.created'
  | 'session.config_changed'
  | 'user.message'
  | 'agent.message'
  | 'agent.thinking'
  | 'tool.call'
  | 'tool.result'
  | 'tool.approval.requested'
  | 'tool.approval.resolved'
  | 'session.forked'
  | 'session.restored'
  | 'error.occurred';

(2) イベント構造

各 SessionEvent は標準フィールドを含みます:

TYPESCRIPT
interface SessionEvent {
  id: string;                  // Unique event ID
  type: SessionEventType;      // Event type
  timestamp: number;           // Unix timestamp (milliseconds)
  sessionId: string;           // Parent session ID
  data: Record<string, unknown>;  // Event payload data
  parentId?: string;           // Parent event ID (used for forks)
}

(3) イベントの詳細説明

ユーザーメッセージイベント:

▶ サンプル 1:user.message イベント

JSON
{
  "id": "evt_001",
  "type": "user.message",
  "timestamp": 1724486400000,
  "sessionId": "sess_abc123",
  "data": {
    "content": "Help me refactor the utils directory",
    "attachments": []
  }
}

ツール呼び出しイベント:

▶ サンプル 2:tool.call イベント

JSON
{
  "id": "evt_002",
  "type": "tool.call",
  "timestamp": 1724486401500,
  "sessionId": "sess_abc123",
  "data": {
    "tool": "search",
    "params": {
      "pattern": "utils/*",
      "type": "file"
    },
    "mode": "standard"
  }
}

ツール結果イベント:

▶ サンプル 3:tool.result イベント

JSON
{
  "id": "evt_003",
  "type": "tool.result",
  "timestamp": 1724486402300,
  "sessionId": "sess_abc123",
  "data": {
    "toolCallId": "evt_002",
    "status": "success",
    "result": {
      "files": ["utils/format.ts", "utils/validate.ts", "utils/helpers.ts"]
    },
    "duration_ms": 800
  }
}

承認イベント:

▶ サンプル 4:tool.approval イベント

JSON
{
  "id": "evt_004",
  "type": "tool.approval.requested",
  "timestamp": 1724486403000,
  "sessionId": "sess_abc123",
  "data": {
    "tool": "file_edit",
    "params": {
      "action": "edit",
      "path": "utils/format.ts"
    },
    "riskLevel": "high"
  }
}
JSON
{
  "id": "evt_005",
  "type": "tool.approval.resolved",
  "timestamp": 1724486405000,
  "sessionId": "sess_abc123",
  "data": {
    "approvalId": "evt_004",
    "decision": "allowed",
    "decidedBy": "user"
  }
}

(4) 完全なイベントストリーム例

TEXT 📖 参照専用
Timeline                  Event Type
─────────────────────────────────────────
10:00:00.000   session.created
10:00:05.120   user.message          "Help me refactor the utils directory"
10:00:06.300   tool.call             search → utils/*
10:00:07.100   tool.result           Found 3 files
10:00:08.200   tool.call             file_edit → read utils/format.ts
10:00:08.500   tool.result           File content returned
10:00:10.800   agent.thinking        Analyzing refactoring plan...
10:00:12.000   tool.approval.requested   file_edit → edit
10:00:15.000   tool.approval.resolved    → allowed
10:00:15.200   tool.call             file_edit → edit utils/format.ts
10:00:15.600   tool.result           Edit complete
10:00:17.000   agent.message         "Refactoring complete!"

4. Trajectory ビュー

(1) Trajectory とは

Trajectory はセッションログの視覚的インターフェースで、Agent の完全な「軌跡」を表示します:

TEXT 📖 参照専用
┌─ Trajectory View ──────────────────────────────────────┐
│                                                         │
│ 10:00  👤 Help me refactor the utils directory          │
│ 10:00    🔍 search(utils/*) → 3 files            0.8s  │
│ 10:00    📄 file_edit(read) → utils/format.ts    0.3s  │
│ 10:00    📄 file_edit(read) → utils/validate.ts  0.2s  │
│ 10:00    🤔 Thinking... Analyzing refactoring plan      │
│ 10:00    ⚠️ Approval: edit utils/format.ts              │
│ 10:00      → ✅ Allowed                                  │
│ 10:00    📝 file_edit(edit) → utils/format.ts    0.4s  │
│ 10:00    ⚠️ Approval: edit utils/validate.ts            │
│ 10:00      → ✅ Allowed                                  │
│ 10:00    📝 file_edit(edit) → utils/validate.ts  0.3s  │
│ 10:00    🤖 Refactoring complete! Extracted shared type definitions... │
│                                                         │
│ [Fork from here] [Restore to here] [Export]             │
└─────────────────────────────────────────────────────────┘

(2) Web UI での Trajectory アクセス

Web UI で、上部コントロールバーのログアイコンをクリックして Trajectory ビューを開きます:

TEXT 📖 参照専用
上部コントロールバー → 📋 → Trajectory

(3) Trajectory のフィルタリングと検索

▶ サンプル 5:イベントタイプでフィルタリング

TEXT 📖 参照専用
Trajectory View Filters:
┌──────────────────────────────────────────┐
│ Filters:                                 │
│ ☑ user.message    ☑ agent.message        │
│ ☑ tool.call       ☑ tool.result          │
│ ☐ agent.thinking  ☐ approval events      │
│                                          │
│ Search: [Enter keywords...]              │
└──────────────────────────────────────────┘

(4) SDK での Trajectory アクセス

▶ サンプル 6:SDK でイベントストリームを取得

PYTHON
from dsh import DSHClient

client = DSHClient(base_url="http://127.0.0.1:3080")
session = client.get_session("sess_abc123")

# すべてのイベントを取得
events = session.get_trajectory()

for event in events:
    print(f"[{event.timestamp}] {event.type}: {event.data}")

# タイプでフィルタリング
tool_events = session.get_trajectory(event_type="tool.call")

for event in tool_events:
    print(f"Tool: {event.data['tool']}")
    print(f"Params: {event.data['params']}")

5. セッションフォークと復元

(1) フォークの概念

フォークは特定の時点からセッションブランチを作成します——メインラインは前進し続け、ブランチは独立して発展します:

100%
graph LR
    E1[Event 1] --> E2[Event 2] --> E3[Event 3] --> E4[Event 4]
    E3 -->|fork| F1[Fork Event 1] --> F2[Fork Event 2]
    
    E4 --> E5[Event 5]
    
    style E1 fill:#e8f5e9
    style E2 fill:#e8f5e9
    style E3 fill:#e8f5e9
    style E4 fill:#e8f5e9
    style E5 fill:#e8f5e9
    style F1 fill:#e3f2fd
    style F2 fill:#e3f2fd

(2) フォークのユースケース

シナリオ 説明
ソリューション探索 同じノードから異なるアプローチを試し、結果を比較
安全なフォールバック 破壊的操作の前にフォーク;失敗したらメインラインに戻る
A/B テスト 同じタスクを異なるモデル/モードで比較
実験的変更 結果が不確かな場合、まずブランチで試す

(3) Web UI でのフォーク

Trajectory ビューで、任意のイベントの横にある「Fork from here」ボタンをクリック:

TEXT 📖 参照専用
10:00  📝 file_edit(edit) → utils/format.ts  [Fork from here]
10:00  ⚠️ Approval: edit utils/validate.ts    [Fork from here]
10:00  🤖 Refactoring complete!               [Fork from here]

フォークは選択したイベントポイントから新しいセッションを作成し、その時点より前のすべてのコンテキストをコピーします。

(4) SDK でのフォーク

▶ サンプル 7:SDK フォーク操作

PYTHON
client = DSHClient(base_url="http://127.0.0.1:3080")
session = client.get_session("sess_abc123")

# 5番目のイベントからフォーク
forked = session.fork(after_event="evt_005")

print(f"Forked session: {forked.id}")
print(f"Parent: {forked.parent_id}")
print(f"Fork point: evt_005")

# フォークブランチで会話を継続
response = forked.send("Try a different refactoring approach, split by function")

(5) 復元

復元はフォークとは異なります——現在のセッションを指定したイベントポイントまでロールバックし、それ以降のイベントを破棄します:

▶ サンプル 8:SDK 復元操作

PYTHON
# 3番目のイベントポイントに復元
session.restore(to_event="evt_003")

# evt_004, evt_005 等のイベントは「restored-away」とマークされる
# 新しいイベントは evt_003 の後に追記される

注意:復元はイベントを削除しません(追記専用の原則)。代わりに、以降のイベントを無効としてマークし、session.restored イベントを追加します。


6. ログの永続化

(1) デフォルトストレージ

DSH セッションログはデフォルトでプロジェクトディレクトリの .dsh/sessions/ に保存されます:

TEXT 📖 参照専用
.dsh/
├── sessions/
│   ├── sess_abc123/
│   │   ├── events.log        # イベントログ
│   │   ├── snapshots/        # 状態スナップショット
│   │   └── metadata.json     # メタデータ
│   └── sess_def456/
│       ├── events.log
│       └── ...
├── config.yaml               # DSH 設定
└── plugins/                  # プラグインディレクトリ

(2) 永続化設定

YAML
# dsh.config.yaml
storage:
  # ストレージパス
  base_path: ".dsh/sessions"
  
  # スナップショット戦略
  snapshots:
    enabled: true
    interval: 10              # 10イベントごとにスナップショットを保存
    max_snapshots: 5          # 最大5つのスナップショットを保持
  
  # ログローテーション
  rotation:
    max_size_mb: 100          # ログファイルあたり最大100MB
    max_files: 50             # 最大50セッションを保持
  
  # アーカイブ
  archive:
    enabled: true
    path: ".dsh/archive/"
    after_days: 30            # 30日後に自動アーカイブ

(3) セッションログのエクスポート

▶ サンプル 9:JSON でエクスポート

PYTHON
# 完全なセッションログをエクスポート
session = client.get_session("sess_abc123")
events = session.get_trajectory()

import json
with open("session_export.json", "w") as f:
    json.dump([e.to_dict() for e in events], f, indent=2)

▶ サンプル 10:Markdown でエクスポート

BASH
# CLI エクスポート
dsh session export sess_abc123 --format markdown --output session.md

# Output format
# # Session: sess_abc123
# ## 10:00 - User
# Help me refactor the utils directory
# ## 10:00 - Tool: search
# Pattern: utils/* → 3 files found
# ...

(4) ログのクリーンアップ

BASH
# すべてのセッションを一覧(サイズ順)
dsh session list --sort size

# 古いセッションをアーカイブ
dsh session archive --older-than 30d

# アーカイブ済みセッションを削除(不可逆)
dsh session clean --archived-only

7. Trajectory と監査

(1) 操作監査

Trajectory はすべての Agent 操作を記録し、監査に自然に適しています:

100%
graph TB
    AUDIT[Audit Need] --> T1[Who executed it?]
    AUDIT --> T2[When?]
    AUDIT --> T3[What was done?]
    AUDIT --> T4[What was the result?]
    
    T1 --> TRAJ[Trajectory Event Stream]
    T2 --> TRAJ
    T3 --> TRAJ
    T4 --> TRAJ

(2) コンプライアンスシナリオ

コンプライアンス要件 Trajectory による対応
操作のトレーサビリティ すべてのイベントに ID、タイムスタンプ、実行者あり
改ざん防止の変更 追記専用ログ、履歴の変更不可
承認記録 approval.requested + approval.resolved の完全な記録
ロールバック機能 任意のチェックポイントから復元

(3) 監査レポートの生成

▶ サンプル 11:監査レポートの生成

PYTHON
session = client.get_session("sess_abc123")
events = session.get_trajectory()

report = {
    "session_id": session.id,
    "duration": events[-1].timestamp - events[0].timestamp,
    "user_messages": len([e for e in events if e.type == "user.message"]),
    "tool_calls": len([e for e in events if e.type == "tool.call"]),
    "approvals_requested": len([e for e in events if e.type == "tool.approval.requested"]),
    "approvals_denied": len([e for e in events if e.type == "tool.approval.resolved" and e.data.get("decision") == "denied"]),
    "files_modified": list(set([
        e.data.get("path") for e in events
        if e.type == "tool.call" and e.data.get("tool") == "file_edit"
    ])),
    "errors": len([e for e in events if e.type == "error.occurred"])
}

import json
print(json.dumps(report, indent=2))

❓ よくある質問

Q 追記専用ログは無限に増大しますか?
A はい、しかし DSH はアーカイブとローテーション機構を提供します。rotation.max_size_mbarchive.after_days で自動ストレージ管理を設定してください。
Q フォークされたセッションは元のセッションとデータを共有しますか?
A フォークはフォーク時点のコンテキストスナップショットをコピーします;その後は完全に独立です。変更は互いに影響しません。
Q 復元は実際に履歴イベントを削除しますか?
A いいえ。追記専用の原則により、イベントは決して削除されません。復元は以降のイベントを無効としてマークし、復元ポイントから新しいイベントの追記を開始するだけです。
Q Trajectory データはエクスポートできますか?
A はい。JSON、Markdown、CSV 形式のエクスポートをサポートします。CLI では dsh session export;SDK では get_trajectory() メソッドを使用します。
Q 複数ユーザーが同じセッションの Trajectory を閲覧できますか?
A DSH はデフォルトでシングルユーザーモードなので、マルチユーザー共有の問題はありません。共有ストレージ(例:NFS)を使用する場合、複数の DSH インスタンスが同じログを読み取ることができます。
Q CI/CD で Trajectory を使用するには?
A SDK を使ってイベントストリームをエクスポートし、ツール呼び出し回数、承認拒否率、エラー率等を分析して、品質ゲートとして使用します。

📖 まとめ


📝 練習問題

1. ⭐ 基礎:Agent 会話を完了させ(少なくとも2つのツール呼び出しを含む)、Trajectory ビューを開いて、すべてのイベントのタイプとタイムスタンプをリストしてください。

2. ⭐⭐ 応用:セッションの3番目のイベントからフォークブランチを作成し、ブランチで異なるアプローチを試してください。メインラインとブランチの最終結果を比較すること。

3. ⭐⭐⭐ チャレンジ:Python SDK を使って Trajectory 分析ツールを書いてください——セッション ID を入力として、監査レポート(操作統計、承認記録、変更ファイル一覧、エラーサマリーを含む)を自動生成し、JSON 形式で出力すること。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%