Deep Dive | src/commands/insights.ts 3200 行 — /insights 用量分析报告¶
重要性:⭐⭐⭐(/insights 命令——全 session 扫描 + 统计 + HTML 报告生成) 真实位置:
src/commands/insights.ts(3200 行) 角色:扫描所有 session 日志、提取元数据 / facets(通过 API)、聚合数据、生成 HTML 用量报告 关联:topics/deep-dive-session-storage.md(session 持久化)、topics/deep-dive-claude-api.md(facets 提取调用)
1. 文件全景¶
insights.ts (3200 行)
│
├── 行 1-50 :imports + 2 个 model helper
│ ├── getAnalysisModel() —— facets 提取用的模型
│ └── getInsightsModel() —— insight 生成用的模型
│
├── 行 50-420 :4 个 type 定义
│ ├── RemoteHostInfo
│ ├── SessionMeta (行 228)
│ ├── SessionFacets (行 260)
│ └── AggregatedData (行 275)
│
├── 行 420-470 :3 个路径 helper + 1 个 prompt
│ ├── getDataDir / getFacetsDir / getSessionMetaDir
│ └── FACET_EXTRACTION_PROMPT (行 430, ~30 行)
│
├── 行 462-940 :单 session 分析
│ ├── getLanguageFromPath (行 462)
│ ├── extractToolStats (行 467, ~260 行) — 工具使用统计
│ ├── hasValidDates (行 730)
│ ├── logToSessionMeta (行 737, ~75 行) — 提取 session 元数据
│ ├── deduplicateSessionBranches (行 812)
│ ├── formatTranscriptForFacets (行 831, ~40 行)
│ ├── SUMMARIZE_CHUNK_PROMPT (行 870, ~10 行)
│ ├── summarizeTranscriptChunk (行 881, ~25 行)
│ └── formatTranscriptWithSummarization (行 906, ~35 行)
│
├── 行 941-1000:缓存层
│ ├── loadCachedFacets (行 941)
│ ├── saveFacets (行 963)
│ ├── loadCachedSessionMeta (行 976)
│ └── saveSessionMeta (行 988)
│
├── 行 1001-1062:extractFacetsFromAPI (行 1001, ~60 行) — 调 API 提取 facets
│
├── 行 1062-1145:detectMultiClauding (行 1062, ~80 行) — 检测多 claude 实例
│
├── 行 1145-1330:aggregateData (行 1145, ~180 行) — 聚合所有 sessions
│
├── 行 1329-1610:Insight section
│ ├── InsightSection type (行 1329, ~170 行)
│ ├── InsightResults type (行 1497, ~75 行)
│ ├── generateSectionInsight (行 1572, ~40 行)
│ └── generateParallelInsights (行 1612, ~190 行) — 并行生成
│
├── 行 1610-1947:HTML 生成 helpers
│ ├── escapeHtmlWithBold (行 1801)
│ ├── SATISFACTION_ORDER / OUTCOME_ORDER
│ ├── generateBarChart (行 1824, ~40 行)
│ ├── generateResponseTimeHistogram (行 1863, ~40 行)
│ ├── generateTimeOfDayChart (行 1902, ~40 行)
│ └── getHourCountsJson (行 1939)
│
├── 行 1947-2655:**generateHtmlReport (行 1947, ~700 行)** — 完整 HTML 报告
│
├── 行 2655-2796:导出
│ ├── InsightsExport type (行 2655)
│ ├── buildExportData (行 2679, ~65 行)
│ └── LiteSessionInfo type (行 2743)
│
└── 行 2755-3200:generateUsageReport (行 2796, ~230 行) + safeEntries + safeKeys + isValidSessionFacets
2. 2 个 Model 助手¶
function getAnalysisModel(): string { ... } // facets 提取模型
function getInsightsModel(): string { ... } // insight 生成模型
2 个模型:
- getAnalysisModel —— 用于"分析 session 提取结构化 facets"(快模型)
- getInsightsModel —— 用于"从 facets 生成可读 insight"(可能更大模型)
3. 4 个核心类型¶
type SessionMeta = { ... } // 单 session 元数据
type SessionFacets = { ... } // LLM 提取的结构化 facets
type AggregatedData = { ... } // 聚合后的数据
type InsightSection = { ... } // 报告 section
type InsightResults = { ... } // 多 sections 结果
数据流:
4. extractToolStats — 260 行(行 467)¶
function extractToolStats(log: LogOption): ToolStats {
// 行 467
// 遍历 messages,统计每个 tool 的:
// - 调用次数
// - 成功 / 失败次数
// - 平均响应时间
// - 关联文件
}
单 session 工具统计——260 行反映"工具分析"是核心。
5. logToSessionMeta — 75 行(行 737)¶
function logToSessionMeta(log: LogOption): SessionMeta {
// 行 737
// 提取 session 元数据:起始时间、消息数、模型、文件、用户文本
}
Session → Meta——SessionMeta 是"轻量级"摘要。
6. formatTranscriptForFacets + formatTranscriptWithSummarization¶
2 个 transcript 格式化函数:
- formatTranscriptForFacets —— 直接格式化(短 transcript)
- formatTranscriptWithSummarization —— 长 transcript 先 summarize(调 API)
为什么 2 个: - 短 transcript:直接发(节省 API 调用) - 长 transcript:先 Haiku summarize,再发(避免超 token)
7. extractFacetsFromAPI — 60 行(行 1001)¶
async function extractFacetsFromAPI(log: LogOption, model: string): Promise<SessionFacets> {
// 行 1001
// 1. 格式化 transcript
// 2. 调模型
// 3. 解析 JSON facets
// 4. 校验
}
API 提取 facets —— 用 FACET_EXTRACTION_PROMPT 让模型返回结构化 JSON。
Facets 提取的字段(推测): - 主要任务 - 用户满意度 - 结果(成功/失败/部分) - 工具使用模式 - 用户/Claude 比例
8. detectMultiClauding — 80 行(行 1062)¶
export function detectMultiClauding(sessions: SessionMeta[]): ... {
// 行 1062
// 检测多 claude 实例并行运行
}
多 Claude 检测 —— 当用户并行多个 claude 时,识别这种模式。
9. aggregateData — 180 行(行 1145)¶
function aggregateData(sessions: SessionMeta[], facets: SessionFacets[]): AggregatedData {
// 行 1145
// 1. 累计工具调用
// 2. 时间分布
// 3. 模型使用
// 4. 任务类型分布
// 5. 多 claude 标志
}
聚合 —— 多个 session → 整体统计。
10. Insight 生成¶
10.1 generateSectionInsight — 40 行(行 1572)¶
async function generateSectionInsight(section: InsightSection, data: AggregatedData): Promise<string> {
// 行 1572
// 单 section 生成可读文字
}
单 section —— 一个 insight section → 一段文字。
10.2 generateParallelInsights — 190 行(行 1612)¶
async function generateParallelInsights(sections: InsightSection[], data: AggregatedData): Promise<InsightResults> {
// 行 1612
// 并行生成所有 sections
}
并行 —— Promise.all 同时生成多个 section 的 insight。
11. HTML 报告生成¶
11.1 4 个 chart helper¶
function generateBarChart(...) // 柱状图(SVG)
function generateResponseTimeHistogram(...) // 响应时间直方图
function generateTimeOfDayChart(...) // 时间分布
function getHourCountsJson(...) // JSON 数据
SVG chart helpers —— 不依赖外部库,手写 SVG。
11.2 generateHtmlReport — 700 行(行 1947-2655)¶
function generateHtmlReport(
data: AggregatedData,
insights: InsightResults,
exportData: InsightsExport,
): string {
// 行 1947
// 完整 HTML 报告
// 含 CSS + SVG + 数据可视化
}
700 行——单文件 700 行 HTML 生成: - 顶部摘要 - 多个 sections - 多个 charts (SVG) - 数据表 - 完整 CSS
自包含——单 HTML 文件,无外部依赖。
12. generateUsageReport — 230 行(行 2796)¶
export async function generateUsageReport(options?: {
daysBack?: number;
format?: 'html' | 'json';
outputPath?: string;
}): Promise<...> {
// 1. scanAllSessions()
// 2. 提取 facets (并行)
// 3. 聚合
// 4. 生成 insight
// 5. 输出 HTML/JSON
}
主入口 —— /insights 命令调它。
13. 关键设计模式¶
13.1 3 阶段:scan → extract → aggregate → generate¶
4 阶段管道: 1. Scan —— 读所有 session log 文件 2. Extract —— 调 API 提取 facets 3. Aggregate —— 聚合成统计 4. Generate —— 输出 HTML/JSON
13.2 缓存层(4 个 cache)¶
避免重复 API 调用 —— 第二次跑 /insights 毫秒级返回。
13.3 Long transcript 处理¶
formatTranscriptWithSummarization —— 长 transcript 先 Haiku summarize。
节省 token——避免一次 API 调用超过上下文窗口。
13.4 并行生成 insight¶
generateParallelInsights —— Promise.all 并行。
多 section 报告从 ~10s 降到 ~2s。
13.5 SVG charts 无外部库¶
generateBarChart / generateHistogram —— 手写 SVG。
单 HTML 文件——无 CDN 依赖。
13.6 Facets 提取 = "AI 总结 session"¶
FACET_EXTRACTION_PROMPT —— LLM 提取结构化字段。
LLM-as-classifier 模式。
13.7 安全 / 隐私¶
t('F') (isValidSessionFacets) 校验 facets 结构 —— 防止恶意 log 注入。
13.8 LiteSessionInfo 模式¶
减少内存 —— 不存完整 log,只存摘要。
14. 复杂度分析¶
| 维度 | 数字 |
|---|---|
| 总行数 | 3200 |
| 阶段 | 4 (scan/extract/aggregate/generate) |
| Cache 函数 | 4 (load/save × 2) |
| Chart helpers | 4 |
| generateHtmlReport | 700 行 |
| 模型调用 | 2 (analysis + insights) |
15. 性能特征¶
15.1 首次跑¶
- 扫描:~100ms-1s(取决于 session 数)
- Facets 提取:~30-60s(每个 session 调 API)
- 聚合:~100ms
- Insight 生成:~10-20s(多个 section 并行)
- HTML 生成:~100ms
- 总计 ~1-2min(100 sessions)
15.2 第二次跑(cache 命中)¶
- 全部从 cache 读
- ~1-2s 总时间
15.3 优化¶
- 4 层 cache
- 并行 API 调用
- Haiku summarize 节省 token
- 轻量级 session 索引
16. 与其他文件的关系¶
insights.ts
├──→ sessionStorage.ts (读 session log)
├──→ claude.ts (调 API 提取 facets / insight)
├──→ analytics/ (telemetry: 用户跑 /insights)
└──→ report.html (输出)
/insights 是"自省工具"——用户用它理解自己的使用模式。
17. 关键洞察¶
17.1 LLM-as-classifier = "用 LLM 提取结构化字段"¶
FACET_EXTRACTION_PROMPT 让 LLM 输出 JSON,比正则/规则强 100 倍。
17.2 Cache 是必需¶
不 cache 会每次跑都重新分析所有 session——慢得不可用。
17.3 长 transcript 分块 summarize¶
避免单次 API 超 token 限制——实际工程考量。
17.4 SVG charts 自包含¶
不用 Chart.js / D3 —— 单 HTML 文件可分享。
17.5 4 阶段管道清晰¶
scan → extract → aggregate → generate —— 每阶段可独立测试。
17.6 isValidSessionFacets 是安全¶
unknown → SessionFacets —— zod-like 校验防止恶意 log。
18. 阅读建议¶
- 看 4 个 type(行 228-420)—— 数据模型
- 看 extractToolStats(行 467)—— 工具统计
- 看 extractFacetsFromAPI(行 1001)—— LLM 提取
- 看 aggregateData(行 1145)—— 聚合
- 跳看 generateHtmlReport(行 1947)—— 700 行 HTML
- 看 generateUsageReport(行 2796)—— 入口
19. 与其他深度拆解的关系¶
| 文件 | 关系 |
|---|---|
sessionStorage.ts |
读 session log |
claude.ts |
调 API |
analytics/ |
telemetry |
report.html |
输出(运行时生成) |
20. 阅读清单¶
- ✅ 看 4 个 type(行 228-420)
- ✅ 看 extractToolStats(行 467)
- ✅ 看 extractFacetsFromAPI(行 1001)
- ✅ 看 aggregateData(行 1145)
- ✅ 看 generateUsageReport(行 2796)
- 📌 跑
/insights看实际报告
21. 练习任务¶
- 数 chart helpers(grep)—— 4 个 SVG 生成
- 数 cache 函数(grep)—— 4 个
- 画 4 阶段管道 —— scan → extract → aggregate → generate
- 手写迷你 insights(~50 行)—— 1 个 chart + 1 个 summary
- 思考:除了 LLM 提取 facets,还有什么方式能从 log 提取模式?