fix: code compliance audit and fix across all services
NestJS (6 services): implement @RequirePermission decorator with SetMetadata+Reflector, register APP_GUARD globally, fix as assertions to type guards, add explicit return types, fix import type for express, fix /metrics implicit any, replace native Error with ApplicationError, remove typeorm remnants, register LifecycleService. teacher-bff: add logger, ApplicationError, GlobalErrorFilter, forward real userId to downstream, log downstream failures, migrate health controller to shared/health. Go (2 services): interface to any, doc comments, CORS dev whitelist, JWT secret fail-fast, push-gateway internal API auth, metrics and readyz endpoints, remove dead code. Python (2 services): lifespan return type, dev_mode to bool, data-ana APIRouter, ai POST body model, ClickHouse async wrapping.
This commit is contained in:
333
docs/architecture/ai06-phase1-understanding.md
Normal file
333
docs/architecture/ai06-phase1-understanding.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# ai06 阶段 1 交付物:模块理解确认书
|
||||
|
||||
> AI 标识:ai06
|
||||
> 负责模块:data-ana(P4)、ai(P5)
|
||||
> 语言:Python 3.12+ / FastAPI 0.115+
|
||||
> 阶段:架构设计外包 · 阶段 1(全局理解)
|
||||
> 日期:2026-07-09
|
||||
> 关联文档:[ai-allocation.md](./ai-allocation.md)、[004 架构影响地图](./004_architecture_impact_map.md)、[pending-features.md](./roadmap/pending-features.md)、[known-issues.md](../troubleshooting/known-issues.md)
|
||||
|
||||
---
|
||||
|
||||
## 阶段 1 必读清单完成确认
|
||||
|
||||
按 ai-allocation.md §4,ai06 必读 7 份全局文档 + 全部 `.proto` + `services/data-ana/`、`services/ai/` 骨架源码:
|
||||
|
||||
| # | 文档 | 状态 |
|
||||
| --- | ------------------------------------------------------------------- | ------------------------------ |
|
||||
| 1 | [README.md](../../README.md) | ✅ 已读 |
|
||||
| 2 | [MIGRATION_GUIDE.md](../../MIGRATION_GUIDE.md) | ✅ 已读 |
|
||||
| 3 | [004 架构影响地图](./004_architecture_impact_map.md) | ✅ 已读 |
|
||||
| 4 | [pending-features.md](./roadmap/pending-features.md) | ✅ 已读 |
|
||||
| 5 | [project_rules.md](../../.trae/rules/project_rules.md) | ✅ 已读(workspace 规则) |
|
||||
| 6 | [coding-standards.md](../standards/coding-standards.md) | ✅ 已读(重点 §4 Python 规范) |
|
||||
| 7 | [multi-ai-collaboration.md](../standards/multi-ai-collaboration.md) | ✅ 已读 |
|
||||
| 8 | `packages/shared-proto/proto/*.proto`(8 份) | ✅ 已读 |
|
||||
| 9 | `services/data-ana/src/`、`services/ai/src/` 全部源码 | ✅ 已读 |
|
||||
|
||||
> ai06 不需要读 classes 黄金模板(ai-allocation.md §4 矩阵 ai06 列对黄金模板行为 "—"),但审计表横切关注点对齐仍参考 classes 标准。
|
||||
|
||||
---
|
||||
|
||||
## 模块理解确认书 — data-ana
|
||||
|
||||
### 1. 我在架构中的位置
|
||||
|
||||
- **层级**:业务微服务层(L5),属 **D6 智能洞察领域**(004 §1.1b)
|
||||
- **上游**:
|
||||
- api-gateway 直接 HTTP 代理 `/api/v1/analytics/*` → data-ana:3006(见 [api-gateway main.go:142-148](../../services/api-gateway/main.go))
|
||||
- teacher-bff / student-bff 聚合查询(004 §4.1:BFF → 业务服务 gRPC;当前为 REST)
|
||||
- **下游**:
|
||||
- ClickHouse(独占读模型,宽表 `student_dashboard_view` / `student_errors`)
|
||||
- Kafka(消费 Debezium CDC 事件 + 待发布 `edu.insight.mastery.updated` 领域事件)
|
||||
- **通信方式**:
|
||||
- 入口:当前 REST(`/analytics/class/{id}/performance`、`/analytics/student/{id}/weakness`、`/analytics/student/{id}/errorbook`);目标态(004 §4.1 + analytics.proto)转 **gRPC** 暴露 `AnalyticsService`
|
||||
- 出口:Kafka 消费(CDC + 领域事件订阅);Kafka 发布(`edu.insight.mastery.updated`,**未实现**)
|
||||
- **端口**:3006(见 [data-ana config.py:7](../../services/data-ana/src/data_ana/config.py) + [api-gateway config.go:55](../../services/api-gateway/internal/config/config.go))
|
||||
|
||||
### 2. 我的限界上下文
|
||||
|
||||
- **聚合职责**:学情分析读模型构建 + 查询服务,承载 **D6 智能洞察领域**的"分析/诊断"子域
|
||||
- **聚合根 / 实体**:
|
||||
- `StudentDashboard`(学生学情宽表视图,ClickHouse 物化)
|
||||
- `StudentErrorBook`(学生错题本,ClickHouse 物化)
|
||||
- `ClassPerformance`(班级成绩聚合,ClickHouse 即时聚合)
|
||||
- `MasterySnapshot`(知识点掌握度快照,**待实现**)
|
||||
- **业务领域**:D6 智能洞察(与 ai 服务共享领域,ai 偏"生成",data-ana 偏"分析")
|
||||
- **我不负责**:
|
||||
- 不负责写模型(成绩由 core-edu 写 MySQL,data-ana 只消费 CDC)
|
||||
- 不负责题库内容(→ content 服务)
|
||||
- 不负责通知投递(→ msg 服务消费 data-ana 发布的 `mastery.updated` 事件触发预警)
|
||||
- 不负责 AI 推理(→ ai 服务,ai 通过 gRPC 反向查询 data-ana 学情数据)
|
||||
- **数据自治**:独占 `edu_analytics` ClickHouse 数据库(不与 MySQL 写模型混用)
|
||||
|
||||
### 3. 我与外部的契约
|
||||
|
||||
#### 消费的 proto message
|
||||
|
||||
| 来源 | message | 用途 |
|
||||
| --------------- | ------------------------------- | ---------------------------------------------- |
|
||||
| events.proto | `GradeEvent` | 消费 core-edu 成绩写入事件 → 更新学情宽表 |
|
||||
| events.proto | `ExamEvent` | 消费考试事件 → 缓存 exam_id→class_id 映射 |
|
||||
| events.proto | `HomeworkEvent` | 消费作业提交/批改事件 → 更新学情(**待实现**) |
|
||||
| events.proto | `ClassEvent` | 消费班级变更事件 → 同步班级维度(**待实现**) |
|
||||
| analytics.proto | `GetClassPerformanceRequest` 等 | gRPC 暴露契约(**待实现 gRPC server**) |
|
||||
|
||||
> **CDC 直连 vs 领域事件双通道**:当前实现走 Debezium CDC(直接监听 MySQL binlog),不依赖 core-edu 的 Outbox。这是 ADR-008 的设计决策(CDC 解耦 Outbox Relay,减少业务侵入)。Outbox 领域事件(events.proto)作为业务语义更清晰的补充通道,待 P4 后期评估是否双消费。
|
||||
|
||||
#### 暴露的 API / 事件
|
||||
|
||||
**HTTP 端点**(当前实现,见 [main.py](../../services/data-ana/src/data_ana/main.py)):
|
||||
|
||||
| method | path | 说明 |
|
||||
| ------ | ------------------------------------------- | -------------------------------------- |
|
||||
| GET | `/healthz` | liveness |
|
||||
| GET | `/readyz` | readiness(含 ClickHouse + CDC 状态) |
|
||||
| GET | `/metrics` | Prometheus 指标 |
|
||||
| GET | `/analytics/class/{class_id}/performance` | 班级成绩分析(平均分/及格率/参考人数) |
|
||||
| GET | `/analytics/student/{student_id}/weakness` | 学生薄弱知识点(mastery < 0.6) |
|
||||
| GET | `/analytics/student/{student_id}/errorbook` | 学生错题本 |
|
||||
|
||||
**gRPC 契约**(analytics.proto,**待实现**):
|
||||
|
||||
- `GetClassPerformance(GetClassPerformanceRequest) → ClassPerformance`
|
||||
- `GetStudentWeakness(GetStudentWeaknessRequest) → StudentWeakness`
|
||||
- `GetLearningTrend(GetLearningTrendRequest) → LearningTrend`(**当前 HTTP 未暴露**)
|
||||
|
||||
**发布的领域事件**:
|
||||
|
||||
| 事件 | Topic(004 §7.2) | 触发时机 | 消费者(004 §7.3) |
|
||||
| ---------------- | ----------------------------- | -------------- | --------------------------------------- |
|
||||
| `MasteryUpdated` | `edu.insight.mastery.updated` | 掌握度计算完成 | core-edu(推荐个性化练习)、msg(预警) |
|
||||
|
||||
> **当前未实现发布**:data-ana 当前只消费不发布。掌握度计算完成后应通过 Kafka 发布 `MasteryUpdated`,下游 core-edu / msg 消费。阶段 2 设计需补全此发布链路(Python 无 Outbox 模式,需评估直接 producer 还是引入 Outbox 表)。
|
||||
|
||||
- **错误码前缀**:`DATA_ANA_*`(待定义清单,见阶段 2 §6)
|
||||
- **缓存**:当前无 Redis 缓存;004 §6.3 学情宽表走 ClickHouse 实时,CDC 同步延迟 < 5s
|
||||
|
||||
### 4. 我的技术栈
|
||||
|
||||
- 语言:Python 3.12+
|
||||
- 框架:FastAPI 0.115+ / uvicorn
|
||||
- ORM / 客户端:`clickhouse-connect`(HTTP 协议,非原生协议)
|
||||
- 消息:`aiokafka`(CDC 消费者,AIOKafkaConsumer)
|
||||
- 配置:`pydantic-settings` BaseSettings(env_prefix="",全大写环境变量)
|
||||
- 可观测:
|
||||
- 日志:`structlog` 24.x(`make_filtering_bound_logger`,**注意**:旧版 `make_filtering_logger` 已废弃)
|
||||
- 指标:`prometheus-client` + `make_asgi_app()` 挂载 `/metrics`
|
||||
- 链路:`opentelemetry-sdk` + `OTLPSpanExporter` + `FastAPIInstrumentor.instrument_app(app)`
|
||||
- 序列化:JSON(Debezium 事件 `schemas.enable=false`,直接 `json.loads`)
|
||||
- 测试:pytest + pytest-asyncio(**当前 0% 覆盖率**)
|
||||
|
||||
### 5. 我的阶段归属
|
||||
|
||||
- **P4 内容分析阶段(M11-M13)**:建 DataAna 服务 + CDC 链路落地
|
||||
- **退出标准**(pending-features P4):学生查看学情诊断 ClickHouse 宽表 5s 内返回 + CDC 链路延迟 < 5s
|
||||
- **依赖上游**:
|
||||
- P1 地基:api-gateway 路由 + arch.db 扫描器 Python 支持
|
||||
- P3 核心教学:core-edu 写成绩到 MySQL(Debezium 监听 binlog)
|
||||
- P4 同期:content 服务(提供知识点 ID 供掌握度计算)
|
||||
- **下游依赖我**:
|
||||
- P5 ai 服务通过 gRPC 查询学情数据(004 §4.1:AI → DataAna gRPC)
|
||||
- P5 msg 服务消费 `mastery.updated` 触发预警
|
||||
|
||||
### 6. 我需要对齐的黄金模板项(对照 classes 服务 + Python 规范)
|
||||
|
||||
> Python 服务无 NestJS 装饰器体系,权限校验等通过等价方式实现。
|
||||
|
||||
- [ ] 权限装饰器等价物:**当前 HTTP 端点全部裸露,无权限校验**。Gateway 层做 JWT 校验,但 data-ana 本身未校验 `x-user-id` / DataScope。**阶段 2 需设计 FastAPI Depends 权限依赖 + DataScope 过滤注入**
|
||||
- [ ] 错误码前缀统一:**当前无错误码体系**,降级时返回 `degraded: true` 标记但无业务错误码。**阶段 2 需定义 `DATA_ANA_*` 错误码清单**
|
||||
- [x] logger / metrics / tracer 三支柱(已具备,见 main.py + clickhouse_client.py)
|
||||
- [x] `/healthz` + `/readyz` 健康检查(已具备,readyz 含 ClickHouse ping + CDC 状态)
|
||||
- [ ] 优雅关闭 SIGTERM:当前 lifespan 仅关闭 CDC task + ClickHouse client,**未注册 SIGTERM 信号处理器**显式 drain
|
||||
- [ ] 测试覆盖率 ≥ 80%:**当前 0%**,无 tests/ 目录
|
||||
- [ ] Dockerfile 多阶段构建:**当前单阶段**(`FROM python:3.12-slim` → `uv sync` → `COPY src`),非多阶段
|
||||
- [ ] Pydantic 输入验证:**当前端点直接接收 path param,无 Pydantic 请求模型校验**(应补 `ClassPerformanceResponse` 等 response_model)
|
||||
- [x] 配置通过 pydantic-settings 管理(已具备)
|
||||
- [x] 异步优先(async def,aiokafka async consumer)
|
||||
- [ ] 类型注解强制:**部分函数缺返回值标注**(如 `init_logger` 返回 `BoundLogger` 但 `_logger` 全局变量标注 `None`,需统一)
|
||||
- [ ] ruff check 零错误:需阶段 2 验证
|
||||
|
||||
---
|
||||
|
||||
## 模块理解确认书 — ai
|
||||
|
||||
### 1. 我在架构中的位置
|
||||
|
||||
- **层级**:业务微服务层(L5),属 **D6 智能洞察领域**(004 §1.1b,与 data-ana 共享领域)
|
||||
- **上游**:
|
||||
- api-gateway 直接 HTTP 代理 `/api/v1/ai/*` → ai:3008(见 [api-gateway main.go:138-139](../../services/api-gateway/main.go))
|
||||
- teacher-bff 聚合 AI 出题/优化能力(004 §4.1:BFF → ai,当前 REST)
|
||||
- **下游**:
|
||||
- content 服务(gRPC 查询知识点 / 题库,004 §4.1:AI → Content gRPC)
|
||||
- data-ana 服务(gRPC 查询学情数据,004 §4.1:AI → DataAna gRPC)
|
||||
- LLM Provider(外部 HTTP,OpenAI 兼容 REST API)
|
||||
- **通信方式**:
|
||||
- 入口:当前 REST(`/ai/chat`、`/ai/chat/stream`、`/ai/generate/question`、`/ai/optimize/expression`);目标态(ai.proto)转 **gRPC** 暴露 `AiService`(含 `StreamChat` 流式 RPC)
|
||||
- 出口:gRPC 调 content / data-ana(**当前未实现,仅 LLM HTTP 调用**);SSE 流式对前端
|
||||
- **端口**:3008(见 [ai config.py:8](../../services/ai/src/ai/config.py) + [api-gateway config.go:57](../../services/api-gateway/internal/config/config.go))
|
||||
|
||||
### 2. 我的限界上下文
|
||||
|
||||
- **聚合职责**:LLM 调用网关 + 教学场景 AI 编排(备课 / 出题 / 表达优化),承载 **D6 智能洞察领域**的"生成"子域
|
||||
- **聚合根 / 实体**:
|
||||
- `ChatConversation`(聊天会话,**待实现**,当前无状态)
|
||||
- `GeneratedQuestion`(生成的题目,待审核入库)
|
||||
- `PromptTemplate`(Prompt 模板,**待实现**)
|
||||
- `UsageRecord`(用量计费记录,**待实现**)
|
||||
- **业务领域**:D6 智能洞察(与 data-ana 共享,data-ana 偏"分析",ai 偏"生成")
|
||||
- **我不负责**:
|
||||
- 不负责题库存储(→ content 服务,ai 生成后调 content.CreateQuestions 入库)
|
||||
- 不负责学情计算(→ data-ana 服务,ai 查询学情用于个性化出题)
|
||||
- 不负责通知投递(→ msg 服务)
|
||||
- 不持有业务状态(无 DB 写入,无 Outbox;用量计费记录可走 Kafka 事件给 data-ana 落 ClickHouse)
|
||||
- **数据自治**:**无独占数据库**(设计上无状态;用量计费通过 Kafka 事件外发)
|
||||
|
||||
### 3. 我与外部的契约
|
||||
|
||||
#### 消费的 proto message
|
||||
|
||||
| 来源 | message / service | 用途 |
|
||||
| --------------- | ---------------------------------------- | --------------------------------------- |
|
||||
| content.proto | `KnowledgeGraphService.GetPrerequisites` | 查询知识点前置依赖用于出题上下文 |
|
||||
| content.proto | `KnowledgeGraphService.GetLearningPath` | 查询学生学习路径用于个性化出题 |
|
||||
| analytics.proto | `AnalyticsService.GetStudentWeakness` | 查询学生薄弱知识点用于靶向出题 |
|
||||
| analytics.proto | `AnalyticsService.GetLearningTrend` | 查询学习趋势用于难度调节 |
|
||||
| ai.proto | `ChatRequest` 等 | gRPC 暴露契约(**待实现 gRPC server**) |
|
||||
|
||||
#### 暴露的 API / 事件
|
||||
|
||||
**HTTP 端点**(当前实现,见 [main.py](../../services/ai/src/ai/main.py)):
|
||||
|
||||
| method | path | 说明 |
|
||||
| ------ | ------------------------- | ---------------------------- |
|
||||
| GET | `/healthz` | liveness |
|
||||
| GET | `/readyz` | readiness(含 LLM 是否配置) |
|
||||
| GET | `/metrics` | Prometheus 指标 |
|
||||
| POST | `/ai/chat` | LLM 聊天(非流式) |
|
||||
| POST | `/ai/chat/stream` | LLM 流式聊天(SSE) |
|
||||
| POST | `/ai/generate/question` | 生成题目 |
|
||||
| POST | `/ai/optimize/expression` | 优化表达 |
|
||||
|
||||
**gRPC 契约**(ai.proto,**待实现**):
|
||||
|
||||
- `Chat(ChatRequest) → ChatResponse`
|
||||
- `StreamChat(ChatRequest) → stream ChatChunk`(流式 RPC)
|
||||
- `GenerateQuestion(GenerateQuestionRequest) → GeneratedQuestion`
|
||||
- `OptimizeExpression(OptimizeExpressionRequest) → OptimizedExpression`
|
||||
|
||||
**发布的领域事件**:**当前无发布**。设计上可发布 `AIUsageRecorded` 事件(用量计费),由 data-ana 消费落 ClickHouse。004 §7.2 未列出此 topic,**阶段 2 需与 coord 确认是否新增 `edu.insight.ai.usage` topic**。
|
||||
|
||||
- **错误码前缀**:`AI_*`(待定义清单,见阶段 2 §6)
|
||||
- **降级策略**:LLM API key 为空或调用失败时返回 `degraded: true` 骨架响应(见 [llm_client.py](../../services/ai/src/ai/llm_client.py))
|
||||
|
||||
### 4. 我的技术栈
|
||||
|
||||
- 语言:Python 3.12+
|
||||
- 框架:FastAPI 0.115+ / uvicorn
|
||||
- LLM 客户端:`httpx` 异步直接调 OpenAI 兼容 REST API(**不依赖 openai SDK**,见 [llm_client.py:1-7](../../services/ai/src/ai/llm_client.py))
|
||||
- 配置:`pydantic-settings` BaseSettings(env_prefix="")
|
||||
- 可观测:
|
||||
- 日志:`structlog`
|
||||
- 指标:`prometheus-client` + `make_asgi_app()`
|
||||
- 链路:`opentelemetry-sdk` + `OTLPSpanExporter` + `FastAPIInstrumentor`(dev_mode=true 时跳过 exporter 初始化避免本地无 collector 报错)
|
||||
- 流式响应:FastAPI `StreamingResponse` + `AsyncGenerator`,SSE 格式 `data: <chunk>\n\n`
|
||||
- 测试:pytest(**当前 0% 覆盖率**)
|
||||
|
||||
### 5. 我的阶段归属
|
||||
|
||||
- **P5 沟通与 AI 阶段(M14-M16)**:建 AI 网关 + LLM Provider 适配 + 流式 SSE
|
||||
- **退出标准**(pending-features P5):AI 辅助出题流式返回 + 题库全文检索 < 200ms(ES 部分由 ai05 负责)
|
||||
- **依赖上游**:
|
||||
- P1 地基:api-gateway 路由
|
||||
- P4 内容分析:content 服务(gRPC 查询知识点 / 题库)+ data-ana 服务(gRPC 查询学情)
|
||||
- 外部:LLM Provider API key(OpenAI / Anthropic / 百川 / 本地模型)
|
||||
- **下游依赖我**:
|
||||
- P5 teacher-bff 聚合 AI 出题 mutation(004 §9.3:教师用 AI 出题并发布到班级)
|
||||
- P5 teacher-portal SSE 流式 AI 对话(前端)
|
||||
|
||||
### 6. 我需要对齐的黄金模板项(对照 classes 服务 + Python 规范)
|
||||
|
||||
- [ ] 权限装饰器等价物:**当前 HTTP 端点全部裸露,无权限校验**。阶段 2 需设计 FastAPI Depends 权限依赖(AI 出题需 `AI_QUESTION_GENERATE` 权限,表达优化需 `AI_EXPRESSION_OPTIMIZE`)
|
||||
- [ ] 错误码前缀统一:**当前无错误码体系**,降级时返回 `degraded: true` 但无业务错误码。**阶段 2 需定义 `AI_*` 错误码清单**
|
||||
- [x] logger / metrics / tracer 三支柱(已具备)
|
||||
- [x] `/healthz` + `/readyz` 健康检查(已具备,readyz 含 LLM 配置状态)
|
||||
- [ ] 优雅关闭 SIGTERM:当前 lifespan 无显式 drain(LLM 流式请求需等待完成)
|
||||
- [ ] 测试覆盖率 ≥ 80%:**当前 0%**,无 tests/ 目录
|
||||
- [ ] Dockerfile 多阶段构建:**当前单阶段**(`FROM python:3.12-slim`)
|
||||
- [ ] Pydantic 输入验证:**当前仅 `ChatRequest` 是 BaseModel,`generate/question` 和 `optimize/expression` 直接接收 `prompt: str` / `text: str` query param,无请求体模型**。阶段 2 需补完整 Pydantic 请求/响应模型
|
||||
- [x] 配置通过 pydantic-settings 管理(已具备)
|
||||
- [x] 异步优先(httpx async + AsyncGenerator stream)
|
||||
- [x] 类型注解强制(已基本符合,main.py 函数返回值已标注)
|
||||
- [ ] LLM Provider 适配器模式:**当前仅 OpenAI 兼容 REST**,未抽象 Provider 接口。阶段 2 需设计 `LLMProvider` 抽象 + OpenAI/Anthropic/百川/本地 多适配器
|
||||
- [ ] Prompt 模板管理:**当前 Prompt 硬编码在 main.py**,阶段 2 需设计模板管理(DB 或文件)
|
||||
- [ ] 用量计费 / 频率限制:**当前无用量记录和限流**,阶段 2 需设计(Kafka 事件 + Redis 限流)
|
||||
- [ ] 备课工作流:**当前未实现**,pending-features P5 要求"分析学情 → 推荐知识点 → 生成题目 → 教师审核 → 入库"完整工作流
|
||||
- [ ] ruff check 零错误:需阶段 2 验证
|
||||
|
||||
---
|
||||
|
||||
## ai06 服务审计表
|
||||
|
||||
> 对照 ai-allocation.md §10 审计模板。data-ana 与 ai 均为 Python/FastAPI,黄金模板对齐按 Python 规范(coding-standards §4)评估。
|
||||
> 符号说明:✅ 已实现 | ❌ 缺失 | ⚠️ 部分实现
|
||||
|
||||
| 服务 | 权限校验 | 错误码前缀 | logger | metrics | tracer | /healthz | /readyz | 优雅关闭 | 测试覆盖率 | Dockerfile |
|
||||
| -------- | -------- | ---------- | ------------ | ------------- | ------------------- | -------- | -------------------- | ------------------- | ---------- | ---------- |
|
||||
| data-ana | ❌ | ❌ | ✅ structlog | ✅ prometheus | ✅ OTel | ✅ | ✅(含 CH+CDC 状态) | ⚠️ 仅 lifespan 关闭 | 0% | ❌ 单阶段 |
|
||||
| ai | ❌ | ❌ | ✅ structlog | ✅ prometheus | ✅ OTel(dev 跳过) | ✅ | ✅(含 LLM 状态) | ⚠️ 仅 lifespan 关闭 | 0% | ❌ 单阶段 |
|
||||
|
||||
### 审计发现的关键差距清单
|
||||
|
||||
#### data-ana 关键差距(按优先级)
|
||||
|
||||
1. **P0 权限校验缺失**:所有 `/analytics/*` 端点裸露,无 DataScope 过滤。学生 A 可查询学生 B 的错题本(越权风险)。阶段 2 必须设计 `Depends(require_permission)` + `Depends(inject_data_scope)` 依赖注入
|
||||
2. **P0 gRPC server 未实现**:analytics.proto 定义了 `AnalyticsService` 但 data-ana 当前仅 HTTP。004 §4.1 明确 BFF → 业务服务走 gRPC,阶段 2 需引入 `grpc.aio` + `betterproto` 实现 gRPC server
|
||||
3. **P1 事件发布缺失**:`edu.insight.mastery.updated` 事件未发布,下游 core-edu/msg 无法消费。需设计掌握度计算 + Kafka producer 发布链路
|
||||
4. **P1 ClickHouse schema 不规范**:当前 `student_dashboard_view` 实为 MergeTree 表(注释提到应为 ReplacingMergeTree(last_updated) 实现幂等去重),无 DDL 文件管理。阶段 2 需产出完整 ClickHouse DDL(5 张宽表:考试/作业/成绩/掌握度/出勤)
|
||||
5. **P2 测试覆盖率 0%**:无 tests/ 目录,pytest 未配置
|
||||
6. **P2 Dockerfile 单阶段**:未做多阶段构建(builder + runtime),镜像体积大
|
||||
7. **P2 掌握度计算算法缺失**:当前 `_handle_grades_event` 用 `score / 100.0` 简化,未实现 pending-features 要求的"加权滑动平均"算法
|
||||
8. **P2 无 Pydantic 响应模型**:端点返回 `dict` 而非 `BaseModel`,无 `response_model` 校验
|
||||
|
||||
#### ai 关键差距(按优先级)
|
||||
|
||||
1. **P0 权限校验缺失**:所有 `/ai/*` 端点裸露,AI 出题等敏感操作无权限校验
|
||||
2. **P0 gRPC server 未实现**:ai.proto 定义了 `AiService`(含 `StreamChat` 流式 RPC)但 ai 当前仅 HTTP。阶段 2 需引入 `grpc.aio` 实现 gRPC server + 流式 RPC
|
||||
3. **P0 gRPC client 未实现**:004 §4.1 明确 AI → Content / AI → DataAna 走 gRPC,当前未实现。阶段 2 需设计 gRPC client 调用 content / data-ana
|
||||
4. **P1 LLM Provider 适配器缺失**:当前 `llm_client.py` 仅 OpenAI 兼容 REST,未抽象 Provider 接口。pending-features P5 要求"LLM Provider 适配(OpenAI/Anthropic/百川/本地模型)"
|
||||
5. **P1 Prompt 模板管理缺失**:system prompt 硬编码在 main.py,无模板管理。阶段 2 需设计模板存储(文件 or DB)+ 模板渲染
|
||||
6. **P1 备课工作流缺失**:pending-features P5 要求"分析学情 → 推荐知识点 → 生成题目 → 教师审核 → 入库"完整工作流,当前仅"生成题目"单步
|
||||
7. **P1 用量计费 / 频率限制缺失**:无用量记录(token 消耗)、无频率限制(用户可无限调用 LLM)。阶段 2 需设计 Redis 限流 + Kafka 事件外发用量
|
||||
8. **P2 测试覆盖率 0%**:无 tests/ 目录
|
||||
9. **P2 Dockerfile 单阶段**:未做多阶段构建
|
||||
10. **P2 Pydantic 输入验证不完整**:`generate/question` 和 `optimize/expression` 直接接收 query param,无请求体模型
|
||||
|
||||
---
|
||||
|
||||
## 阶段 1 待 coord 交叉审查的跨模块契约对齐项
|
||||
|
||||
以下项需 coord 在交叉审查时仲裁(见 ai-allocation.md §8):
|
||||
|
||||
| # | 议题 | 涉及方 | 当前状态 | ai06 建议 |
|
||||
| --- | -------------------------------------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1 | **data-ana 是否发布 `edu.insight.mastery.updated` 事件** | data-ana → core-edu / msg | 004 §7.2 列出此 topic,但当前 data-ana 未实现发布 | 阶段 2 设计发布链路;Python 无 Outbox,建议直接 Kafka producer(掌握度计算是派生数据,非事务写) |
|
||||
| 2 | **ai 是否发布 `edu.insight.ai.usage` 用量事件** | ai → data-ana | 004 §7.2 未列出此 topic | 建议 coord 新增此 topic 用于用量计费落 ClickHouse;若 coord 不同意则 ai 自建用量记录表(破坏无状态原则) |
|
||||
| 3 | **data-ana / ai 是否需要实现 gRPC server** | data-ana / ai ← teacher-bff / student-bff / ai | 004 §4.1 明确 BFF → 业务服务走 gRPC,analytics.proto / ai.proto 已定义 service,但当前两服务仅 HTTP | 阶段 2 引入 `grpc.aio` + `betterproto` 实现 gRPC server;HTTP 端点保留作为 Gateway 直连降级通道 |
|
||||
| 4 | **CDC 直连 vs Outbox 领域事件双通道** | data-ana ← core-edu | 当前 data-ana 走 Debezium CDC(监听 binlog),不消费 core-edu Outbox 事件(events.proto) | 维持 CDC 为主通道(ADR-008 决策);events.proto 作为业务语义补充,待 P4 后期评估是否双消费 |
|
||||
| 5 | **data-ana DataScope 过滤实现位置** | data-ana + iam | 004 §5.3 DataScope 6 级,业务服务在 Repository 层注入 WHERE;data-ana 是 ClickHouse 查询无 Repository 层 | 阶段 2 在 ClickHouse 查询 SQL 拼接时注入 DataScope WHERE(学生只能看自己,教师看本班,校管理员看本校);需 iam 提供 `getEffectiveDataScope(userId)` API |
|
||||
| 6 | **ai 备课工作流是否引入 Temporal** | ai + coord | 004 §2.3 列出 Temporal 用于"工作流编排(考试生命周期、AI 编排)",P3 已引入 Temporal 试点 | 阶段 2 评估:简单工作流(4 步)可用 FastAPI BackgroundTasks;复杂工作流(含教师审核等待)建议 Temporal;待 coord 仲裁 |
|
||||
| 7 | **LLM Provider 切换的配置化** | ai + coord | 当前 ai config.py 仅 OpenAI + Anthropic 字段 | 阶段 2 设计 `LLMProvider` 抽象 + 配置化路由(按 model 名路由到不同 provider);本地模型走 Ollama REST API |
|
||||
| 8 | **data-ana ClickHouse DDL 管理位置** | data-ana + coord | 当前无 DDL 文件,宽表手动创建 | 建议 coord 在 `infra/clickhouse/` 下建立 DDL 目录(类似 MySQL init.sql),data-ana 提供 DDL 内容 |
|
||||
|
||||
---
|
||||
|
||||
## 阶段 1 总结
|
||||
|
||||
ai06 已完成阶段 1 全局理解,产出本确认书。核心结论:
|
||||
|
||||
1. **data-ana**(P4):CDC 链路已跑通(Debezium → Kafka → ClickHouse),3 个分析端点已实现降级模式。**关键差距**:权限校验、gRPC server、事件发布(mastery.updated)、ClickHouse DDL 规范化、掌握度算法、测试覆盖。
|
||||
2. **ai**(P5):LLM 客户端已实现降级模式(httpx 异步 + SSE 流式),4 个端点已实现。**关键差距**:权限校验、gRPC server + client、LLM Provider 适配器、Prompt 模板管理、备课工作流、用量计费、测试覆盖。
|
||||
3. **跨模块契约**:8 项待 coord 仲裁,最关键的是 gRPC server 实现决策(影响阶段 2 设计核心)和事件发布 topic 新增决策。
|
||||
|
||||
下一步进入阶段 2,按 ai-allocation.md §7 模板产出 data-ana 与 ai 的模块架构设计文档。
|
||||
Reference in New Issue
Block a user