From ae83b9d4d81239e805b66da94b490404a86a90b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=97=AB=E6=97=AD=E9=9A=86?= <15945644+yan-xulong@user.noreply.gitee.com> Date: Wed, 12 Nov 2025 10:27:56 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=90=86=E8=A7=A3skill-v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- codebase_architecture_analyzer_v1.zip | Bin 0 -> 42428 bytes .../assets/report.md | 204 ++++++ .../assets/sequence.mermaid | 24 + .../reference/data-flow-analysis.md | 204 ++++++ .../reference/examples.md | 452 ++++++++++++ .../reference/knowledge.md | 511 ++++++++++++++ .../reference/patterns.md | 641 ++++++++++++++++++ .../reference/quick-scan.md | 408 +++++++++++ .../reference/report-generation.md | 259 +++++++ .../reference/system-analysis.md | 124 ++++ .../reference/workflow-extraction.md | 582 ++++++++++++++++ .../scripts/detect_tech_stack.py | 266 ++++++++ .../scripts/extract_dependencies.py | 167 +++++ codebase_architecture_analyzer_v1/skill.md | 165 +++++ 14 files changed, 4007 insertions(+) create mode 100644 codebase_architecture_analyzer_v1.zip create mode 100644 codebase_architecture_analyzer_v1/assets/report.md create mode 100644 codebase_architecture_analyzer_v1/assets/sequence.mermaid create mode 100644 codebase_architecture_analyzer_v1/reference/data-flow-analysis.md create mode 100644 codebase_architecture_analyzer_v1/reference/examples.md create mode 100644 codebase_architecture_analyzer_v1/reference/knowledge.md create mode 100644 codebase_architecture_analyzer_v1/reference/patterns.md create mode 100644 codebase_architecture_analyzer_v1/reference/quick-scan.md create mode 100644 codebase_architecture_analyzer_v1/reference/report-generation.md create mode 100644 codebase_architecture_analyzer_v1/reference/system-analysis.md create mode 100644 codebase_architecture_analyzer_v1/reference/workflow-extraction.md create mode 100644 codebase_architecture_analyzer_v1/scripts/detect_tech_stack.py create mode 100644 codebase_architecture_analyzer_v1/scripts/extract_dependencies.py create mode 100644 codebase_architecture_analyzer_v1/skill.md diff --git a/codebase_architecture_analyzer_v1.zip b/codebase_architecture_analyzer_v1.zip new file mode 100644 index 0000000000000000000000000000000000000000..049439308c08ee6158306cfbdbfa9c9ab0c921bf GIT binary patch literal 42428 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 生成时间: {TIMESTAMP} +> 分析工具: Claude Code - Codebase Architecture Analyzer + +--- + +## 一、项目概览 + +### 1.1 基本信息 + +- **项目类型**: {PROJECT_TYPE} +- **主要语言**: {PRIMARY_LANGUAGE} ({PRIMARY_FILE_COUNT} 个文件) +- **次要语言**: {SECONDARY_LANGUAGE} ({SECONDARY_FILE_COUNT} 个文件) +- **代码规模**: 约 {TOTAL_LINES} 行代码 + +### 1.2 技术栈 + +**后端**: +{BACKEND_STACK} + +**前端**: +{FRONTEND_STACK} + +**数据库**: +{DATABASE_STACK} + +**基础设施**: +{INFRASTRUCTURE_STACK} + +### 1.3 子系统组成 + +{SUBSYSTEMS_LIST} + +--- + +## 二、系统架构 + +### 2.1 架构图 + +```mermaid +{SYSTEM_ARCHITECTURE_DIAGRAM} +``` + +### 2.2 子系统详情 + +{SUBSYSTEMS_DETAILS} + +### 2.3 通信机制 + +{COMMUNICATION_MECHANISMS} + +--- + +## 三、核心业务流程 + +### 3.1 识别的架构模式 + +**核心模式**: {DETECTED_PATTERN} + +{PATTERN_DESCRIPTION} + +### 3.2 业务流程图 + +```mermaid +{WORKFLOW_DIAGRAM} +``` + +### 3.3 执行单元清单 + +{EXECUTION_UNITS_LIST} + +### 3.4 关键决策点 + +{DECISION_POINTS} + +--- + +## 四、数据流分析 + +### 4.1 数据流序列图 + +```mermaid +{SEQUENCE_DIAGRAM} +``` + +### 4.2 核心数据模型 + +{DATA_MODELS_LIST} + +### 4.3 数据转换链路 + +{DATA_TRANSFORMATION_CHAIN} + +--- + +## 五、快速上手指南 + +### 5.1 环境要求 + +{ENVIRONMENT_REQUIREMENTS} + +### 5.2 安装步骤 + +```bash +{INSTALLATION_STEPS} +``` + +### 5.3 启动命令 + +```bash +{STARTUP_COMMANDS} +``` + +### 5.4 核心入口文件 + +{ENTRY_POINTS_LIST} + +--- + +## 六、代码位置索引 + +### 6.1 核心业务逻辑 + +{CORE_LOGIC_INDEX} + +### 6.2 API 端点 + +{API_ENDPOINTS_INDEX} + +### 6.3 数据模型定义 + +{DATA_MODELS_INDEX} + +### 6.4 配置文件 + +{CONFIG_FILES_INDEX} + +--- + +## 七、代码质量概览 + +### 7.1 统计指标 + +- 总文件数: {TOTAL_FILES} +- 代码行数: {CODE_LINES} +- 注释行数: {COMMENT_LINES} +- 空行数: {BLANK_LINES} + +### 7.2 目录结构树 + +``` +{DIRECTORY_TREE} +``` + +--- + +## 八、外部资源 + +### 8.1 文档链接 + +{DOCUMENTATION_LINKS} + +### 8.2 学术论文 + +{PAPERS_LIST} + +### 8.3 参考资料 + +{REFERENCES_LIST} + +--- + +## 九、注意事项 + +### 9.1 已知限制 + +{KNOWN_LIMITATIONS} + +### 9.2 待验证事项 + +{TODO_VERIFY} + +--- + +## 附录 + +### A. 依赖清单 + +{DEPENDENCIES_LIST} + +### B. 环境变量 + +{ENVIRONMENT_VARIABLES} + +### C. 分析方法 + +本报告基于以下方法生成: +- 静态代码分析(AST 解析) +- 配置文件解析 +- 目录结构分析 +- 模式匹配识别 + +所有结论均基于代码事实,标注了具体的文件位置以供验证。 diff --git a/codebase_architecture_analyzer_v1/assets/sequence.mermaid b/codebase_architecture_analyzer_v1/assets/sequence.mermaid new file mode 100644 index 0000000..47e697e --- /dev/null +++ b/codebase_architecture_analyzer_v1/assets/sequence.mermaid @@ -0,0 +1,24 @@ +sequenceDiagram + participant U as 用户 + participant F as {FRONTEND_NAME} + participant B as {BACKEND_NAME} + participant C as {CORE_LOGIC_NAME} + participant D as {DATABASE_NAME} + + U->>F: {USER_ACTION} + Note over F: {FRONTEND_PROCESSING} + + F->>B: {API_REQUEST}
{REQUEST_PAYLOAD} + Note over B: {BACKEND_PROCESSING} + + B->>C: {CORE_INVOCATION}
{INVOCATION_PARAMS} + Note over C: {CORE_PROCESSING} + + C->>D: {DATA_OPERATION} + D-->>C: {DATA_RESPONSE} + + C-->>B: {CORE_RESULT} + B-->>F: {API_RESPONSE} + + Note over F: {FRONTEND_RENDERING} + F-->>U: {USER_RESULT} diff --git a/codebase_architecture_analyzer_v1/reference/data-flow-analysis.md b/codebase_architecture_analyzer_v1/reference/data-flow-analysis.md new file mode 100644 index 0000000..ab3c0dc --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/data-flow-analysis.md @@ -0,0 +1,204 @@ +# Phase 4: 数据流追踪指南 + +**执行时间**:约 1-2 分钟 + +**目标**:追踪核心数据的转换链路 + +--- + +## ⚠️ 重要约束 + +**在调用 Task tool 时,必须在 prompt 开头包含以下约束:** + +``` +⚠️ 重要约束:本次分析只返回文本结果,禁止生成任何文件(.md, .txt 等)。 +所有 Mermaid 图表、数据模型清单、转换链路都应包含在你的文本回复中,不要使用 Write 或其他文件创建工具。 +``` + +**Explore agent 只返回文本结果,不要生成任何文件。** + +--- + +## 分析步骤 + +### 步骤 1: 识别核心数据模型 + +使用 Grep 工具搜索数据模型定义: + +#### Python 项目 + +```bash +# Pydantic 模型 +grep -r "class.*BaseModel" --include="*.py" + +# Dataclass +grep -r "@dataclass" --include="*.py" + +# SQLAlchemy 模型 +grep -r "class.*Base" --include="*.py" +``` + +#### TypeScript 项目 + +```bash +# Interface 定义 +grep -r "interface.*{" --include="*.ts" + +# Type 别名 +grep -r "type.*=" --include="*.ts" + +# Class 定义 +grep -r "export class" --include="*.ts" +``` + +#### Go 项目 + +```bash +# Struct 定义 +grep -r "type.*struct" --include="*.go" +``` + +### 步骤 2: 追踪数据转换 + +1. **定位数据入口** + - 从 API 端点的请求体开始 + - 识别请求参数的类型定义 + +2. **追踪转换链路** + - 读取每个业务函数的参数类型和返回值类型 + - 记录每次类型转换的代码位置 + - 识别数据验证、清洗、增强步骤 + +3. **标注关键转换点** + - 序列化/反序列化 + - 数据库 ORM 映射 + - DTO(Data Transfer Object)转换 + - 业务逻辑处理 + +### 步骤 3: 生成序列图 + +使用 `assets/sequence.mermaid` 模板生成 Mermaid 序列图。 + +**⚠️ sequenceDiagram 语法约束(版本 11.x)**: +- `alt/loop/par` 块必须正确配对 `end` +- 使用 `
` 换行 + +--- + +## 预期输出格式 + +### 1. Mermaid 序列图 + +```mermaid +sequenceDiagram + participant U as 用户 + participant F as Frontend + participant B as Backend + participant R as Researcher + participant W as Writer + + U->>F: 输入查询 "AI 发展趋势" + F->>B: POST /api/research
{query, depth: 3} + Note over B: 构造 ResearchTask + B->>R: invoke(ResearchTask) + R->>R: 搜索引擎调用 + R-->>B: SearchResults (10 个文档) + B->>W: 传递 SearchResults + W->>W: GPT-4 生成报告 + W-->>B: Report (2000 字) + B->>F: 返回 HTML + F->>U: 展示报告 +``` + +### 2. 数据模型清单 + +列出所有核心数据模型及其位置: + +``` +核心数据模型: +1. ResearchTask (models/task.py:8) + - 用途: 用户查询任务 + - 字段: query: str, depth: int, filters: Optional[List[str]] + +2. SearchResults (models/results.py:15) + - 用途: 搜索结果集合 + - 字段: documents: List[Document], total: int, timestamp: datetime + +3. Report (models/report.py:22) + - 用途: 最终生成的报告 + - 字段: content: str, score: float, metadata: Dict[str, Any] +``` + +### 3. 数据转换链路 + +``` +数据流转路径: +用户输入 (str) + → ResearchTask (构造于 backend/routes.py:42) + → SearchResults (返回于 agents/researcher.py:67) + → Report (生成于 agents/writer.py:89) + → HTML (渲染于 backend/routes.py:58) + → 前端展示 +``` + +--- + +## 分析技巧 + +### 1. 类型提示追踪 + +Python 示例: +```python +# 从函数签名追踪类型流转 +def process_query(task: ResearchTask) -> SearchResults: + # task 类型: ResearchTask + results = search_engine.search(task.query) + # results 类型: SearchResults + return results +``` + +TypeScript 示例: +```typescript +// 从接口定义追踪 +interface ApiRequest { + query: string; + depth: number; +} + +async function handleRequest(req: ApiRequest): Promise { + // req 类型: ApiRequest + const results = await research(req); + // results 类型: Report + return results; +} +``` + +### 2. ORM 映射识别 + +SQLAlchemy 示例: +```python +# 数据库模型 → Pydantic 模型 +class UserDB(Base): + __tablename__ = "users" + id = Column(Integer, primary_key=True) + +class UserSchema(BaseModel): + id: int + # 从 UserDB 转换到 UserSchema +``` + +### 3. DTO 转换模式 + +```python +# 请求 DTO → 领域对象 → 响应 DTO +RequestDTO → DomainModel → ResponseDTO +``` + +--- + +## 注意事项 + +1. **关注核心路径**:只追踪主要业务流程的数据转换,忽略辅助功能 +2. **最多 5 层深度**:避免追踪过深导致图表过于复杂 +3. **标注转换位置**:每次类型转换都记录文件名和行号 +4. **区分同步/异步**:在序列图中用实线(同步)和虚线(异步)区分 diff --git a/codebase_architecture_analyzer_v1/reference/examples.md b/codebase_architecture_analyzer_v1/reference/examples.md new file mode 100644 index 0000000..7513e08 --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/examples.md @@ -0,0 +1,452 @@ +# 使用示例 + +本文档提供实际使用场景的示例。 + +## 示例 1: 分析 Multi-Agent AI 项目 + +### 项目结构 + +``` +ai-research-assistant/ +├── frontend/ +│ ├── src/ +│ │ ├── components/ +│ │ └── main.tsx +│ └── package.json +├── backend/ +│ ├── app/ +│ │ ├── main.py +│ │ └── routes.py +│ └── requirements.txt +└── agents/ + ├── graph.py + └── nodes.py +``` + +### 用户操作 + +``` +用户: 理解项目 +``` + +### Skill 执行过程 + +#### Phase 1: 快速扫描 (30秒) + +``` +⏳ 正在扫描项目结构... + +✓ 检测到配置文件: + - backend/requirements.txt (Python) + - frontend/package.json (JavaScript) + +✓ 读取依赖: + - Python: fastapi, langgraph, openai + - JavaScript: react, typescript + +✓ 扫描目录: + - frontend/ (82 个 .tsx 文件) + - backend/ (45 个 .py 文件) + - agents/ (8 个 .py 文件) + +✓ 快速扫描完成 + +项目类型: AI 驱动的 Web 应用 +主语言: Python (后端 + AI) +次要语言: TypeScript (前端) +核心框架: FastAPI + LangGraph + React +架构: 前后端分离 + Multi-Agent +``` + +#### Phase 2: 系统架构分析 (2分钟) + +``` +⏳ 调用 Explore sub-agent 分析系统架构... + +[Sub-agent 执行] +- 搜索 API 端点: @app.post, @router. +- 发现端点: /api/research, /api/status +- 搜索 WebSocket: WebSocket( +- 发现: /ws 实时通信端点 +- 搜索数据库: Redis, PostgreSQL +- 发现: Redis 缓存, PostgreSQL 持久化 + +✓ 系统架构分析完成 + +识别出 3 个子系统: +├─ Frontend (frontend/) +│ ├─ 技术: React 18 + TypeScript +│ └─ 入口: src/main.tsx:1 +├─ Backend (backend/) +│ ├─ 技术: FastAPI + Python 3.11 +│ └─ 入口: app/main.py:1 +└─ Agent Layer (agents/) + ├─ 技术: LangGraph 0.2.5 + └─ 入口: graph.py:1 + +通信机制: +- Frontend → Backend: WebSocket (/ws) +- Frontend → Backend: HTTP POST (/api/research) +- Backend → Agent Layer: 直接调用 invoke() +- Agent Layer → Redis: 缓存中间结果 +- Agent Layer → PostgreSQL: 持久化数据 +``` + +**生成的架构图**: + +```mermaid +graph TB + User[用户] --> Frontend[前端
React + TypeScript] + Frontend -->|WebSocket /ws| Backend[后端 API
FastAPI] + Frontend -->|POST /api/research| Backend + Backend -->|invoke| AgentLayer[Agent 编排层
LangGraph] + AgentLayer -->|缓存| Redis[(Redis)] + AgentLayer -->|持久化| DB[(PostgreSQL)] + + style AgentLayer fill:#f9f,stroke:#333,stroke-width:3px +``` + +**代码位置索引**: +- Frontend 入口: `frontend/src/main.tsx:1` +- Backend 入口: `backend/app/main.py:1` +- API 定义: `backend/app/routes.py:42` +- Agent 调用: `backend/app/routes.py:58` + +#### Phase 3: 核心流程提取 (5分钟) + +``` +⏳ 检测到 agents/ 目录,正在深度分析 Multi-Agent 编排... + +⏳ 调用 Explore sub-agent 提取工作流... + +[Sub-agent 执行] +- 搜索 StateGraph 定义 +- 发现: agents/graph.py:23 +- 提取 Agent 节点: + * researcher (agents/nodes.py:45) + * writer (agents/nodes.py:78) + * reviewer (agents/nodes.py:112) +- 分析流转规则: + * researcher → writer (顺序) + * writer → reviewer (顺序) + * reviewer → researcher (条件: quality < 7) + * reviewer → END (条件: quality >= 7) + +✓ Multi-Agent 编排流程解析完成 + +识别出 3 个 Agent: +1. Researcher (agents/nodes.py:45) + - 职责: 调用搜索 API 收集资料 + - 输入: ResearchTask + - 输出: List[Document] + +2. Writer (agents/nodes.py:78) + - 职责: 基于资料生成报告 + - 输入: List[Document] + - 输出: Report + +3. Reviewer (agents/edges.py:12) + - 职责: 评估报告质量 + - 决策: quality < 7 → 返回 Researcher + quality >= 7 → 结束流程 +``` + +**生成的流程图**: + +```mermaid +stateDiagram-v2 + [*] --> Researcher: 用户查询 + Researcher --> Writer: 研究完成 + Writer --> Reviewer: 生成草稿 + Reviewer --> Researcher: 质量不足
评分 < 7 + Reviewer --> [*]: 质量通过 + + note right of Researcher + agents/nodes.py:45 + 调用 Tavily 搜索 API + 返回 List[Document] + end note + + note right of Writer + agents/nodes.py:78 + 基于搜索结果 + 调用 GPT-4 生成报告 + end note + + note right of Reviewer + agents/edges.py:12 + 评估报告质量 + 决定是否重新研究 + end note +``` + +#### Phase 4: 数据流追踪 (1分钟) + +``` +⏳ 追踪数据流... + +✓ 识别核心数据模型: + - ResearchTask (models/task.py:8) + - SearchResults (models/results.py:15) + - Report (models/report.py:22) + +✓ 数据转换链路: + 用户输入 (str) + → ResearchTask (models/task.py:8) + → SearchResults (agents/researcher.py:45) + → Report (agents/writer.py:78) + → HTML (backend/routes.py:65) +``` + +**生成的序列图**: + +```mermaid +sequenceDiagram + participant U as 用户 + participant F as Frontend + participant B as Backend + participant R as Researcher + participant W as Writer + + U->>F: 输入查询 "AI 发展趋势" + F->>B: POST /api/research
{query, depth: 3} + Note over B: 构造 ResearchTask + B->>R: invoke(ResearchTask) + R->>R: 调用搜索引擎 + R-->>B: SearchResults (10 文档) + B->>W: 传递 SearchResults + W->>W: GPT-4 生成报告 + W-->>B: Report (2000 字) + B->>F: 返回 HTML + F->>U: 展示报告 +``` + +#### Phase 5: 生成报告 (30秒) + +``` +⏳ 生成最终报告... + +✓ 分析完成! + +报告已保存: PROJECT_ARCHITECTURE.md + +核心发现: +- 采用 LangGraph 编排 Multi-Agent 工作流 +- 支持条件路由和循环优化 +- 数据流: 查询 → 搜索 → 写作 → 审核 → 报告 + +快速上手: +1. 安装依赖: pip install -r backend/requirements.txt +2. 配置环境: cp .env.example .env +3. 启动后端: cd backend && uvicorn app.main:app --reload +4. 启动前端: cd frontend && npm install && npm start +5. 访问: http://localhost:3000 +``` + +--- + +## 示例 2: 分析微服务项目 + +### 项目结构 + +``` +ecommerce-platform/ +├── docker-compose.yml +├── services/ +│ ├── api-gateway/ +│ ├── user-service/ +│ ├── order-service/ +│ └── notification-service/ +└── shared/ +``` + +### 用户操作 + +``` +用户: 分析代码库架构 +``` + +### 执行过程(简化版) + +``` +[30s] ✓ 检测到 docker-compose.yml + 识别为微服务架构 + 发现 4 个服务: api-gateway, user-service, order-service, notification-service + +[2min] ✓ 服务调用拓扑图已生成 + api-gateway → user-service (HTTP GET /users/:id) + api-gateway → order-service (HTTP POST /orders) + api-gateway → notification-service (HTTP POST /notify) + +[5min] ✓ 报告已保存: PROJECT_ARCHITECTURE.md +``` + +**生成的架构图**: + +```mermaid +graph TB + Client[客户端] --> Gateway[API Gateway
:8000] + + Gateway -->|GET /users/:id| UserSvc[User Service
:8001] + Gateway -->|POST /orders| OrderSvc[Order Service
:8002] + Gateway -->|POST /notify| NotifySvc[Notification Service
:8003] + + UserSvc --> UserDB[(User DB
PostgreSQL)] + OrderSvc --> OrderDB[(Order DB
PostgreSQL)] + + style Gateway fill:#ff6b6b + style UserSvc fill:#4ecdc4 + style OrderSvc fill:#45b7d1 + style NotifySvc fill:#f9ca24 +``` + +--- + +## 示例 3: 分析 ETL 数据管道 + +### 项目结构 + +``` +data-pipeline/ +├── pipeline.py +├── extractors/ +├── transformers/ +└── loaders/ +``` + +### 执行结果 + +``` +[30s] ✓ 检测到 ETL 模式 + 识别函数: extract_from_csv, transform_data, load_to_database + +[3min] ✓ 数据管道流程图已生成 +``` + +**生成的流程图**: + +```mermaid +flowchart LR + CSV[CSV 文件] --> Extract[Extract
提取数据] + Extract --> Clean[Clean
去重] + Clean --> Enrich[Enrich
添加元数据] + Enrich --> Validate[Validate
校验] + Validate --> DB[(PostgreSQL)] + Validate --> S3[(S3 存储)] +``` + +--- + +## 示例 4: 只分析特定模块 + +### 用户操作 + +``` +用户: 只分析 agents/ 目录的工作流编排 +``` + +### 执行过程 + +``` +✓ 限定分析范围: agents/ + +[跳过 Phase 1, Phase 2] + +[3min] ✓ 深度分析 agents/ 目录完成 + +识别出 LangGraph 编排: +- 3 个 Agent 节点 +- 2 个条件分支 +- 1 个循环优化路径 + +流程图已生成(仅包含 agents/ 的逻辑) +``` + +--- + +## 示例 5: 更新现有分析 + +### 场景 + +项目代码已更新,需要重新分析。 + +### 用户操作 + +``` +用户: 更新架构分析报告 +``` + +### 执行过程 + +``` +✓ 检测到已存在 PROJECT_ARCHITECTURE.md + +[对比文件时间戳] +- agents/graph.py 已修改(2 天前) +- backend/routes.py 未修改 + +⏳ 只重新分析有变更的部分... + +[2min] ✓ 增量分析完成 + - Agent 层新增 1 个节点: Optimizer + - 流程图已更新 + +✓ 报告已更新: PROJECT_ARCHITECTURE.md +``` + +--- + +## 最佳实践 + +### 1. 项目克隆后立即分析 + +```bash +git clone https://github.com/user/project.git +cd project +# 打开 Claude Code +``` + +``` +理解项目 +``` + +优势:快速建立项目全景认知。 + +### 2. 结合其他 Skills + +``` +理解项目,然后生成开发者入门文档 +``` + +先分析架构,再基于分析结果生成文档。 + +### 3. 针对性分析 + +``` +只分析后端的 API 路由和业务逻辑 +``` + +节省时间,聚焦关键部分。 + +--- + +## 故障排除示例 + +### 问题: 无法识别自定义框架 + +**场景**: 公司内部自研框架 + +**解决方案**: + +手动提示: + +``` +这个项目使用了内部框架 InternalFlow,它的工作流定义在 workflows/ 目录, +请分析 workflows/ 中的 YAML 文件来理解流程编排。 +``` + +--- + +## 更多示例 + +查看 `patterns.md` 了解各种架构模式的详细识别案例。 diff --git a/codebase_architecture_analyzer_v1/reference/knowledge.md b/codebase_architecture_analyzer_v1/reference/knowledge.md new file mode 100644 index 0000000..d351647 --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/knowledge.md @@ -0,0 +1,511 @@ +# 架构分析方法论 + +本文档提供代码库架构分析的核心方法论和最佳实践。 + +## 目录 + +- [1. 子系统边界识别](#1-子系统边界识别) +- [2. 工作流模式识别](#2-工作流模式识别) +- [3. 通信机制识别](#3-通信机制识别) +- [4. Mermaid 图表选择策略](#4-mermaid-图表选择策略) +- [5. 业务函数识别规则](#5-业务函数识别规则) + +--- + +## 1. 子系统边界识别 + +### 规则 1: 目录命名模式 + +通过目录名称识别子系统: + +| 目录模式 | 子系统类型 | 常见技术栈 | +|---------|-----------|-----------| +| `frontend/`, `ui/`, `web/`, `client/` | 前端子系统 | React, Vue, Angular | +| `backend/`, `api/`, `server/` | 后端子系统 | FastAPI, Express, Django | +| `agent/`, `agents/`, `workers/` | Agent 系统 | LangGraph, CrewAI, Celery | +| `services/` + 多个子目录 | 微服务集群 | Spring Boot, Go microservices | +| `database/`, `models/`, `schema/` | 数据层 | SQLAlchemy, Prisma | +| `shared/`, `common/`, `lib/` | 共享库 | 工具函数、类型定义 | + +### 规则 2: 独立配置文件识别 + +每个子系统通常有独立的配置文件: + +``` +frontend/ +├── package.json → 独立的 Node.js 项目 +├── tsconfig.json +└── vite.config.js + +backend/ +├── requirements.txt → 独立的 Python 项目 +├── pyproject.toml +└── Dockerfile +``` + +**识别方法**: +```bash +# 查找独立的依赖文件 +find . -name "package.json" -o -name "requirements.txt" -o -name "go.mod" +``` + +### 规则 3: Docker Compose 服务划分 + +分析 `docker-compose.yml` 识别服务边界: + +```yaml +services: + frontend: # 前端服务 + build: ./frontend + api: # API 服务 + build: ./backend + worker: # 后台任务 + build: ./worker + db: # 数据库 + image: postgres:15 +``` + +每个 service 通常对应一个独立的子系统。 + +--- + +## 2. 工作流模式识别 + +### 模式 1: Multi-Agent 编排 + +**特征**: +- 导入 `langgraph`, `crewai`, `autogen` +- 存在 `StateGraph()`, `Crew()`, `Sequential()` 调用 +- 使用 `add_node()`, `add_edge()` 方法 + +**提取方法**: + +1. **定位编排定义** + ```bash + grep -r "StateGraph\|Crew\|AutoGen" --include="*.py" + ``` + +2. **提取 Agent 节点** + ```python + # 示例代码 + graph = StateGraph(AgentState) + graph.add_node("researcher", research_agent) # Agent 1 + graph.add_node("writer", writing_agent) # Agent 2 + graph.add_node("reviewer", review_agent) # Agent 3 + ``` + +3. **分析状态流转** + ```python + graph.add_edge("researcher", "writer") # 顺序流转 + graph.add_conditional_edges("writer", should_revise, { + "revise": "researcher", # 条件分支 + "finish": END + }) + ``` + +**生成图表类型**: `stateDiagram-v2` + +--- + +### 模式 2: 数据管道(ETL/Pipeline) + +**特征**: +- 目录名包含 `pipeline`, `etl`, `workflow` +- 函数名包含 `extract`, `transform`, `load` +- 使用 Airflow, Prefect, Dagster 框架 + +**提取方法**: + +1. **识别管道阶段** + ```python + # 示例代码 + def run_pipeline(source): + raw = extract(source) # 阶段 1 + clean = transform(raw) # 阶段 2 + load(clean) # 阶段 3 + ``` + +2. **追踪数据转换** + - 输入:CSV 文件 + - → DataFrame (pandas) + - → 清洗后 DataFrame + - → PostgreSQL 表 + +**生成图表类型**: `flowchart LR` (从左到右) + +--- + +### 模式 3: 事件驱动架构 + +**特征**: +- 使用 `EventEmitter`, `event_bus`, `@subscribe` +- 发布订阅模式:`emit()`, `on()`, `subscribe()` +- 消息队列:RabbitMQ, Kafka, Redis Pub/Sub + +**提取方法**: + +1. **识别事件定义** + ```python + # 发布事件 + event_bus.emit("order_created", order) + ``` + +2. **识别订阅者** + ```python + @event_bus.on("order_created") + def handle_order(order): + send_confirmation(order) + + @event_bus.on("order_created") + def update_inventory(order): + inventory.decrease(order.items) + ``` + +**生成图表类型**: `graph TB` (显示发布-订阅关系) + +--- + +### 模式 4: 微服务调用链 + +**特征**: +- `docker-compose.yml` 中有多个 services +- 使用 `requests.get()`, `httpx.get()` 调用其他服务 +- gRPC 调用:`stub.MethodCall()` + +**提取方法**: + +1. **识别服务间调用** + ```python + # api-gateway 调用其他服务 + user = requests.get("http://user-service/users/{id}") + order = requests.post("http://order-service/orders", ...) + ``` + +2. **绘制调用拓扑** + - api-gateway → user-service + - api-gateway → order-service + - order-service → payment-service + +**生成图表类型**: `graph TB` (服务拓扑) + +--- + +### 模式 5: 传统分层架构(MVC) + +**特征**: +- 目录结构:`controllers/`, `services/`, `models/` +- 装饰器:`@app.route`, `@Controller` +- ORM 使用:SQLAlchemy, Sequelize + +**提取方法**: + +1. **识别三层结构** + - Controller: 处理 HTTP 请求 + - Service: 业务逻辑 + - Model: 数据模型 + +2. **追踪调用链** + ``` + routes.py (@app.route) + → UserService.create() + → User model + → Database + ``` + +**生成图表类型**: `graph TD` (分层图) + +--- + +## 3. 通信机制识别 + +### HTTP/REST API + +**搜索关键词**: +```bash +# 服务端 +grep -r "@app\.(get|post|put|delete)" --include="*.py" +grep -r "router\.(get|post)" --include="*.js" +grep -r "@RestController" --include="*.java" + +# 客户端 +grep -r "axios\.(get|post)" --include="*.js" +grep -r "requests\.(get|post)" --include="*.py" +grep -r "fetch(" --include="*.ts" +``` + +### WebSocket + +**搜索关键词**: +```bash +grep -r "WebSocket\|socket.io\|ws://" --include="*.{py,js,ts}" +``` + +### 消息队列 + +**搜索关键词**: +```bash +# RabbitMQ +grep -r "pika\|RabbitMQ" --include="*.py" + +# Kafka +grep -r "kafka\|KafkaProducer" --include="*.{py,java}" + +# Redis Pub/Sub +grep -r "redis.*publish\|redis.*subscribe" --include="*.py" +``` + +### gRPC + +**搜索关键词**: +```bash +grep -r "grpc\|\.proto" --include="*.{py,go,java}" +``` + +--- + +## 4. Mermaid 图表选择策略 + +根据识别到的模式选择合适的图表类型: + +| 场景 | 图表类型 | 适用情况 | +|------|---------|---------| +| 状态转换明显(Multi-Agent) | `stateDiagram-v2` | 有明确的状态节点和转换条件 | +| 顺序+条件流程(业务流程) | `flowchart TD` | 顺序执行 + if/else 分支 | +| 数据管道(ETL) | `flowchart LR` | 线性的数据转换流程 | +| 系统拓扑(微服务) | `graph TB` | 多个系统/服务的交互关系 | +| 时序交互(API 调用) | `sequenceDiagram` | 多个参与者的时序消息传递 | +| 并发任务 | `graph TB` + subgraph | 多个并行任务分组 | + +### 语法注意事项 + +**⚠️ Mermaid 语法约束(基于版本 11.x)**: +- **stateDiagram-v2**: 禁用 `--` 分隔符(会报错 "No such shape: divider") +- **stateDiagram-v2**: 不支持 `
` 标签 +- **sequenceDiagram**: `alt/loop/par` 块必须正确配对 `end` +- **所有类型**: 避免过深嵌套的控制结构 + +**stateDiagram-v2 限制**: +- ❌ 不支持 `
` 标签,使用 `note` 块代替 +- ❌ 不支持 `--` 分隔符 +- ❌ 标签文本避免 `!=`, `==` 等比较运算符 +- ✅ 复杂信息放在 `note right/left of NodeName` 块中 + +**flowchart/graph**: +- ✅ 可使用 `
` 换行 +- ✅ 支持富文本标签 +- ✅ 使用 `style` 设置节点颜色 + +### 示例:选择决策树 + +``` +检测到的特征: + ├─ 有状态变量 + 转换逻辑? + │ → 是:使用 stateDiagram-v2 + │ → 否:继续判断 + │ + ├─ 有多个参与者 + 时序消息? + │ → 是:使用 sequenceDiagram + │ → 否:继续判断 + │ + ├─ 线性数据转换? + │ → 是:使用 flowchart LR + │ → 否:继续判断 + │ + └─ 默认:使用 graph TB 或 flowchart TD +``` + +--- + +## 5. 业务函数识别规则 + +### 排除辅助函数 + +**规则**:以下函数不算业务逻辑 + +```python +# 1. 私有函数(下划线开头) +def _internal_helper(): + pass + +# 2. 工具函数 +def format_date(date): + pass + +def validate_email(email): + pass + +# 3. Getter/Setter +def get_user(): + pass + +def set_config(): + pass + +# 4. 过短的函数(< 5 行) +def simple_wrapper(): + return another_function() +``` + +### 识别业务函数 + +**特征 1:函数名包含业务关键词** + +```python +业务动词: +- process_*, handle_*, execute_*, run_* +- create_*, update_*, delete_* +- generate_*, analyze_*, calculate_* +- search_*, fetch_*, query_* +- build_*, transform_*, convert_* +``` + +**特征 2:处理核心数据模型** + +```python +# 函数参数或返回值包含核心数据类 +def process_order(order: Order) -> OrderResult: # ✓ 业务函数 + ... + +def format_string(s: str) -> str: # ✗ 工具函数 + ... +``` + +**特征 3:函数体较长(> 10 行)** + +通常业务逻辑较复杂,函数体较长。 + +**特征 4:调用外部服务或数据库** + +```python +def create_user(data): + user = User(**data) + db.session.add(user) # ✓ 数据库操作 + db.session.commit() + send_email(user.email) # ✓ 外部服务 + return user +``` + +--- + +## 6. 调用链追踪深度控制 + +### 最大深度策略 + +**问题**:递归追踪可能陷入无限循环 + +**解决方案**:限制最大深度 + +```python +MAX_DEPTH = 5 # 最多追踪 5 层 + +def trace_calls(func_name, current_depth=0): + if current_depth >= MAX_DEPTH: + return + + calls = extract_function_calls(func_name) + for call in calls: + trace_calls(call, current_depth + 1) +``` + +### 广度优先 vs 深度优先 + +**广度优先(BFS)**: +- 优先展示同一层级的所有函数 +- 适合识别并发任务 + +**深度优先(DFS)**: +- 优先追踪单一调用链 +- 适合追踪数据转换流程 + +**推荐**:对于流程分析,使用 **广度优先**。 + +--- + +## 7. 最佳实践 + +### ✅ 应该做的 + +1. **先宽后深** - 先了解整体结构,再深入细节 +2. **只读分析** - 不修改任何代码 +3. **标注位置** - 所有结论都附带文件:行号 +4. **可视化优先** - 用图表表达复杂关系 +5. **分阶段输出** - 边分析边展示进度 + +### ❌ 不应该做的 + +1. **不要臆测** - 所有结论必须基于代码事实 +2. **不要分析 node_modules/** - 跳过第三方依赖 +3. **不要暴露敏感信息** - 不读取 `.env`, `secrets.yaml` +4. **不要过度深入** - 不需要分析每一个辅助函数 +5. **不要修改代码** - 纯只读分析 + +--- + +## 8. 故障排除 + +### 问题 1: 找不到入口点 + +**症状**:无法识别主函数 + +**解决方案**: +```bash +# 多种方式查找 +grep -r "if __name__ == '__main__'" --include="*.py" +grep -r "@app.route\|@app.post" --include="*.py" +grep -r "func main()" --include="*.go" +ls -la | grep -i "main\|index\|app" +``` + +### 问题 2: 调用链太复杂 + +**症状**:函数调用超过 100 层 + +**解决方案**: +- 只追踪业务函数,忽略工具函数 +- 限制最大深度为 5 +- 聚焦核心路径(最常用的调用链) + +### 问题 3: 动态导入无法追踪 + +**症状**:Python 的 `importlib`, JavaScript 的 `require(variable)` + +**解决方案**: +- 结合运行时日志分析 +- 搜索字符串模式猜测可能的模块名 +- 在报告中标注"动态导入,无法静态分析" + +--- + +## 9. 工具推荐 + +### Python 项目 + +- `ast` 模块 - 解析 Python AST +- `radon` - 复杂度分析 +- `pydeps` - 依赖可视化 + +### JavaScript/TypeScript 项目 + +- `@typescript-eslint/parser` - 解析 TS AST +- `madge` - 依赖关系图 +- `dependency-cruiser` - 依赖验证 + +### Go 项目 + +- `go-callvis` - 调用图可视化 +- `gocyclo` - 圈复杂度 + +### 通用工具 + +- `tree` - 目录结构可视化 +- `tokei` - 代码统计 +- `cloc` - 代码行数统计 + +--- + +## 10. 参考资源 + +- **C4 模型**: 系统架构可视化的四层模型 +- **UML 类图**: 面向对象系统的标准表示 +- **事件风暴**: 领域驱动设计的建模方法 +- **架构决策记录 (ADR)**: 记录架构决策的最佳实践 diff --git a/codebase_architecture_analyzer_v1/reference/patterns.md b/codebase_architecture_analyzer_v1/reference/patterns.md new file mode 100644 index 0000000..4ce5294 --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/patterns.md @@ -0,0 +1,641 @@ +# 常见架构模式参考 + +本文档提供各种架构模式的识别方法和 Mermaid 模板。 + +## 目录 + +- [1. Multi-Agent 架构](#1-multi-agent-架构) +- [2. 微服务架构](#2-微服务架构) +- [3. 事件驱动架构](#3-事件驱动架构) +- [4. 数据管道(ETL)](#4-数据管道etl) +- [5. 分层架构(MVC)](#5-分层架构mvc) +- [6. CQRS 架构](#6-cqrs-架构) + +--- + +## 1. Multi-Agent 架构 + +### 模式 1.1: LangGraph 编排 + +**代码特征**: +```python +from langgraph.graph import StateGraph, END + +# 定义状态 +class AgentState(TypedDict): + query: str + data: List[str] + result: str + +# 创建图 +graph = StateGraph(AgentState) + +# 添加节点(Agent) +graph.add_node("researcher", research_agent) +graph.add_node("writer", writing_agent) + +# 添加边(流转规则) +graph.add_edge("researcher", "writer") +graph.add_conditional_edges( + "writer", + should_continue, + { + "continue": "researcher", + "end": END + } +) + +# 设置入口 +graph.set_entry_point("researcher") +``` + +**识别方法**: +1. 搜索 `from langgraph` 或 `StateGraph` +2. 提取所有 `add_node()` 调用 → Agent 清单 +3. 提取所有 `add_edge()` 和 `add_conditional_edges()` → 流转规则 +4. 读取每个 Agent 函数的实现 + +**Mermaid 模板**: +```mermaid +stateDiagram-v2 + [*] --> Researcher: 用户查询 + Researcher --> Writer: 数据收集完成 + Writer --> QualityChecker: 生成草稿 + + QualityChecker --> Researcher: 质量不足
评分 < 7 + QualityChecker --> [*]: 质量通过 + + note right of Researcher + 文件: agents/researcher.py:45 + 职责: 调用搜索 API 收集资料 + 输入: ResearchTask + 输出: List[Document] + end note + + note right of Writer + 文件: agents/writer.py:78 + 职责: 基于资料生成报告 + 输入: List[Document] + 输出: Report + end note +``` + +**关键信息提取**: +- Agent 名称 +- 文件位置(文件:行号) +- 职责描述 +- 输入/输出类型 +- 条件分支逻辑 + +--- + +### 模式 1.2: CrewAI 编排 + +**代码特征**: +```python +from crewai import Agent, Task, Crew + +# 定义 Agent +researcher = Agent( + role="Researcher", + goal="Collect comprehensive information", + tools=[search_tool] +) + +writer = Agent( + role="Writer", + goal="Write engaging articles", + tools=[writing_tool] +) + +# 定义任务 +research_task = Task( + description="Research AI trends", + agent=researcher +) + +writing_task = Task( + description="Write article based on research", + agent=writer +) + +# 创建 Crew +crew = Crew( + agents=[researcher, writer], + tasks=[research_task, writing_task], + process=Process.sequential +) +``` + +**识别方法**: +1. 搜索 `from crewai` 或 `Agent(` +2. 提取所有 `Agent()` 定义 +3. 提取所有 `Task()` 定义 +4. 分析 `Crew()` 的 process 类型(sequential/hierarchical) + +**Mermaid 模板**: +```mermaid +flowchart TD + Start([开始]) --> Task1[Research Task
Agent: Researcher] + Task1 --> Task2[Writing Task
Agent: Writer] + Task2 --> End([结束]) + + style Task1 fill:#e1f5ff + style Task2 fill:#fff4e1 +``` + +--- + +### 模式 1.3: AutoGen 多智能体 + +**代码特征**: +```python +from autogen import AssistantAgent, UserProxyAgent + +# 定义 Agent +assistant = AssistantAgent( + name="assistant", + llm_config={"config_list": config_list} +) + +user_proxy = UserProxyAgent( + name="user_proxy", + code_execution_config={"work_dir": "coding"} +) + +# 发起对话 +user_proxy.initiate_chat( + assistant, + message="Analyze this dataset" +) +``` + +**Mermaid 模板**: +```mermaid +sequenceDiagram + participant User as UserProxy + participant Asst as AssistantAgent + + User->>Asst: 发起任务 + Asst->>Asst: 生成代码 + Asst->>User: 返回代码 + User->>User: 执行代码 + User->>Asst: 反馈执行结果 + Asst->>User: 最终答案 +``` + +--- + +## 2. 微服务架构 + +### 模式 2.1: Docker Compose 微服务 + +**代码特征**: +```yaml +# docker-compose.yml +services: + api-gateway: + build: ./api-gateway + ports: + - "8000:8000" + + user-service: + build: ./services/user-service + environment: + - DATABASE_URL=postgres://... + + order-service: + build: ./services/order-service + + notification-service: + build: ./services/notification-service +``` + +```python +# api-gateway/routes.py +@app.post("/orders") +def create_order(order_data): + # 调用 user-service + user = requests.get(f"http://user-service:8001/users/{user_id}") + + # 调用 order-service + order = requests.post("http://order-service:8002/orders", json=order_data) + + # 调用 notification-service + requests.post("http://notification-service:8003/notify", json={ + "user_id": user_id, + "order_id": order["id"] + }) + + return order +``` + +**识别方法**: +1. 读取 `docker-compose.yml`,提取所有 services +2. 在每个服务的代码中搜索 `requests.get|post`, `httpx.` +3. 提取目标 URL,识别服务间调用关系 + +**Mermaid 模板**: +```mermaid +graph TB + Client[客户端] --> Gateway[API Gateway
:8000] + + Gateway -->|GET /users/:id| UserSvc[User Service
:8001] + Gateway -->|POST /orders| OrderSvc[Order Service
:8002] + Gateway -->|POST /notify| NotifySvc[Notification Service
:8003] + + UserSvc --> UserDB[(User DB
PostgreSQL)] + OrderSvc --> OrderDB[(Order DB
PostgreSQL)] + + style Gateway fill:#ff6b6b + style UserSvc fill:#4ecdc4 + style OrderSvc fill:#45b7d1 + style NotifySvc fill:#f9ca24 +``` + +**关键信息提取**: +- 服务名称 +- 端口号 +- 服务间调用关系(from → to) +- 数据库连接 + +--- + +### 模式 2.2: Kubernetes 微服务 + +**代码特征**: +```yaml +# k8s/user-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: user-service +spec: + selector: + app: user-service + ports: + - port: 8001 +``` + +**识别方法**: +1. 查找 `k8s/`, `kubernetes/`, `.yaml` 文件 +2. 提取所有 `kind: Service` 定义 + +--- + +## 3. 事件驱动架构 + +### 模式 3.1: 事件总线(Event Bus) + +**代码特征**: +```python +# event_bus.py +class EventBus: + def __init__(self): + self._listeners = {} + + def on(self, event_name, handler): + self._listeners.setdefault(event_name, []).append(handler) + + def emit(self, event_name, data): + for handler in self._listeners.get(event_name, []): + handler(data) + +# handlers.py +@event_bus.on("order_created") +def send_confirmation_email(order): + email.send(order.customer_email, ...) + +@event_bus.on("order_created") +def update_inventory(order): + inventory.decrease(order.items) + +@event_bus.on("order_created") +def log_order(order): + logger.info(f"Order {order.id} created") + +# service.py +def create_order(order_data): + order = Order(**order_data) + db.save(order) + event_bus.emit("order_created", order) # 发布事件 +``` + +**识别方法**: +1. 搜索 `emit(`, `publish(`, `dispatch(` +2. 搜索 `@on(`, `@subscribe(`, `.on(` +3. 提取事件名称和对应的处理器 + +**Mermaid 模板**: +```mermaid +graph TB + OrderService[Order Service] -->|emit| Event[order_created 事件] + + Event --> Handler1[send_confirmation_email
handlers.py:15] + Event --> Handler2[update_inventory
handlers.py:28] + Event --> Handler3[log_order
handlers.py:42] + + Handler1 --> EmailSvc[Email Service] + Handler2 --> InventoryDB[(Inventory DB)] + Handler3 --> Logger[Logger] + + style Event fill:#ffd93d,stroke:#333,stroke-width:3px +``` + +--- + +### 模式 3.2: 消息队列(RabbitMQ/Kafka) + +**代码特征**: +```python +# producer.py +import pika + +connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) +channel = connection.channel() +channel.queue_declare(queue='tasks') + +def publish_task(task_data): + channel.basic_publish( + exchange='', + routing_key='tasks', + body=json.dumps(task_data) + ) + +# consumer.py +def callback(ch, method, properties, body): + task = json.loads(body) + process_task(task) + +channel.basic_consume( + queue='tasks', + on_message_callback=callback, + auto_ack=True +) +``` + +**Mermaid 模板**: +```mermaid +graph LR + Producer[任务生产者] -->|发布| Queue[(RabbitMQ
tasks 队列)] + Queue -->|消费| Consumer1[Worker 1] + Queue -->|消费| Consumer2[Worker 2] + Queue -->|消费| Consumer3[Worker 3] + + style Queue fill:#ff6b6b +``` + +--- + +## 4. 数据管道(ETL) + +### 模式 4.1: 顺序管道 + +**代码特征**: +```python +def run_pipeline(source_file): + # Step 1: Extract + raw_data = extract_from_csv(source_file) + + # Step 2: Transform + cleaned_data = remove_duplicates(raw_data) + enriched_data = add_metadata(cleaned_data) + validated_data = validate_schema(enriched_data) + + # Step 3: Load + load_to_database(validated_data) + load_to_s3(validated_data) +``` + +**Mermaid 模板**: +```mermaid +flowchart LR + CSV[CSV 文件] --> Extract[Extract
提取数据] + Extract --> Clean[Clean
去重] + Clean --> Enrich[Enrich
添加元数据] + Enrich --> Validate[Validate
校验] + Validate --> DB[(PostgreSQL)] + Validate --> S3[(S3 存储)] + + style Extract fill:#e1f5ff + style Clean fill:#fff4e1 + style Enrich fill:#e8f5e8 + style Validate fill:#ffe1e1 +``` + +--- + +### 模式 4.2: Airflow DAG + +**代码特征**: +```python +from airflow import DAG +from airflow.operators.python import PythonOperator + +dag = DAG('data_pipeline', schedule_interval='@daily') + +extract_task = PythonOperator( + task_id='extract', + python_callable=extract_data, + dag=dag +) + +transform_task = PythonOperator( + task_id='transform', + python_callable=transform_data, + dag=dag +) + +load_task = PythonOperator( + task_id='load', + python_callable=load_data, + dag=dag +) + +extract_task >> transform_task >> load_task +``` + +**Mermaid 模板**: +```mermaid +graph LR + Start([每日触发]) --> Extract[Extract Task] + Extract --> Transform[Transform Task] + Transform --> Load[Load Task] + Load --> End([完成]) +``` + +--- + +## 5. 分层架构(MVC) + +### 模式 5.1: 三层架构 + +**代码特征**: +```python +# routes.py (Controller 层) +@app.route("/users", methods=["POST"]) +def create_user(): + data = request.json + user = UserService.create(data) # 调用 Service 层 + return jsonify(user.to_dict()) + +# services/user_service.py (Service 层) +class UserService: + @staticmethod + def create(data): + # 业务逻辑 + if not validate_email(data["email"]): + raise ValueError("Invalid email") + + user = User(**data) # 使用 Model 层 + db.session.add(user) + db.session.commit() + return user + +# models/user.py (Model 层) +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + email = db.Column(db.String(120), unique=True) + name = db.Column(db.String(80)) +``` + +**Mermaid 模板**: +```mermaid +graph TD + Client[HTTP 客户端] -->|POST /users| Controller[Controller
routes.py] + + Controller --> Service[Service 层
user_service.py] + Service --> Model[Model 层
user.py] + Model --> DB[(Database)] + + Service --> Validator[验证器
validate_email] + + style Controller fill:#ff6b6b + style Service fill:#4ecdc4 + style Model fill:#45b7d1 +``` + +--- + +## 6. CQRS 架构 + +### 模式 6.1: 命令查询分离 + +**代码特征**: +```python +# commands/create_order.py (写操作) +class CreateOrderCommand: + def execute(self, order_data): + order = Order(**order_data) + write_db.save(order) + event_bus.emit("order_created", order) + +# queries/get_order.py (读操作) +class GetOrderQuery: + def execute(self, order_id): + return read_db.query(Order).filter_by(id=order_id).first() +``` + +**Mermaid 模板**: +```mermaid +graph TB + Client[客户端] + + Client -->|写操作| CommandHandler[Command Handler] + CommandHandler --> WriteDB[(Write DB
PostgreSQL)] + CommandHandler -->|发布事件| EventBus[Event Bus] + + Client -->|读操作| QueryHandler[Query Handler] + QueryHandler --> ReadDB[(Read DB
Redis/Elasticsearch)] + + EventBus -->|同步| ReadDB + + style CommandHandler fill:#ff6b6b + style QueryHandler fill:#4ecdc4 +``` + +--- + +## 7. 混合架构识别 + +### 示例:微服务 + 事件驱动 + CQRS + +**特征**: +- 多个独立服务(微服务) +- 服务间通过事件通信(事件驱动) +- 每个服务内部 CQRS(命令查询分离) + +**Mermaid 模板**: +```mermaid +graph TB + subgraph "Order Service" + OrderCmd[Command Handler] + OrderQuery[Query Handler] + OrderWriteDB[(Write DB)] + OrderReadDB[(Read DB)] + end + + subgraph "Inventory Service" + InvCmd[Command Handler] + InvQuery[Query Handler] + InvWriteDB[(Write DB)] + InvReadDB[(Read DB)] + end + + EventBus[Event Bus
RabbitMQ] + + OrderCmd --> OrderWriteDB + OrderCmd --> EventBus + OrderQuery --> OrderReadDB + + EventBus -->|order_created| InvCmd + InvCmd --> InvWriteDB + InvQuery --> InvReadDB + + style EventBus fill:#ffd93d +``` + +--- + +## 8. 模式识别决策树 + +``` +1. 检测 docker-compose.yml 或 k8s/ 目录 + → 是: 可能是微服务架构 + → 否: 继续 + +2. 检测 agents/ 目录 OR langgraph/crewai 导入 + → 是: Multi-Agent 架构 + → 否: 继续 + +3. 检测 emit/publish/subscribe + → 是: 事件驱动架构 + → 否: 继续 + +4. 检测 extract/transform/load 函数 + → 是: 数据管道架构 + → 否: 继续 + +5. 检测 routes/ + services/ + models/ + → 是: 分层架构(MVC) + → 否: 继续 + +6. 默认: 通用应用,分析主要调用链 +``` + +--- + +## 9. 使用建议 + +1. **不要生搬硬套** - 并非所有项目都符合标准模式 +2. **可以组合** - 一个项目可能同时使用多种模式 +3. **关注核心** - 识别最重要的架构特征 +4. **标注依据** - 在报告中注明识别依据(代码位置) + +--- + +## 10. 扩展阅读 + +- **Martin Fowler's Architecture Patterns**: https://martinfowler.com/architecture/ +- **Microservices Patterns**: https://microservices.io/patterns/ +- **Event Driven Architecture**: https://martinfowler.com/articles/201701-event-driven.html diff --git a/codebase_architecture_analyzer_v1/reference/quick-scan.md b/codebase_architecture_analyzer_v1/reference/quick-scan.md new file mode 100644 index 0000000..4b62774 --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/quick-scan.md @@ -0,0 +1,408 @@ +# 快速扫描指南 + +本指南提供项目快速扫描的详细步骤。 + +## 目标 + +在 30 秒内识别: +- 项目类型 +- 主要编程语言 +- 核心框架 +- 子系统组成 + +--- + +## 步骤 1: 运行技术栈检测脚本(推荐) + +**使用自动化脚本**: + +```bash +python ~/.claude/skills/codebase-architecture-analyzer/scripts/detect_tech_stack.py . +``` + +**脚本输出示例**: + +```json +{ + "project_path": "/path/to/project", + "stacks": [ + { + "language": "Python", + "frameworks": ["FastAPI", "LangGraph"], + "config_file": "pyproject.toml", + "version": "3.11" + }, + { + "language": "TypeScript", + "frameworks": ["React", "Next.js"], + "version": ">=18" + } + ], + "docker": { + "containerized": true, + "compose": true, + "services": ["backend", "frontend", "redis"] + } +} +``` + +**从输出提取信息**: + +- `stacks[].language` - 主要编程语言 +- `stacks[].frameworks` - 核心框架列表 +- `stacks[].version` - 语言/运行时版本 +- `docker.services` - Docker 服务列表(如果有) + +**脚本支持的语言**: +- Python (FastAPI, Django, Flask, LangGraph, CrewAI) +- JavaScript/TypeScript (React, Vue, Next.js, Express, NestJS) +- Go (Gin, Gorilla Mux, Fiber) +- Rust (Actix Web, Rocket, Axum) +- Java (Spring Boot, Quarkus) + +--- + +## 步骤 1.5: 分析依赖关系(可选,用于深度分析) + +**使用依赖分析脚本**: + +```bash +python ~/.claude/skills/codebase-architecture-analyzer/scripts/extract_dependencies.py . +``` + +**脚本输出示例**: + +```json +{ + "project_path": ".", + "analyses": [ + { + "language": "Python", + "files_analyzed": 45, + "total_imports": 23, + "third_party_imports": ["fastapi", "pydantic", "langchain", "openai"], + "declared_dependencies": ["fastapi", "pydantic", "langchain", "openai", "requests"], + "undeclared_usage": [], + "unused_dependencies": ["requests"] + }, + { + "language": "JavaScript/TypeScript", + "dependencies": ["react", "next", "tailwindcss"], + "dev_dependencies": ["typescript", "@types/react", "eslint"], + "total_dependencies": 6 + } + ] +} +``` + +**关键信息提取**: + +- `third_party_imports` - 实际使用的第三方包 +- `declared_dependencies` - 在配置文件中声明的依赖 +- `undeclared_usage` - **缺失的依赖**(代码中使用了,但未在 requirements.txt/pyproject.toml 中声明) +- `unused_dependencies` - **冗余的依赖**(声明了但代码中未使用) + +**使用场景**: + +✅ **推荐使用**(当满足以下条件时): +- 需要验证依赖完整性 +- 准备部署到生产环境 +- 项目有复杂的依赖关系 +- 发现依赖相关的 bug + +⚠️ **可跳过**(当满足以下条件时): +- 快速了解项目即可 +- 项目很小(< 10 个文件) +- 只关注整体架构 + +**输出解读**: + +1. **缺失依赖警告**:如果 `undeclared_usage` 不为空,说明需要更新 requirements.txt +2. **冗余依赖清理**:如果 `unused_dependencies` 不为空,可以移除不需要的依赖 +3. **依赖健康度**:`total_imports` vs `declared_dependencies` 的比例 + +--- + +## 步骤 2: 检测技术栈(手动方法) + +如果脚本无法运行或需要更详细分析,使用以下手动方法: + +### Python 项目 + +**识别文件**: +```bash +# 优先级从高到低 +1. pyproject.toml # 现代 Python 项目(Poetry/Hatch) +2. setup.py # 传统 Python 包 +3. requirements.txt # 依赖清单 +4. Pipfile # Pipenv 项目 +5. environment.yml # Conda 项目 +``` + +**提取信息**: +```bash +# 从 pyproject.toml 提取 +cat pyproject.toml | grep "python =" # Python 版本 +cat pyproject.toml | grep "\[tool.poetry.dependencies\]" -A 20 # 依赖 + +# 从 requirements.txt 提取 +cat requirements.txt | grep -E "fastapi|django|flask|langgraph" +``` + +--- + +### JavaScript/TypeScript 项目 + +**识别文件**: +```bash +1. package.json # Node.js 项目 +2. yarn.lock # Yarn 包管理 +3. pnpm-lock.yaml # pnpm 包管理 +4. tsconfig.json # TypeScript 配置 +``` + +**提取信息**: +```bash +# 从 package.json 提取 +cat package.json | grep "\"react\"\|\"vue\"\|\"express\"\|\"next\"" +``` + +--- + +### Go 项目 + +**识别文件**: +```bash +1. go.mod # Go modules +2. go.sum # 依赖锁文件 +``` + +**提取信息**: +```bash +cat go.mod | grep "require" -A 20 +``` + +--- + +### Rust 项目 + +**识别文件**: +```bash +1. Cargo.toml # Rust 项目配置 +2. Cargo.lock # 依赖锁文件 +``` + +--- + +### Java 项目 + +**识别文件**: +```bash +1. pom.xml # Maven 项目 +2. build.gradle # Gradle 项目 +``` + +--- + +## 步骤 3: 扫描目录结构 + +### 列出顶层目录 + +```bash +ls -d */ | head -20 +``` + +### 识别子系统模式 + +| 目录名 | 子系统类型 | +|-------|-----------| +| `frontend/`, `ui/`, `web/`, `client/` | 前端 | +| `backend/`, `api/`, `server/` | 后端 | +| `agents/`, `workers/` | Agent 系统 | +| `services/` + 多个子目录 | 微服务 | +| `src/components/` | React/Vue 组件 | +| `app/` | Next.js/Django 应用 | + +--- + +## 步骤 4: 检测关键配置文件 + +### Docker 相关 + +```bash +# docker-compose.yml → 多服务架构 +cat docker-compose.yml | grep "services:" -A 50 + +# Dockerfile → 容器化应用 +ls -la | grep Dockerfile +``` + +### 环境配置 + +```bash +# .env.example → 环境变量配置 +cat .env.example | grep -E "DATABASE_URL|REDIS_URL|API_KEY" +``` + +--- + +## 步骤 5: 识别项目规模 + +### 统计代码文件 + +```bash +# 统计各语言文件数量 +find . -type f -name "*.py" | wc -l +find . -type f -name "*.ts" -o -name "*.tsx" | wc -l +find . -type f -name "*.go" | wc -l +``` + +### 估算代码规模 + +```bash +# 使用 cloc(如果已安装) +cloc . --exclude-dir=node_modules,venv,.git +``` + +--- + +## 输出格式模板 + +``` +✓ 项目类型: [AI 研究助手 / Web 应用 / CLI 工具 / ...] +✓ 主语言: Python 3.11 (156 个文件) +✓ 次要语言: TypeScript (89 个文件) +✓ 核心框架: + - 后端: FastAPI 0.104.1 + - 前端: React 18.2.0 + - AI: LangGraph 0.2.5 +✓ 子系统: + - frontend/ (React + TypeScript) + - backend/ (FastAPI + Python) + - agents/ (LangGraph) +✓ 容器化: 是(docker-compose.yml) +✓ 代码规模: 约 12,500 行 +``` + +--- + +## 常见框架识别规则 + +### Python Web 框架 + +```python +依赖中包含: +- fastapi → FastAPI +- django → Django +- flask → Flask +- starlette → Starlette +- aiohttp → aiohttp +``` + +### Python AI 框架 + +```python +依赖中包含: +- langgraph → LangGraph +- crewai → CrewAI +- autogen → AutoGen +- langchain → LangChain +- transformers → Hugging Face +``` + +### JavaScript 框架 + +```json +dependencies 中包含: +- "react" → React +- "vue" → Vue.js +- "next" → Next.js +- "express" → Express.js +- "nestjs" → NestJS +``` + +--- + +## 快速判断项目类型 + +### CLI 工具 + +**特征**: +- 存在 `cli.py`, `main.py`, `cmd/` 目录 +- 依赖包含 `click`, `typer`, `argparse` +- `pyproject.toml` 中有 `[project.scripts]` + +### Web 应用 + +**特征**: +- 存在 `routes.py`, `views.py`, `app.py` +- 依赖包含 `fastapi`, `django`, `express` +- 存在 `assets/`, `static/` 目录 + +### AI/ML 项目 + +**特征**: +- 存在 `models/`, `agents/`, `pipelines/` +- 依赖包含 `tensorflow`, `pytorch`, `langchain` +- 存在 `notebooks/` 目录(Jupyter) + +### 数据工程项目 + +**特征**: +- 存在 `etl/`, `pipelines/`, `dags/` +- 依赖包含 `airflow`, `prefect`, `dbt` +- 存在 `sql/`, `queries/` 目录 + +--- + +## 故障排除 + +### 问题 1: 无法识别项目类型 + +**解决方案**: +1. 查看 README.md 的描述 +2. 搜索常见入口文件:`main.*`, `index.*`, `app.*` +3. 查看 git 提交历史:`git log --oneline | head -20` + +### 问题 2: 多语言混合项目 + +**解决方案**: +- 统计各语言文件数量,确定主次 +- 识别前后端分离:`frontend/` + `backend/` + +--- + +## 完整示例 + +```bash +# 1. 检测配置文件 +ls -la | grep -E "package.json|pyproject.toml|go.mod|Cargo.toml" + +# 输出: pyproject.toml, package.json (前后端分离项目) + +# 2. 读取 Python 依赖 +cat pyproject.toml | grep -A 30 dependencies + +# 输出: fastapi, langgraph, openai (AI Web 应用) + +# 3. 读取 JS 依赖 +cat package.json | grep -A 20 dependencies + +# 输出: react, typescript (React 前端) + +# 4. 扫描目录 +ls -d */ + +# 输出: frontend/, backend/, agents/, docs/ + +# 5. 统计代码 +find backend -name "*.py" | wc -l # 156 个文件 +find frontend -name "*.ts*" | wc -l # 89 个文件 + +# 最终识别结果: +✓ 项目类型: AI 驱动的 Web 应用 +✓ 主语言: Python (后端 + AI) +✓ 次要语言: TypeScript (前端) +✓ 核心框架: FastAPI + LangGraph + React +✓ 架构: 前后端分离 + Multi-Agent +``` diff --git a/codebase_architecture_analyzer_v1/reference/report-generation.md b/codebase_architecture_analyzer_v1/reference/report-generation.md new file mode 100644 index 0000000..9381a91 --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/report-generation.md @@ -0,0 +1,259 @@ +# Phase 5: 报告生成指南 + +**执行时间**:约 30 秒 + +**目标**:汇总所有分析结果,生成完整的架构分析报告 + +--- + +## 生成步骤 + +### 步骤 1: 收集所有分析结果 + +从前 4 个 Phase 收集以下信息: + +1. **Phase 1 - 快速扫描** + - 项目类型 + - 主要编程语言 + - 核心框架 + - 子系统列表 + - 代码规模 + +2. **Phase 2 - 系统架构** + - 系统架构 Mermaid 图 + - 子系统清单(名称、路径、技术栈、入口文件) + - 通信关系列表 + +3. **Phase 3 - 核心流程** + - 工作流 Mermaid 图(stateDiagram-v2 / flowchart) + - 执行单元清单(Agent / 服务 / 函数) + - 关键决策点 + +4. **Phase 4 - 数据流** + - 序列图 Mermaid + - 数据模型清单 + - 数据转换链路 + +### 步骤 2: 使用模板生成报告 + +使用 `assets/report.md` 模板,将收集的信息填充到相应章节。 + +### 步骤 3: 添加快速上手指南 + +从项目文件中提取以下信息: + +1. **环境要求** + - 从 README.md 或 pyproject.toml 提取 + - Python/Node.js 版本要求 + - 系统依赖(Docker、Redis 等) + +2. **安装步骤** + - 依赖安装命令 + - 环境变量配置 + - 数据库初始化 + +3. **启动命令** + - 开发环境启动命令 + - 生产环境部署命令 + - 测试运行命令 + +4. **核心入口文件** + - 主入口文件路径 + - 配置文件路径 + - 关键模块路径 + +### 步骤 4: 生成代码位置索引 + +汇总所有关键文件的位置: + +``` +代码位置索引: +├─ 入口文件 +│ ├─ 后端入口: backend/app/main.py:1 +│ └─ 前端入口: frontend/src/main.tsx:1 +├─ 核心模块 +│ ├─ Agent 编排: agents/graph.py:23 +│ ├─ 研究 Agent: agents/nodes.py:45 +│ └─ 写作 Agent: agents/nodes.py:78 +├─ API 端点 +│ ├─ 研究 API: backend/app/routes.py:42 +│ └─ WebSocket: backend/app/routes.py:58 +└─ 数据模型 + ├─ ResearchTask: models/task.py:8 + └─ Report: models/report.py:22 +``` + +### 步骤 5: 保存报告 + +将生成的报告保存到项目根目录: + +- **保存路径**: `PROJECT_ARCHITECTURE.md` + +--- + +## 报告结构模板 + +```markdown +# [项目名] 架构分析报告 + +> 生成时间: [YYYY-MM-DD HH:MM:SS] +> 分析工具: Claude Code - Codebase Architecture Analyzer + +--- + +## 一、项目概览 + +**项目类型**: [自动推断] +**主要语言**: [Python 3.11] +**核心框架**: [FastAPI + LangGraph] +**代码规模**: [156 个 Python 文件, 89 个 TypeScript 文件] + +**子系统**: +- frontend/ (React + TypeScript) +- backend/ (FastAPI + Python) +- agents/ (LangGraph) + +--- + +## 二、系统架构 + +### 2.1 架构图 + +```mermaid +[Phase 2 生成的 Mermaid 图] +``` + +### 2.2 子系统详情 + +[Phase 2 生成的子系统清单] + +### 2.3 通信机制 + +[Phase 2 生成的通信关系列表] + +--- + +## 三、核心业务流程 + +### 3.1 流程图 + +```mermaid +[Phase 3 生成的 Mermaid 图] +``` + +### 3.2 执行单元清单 + +[Phase 3 生成的 Agent/服务/函数清单] + +### 3.3 关键决策点 + +[Phase 3 识别的条件分支和路由规则] + +--- + +## 四、数据流分析 + +### 4.1 序列图 + +```mermaid +[Phase 4 生成的 Mermaid 序列图] +``` + +### 4.2 数据模型清单 + +[Phase 4 生成的数据模型列表] + +### 4.3 数据转换链路 + +[Phase 4 追踪的数据流转路径] + +--- + +## 五、快速上手指南 + +### 5.1 环境要求 + +- Python 3.11+ +- Node.js 18+ +- Docker (可选) + +### 5.2 安装步骤 + +```bash +# 1. 安装后端依赖 +pip install -r backend/requirements.txt + +# 2. 安装前端依赖 +cd frontend && npm install + +# 3. 配置环境变量 +cp .env.example .env +``` + +### 5.3 启动命令 + +```bash +# 启动后端 +cd backend && uvicorn app.main:app --reload + +# 启动前端 +cd frontend && npm start +``` + +### 5.4 核心入口文件 + +- 后端入口: `backend/app/main.py` +- 前端入口: `frontend/src/main.tsx` +- Agent 编排: `agents/graph.py` + +--- + +## 六、代码位置索引 + +[Phase 2-4 汇总的所有关键文件位置] + +--- + +## 附录:分析方法说明 + +本报告由 Claude Code 的 `codebase-architecture-analyzer` Skill 自动生成。 + +分析方法: +- Phase 1: 快速扫描(识别技术栈) +- Phase 2: 系统架构分析(Explore sub-agent) +- Phase 3: 核心流程提取(智能模式识别) +- Phase 4: 数据流追踪(类型追踪) +- Phase 5: 报告生成(本文档) +``` + +--- + +## 输出示例 + +执行完成后,向用户显示: + +``` +✓ 分析完成! + +报告已保存: PROJECT_ARCHITECTURE.md + +核心发现: +- 采用 LangGraph 编排 Multi-Agent 工作流 +- 支持条件路由和循环优化 +- 数据流: 查询 → 搜索 → 写作 → 审核 → 报告 + +快速上手: +1. 安装依赖: pip install -r requirements.txt +2. 配置环境: cp .env.example .env +3. 启动后端: uvicorn app.main:app --reload +4. 启动前端: cd frontend && npm start +``` + +--- + +## 注意事项 + +1. **Mermaid 图表检查**:确保所有 Mermaid 代码块语法正确 +2. **代码位置准确性**:所有文件路径和行号必须准确 +3. **快速上手可用性**:安装步骤必须可执行,不能遗漏关键步骤 +4. **避免敏感信息**:不要在报告中包含 `.env` 文件内容或 API 密钥 diff --git a/codebase_architecture_analyzer_v1/reference/system-analysis.md b/codebase_architecture_analyzer_v1/reference/system-analysis.md new file mode 100644 index 0000000..9af8ae9 --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/system-analysis.md @@ -0,0 +1,124 @@ +# Phase 2: 系统架构分析指南 + +**执行时间**:约 2 分钟 + +**目标**:识别子系统边界和通信机制 + +--- + +## ⚠️ 重要约束 + +**Explore agent 只返回文本结果,不要生成任何文件。** + +--- + +## 分析方法 + +使用 **Task tool** 调用内置的 **Explore sub-agent** 进行深度分析。 + +### 步骤 1: 启动 Task tool + +指定以下参数: +- `subagent_type: Explore` +- `description: "系统架构分析"` +- `prompt`: 包含下面的详细任务 + +### 步骤 2: Sub-agent 任务定义 + +``` +⚠️ 重要约束:本次分析只返回文本结果,禁止生成任何文件(.md, .txt 等)。 +所有 Mermaid 图表、清单、分析结论都应包含在你的文本回复中,不要使用 Write 或其他文件创建工具。 + +分析项目的子系统划分和通信机制: + +1. 子系统边界识别 + - 扫描顶层目录,识别 frontend/, backend/, agents/ 等模式 + - 查找独立配置文件(package.json, requirements.txt) + - 解析 docker-compose.yml 中的 services + +2. API 端点定位 + - 搜索:@app.(get|post|put|delete) + - 搜索:@router., app.route + - 提取端点路径和处理函数位置 + +3. 通信协议识别 + - HTTP: requests.get/post, axios, fetch + - WebSocket: WebSocket, socket.io + - 消息队列: RabbitMQ, Kafka, Redis pub/sub + - gRPC: grpc, .proto + +4. 数据库连接 + - PostgreSQL: psycopg2, SQLAlchemy + - Redis: redis.Redis + - MongoDB: pymongo + +输出格式: +- 子系统清单(名称、路径、技术栈、入口文件:行号) +- 通信关系(from → to, 协议, 端点) +- 生成 Mermaid graph TB 架构图(使用 `
` 换行) +``` + +### 步骤 3: 执行过程 + +1. **Explore sub-agent 自动执行**:使用 Glob、Grep、Read 工具搜索代码 +2. **接收结果**:sub-agent 返回分析报告 +3. **验证结果**:检查是否包含所有子系统和通信关系 + +--- + +## 预期输出格式 + +### 1. Mermaid 系统架构图 + +```mermaid +graph TB + User[用户] --> Frontend[前端
React + TypeScript] + Frontend -->|HTTP POST /api/research| Backend[后端 API
FastAPI] + Frontend -->|WebSocket /ws| Backend + Backend -->|invoke| AgentLayer[Agent 编排层
LangGraph] + AgentLayer -->|缓存| Redis[(Redis)] + AgentLayer -->|持久化| DB[(PostgreSQL)] + + style AgentLayer fill:#f9f,stroke:#333,stroke-width:3px +``` + +### 2. 代码位置索引 + +- Frontend 入口: `frontend/src/main.tsx:1` +- Backend 入口: `backend/app/main.py:1` +- API 定义: `backend/app/routes.py:42` +- Agent 调用: `backend/app/routes.py:58` + +### 3. 子系统清单 + +``` +识别出 3 个子系统: +├─ Frontend (frontend/) +│ ├─ 技术: React 18 + TypeScript +│ └─ 入口: src/main.tsx:1 +├─ Backend (backend/) +│ ├─ 技术: FastAPI + Python 3.11 +│ └─ 入口: app/main.py:1 +└─ Agent Layer (agents/) + ├─ 技术: LangGraph 0.2.5 + └─ 入口: graph.py:1 +``` + +### 4. 通信机制 + +``` +- Frontend → Backend: WebSocket (/ws) +- Frontend → Backend: HTTP POST (/api/research) +- Backend → Agent Layer: 直接调用 invoke() +- Agent Layer → Redis: 缓存中间结果 +- Agent Layer → PostgreSQL: 持久化数据 +``` + +--- + +## 注意事项 + +1. **配置文件优先**:优先解析 docker-compose.yml,它通常包含完整的服务拓扑 +2. **多种通信协议**:一个项目可能同时使用 HTTP、WebSocket、消息队列 +3. **入口文件定位**:确保记录每个子系统的主入口文件和行号 +4. **Mermaid 样式**:使用 `style` 语法突出显示核心子系统 diff --git a/codebase_architecture_analyzer_v1/reference/workflow-extraction.md b/codebase_architecture_analyzer_v1/reference/workflow-extraction.md new file mode 100644 index 0000000..7476f48 --- /dev/null +++ b/codebase_architecture_analyzer_v1/reference/workflow-extraction.md @@ -0,0 +1,582 @@ +# 工作流提取详细指南 + +本指南提供通用的工作流提取算法,适用于各种架构模式。 + +## ⚠️ 重要约束 + +**在调用 Task tool 时,必须在 prompt 开头包含以下约束:** + +``` +⚠️ 重要约束:本次分析只返回文本结果,禁止生成任何文件(.md, .txt 等)。 +所有 Mermaid 图表、清单、分析结论都应包含在你的文本回复中,不要使用 Write 或其他文件创建工具。 +``` + +**Explore agent 只返回文本结果,不要生成任何文件。** + +--- + +## 核心思想 + +**不预设架构类型,而是从代码中提取执行流程特征。** + +--- + +## 算法概览 + +``` +1. 定位入口点(CLI/Web/定时任务) +2. 提取函数调用链(递归追踪) +3. 识别业务函数(排除辅助函数) +4. 分析流程模式(顺序/分支/循环/并发) +5. 生成 Mermaid 图表 +``` + +--- + +## 步骤 1: 定位入口点 + +### 1.1 CLI 应用 + +**Python**: +```bash +grep -rn "if __name__ == '__main__'" --include="*.py" +grep -rn "@click.command\|@click.group" --include="*.py" +grep -rn "argparse.ArgumentParser" --include="*.py" +``` + +**示例**: +```python +# main.py:45 +if __name__ == "__main__": + main() # ← 入口函数 +``` + +**Go**: +```bash +grep -rn "func main()" --include="*.go" +``` + +--- + +### 1.2 Web 应用 + +**FastAPI/Flask**: +```bash +grep -rn "@app\.(get|post|put|delete)" --include="*.py" +grep -rn "@router\." --include="*.py" +``` + +**示例**: +```python +# routes.py:42 +@app.post("/api/research") # ← 入口点 +def research_endpoint(query: str): + ... +``` + +**Express.js**: +```bash +grep -rn "app\.(get|post)" --include="*.js" +grep -rn "router\." --include="*.js" +``` + +--- + +### 1.3 定时任务 + +**Celery**: +```bash +grep -rn "@celery.task\|@shared_task" --include="*.py" +``` + +**Airflow**: +```bash +grep -rn "DAG(" --include="*.py" +``` + +**Cron/APScheduler**: +```bash +grep -rn "@schedule\|@cron" --include="*.py" +``` + +--- + +### 1.4 消息消费者 + +**RabbitMQ/Kafka**: +```bash +grep -rn "basic_consume\|KafkaConsumer" --include="*.py" +``` + +**示例**: +```python +# consumer.py:25 +def callback(ch, method, properties, body): # ← 入口点 + process_message(body) +``` + +--- + +## 步骤 2: 提取函数调用链 + +### 2.1 读取入口函数 + +从步骤 1 识别的入口点开始: + +```python +# 示例:routes.py:42 +@app.post("/api/research") +def research_endpoint(query: str): + task = create_task(query) # 调用 1 + results = executor.run(task) # 调用 2 + return format_response(results) # 调用 3 +``` + +**提取调用清单**: +``` +research_endpoint +├── create_task +├── executor.run +└── format_response +``` + +--- + +### 2.2 递归追踪 + +读取 `executor.run` 的实现: + +```python +# executor.py:78 +def run(self, task): + data = self.fetch_data(task) # 调用 2.1 + processed = self.process(data) # 调用 2.2 + return self.finalize(processed) # 调用 2.3 +``` + +**更新调用树**: +``` +research_endpoint +├── create_task +├── executor.run +│ ├── fetch_data +│ ├── process +│ └── finalize +└── format_response +``` + +--- + +### 2.3 控制递归深度 + +**问题**: 可能陷入无限递归 + +**解决方案**: 限制最大深度 + +```python +MAX_DEPTH = 5 # 最多追踪 5 层 + +def trace_calls(func_name, depth=0): + if depth >= MAX_DEPTH: + return [] + + calls = extract_calls_from_function(func_name) + result = [] + + for call in calls: + result.append(call) + result.extend(trace_calls(call, depth + 1)) + + return result +``` + +--- + +## 步骤 3: 识别业务函数 + +### 3.1 排除辅助函数 + +**规则**: + +| 函数特征 | 是否保留 | +|---------|---------| +| 私有函数 `_helper()` | ❌ 排除 | +| 工具函数 `format_date()` | ❌ 排除 | +| Getter/Setter | ❌ 排除 | +| 函数体 < 5 行 | ❌ 排除 | +| 包含业务关键词 | ✅ 保留 | +| 调用数据库/外部 API | ✅ 保留 | +| 处理核心数据模型 | ✅ 保留 | + +--- + +### 3.2 业务关键词清单 + +```python +BUSINESS_KEYWORDS = [ + # 处理动词 + "process", "handle", "execute", "run", + + # CRUD 操作 + "create", "update", "delete", "query", "fetch", + + # 业务逻辑 + "calculate", "analyze", "generate", "transform", + "search", "filter", "validate", "verify", + + # 工作流 + "orchestrate", "coordinate", "schedule" +] +``` + +**示例判断**: +```python +✅ process_order() # 包含 "process" +✅ create_user() # 包含 "create" +✅ analyze_data() # 包含 "analyze" +❌ format_string() # 工具函数 +❌ _internal_helper() # 私有函数 +❌ get_config() # Getter +``` + +--- + +### 3.3 检测数据库/API 调用 + +**数据库调用**: +```python +def create_user(data): + user = User(**data) + db.session.add(user) # ✅ 数据库操作 + db.session.commit() + return user +``` + +**外部 API 调用**: +```python +def fetch_weather(city): + response = requests.get( # ✅ 外部 API + f"https://api.weather.com/{city}" + ) + return response.json() +``` + +**搜索模式**: +```bash +# 数据库 +grep -n "db\.session\|query(\|execute(" file.py + +# HTTP 请求 +grep -n "requests\.\|httpx\.\|fetch(" file.py +``` + +--- + +## 步骤 4: 分析流程模式 + +### 4.1 顺序流程 + +**代码特征**: +```python +def process(): + step1() + step2() + step3() +``` + +**识别**: 连续的函数调用,无分支 + +**生成图表**: `flowchart TD` (从上到下) + +--- + +### 4.2 条件分支 + +**代码特征**: +```python +def process(data): + if validate(data): + path_a() + else: + path_b() +``` + +**识别**: `if/else`, `match/case`, 三元运算符 + +**生成图表**: `flowchart TD` (带菱形决策节点) + +--- + +### 4.3 循环优化 + +**代码特征**: +```python +def optimize(data): + while not is_good_enough(data): + data = improve(data) + return data +``` + +**识别**: `while` + 条件判断 + +**生成图表**: `flowchart TD` (带循环边) + +--- + +### 4.4 状态机 + +**代码特征**: +```python +state = "init" + +if state == "init": + state = "processing" +elif state == "processing": + if condition: + state = "done" + else: + state = "error" +``` + +**识别**: 状态变量 + 状态转换逻辑 + +**生成图表**: `stateDiagram-v2` + +--- + +### 4.5 并发编排 + +**Python asyncio**: +```python +results = await asyncio.gather( + task1(), + task2(), + task3() +) +``` + +**JavaScript Promise.all**: +```javascript +const results = await Promise.all([ + fetchUser(), + fetchOrders(), + fetchProducts() +]); +``` + +**识别**: `asyncio.gather`, `Promise.all`, `WaitGroup` + +**生成图表**: `graph TB` + subgraph (并行任务分组) + +--- + +### 4.6 图编排(LangGraph) + +**代码特征**: +```python +graph = StateGraph(State) +graph.add_node("a", func_a) +graph.add_node("b", func_b) +graph.add_edge("a", "b") +graph.add_conditional_edges("b", router, { + "continue": "a", + "end": END +}) +``` + +**识别**: `add_node`, `add_edge`, `add_conditional_edges` + +**生成图表**: `stateDiagram-v2` + +--- + +## 步骤 5: 生成 Mermaid 图表 + +**⚠️ Mermaid 语法约束(版本 11.x)**: +- **stateDiagram-v2**: 禁用 `--` 分隔符,不支持 `
` +- **sequenceDiagram**: `alt/loop/par` 块必须正确配对 `end` +- **所有类型**: 使用 `
` 换行(stateDiagram-v2 除外) + +### 5.1 选择图表类型 + +```python +def select_diagram_type(flow_pattern): + if flow_pattern == "state_machine": + return "stateDiagram-v2" + + elif flow_pattern == "concurrent": + return "graph TB" # 带 subgraph + + elif flow_pattern == "sequential_with_conditions": + return "flowchart TD" + + elif flow_pattern == "linear_pipeline": + return "flowchart LR" + + else: + return "graph TB" # 默认 +``` + +--- + +### 5.2 生成状态图(Multi-Agent) + +**输入数据**: +```python +nodes = [ + {"name": "researcher", "file": "agents/nodes.py", "line": 45}, + {"name": "writer", "file": "agents/nodes.py", "line": 78} +] + +edges = [ + {"from": "researcher", "to": "writer"}, + { + "from": "writer", + "to": "researcher", + "condition": "quality < 7" + } +] +``` + +**生成代码**: +```python +def generate_state_diagram(nodes, edges): + mermaid = "stateDiagram-v2\n" + mermaid += f" [*] --> {nodes[0]['name']}\n" + + for edge in edges: + if "condition" in edge: + mermaid += f" {edge['from']} --> {edge['to']}: {edge['condition']}\n" + else: + mermaid += f" {edge['from']} --> {edge['to']}\n" + + # 添加注释 + for node in nodes: + mermaid += f"\n note right of {node['name']}\n" + mermaid += f" {node['file']}:{node['line']}\n" + mermaid += f" end note\n" + + return mermaid +``` + +--- + +### 5.3 生成流程图(顺序+分支) + +**输入数据**: +```python +steps = [ + {"name": "extract", "type": "process"}, + {"name": "validate", "type": "decision"}, + {"name": "transform", "type": "process"}, + {"name": "load", "type": "process"} +] + +connections = [ + {"from": "extract", "to": "validate"}, + {"from": "validate", "to": "transform", "condition": "valid"}, + {"from": "validate", "to": "error_handler", "condition": "invalid"} +] +``` + +**生成代码**: +```python +def generate_flowchart(steps, connections): + mermaid = "flowchart TD\n" + + # 定义节点 + for step in steps: + if step["type"] == "decision": + mermaid += f" {step['name']}{{{step['name']}}}\n" # 菱形 + else: + mermaid += f" {step['name']}[{step['name']}]\n" # 矩形 + + # 连接 + for conn in connections: + if "condition" in conn: + mermaid += f" {conn['from']} -->|{conn['condition']}| {conn['to']}\n" + else: + mermaid += f" {conn['from']} --> {conn['to']}\n" + + return mermaid +``` + +--- + +## 完整示例 + +### 示例代码 + +```python +# routes.py:42 +@app.post("/api/research") +def research_endpoint(query: str): + task = create_research_task(query) + results = execute_research(task) + return results + +# research.py:15 +def execute_research(task): + # 并发搜索 + search_results = asyncio.gather( + search_google(task.query), + search_arxiv(task.query) + ) + + # 生成报告 + if len(search_results) > 5: + report = generate_detailed_report(search_results) + else: + report = generate_summary(search_results) + + return report +``` + +--- + +### 提取结果 + +**入口点**: `research_endpoint` (routes.py:42) + +**调用链**: +``` +research_endpoint +├── create_research_task +└── execute_research + ├── search_google (并发) + ├── search_arxiv (并发) + └── generate_detailed_report OR generate_summary (条件) +``` + +**流程模式**: 顺序 + 并发 + 条件分支 + +--- + +### 生成 Mermaid 图 + +```mermaid +flowchart TD + Start([API 请求]) --> CreateTask[创建研究任务] + CreateTask --> Concurrent{并发搜索} + + Concurrent --> Google[搜索 Google] + Concurrent --> ArXiv[搜索 ArXiv] + + Google --> Merge[合并结果] + ArXiv --> Merge + + Merge --> Decision{结果数量} + Decision -->|> 5 篇| Detailed[生成详细报告] + Decision -->|≤ 5 篇| Summary[生成摘要] + + Detailed --> End([返回结果]) + Summary --> End +``` + +## 最佳实践 + +1. **先广度后深度** - 先了解整体流程 +2. **限制递归深度** - 避免无限循环 +3. **过滤辅助函数** - 只关注业务逻辑 +4. **标注代码位置** - 便于验证 +5. **可视化优先** - 图表比文字更直观 diff --git a/codebase_architecture_analyzer_v1/scripts/detect_tech_stack.py b/codebase_architecture_analyzer_v1/scripts/detect_tech_stack.py new file mode 100644 index 0000000..7350c8c --- /dev/null +++ b/codebase_architecture_analyzer_v1/scripts/detect_tech_stack.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python3 +""" +技术栈检测脚本 + +用法: python detect_tech_stack.py [项目路径] + +输出: JSON 格式的技术栈信息 +""" + +import json +import sys +from pathlib import Path +from typing import Dict, List, Optional + + +def detect_python_stack(project_path: Path) -> Optional[Dict]: + """检测 Python 技术栈""" + result = {"language": "Python", "frameworks": [], "dependencies": []} + + # 查找配置文件 + pyproject = project_path / "pyproject.toml" + requirements = project_path / "requirements.txt" + setup_py = project_path / "setup.py" + + if pyproject.exists(): + content = pyproject.read_text(encoding='utf-8') + result["config_file"] = "pyproject.toml" + + # 检测 Python 版本 + if 'python = "^' in content: + version = content.split('python = "^')[1].split('"')[0] + result["version"] = version + + # 检测框架 + if "fastapi" in content.lower(): + result["frameworks"].append("FastAPI") + if "django" in content.lower(): + result["frameworks"].append("Django") + if "flask" in content.lower(): + result["frameworks"].append("Flask") + if "langgraph" in content.lower(): + result["frameworks"].append("LangGraph") + if "crewai" in content.lower(): + result["frameworks"].append("CrewAI") + + elif requirements.exists(): + content = requirements.read_text(encoding='utf-8') + result["config_file"] = "requirements.txt" + + # 检测框架 + for line in content.split('\n'): + line = line.strip().lower() + if line.startswith('fastapi'): + result["frameworks"].append("FastAPI") + elif line.startswith('django'): + result["frameworks"].append("Django") + elif line.startswith('flask'): + result["frameworks"].append("Flask") + elif line.startswith('langgraph'): + result["frameworks"].append("LangGraph") + + else: + return None + + return result + + +def detect_javascript_stack(project_path: Path) -> Optional[Dict]: + """检测 JavaScript/TypeScript 技术栈""" + package_json = project_path / "package.json" + + if not package_json.exists(): + return None + + result = {"language": "JavaScript/TypeScript", "frameworks": [], "dependencies": []} + + try: + import json as json_module + content = json_module.loads(package_json.read_text(encoding='utf-8')) + + # 检测框架 + deps = {**content.get("dependencies", {}), **content.get("devDependencies", {})} + + if "react" in deps: + result["frameworks"].append("React") + if "@types/react" in deps: + result["language"] = "TypeScript" + if "vue" in deps: + result["frameworks"].append("Vue.js") + if "next" in deps: + result["frameworks"].append("Next.js") + if "express" in deps: + result["frameworks"].append("Express.js") + if "@nestjs/core" in deps: + result["frameworks"].append("NestJS") + + # 检测 Node 版本 + if "engines" in content and "node" in content["engines"]: + result["version"] = content["engines"]["node"] + + except Exception as e: + print(f"Error parsing package.json: {e}", file=sys.stderr) + return None + + return result + + +def detect_go_stack(project_path: Path) -> Optional[Dict]: + """检测 Go 技术栈""" + go_mod = project_path / "go.mod" + + if not go_mod.exists(): + return None + + result = {"language": "Go", "frameworks": [], "dependencies": []} + + content = go_mod.read_text(encoding='utf-8') + + # 检测 Go 版本 + for line in content.split('\n'): + if line.strip().startswith('go '): + result["version"] = line.strip().split()[1] + break + + # 检测框架 + if "gin-gonic/gin" in content: + result["frameworks"].append("Gin") + if "gorilla/mux" in content: + result["frameworks"].append("Gorilla Mux") + if "fiber" in content: + result["frameworks"].append("Fiber") + + return result + + +def detect_rust_stack(project_path: Path) -> Optional[Dict]: + """检测 Rust 技术栈""" + cargo_toml = project_path / "Cargo.toml" + + if not cargo_toml.exists(): + return None + + result = {"language": "Rust", "frameworks": [], "dependencies": []} + + content = cargo_toml.read_text(encoding='utf-8') + + # 检测框架 + if "actix-web" in content: + result["frameworks"].append("Actix Web") + if "rocket" in content: + result["frameworks"].append("Rocket") + if "axum" in content: + result["frameworks"].append("Axum") + + return result + + +def detect_java_stack(project_path: Path) -> Optional[Dict]: + """检测 Java 技术栈""" + pom_xml = project_path / "pom.xml" + build_gradle = project_path / "build.gradle" + + if pom_xml.exists(): + result = {"language": "Java", "frameworks": [], "build_tool": "Maven"} + content = pom_xml.read_text(encoding='utf-8') + + # 检测框架 + if "spring-boot" in content: + result["frameworks"].append("Spring Boot") + if "quarkus" in content: + result["frameworks"].append("Quarkus") + + return result + + elif build_gradle.exists(): + result = {"language": "Java", "frameworks": [], "build_tool": "Gradle"} + content = build_gradle.read_text(encoding='utf-8') + + # 检测框架 + if "spring-boot" in content: + result["frameworks"].append("Spring Boot") + + return result + + return None + + +def detect_docker_usage(project_path: Path) -> Dict: + """检测 Docker 使用情况""" + docker_compose = project_path / "docker-compose.yml" + dockerfile = project_path / "Dockerfile" + + result = {"containerized": False, "services": []} + + if docker_compose.exists(): + result["containerized"] = True + result["compose"] = True + + # 简单解析 services + content = docker_compose.read_text(encoding='utf-8') + in_services = False + for line in content.split('\n'): + if line.strip() == "services:": + in_services = True + continue + if in_services and line.startswith(' ') and ':' in line and not line.strip().startswith('#'): + service_name = line.strip().rstrip(':') + if service_name and not service_name.startswith('-'): + result["services"].append(service_name) + + elif dockerfile.exists(): + result["containerized"] = True + result["compose"] = False + + return result + + +def main(): + # 获取项目路径 + if len(sys.argv) > 1: + project_path = Path(sys.argv[1]) + else: + project_path = Path.cwd() + + if not project_path.exists(): + print(f"Error: Path {project_path} does not exist", file=sys.stderr) + sys.exit(1) + + # 检测各种技术栈 + stacks = [] + + python_stack = detect_python_stack(project_path) + if python_stack: + stacks.append(python_stack) + + js_stack = detect_javascript_stack(project_path) + if js_stack: + stacks.append(js_stack) + + go_stack = detect_go_stack(project_path) + if go_stack: + stacks.append(go_stack) + + rust_stack = detect_rust_stack(project_path) + if rust_stack: + stacks.append(rust_stack) + + java_stack = detect_java_stack(project_path) + if java_stack: + stacks.append(java_stack) + + # 检测 Docker + docker_info = detect_docker_usage(project_path) + + # 输出结果 + result = { + "project_path": str(project_path), + "stacks": stacks, + "docker": docker_info + } + + print(json.dumps(result, indent=2, ensure_ascii=False)) + + +if __name__ == "__main__": + main() diff --git a/codebase_architecture_analyzer_v1/scripts/extract_dependencies.py b/codebase_architecture_analyzer_v1/scripts/extract_dependencies.py new file mode 100644 index 0000000..ad420ac --- /dev/null +++ b/codebase_architecture_analyzer_v1/scripts/extract_dependencies.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +""" +依赖提取脚本 + +用法: python extract_dependencies.py [项目路径] + +输出: JSON 格式的依赖信息 +""" + +import ast +import json +import sys +from pathlib import Path +from typing import Dict, List, Set + + +def extract_python_imports(file_path: Path) -> Set[str]: + """从 Python 文件提取 import""" + imports = set() + + try: + with open(file_path, 'r', encoding='utf-8') as f: + tree = ast.parse(f.read(), filename=str(file_path)) + + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + # 只保留顶层包名 + module = alias.name.split('.')[0] + imports.add(module) + + elif isinstance(node, ast.ImportFrom): + if node.module: + module = node.module.split('.')[0] + imports.add(module) + + except Exception as e: + print(f"Warning: Failed to parse {file_path}: {e}", file=sys.stderr) + + return imports + + +def analyze_python_project(project_path: Path) -> Dict: + """分析 Python 项目的依赖""" + all_imports = set() + file_count = 0 + + # 遍历所有 Python 文件 + for py_file in project_path.rglob("*.py"): + # 跳过虚拟环境和 node_modules + if any(part in py_file.parts for part in ['venv', 'env', '.venv', 'node_modules', '__pycache__']): + continue + + file_count += 1 + imports = extract_python_imports(py_file) + all_imports.update(imports) + + # 读取声明的依赖 + declared_deps = set() + + requirements_txt = project_path / "requirements.txt" + if requirements_txt.exists(): + for line in requirements_txt.read_text(encoding='utf-8').split('\n'): + line = line.strip() + if line and not line.startswith('#'): + # 去掉版本号 + dep = line.split('==')[0].split('>=')[0].split('~=')[0].strip() + declared_deps.add(dep) + + pyproject_toml = project_path / "pyproject.toml" + if pyproject_toml.exists(): + content = pyproject_toml.read_text(encoding='utf-8') + # 简单提取(不使用 toml 库) + in_deps = False + for line in content.split('\n'): + if '[tool.poetry.dependencies]' in line or '[project.dependencies]' in line: + in_deps = True + continue + if in_deps and line.strip().startswith('['): + break + if in_deps and '=' in line: + dep = line.split('=')[0].strip().strip('"') + if dep != 'python': + declared_deps.add(dep) + + # Python 标准库(部分常见的) + stdlib = { + 'os', 'sys', 'json', 'time', 'datetime', 'collections', 'itertools', + 'functools', 'pathlib', 're', 'math', 'random', 'typing', 'abc', + 'asyncio', 'logging', 'unittest', 'argparse', 'subprocess', 'io', + 'copy', 'pickle', 'sqlite3', 'http', 'urllib', 'email', 'uuid' + } + + # 区分第三方包和标准库 + third_party = all_imports - stdlib + + return { + "language": "Python", + "files_analyzed": file_count, + "total_imports": len(all_imports), + "third_party_imports": list(sorted(third_party)), + "declared_dependencies": list(sorted(declared_deps)), + "undeclared_usage": list(sorted(third_party - declared_deps)), + "unused_dependencies": list(sorted(declared_deps - third_party)) + } + + +def analyze_javascript_project(project_path: Path) -> Dict: + """分析 JavaScript 项目的依赖""" + package_json = project_path / "package.json" + + if not package_json.exists(): + return None + + try: + import json as json_module + content = json_module.loads(package_json.read_text(encoding='utf-8')) + + dependencies = content.get("dependencies", {}) + dev_dependencies = content.get("devDependencies", {}) + + return { + "language": "JavaScript/TypeScript", + "dependencies": list(dependencies.keys()), + "dev_dependencies": list(dev_dependencies.keys()), + "total_dependencies": len(dependencies) + len(dev_dependencies) + } + + except Exception as e: + print(f"Error parsing package.json: {e}", file=sys.stderr) + return None + + +def main(): + # 获取项目路径 + if len(sys.argv) > 1: + project_path = Path(sys.argv[1]) + else: + project_path = Path.cwd() + + if not project_path.exists(): + print(f"Error: Path {project_path} does not exist", file=sys.stderr) + sys.exit(1) + + results = [] + + # 分析 Python + python_result = analyze_python_project(project_path) + if python_result["files_analyzed"] > 0: + results.append(python_result) + + # 分析 JavaScript + js_result = analyze_javascript_project(project_path) + if js_result: + results.append(js_result) + + # 输出结果 + output = { + "project_path": str(project_path), + "analyses": results + } + + print(json.dumps(output, indent=2, ensure_ascii=False)) + + +if __name__ == "__main__": + main() diff --git a/codebase_architecture_analyzer_v1/skill.md b/codebase_architecture_analyzer_v1/skill.md new file mode 100644 index 0000000..2e554c5 --- /dev/null +++ b/codebase_architecture_analyzer_v1/skill.md @@ -0,0 +1,165 @@ +--- +name: codebase-architecture-analyzer +description: 用于理解开源项目。当用户说"理解项目"、"分析代码库"、"项目架构"、"梳理架构"时自动触发。自动识别技术栈、子系统边界、核心业务流程,生成 Mermaid 架构图和流程图。 +allowed-tools: [Read, Glob, Grep, Bash, Task] +--- + +# 代码库架构分析 Skill + +你是架构逆向工程专家,能从源代码反向推导系统架构和业务逻辑流程。 + +## 核心任务 + +- 📊 识别子系统边界(frontend/backend/agent/database) +- 🔄 追踪核心业务流程(工作流编排/数据管道/事件驱动) +- 📈 生成 Mermaid 架构图和流程图 +- 🧠 智能模式识别(Multi-Agent/微服务/分层架构) +- 📝 生成项目理解报告 + +--- + +## 执行流程 + +### ⚠️ 路径使用规范 + +所有脚本路径**必须使用波浪号 `~` 表示法**(跨平台兼容): + +```bash +export PYTHONIOENCODING=utf-8 && python ~/.claude/skills/codebase-architecture-analyzer/scripts/detect_tech_stack.py . +``` + +**说明**: +- `~/.claude/...` 在 Windows/macOS/Linux 均可正确解析 +- `export PYTHONIOENCODING=utf-8` 用于处理中文/emoji 输出 + +--- + +### Phase 1: 快速扫描 + +**目标**:识别项目类型和主要组成 + +**执行步骤**: +1. **运行技术栈检测脚本** + - 使用 Bash 工具执行:`export PYTHONIOENCODING=utf-8 && python ~/.claude/skills/codebase-architecture-analyzer/scripts/detect_tech_stack.py .` + - 脚本会输出 JSON 格式的技术栈信息(语言、框架、Docker 配置等) + - 解析 JSON 结果获取: + - 主要编程语言(Python/JavaScript/Go/Rust/Java) + - 核心框架(FastAPI/React/Django/LangGraph 等) + - Docker 服务配置 + +2. **分析依赖关系** + - 使用 Bash 工具执行:`export PYTHONIOENCODING=utf-8 && python ~/.claude/skills/codebase-architecture-analyzer/scripts/extract_dependencies.py .` + - 脚本会分析实际使用的依赖 vs 声明的依赖 + - 识别: + - 第三方依赖列表 + - 缺失的依赖声明(使用了但未声明) + - 未使用的依赖(声明了但未使用) + +3. **扫描目录结构** + - 使用 Glob 工具识别顶层目录(frontend/, backend/, agents/, services/ 等) + - 确认子系统边界 + +4. **统计代码规模** + - 使用 Bash 工具执行:`find . -type f -name "*.py" | wc -l`(针对主要语言) + - 估算项目规模 + +**详细指南**: `reference/quick-scan.md` + +--- + +### Phase 2: 系统架构分析 + +**目标**:识别子系统边界和通信机制 + +**执行步骤**: +1. **先读取详细指南**:使用 Read 工具读取 `~/.claude/skills/codebase-architecture-analyzer/reference/system-analysis.md` +2. **按照指南执行分析**:使用 Task tool 调用 Explore sub-agent 进行分析 + +**预期输出**: +- Mermaid graph TB 系统架构图 +- 子系统清单(名称、路径、技术栈、入口文件:行号) +- 通信关系列表 + +--- + +### Phase 3: 核心流程提取 + +**目标**:识别项目的核心业务逻辑编排 + +**执行步骤**: +1. **先读取详细指南**:使用 Read 工具读取 `~/.claude/skills/codebase-architecture-analyzer/reference/workflow-extraction.md` +2. **智能路由策略**:根据 Phase 1 的扫描结果自动选择分析重点 + - 检测到 agents/ + (langgraph/crewai/autogen) → Multi-Agent 工作流编排 + - 检测到 docker-compose.yml 多服务 → 微服务调用链 + - 检测到 airflow/workflow/pipeline → 数据管道流程 + - 检测到 EventEmitter/event_bus → 事件驱动流程 + - 其他 → 通用业务流程调用链 +3. **按照指南执行分析**:使用 Task tool 调用 Explore sub-agent 进行分析 + +**预期输出**: +- Mermaid 流程图(stateDiagram-v2 / flowchart TD) +- 执行单元清单(Agent/服务/函数,含文件:行号、职责、输入/输出) +- 关键决策点(条件函数、分支路径) + +--- + +### Phase 4: 数据流追踪 + +**目标**:追踪核心数据的转换链路 + +**执行步骤**: +1. **先读取详细指南**:使用 Read 工具读取 `~/.claude/skills/codebase-architecture-analyzer/reference/data-flow-analysis.md` +2. **按照指南执行分析**:使用 Task tool 调用 Explore sub-agent 进行分析 + +**预期输出**: +- Mermaid 序列图 +- 数据模型清单(名称、文件:行号、用途、字段) +- 数据转换链路 + +--- + +### Phase 5: 生成最终报告 + +**目标**:汇总所有分析结果,生成 Markdown 报告文件 + +**执行步骤**: +1. **先读取详细指南**:使用 Read 工具读取 `~/.claude/skills/codebase-architecture-analyzer/reference/report-generation.md` +2. **收集所有Phase的结果**:汇总 Phase 1-4 的分析数据 +3. **该阶段必须生成报告文件**:在项目根目录下创建真实的 `PROJECT_ARCHITECTURE.md`文件,并使用Write工具写入 + +**报告内容**: + +- 项目概览(Phase 1 结果) +- 系统架构(Phase 2 架构图 + 子系统详情) +- 核心业务流程(Phase 3 流程图 + 执行单元清单) +- 数据流分析(Phase 4 序列图 + 数据模型清单) +- 快速上手指南(环境要求、安装步骤、启动命令) +- 代码位置索引(所有关键文件清单) + +**完成后告知用户**: +``` +✅ 分析完成!报告已保存: PROJECT_ARCHITECTURE.md +``` + +--- + +## 方法论参考 + +执行过程中根据需要查阅以下文档: + +- **reference/knowledge.md** - 架构分析方法论(子系统识别规则、通信机制识别、Mermaid 图表选择策略、业务函数识别规则) +- **reference/patterns.md** - 常见架构模式参考(Multi-Agent、微服务、事件驱动、ETL、MVC、CQRS) +- **reference/examples.md** - 实际使用案例(5 个完整示例) + +--- + +## 注意事项 + +1. **只读分析** - 本 Skill 不会修改任何代码文件 +2. **敏感信息** - 不会在报告中暴露 `.env` 等敏感文件内容 +3. **私有仓库** - 不会访问网络,仅分析本地代码 +4. **自动跳过** - 自动跳过 node_modules, venv, .git 等常见依赖目录 + +--- + +现在开始分析当前项目。