./docs/シーケンス図.md
# 時代考証アシストAIシステム - シーケンス図
## 非同期ジョブモード(画像入力)
```mermaid
---
title: 時代考証システム - 非同期ジョブモード(画像入力)
---
sequenceDiagram
participant U as ユーザー
participant F as フロントエンド
participant API as FastAPI
participant S3In as S3 (inputs/)
participant Lambda as Lambda Worker
participant LA as 文字・物体列挙
participant LU as 検証観点リスト
participant V as 検証エージェント
participant LLM as LLMモデル群
participant Tool as 検索ツール
participant S3Out as S3 (results/)
U->>F: 画像アップロード + 年代入力
F->>API: POST /api/analyze
API->>S3In: 画像保存<br/>inputs/{job_id}_image
S3In-->>API: S3キー
API->>Lambda: 非同期Invoke (Event)<br/>job_id + S3キー + era_year
API-->>F: 202 Accepted + job_id
F-->>U: ジョブID表示
Lambda->>S3In: 画像取得
S3In-->>Lambda: 画像データ
Lambda->>LA: 文字・物体列挙要求
LA->>LLM: Vision LLM呼び出し(画像)
LLM-->>LA: JSON配列(文字・物体)
LA->>LLM: 文字専用で再実行
LLM-->>LA: JSON配列(文字のみ)
LA-->>Lambda: enumerated_items
Lambda->>S3Out: 部分結果保存<br/>results/{job_id}.json
Lambda->>LU: 検証観点リスト要求
LU->>LLM: Vision LLM呼び出し(画像+列挙結果)
LLM-->>LU: JSON配列(観点10-15件)
LU-->>Lambda: observations
Lambda->>S3Out: 部分結果保存<br/>results/{job_id}.json
Lambda->>V: 並列検証要求(全観点)
par 観点1
V->>LLM: Phase1: 曖昧さ判定
LLM-->>V: ambiguity_score
alt 曖昧さ高い
V->>LLM: Phase2: ReActエージェント
LLM->>Tool: Web検索
Tool-->>LLM: 検索結果
LLM->>Tool: 画像検索(必要なら)
Tool-->>LLM: 画像検索結果
LLM-->>V: 検証結果
end
V->>LLM: アンサンブル判定(複数モデル並列)
LLM-->>V: 各モデルの判定
and 観点2〜15
V->>LLM: Phase1-2 + アンサンブル
LLM-->>V: 判定結果
end
V-->>Lambda: verifications(全観点分)
Lambda->>S3Out: 最終結果保存<br/>results/{job_id}.json
loop ロングポーリング(最大20秒)
F->>API: GET /api/jobs/{job_id}?wait=20
API->>S3Out: 結果確認
alt 最終結果あり
S3Out-->>API: 結果データ(summary完了)
API-->>F: 200 + status=completed + result
F-->>U: 検証結果表示
else 部分結果あり
S3Out-->>API: 結果データ(verifications未完了)
API-->>F: 200 + status=partial + result
F-->>U: 途中経過表示
F->>API: 再度GET(リトライ)
else 結果なし(タイムアウト)
API-->>F: 200 + status=pending
F->>API: 再度GET(リトライ)
end
end
```
## 処理フローの詳細
### 1. ジョブ投入フェーズ
#### 1.1. リクエスト受信
1. ユーザーが画像/テキスト + 年代を入力
2. フロントエンドが `POST /api/analyze` を送信
#### 1.2. S3への保存
1. FastAPIが画像/テキストをS3の `inputs/` に保存
- 画像: `inputs/{job_id}_image`
- テキスト: `inputs/{job_id}_text`
2. S3キーを取得
#### 1.3. Lambda Invoke
1. Lambda を非同期モード(InvocationType='Event')で起動
2. ペイロードに以下を含める:
- `job_id`: ジョブID(UUID)
- `era_year`: 考証対象年
- `image_s3_bucket` / `image_s3_key`: 画像のS3参照
- `text_s3_bucket` / `text_s3_key`: テキストのS3参照
#### 1.4. 即座にレスポンス
1. FastAPIが `202 Accepted` と `job_id` を返却
2. フロントエンドがジョブIDを表示
### 2. Lambda処理フェーズ
#### 2.1. 入力データ取得
1. LambdaがS3から画像/テキストを取得
2. base64デコード
#### 2.2. エージェント実行
1. LangGraphを起動
2. 各エージェント(list_all → list_up → verify)を順次実行
#### 2.3. 部分結果の保存
1. 各エージェント完了ごとに、部分結果をS3に保存
- `results/{job_id}.json`
2. フロントエンドが部分結果を取得できるようにする
#### 2.4. 最終結果の保存
1. 全エージェント完了後、最終結果をS3に保存
- `results/{job_id}.json`
2. `summary` フィールドを含める
### 3. ロングポーリングフェーズ
#### 3.1. ジョブ結果取得
1. フロントエンドが `GET /api/jobs/{job_id}?wait=20` を送信
2. FastAPIがS3の `results/{job_id}.json` を確認
#### 3.2. 結果の判定
- **結果あり(verifications + summary 完了)**:
- `200 OK` + `status=completed` + `result`
- **部分結果あり(verifications 未完了)**:
- `200 OK` + `status=partial` + `result`
- **結果なし**:
- 最大20秒までロングポーリング(1秒間隔)
- タイムアウト後: `200 OK` + `status=pending`
- フロントエンドが再度GET(リトライ)
## 環境変数
### FastAPI (app)
```bash
USE_ASYNC_JOBS=true # 非同期ジョブモードを有効化
AWS_REGION=ap-northeast-1
AWS_ENDPOINT_URL=http://localstack:4566 # LocalStackのエンドポイント
JOB_LAMBDA_FUNCTION_NAME=historical-accuracy-worker
JOB_RESULT_BUCKET=historical-accuracy-results
```
### LocalStack (localstack-init)
```bash
JOB_RESULT_BUCKET=historical-accuracy-results
JOB_LAMBDA_FUNCTION_NAME=historical-accuracy-worker
```
## LocalStackのセットアップ
### 1. Lambda関数のzip作成
```bash
make lambda-zip
```
### 2. Docker Composeで起動
```bash
docker compose up --build
```
### 3. LocalStack初期化スクリプト
`scripts/localstack-init.sh` が以下を実行:
1. S3バケット作成: `historical-accuracy-results`
2. Lambda関数作成: `historical-accuracy-worker`
3. Lambda関数のzipをアップロード
## 主な特徴
- **非同期処理**: 重い処理をバックグラウンドで実行
- **ロングポーリング**: 最大20秒まで結果を待機(Next.jsプロキシのタイムアウト対策)
- **部分結果対応**: 各エージェント完了ごとに部分結果を返却
- **S3によるペイロードサイズ回避**: 画像は256KB制限を避けるためS3経由
- **LocalStack対応**: ローカル開発環境でAWS Lambda/S3をエミュレート
## 同期モードとの違い
| 項目 | 同期モード | 非同期モード |
| ---------------- | -------------------- | -------------------------- |
| レスポンス形式 | NDJSONストリーミング | 202 Accepted + job_id |
| 処理場所 | FastAPI内 | Lambda Worker |
| 処理時間 | 即座 | バックグラウンド |
| タイムアウト | なし | Lambda最大15分 |
| スケーラビリティ | 低い | **高い**(Lambda並列実行) |
| コスト | 低い | Lambda実行コスト |
## ユースケース
- **大量の画像を処理**: 複数のジョブを並列投入
- **長時間処理**: 観点数が多い場合
- **高負荷対策**: FastAPIの負荷を減らす
- **本番環境**: AWS Lambda/S3を使った本番デプロイ