Skip to content

Commit 3df4e38

Browse files
authored
Merge pull request #95 from kc3hack/feature/issue-88-skill-tree-ai-improve
feat: #88 スキルツリーAI生成の最適化と三角形レイアウト改善
2 parents dae6acc + a89e6a3 commit 3df4e38

File tree

22 files changed

+2257
-250
lines changed

22 files changed

+2257
-250
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# スキルツリーストリーミング実装ガイド
2+
3+
## 概要
4+
5+
LangChain Expression Language (LCEL) の `astream()` を使用して、スキルツリーをノード単位にプログレッシブ表示します。
6+
7+
## 実装内容
8+
9+
### バックエンド
10+
11+
1. **ストリーミング関数** (`backend/app/core/llm.py`):
12+
- `stream_llm()`: LLMからストリーミングでチャンクを受信
13+
14+
2. **JSON Lines形式プロンプト** (`backend/app/core/prompts_streaming.py`):
15+
- 1行1ノード形式で生成させる
16+
- 例: `{"type":"node","id":"html-css","name":"HTML/CSS基礎",...}`
17+
18+
3. **SSEエンドポイント** (`backend/app/api/endpoints/analyze.py`):
19+
- `GET /api/v1/analyze/skill-tree/stream?category=web`
20+
- Server-Sent Events (SSE) 形式でリアルタイム送信
21+
22+
### フロントエンド
23+
24+
4. **APIクライアント** (`frontend/src/lib/api/skillTree.ts`):
25+
- `streamSkillTree()`: EventSource でSSE受信
26+
- コールバック: `onNode`, `onMetadata`, `onComplete`, `onError`
27+
28+
## 使用方法
29+
30+
### DashboardContainer.tsx での実装例
31+
32+
```typescript
33+
import { streamSkillTree } from "@/lib/api/skillTree";
34+
import { useState, useEffect } from "react";
35+
36+
export function DashboardContainer() {
37+
const [skillTreeNodes, setSkillTreeNodes] = useState<TreeSkillNode[]>([]);
38+
const [isStreaming, setIsStreaming] = useState(false);
39+
const [progress, setProgress] = useState(0);
40+
41+
useEffect(() => {
42+
if (!category) return;
43+
44+
setIsStreaming(true);
45+
setSkillTreeNodes([]); // リセット
46+
47+
const eventSource = streamSkillTree(
48+
category,
49+
// ノード受信時: 段々追加
50+
(node) => {
51+
setSkillTreeNodes((prev) => [...prev, node]);
52+
},
53+
// メタデータ受信時: 進捗表示
54+
(metadata) => {
55+
setProgress(metadata.progress_percentage);
56+
},
57+
// 完了時
58+
() => {
59+
setIsStreaming(false);
60+
console.log("スキルツリー生成完了!");
61+
},
62+
// エラー時
63+
(error) => {
64+
setIsStreaming(false);
65+
setError(error.message);
66+
}
67+
);
68+
69+
// クリーンアップ: カテゴリ変更時にストリーミング停止
70+
return () => {
71+
eventSource.close();
72+
};
73+
}, [category]);
74+
75+
return (
76+
<div>
77+
{isStreaming && (
78+
<div className="loading">
79+
スキルツリー生成中... {progress.toFixed(0)}%
80+
</div>
81+
)}
82+
<SkillTreeCanvas nodes={skillTreeNodes} />
83+
</div>
84+
);
85+
}
86+
```
87+
88+
## テスト方法
89+
90+
### バックエンドのみテスト
91+
92+
```bash
93+
cd backend
94+
poetry run uvicorn app.main:app --reload
95+
```
96+
97+
ブラウザで開く:
98+
99+
```
100+
http://localhost:8000/api/v1/analyze/skill-tree/stream?category=web
101+
```
102+
103+
SSE形式でノードが段々表示されます:
104+
105+
```
106+
data: {"type":"node","id":"html-css","name":"HTML/CSS基礎",...}
107+
108+
data: {"type":"node","id":"javascript","name":"JavaScript基礎",...}
109+
110+
data: {"type":"metadata","total_nodes":15,...}
111+
112+
data: {"type":"done"}
113+
```
114+
115+
### フルスタックテスト
116+
117+
1. バックエンド起動:
118+
119+
```bash
120+
cd backend
121+
poetry run uvicorn app.main:app --reload
122+
```
123+
124+
2. フロントエンド起動:
125+
126+
```bash
127+
cd frontend
128+
npm run dev
129+
```
130+
131+
3. ブラウザで `http://localhost:3000` にアクセス
132+
4. ログイン後、カテゴリを選択
133+
5. スキルツリーが段々できていくのを確認
134+
135+
## パフォーマンス
136+
137+
### 最適化内容
138+
139+
1. **トークン削減**: 60.7% 削減
140+
- ベースライン全体 (1,614 tokens) → Few-shot 2例 (282 tokens)
141+
2. **プロンプト簡潔化**: 要件5つ → 3つ
142+
3. **モデル変更**: gpt-4o-mini → gpt-3.5-turbo-0125 (2-3倍高速)
143+
144+
4. **ノード数削減**: 20-30個 → 15-20個
145+
146+
### 期待される生成時間
147+
148+
- **従来**: 20-30秒(完全なJSONが返るまで待機)
149+
- **ストリーミング**: 最初のノードが2-3秒で表示開始
150+
- ユーザー体感速度: **大幅改善**
151+
- 完了まで: 10-15秒
152+
153+
## 注意事項
154+
155+
### 認証
156+
157+
- GETエンドポイントですが、`Depends(get_current_user)` で認証必須
158+
- フロントエンド: `credentials: "include"` で Cookie 送信
159+
160+
### エラーハンドリング
161+
162+
- プロンプトが不適切で JSON Lines 形式でない場合はパースエラー
163+
- フォールバック: 従来の `/skill-tree` エンドポイントを使用
164+
165+
### ブラウザ互換性
166+
167+
- すべてのモダンブラウザで EventSource をサポート
168+
- IE11 非対応(polyfill 必要)
169+
170+
## まとめ
171+
172+
**完了した実装**:
173+
174+
- バックエンド: LLM ストリーミング + SSE エンドポイント
175+
- フロントエンド: EventSource クライアント
176+
177+
⚠️ **フロントエンドの実装が必要**:
178+
179+
- `DashboardContainer.tsx``streamSkillTree()` を統合
180+
- プログレッシブレンダリングのUI実装
181+
- ローディングインジケーター(進捗率表示)
182+
183+
🚀 **次のステップ**:
184+
185+
1. フロントエンド実装
186+
2. テスト・動作確認
187+
3. UX改善(アニメーション追加)

0 commit comments

Comments
 (0)