Files
Edu/services/ai/docs/nextstep-v2.md
SpecialX aac26c7c6f feat(ai): v2 新增 GenerateReport RPC + ReportService
第 9 个 RPC GenerateReport(学情报告生成):data-ana 学情数据 → LLM 生成 → 结构化提取

新增 ReportService 业务编排层 + GenerateReportRequest/GeneratedReport 模型

gRPC servicer + HTTP POST /v1/ai/generate/report(权限 ai:report:generate)

proto_gen 重新生成 + 测试覆盖(servicer/service/HTTP/模型/权限 共 26 用例)

402 测试通过,覆盖率 88.5%
2026-07-14 22:57:57 +08:00

21 KiB
Raw Blame History

AI 模块 nextstep-v2

模块ai | gRPC 50058 | HTTP 3008 | Python (FastAPI + gRPC aio) 更新时间2026-07-14 前序文档:nextstep.mdv18 RPC / 10 端点)


§1 当前状态

v2 新增第 9 个 RPC GenerateReport(学情报告生成),满足 teacher-bff generateReport mutation 需求。9 RPC 全部实现402 个测试通过,覆盖率 88.5%。

v2 新增

  • ai.proto 新增 GenerateReport RPC + GenerateReportRequest / GeneratedReport message
  • ReportService 业务编排层data-ana 学情数据 → LLM 生成报告 → 结构化提取摘要+建议)
  • gRPC servicer GenerateReport 方法(方案 B 降级)
  • HTTP 端点 POST /v1/ai/generate/report(权限 ai:report:generate
  • 权限点 PERMISSION_AI_REPORT_GENERATEteacher + admin 角色)
  • proto_gen 重新生成ai_pb2.py / ai_pb2_grpc.py
  • 测试覆盖servicer 5 用例 + service 9 用例 + HTTP 5 用例 + 模型 5 用例 + 权限 2 用例)

完整 9 RPC 清单

# RPC 类型 用途 状态
1 Chat 一元 非流式聊天 已实现
2 StreamChat 流式 流式聊天SSE over gRPC 已实现
3 GenerateQuestion 一元 生成题目 已实现
4 StreamGenerateQuestion 流式 流式生成题目 已实现
5 OptimizeExpression 一元 优化表达 已实现
6 GenerateLessonPlan 一元 启动备课工作流 已实现
7 GetLessonPlanStatus 一元 查询备课工作流状态 已实现
8 ConfirmLessonPlan 一元 确认备课结果入库 已实现
9 GenerateReport 一元 生成学情报告v2 新增) 已实现

完整 11 HTTP 端点清单

# 端点 方法 权限 状态
1 /healthz GET - 已实现
2 /readyz GET - 已实现
3 /v1/ai/chat POST ai:chat 已实现
4 /v1/ai/chat/stream POST ai:chat 已实现
5 /v1/ai/generate/question POST ai:question:generate 已实现
6 /v1/ai/generate/question/stream POST ai:question:generate 已实现
7 /v1/ai/optimize/expression POST ai:expression:optimize 已实现
8 /v1/ai/lesson-plan/generate POST ai:lesson:generate 已实现
9 /v1/ai/lesson-plan/status/{id} GET - 已实现
10 /v1/ai/lesson-plan/confirm/{id} POST ai:lesson:confirm 已实现
11 /v1/ai/generate/report POST ai:report:generate 已实现

权限点清单

权限点 teacher admin student 用途
ai:chat 聊天
ai:question:generate 生成题目
ai:expression:optimize 优化表达
ai:lesson:generate 生成教案
ai:lesson:confirm 确认教案
ai:report:generate 生成学情报告

§2 GenerateReport 实现详情

§2.1 数据流

teacher-bff generateReport mutation
  → ai gRPC GenerateReport(:50058)
    → ReportService.generate()
      → data-ana gRPC GetClassPerformance / GetStudentWeakness / GetLearningTrend(:50055)
      → Prompt 组装PromptTemplateService 或内联 fallback
      → LLM FailoverChain.chat()OpenAI → Anthropic → 百川 → Ollama
      → 结构化提取(摘要 + 教学建议)
    ← GeneratedReport { id, content, summary, recommendations, degraded, degraded_reason }

§2.2 报告类型

report_type 用途 必填参数 data-ana 数据源
class_summary 班级学情总结 class_id GetClassPerformance
student_detail 学生个人学情详情 class_id + student_id GetClassPerformance + GetStudentWeakness + GetLearningTrend
exam_analysis 考试分析 class_id GetClassPerformance

§2.3 降级策略

场景 降级行为 degraded degraded_reason
LLM 全部不可用 返回空 content + 空 summary + 空 recommendations true "LLM unavailable: ..."
data-ana 不可用 上下文降级空数据LLM 仍可生成(基于空数据) false (报告内容会说明无数据)
ReportService 未注入 gRPC 返回空 GeneratedReport true "report_service not initialized"
未知异常 gRPC 抛 AIError(AI_INTERNAL_ERROR) - -

§3 上游依赖ai 依赖谁)

§3.1 gRPC 同步调用

被调用方 端口 Service.RPC 用途 状态
content 50054 KnowledgeGraphService.GetPrerequisites 查询知识点前置依赖(备课工作流 Step 2 已实现
content 50054 KnowledgeGraphService.GetLearningPath 查询学习路径(备课工作流 Step 2 已实现
content 50054 QuestionService.BatchCreateQuestions 批量创建题目入库(备课工作流 Confirm 已实现
data-ana 50055 AnalyticsService.GetClassPerformance 查询班级学情(备课工作流 + 学情报告 已实现
data-ana 50055 AnalyticsService.GetStudentWeakness 查询学生薄弱点(备课工作流 + 学情报告 已实现
data-ana 50055 AnalyticsService.GetLearningTrend 查询学习趋势(备课工作流 + 学情报告 已实现
iam 50052 IamService.GetEffectiveDataScope 查询用户数据范围(多租户配额) 已实现

v2 变更data-ana 的 3 个 RPC 现在同时服务于备课工作流和学情报告两条业务线。

§3.2 基础设施依赖

依赖 用途 状态
Redis 限流 + 工作流状态存储 + 用量记录 已实现
Kafka AIUsageEvent 事件发布topic: edu.ai.usage 已实现
OpenTelemetry Collector 链路追踪 + 指标导出 已实现

§3.3 LLM Provider 依赖

Provider 环境变量 用途 状态
OpenAI OPENAI_API_KEY / OPENAI_BASE_URL 首选 LLM 已实现
Anthropic ANTHROPIC_API_KEY Failover 第二 已实现
百川 BAICHUAN_API_KEY Failover 第三 已实现
Ollama OLLAMA_BASE_URL 本地降级 已实现

§4 下游就绪信号(谁依赖 ai

§4.1 teacher-bff — P1

就绪标志 消费方式 状态
AiService.Chat / StreamChat 可调用 gRPC 50058 + SSE 3008 已就绪
AiService.GenerateQuestion 可调用 gRPC 50058 已就绪
AiService.GenerateLessonPlan 可调用 gRPC 50058 已就绪
AiService.GetLessonPlanStatus / ConfirmLessonPlan 可调用 gRPC 50058 已就绪
AiService.OptimizeExpression 可调用 gRPC 50058 已就绪
AiService.GenerateReport 可调用 gRPC 50058 已就绪

teacher-bff 通过 AI_GRPC_TARGET=ai:50058 连接,留空时走降级模式 B。

§4.2 student-bff — P1

就绪标志 消费方式 状态
AiService.Chat 可调用(同步 AI 答疑) gRPC 50058 已就绪
AiService.StreamChat 可调用(流式答疑) gRPC 50058 已就绪

§4.3 api-gateway — P2

就绪标志 消费方式 状态
ai HTTP 3008 /healthz 可达 HTTP 反向代理 /api/v1/ai/*ai:3008 已就绪

§4.4 data-ana — P2

就绪标志 消费方式 状态
Kafka topic edu.ai.usage 有事件发布 CDC 消费者 → ClickHouse ai_usage_log 已就绪

§5 需要上下游实现的工作nextstep-v2 新增)

§5.1 teacher-bff 需要完成

# 工作项 当前状态 优先级
1 AI gRPC 客户端添加 generateReport 方法 当前返回降级响应degraded P1
2 teacher.service.tsgenerateReport() 调用真实 gRPC 当前硬编码降级响应 P1
3 GraphQL schema GeneratedReport type 字段对齐 proto 需确认字段一致性 P2

详细说明

teacher-bff 的 ai-grpc.client.ts 目前实现了 chat / streamChat / generateQuestion / optimizeExpression,但 generateLessonPlangenerateReport 走降级。现在 ai 侧 GenerateReport RPC 已就绪teacher-bff 需:

// ai-grpc.client.ts 需添加
async generateReport(input: GenerateReportInput): Promise<GeneratedReport> {
  const request = new GenerateReportRequest({
    classId: input.classId,
    reportType: input.reportType,
    studentId: input.studentId ?? undefined,
    userId: input.userId,
    dataScope: input.dataScope ?? undefined,
  });
  const response = await this.client.generateReport(request);
  return {
    id: response.id,
    content: response.content,
    summary: response.summary,
    recommendations: response.recommendations,
    degraded: response.degraded,
    degradedReason: response.degradedReason,
  };
}

ai.proto GenerateReportRequest 字段:

message GenerateReportRequest {
  string class_id = 1;
  string report_type = 2;           // class_summary / student_detail / exam_analysis
  optional string student_id = 3;   // student_detail 时必填
  string user_id = 4;
  string data_scope = 5;            // JSON 序列化的 DataScope
}

message GeneratedReport {
  string id = 1;
  string content = 2;               // 报告正文Markdown
  string summary = 3;               // 摘要
  repeated string recommendations = 4;  // 教学建议
  bool degraded = 5;
  string degraded_reason = 6;
}

§5.2 student-bff 需要确认

# 工作项 当前状态 优先级
1 确认 ChatService.Chat gRPC 调用可用 ai 侧已就绪,待 student-bff 确认 P1
2 确认 ChatService.StreamChat gRPC 调用可用 ai 侧已就绪,待 student-bff 确认 P1

student-bff nextstep-v2.md §5.4 标注这两个 RPC "需确认"。ai 侧 ChatStreamChat RPC 已在 v1 实现gRPC 50058 可直接调用。

§5.3 data-ana 需要保持

# 工作项 当前状态 优先级
1 AnalyticsService 3 RPC 保持可用 已就绪 P1
2 GenerateReport 依赖 GetClassPerformance 等 3 RPC 已就绪 P1

学情报告功能依赖 data-ana 的 3 个 AnalyticsService RPC。如果 data-ana 不可用,报告会基于降级上下文(空数据)生成,但 LLM 仍可工作。

§5.4 api-gateway 需要保持

# 工作项 当前状态 优先级
1 /api/v1/ai/*ai:3008 反向代理路由保持可用 已就绪 P2
2 新增 /v1/ai/generate/report 自动被 /api/v1/ai/* 通配覆盖 已就绪 P2

api-gateway 使用通配路由 /api/v1/ai/*,新增的 /v1/ai/generate/report 端点自动被覆盖,无需额外配置。


§6 联调待办

# 联调项 联调方 阻塞条件 状态
1 ai gRPC + teacher-bff SSE 联调 teacher-bff ai 服务容器启动 ai 侧就绪(待 teacher-bff 接入)
2 ai gRPC StreamChat + student-bff 联调 student-bff ai 服务容器启动 ai 侧就绪(待 student-bff 确认)
3 ai /healthz + api-gateway 联调 api-gateway ai 服务容器启动 ai 侧就绪(待 api-gateway 路由)
4 AIUsageEvent + data-ana CDC 消费联调 data-ana ai Kafka 生产 + data-ana 消费 ai 生产就绪(待 data-ana 消费)
5 ai ↔ content gRPC 联调 content 双方容器启动 ai 客户端就绪(待 content 启动)
6 ai ↔ data-ana gRPC 联调 data-ana 双方容器启动 ai 客户端就绪(待 data-ana 启动)
7 ai ↔ iam gRPC 联调 iam 双方容器启动 ai 客户端就绪(待 iam 启动)
8 GenerateReport + teacher-bff 联调 teacher-bff ai RPC 就绪 + teacher-bff 客户端更新 ai RPC 就绪(待 teacher-bff 客户端更新)
9 GenerateReport + data-ana 数据联调 data-ana 双方容器启动 + 真实学情数据 ai 客户端就绪(待 data-ana 有数据)

§7 测试验证

§7.1 单元测试

测试文件 新增用例数 覆盖范围
test_grpc_servicer.py 5 GenerateReport 成功/学生详情/未初始化降级/LLM降级/内部错误
test_services.py 9 ReportService 生成成功/学生详情/LLM降级/无data-ana/摘要提取/建议提取(2)/prompt构建
test_main_app.py 5 HTTP 端点 class_summary/student_detail/invalid_type/missing_class_id/permission_denied
test_models.py 5 report 模型 默认值/invalid_type/missing_class_id/student_detail/data_defaults
test_permission.py 2 teacher 有 report 权限 / student 无 report 权限
合计 26 v1 377 → v2 402+25 净增1 个修复 _extract_recommendations bug

§7.2 质量校验

校验项 结果 详情
ruff check 通过 零警告
pytest 通过 402 passed, 0 failed
覆盖率 88.5% report_service.py 91%models/report.py 100%

§7.3 Docker 验证(待执行)

arch.db 本次不扫描Docker 验证待 infra 环境就绪后执行。

# 验证项 状态
1 Docker 镜像构建 待验证
2 容器启动 + gRPC 50058 待验证
3 HTTP /healthz 待验证
4 HTTP /readyz 待验证
5 GenerateReport gRPC 待验证

§8 关键实现文件

文件 变更类型 说明
packages/shared-proto/proto/ai.proto 修改 新增 GenerateReport RPC + 2 message
src/ai/proto_gen/ai_pb2.py 重新生成 protobuf 代码
src/ai/proto_gen/ai_pb2_grpc.py 重新生成 gRPC stub/servicer 代码
src/ai/models/report.py 新建 Pydantic 请求/响应模型
src/ai/models/__init__.py 修改 导出 report 模型
src/ai/services/report_service.py 新建 ReportService 业务编排
src/ai/services/__init__.py 修改 导出 ReportService
src/ai/grpc_server/servicer.py 修改 GenerateReport 方法 + report_service 注入
src/ai/grpc_server/server.py 修改 create_grpc_server 添加 report_service 参数
src/ai/middleware/permission.py 修改 新增 PERMISSION_AI_REPORT_GENERATE 权限点
src/ai/main.py 修改 ReportService 实例化 + HTTP /generate/report
tests/test_grpc_servicer.py 修改 5 个 GenerateReport servicer 测试
tests/test_services.py 修改 9 个 ReportService 测试
tests/test_main_app.py 修改 5 个 HTTP 端点测试
tests/test_models.py 修改 5 个 report 模型测试
tests/test_permission.py 修改 2 个 report 权限测试

§9 P6+ 待评估

# 待评估项 说明
1 Temporal 引入评估 备课工作流 P5 用 BackgroundTasks + RedisP6 评估是否引入 Temporal
2 content 事件订阅 P5 不订阅 content 事件P6+ 评估是否需要知识点变更事件驱动
3 MockLLMProvider 02 文档提到但未实现,测试环境用 httpx Mock 替代
4 报告持久化 当前 GenerateReport 不持久化报告P6+ 评估是否需要入库
5 报告模板管理 当前用内联 fallback 模板P6+ 评估是否需要独立模板管理服务
6 报告异步生成 当前同步生成长报告可能超时P6+ 评估是否改为异步 + 轮询模式