Files
Edu/docs/architecture/issues/contracts/ai_contract.md

20 KiB
Raw Blame History

ai 对接契约

负责人ai12 关联:matrix.mdport-allocation.mdai.protoevents.proto02-architecture-design.mdobjections/ai_issue.md 端口权威源:port-allocation.md §3/§5 —— ai = HTTP 3008 / gRPC 50058

本契约已对齐 02-architecture-design.md 设计文档。原 coord 模板的 5 处矛盾已修正(见 objections/ai_issue.md ISSUE-05端口 50057→50058、补 HTTP 端点、topic 三义待裁决、错误码对齐 §6.2、消费事件改 P6+ 评估。标注 的字段待 coord 裁决 ISSUE-02/03/04 后最终定稿。


§1 我提供什么(对外接口)

1.1 gRPC 接口

Service RPC 请求 响应 端口 状态
AiService Chat ChatRequest{messages, model, temperature, user_id?, session_id?, data_scope?} ChatResponse{content, model, usage} 50058 待实现
AiService StreamChat ChatRequest stream ChatChunk 50058 待实现
AiService GenerateQuestion GenerateQuestionRequest{prompt, subject, difficulty, grade?, knowledge_point_ids?, question_type?, count?} GeneratedQuestion 50058 待实现
AiService StreamGenerateQuestion GenerateQuestionRequest stream GeneratedQuestionChunk 50058 待补 protoISSUE-03
AiService OptimizeExpression OptimizeExpressionRequest{text, context} OptimizedExpression 50058 待实现
AiService GenerateLessonPlan GenerateLessonPlanRequest{class_id, subject_id, topic, user_id, data_scope} LessonPlanResponse{workflow_id, status, questions?} 50058 待补 protoISSUE-03

RPC 总数P5 目标 6 RPCai12 建议,见 ISSUE-03。备课工作流的"查询状态/确认入库"用 HTTP 端点实现,避免 RPC 膨胀;如 coord 裁定需 gRPC 则扩到 8 RPC追加 GetLessonPlanStatus / ConfirmLessonPlanproto 现状ai.proto 仅 4 RPCChat/StreamChat/GenerateQuestion/OptimizeExpression缺 GenerateLessonPlan / StreamGenerateQuestion且字段未扩展。待 coord 升级 ai.proto 到 v1 完整版ISSUE-03proto package 偏离:现状 next_edu_cloud.ai.v1,不符合 project_rules §5 edu.<domain>.v1,见 ISSUE-08。

1.2 HTTP 端点

HTTP 保留作 api-gateway 直连降级 + SSE 流式。api-gateway 代理 /api/v1/ai/* → ai /ai/v1/*(见 main.py:70 注释 + matrix.md §5

Method Path 权限 响应 说明 状态
GET /healthz {status, service} liveness 已实现
GET /readyz {status, llm_configured, providers, downstream_grpc, redis, kafka} readiness多维度检查 ⚠️ 待扩展
GET /metrics Prometheus 指标 已实现
POST /ai/v1/chat AI_CHAT ActionState<ChatData> LLM 聊天 ⚠️ 当前 /ai/chat,待加 /v1 + ActionState
POST /ai/v1/chat/stream AI_CHAT SSE stream 流式聊天 ⚠️ 同上
POST /ai/v1/generate/question AI_QUESTION_GENERATE ActionState<GeneratedQuestionData> 生成题目 ⚠️ 同上
POST /ai/v1/generate/question/stream AI_QUESTION_GENERATE SSE stream题目逐字生成 题目逐字流式 待实现
POST /ai/v1/optimize/expression AI_EXPRESSION_OPTIMIZE ActionState<OptimizedExpressionData> 优化表达 ⚠️ 同上
POST /ai/v1/lesson/preparation AI_LESSON_PREPARE ActionState<LessonPreparationData> 备课工作流启动 待实现
GET /ai/v1/lesson/preparation/{workflow_id} AI_LESSON_PREPARE ActionState<WorkflowState> 查询工作流状态 待实现
POST /ai/v1/lesson/preparation/{workflow_id}/confirm AI_LESSON_PREPARE ActionState<PersistResult> 教师确认入库 待实现
GET /ai/v1/prompts AI_PROMPT_READ ActionState<Page<TemplateSummary>> 模板列表 待实现
POST /ai/v1/prompts AI_PROMPT_CREATE ActionState<PromptTemplate> 创建模板 待实现
GET /ai/v1/prompts/{id} AI_PROMPT_READ ActionState<PromptTemplate> 获取模板 待实现
PUT /ai/v1/prompts/{id} AI_PROMPT_UPDATE ActionState<PromptTemplate> 更新模板(版本化) 待实现
GET /ai/v1/usage/me AI_USAGE_READ ActionState<UsageSummary> 当前用户用量 待实现
GET /ai/v1/usage/school/{school_id} AI_USAGE_READ_ALL ActionState<UsageSummary> 学校用量(管理员) 待实现

响应信封:所有响应必须为 ActionState004 §11.5 强制,见 ISSUE-09。当前 main.py 返回 {success, data, degraded} 顶层 degraded 字段违反约束P5 必须整改。 路径演进:当前实现是 /ai/*(无 /v1目标态 /ai/v1/*(加版本前缀,便于未来破坏性变更)。

1.3 GraphQL schema如 BFF

不适用。ai 是业务服务,不暴露 GraphQL由 teacher-bff 聚合 ai gRPC 能力为 GraphQL。

1.4 Kafka 事件发布

Topic Event 触发时机 消费方 Payload
edu.ai.usage(建议,待 ISSUE-02 裁决) AIUsageEvent(待 ISSUE-04 补 proto 每次 LLM 调用完成 data-ana {event_id, aggregate_id, event_type, occurred_at, user_id, school_id, request_id, provider, model, operation, prompt_tokens, completion_tokens, total_tokens, latency_ms, success, degraded, metadata}

topic 命名三义01/02 文档写 edu.insight.ai.usage、matrix.md 写 edu.ai.usage、原 contract 写 edu.ai.usage.events。ai12 建议采用 edu.ai.usage(最简短),待 coord 裁决ISSUE-02Outbox 豁免AIUsageEvent 为派生数据事件004 §12.2 + §15.3 #6 仲裁豁免 Outbox允许直接 produceraiokafka + acks=all + idempotent + transactional_idevents.proto 现状:无 AIUsageEvent message待 coord 补全ISSUE-04建议 schema 见 02-architecture-design.md §3.3长期可发布事件P6+ 评估,待 coord 仲裁):AIContentGeneratedtopic edu.ai.generated,生成内容审计)、AIFeedbackRecordedtopic edu.ai.feedbackRLHF 数据)、AIWorkflowEventtopic edu.ai.workflow,工作流监控)。

1.5 错误码前缀

AI_*(对齐 02-architecture-design.md §6.2 完整清单matrix.md §6 已确认 ai 前缀为 AI_

错误码 触发条件 HTTP gRPC status
AI_UNAUTHORIZED 缺失 x-user-id 或 token 无效 401 UNAUTHENTICATED
AI_FORBIDDEN 角色无对应权限 403 PERMISSION_DENIED
AI_RATE_LIMITED 触发限流user/IP/school 429 RESOURCE_EXHAUSTED
AI_QUOTA_EXCEEDED 学校/教师月度 token 配额耗尽 429 RESOURCE_EXHAUSTED
AI_LLM_UNAVAILABLE LLM Provider 不可达(降级骨架) 200 OK + degraded flag
AI_LLM_TIMEOUT LLM 调用超时30s 504 DEADLINE_EXCEEDED
AI_LLM_ALL_PROVIDERS_FAILED 所有 Provider 故障切换链均失败 503 UNAVAILABLE
AI_INVALID_MODEL model 名不支持 400 INVALID_ARGUMENT
AI_INVALID_DIFFICULTY difficulty 不在 easy/medium/hard 400 INVALID_ARGUMENT
AI_INVALID_QUESTION_TYPE question_type 不在枚举内 400 INVALID_ARGUMENT
AI_DOWNSTREAM_UNAVAILABLE content / data-ana gRPC 不可达 502 UNAVAILABLE
AI_PROMPT_RENDER_FAILED Prompt 模板渲染失败 500 INTERNAL
AI_PROMPT_TEMPLATE_NOT_FOUND Prompt 模板不存在 404 NOT_FOUND
AI_WORKFLOW_NOT_FOUND 备课工作流 ID 不存在 404 NOT_FOUND
AI_WORKFLOW_EXPIRED 工作流已过期24h 未审核) 410 FAILED_PRECONDITION
AI_WORKFLOW_STATE_INVALID 工作流状态不允许此操作 409 FAILED_PRECONDITION
AI_EVALUATION_FAILED 生成质量评估未通过且重试耗尽 503 UNAVAILABLE
AI_PII_DETECTED 输入包含未脱敏 PII 400 INVALID_ARGUMENT
AI_PROMPT_INJECTION_DETECTED 输入疑似 Prompt 注入攻击 400 INVALID_ARGUMENT
AI_CONTENT_MODERATION_REJECTED 输出内容审核不通过(敏感词) 503 UNAVAILABLE
AI_INTERNAL_ERROR 未捕获异常 500 INTERNAL

§2 我消费什么(依赖上游)

2.1 gRPC 调用(同步)

被调用方 Service.RPC 用途 mock 策略
content (ai09) KnowledgeGraphService.GetPrerequisites 出题上下文:查询知识点前置依赖 content 就绪前使用本地知识点 stub固定 3 个前置知识点)
content (ai09) KnowledgeGraphService.GetLearningPath 个性化出题:查询学生学习路径 content 就绪前返回空路径
content (ai09) TextbookService.ListTextbooks 备课工作流:查询教材章节关联知识点 content 就绪前返回空列表
content (ai09) QuestionService.CreateQuestions(待 coord 补 proto 备课工作流:生成的题目入库 content 就绪前跳过入库,工作流标记 PersistFailed
data-ana (ai11) AnalyticsService.GetStudentWeakness 靶向出题:查询学生薄弱知识点 data-ana 就绪前使用本地薄弱点 stub固定 2 个 weak_points
data-ana (ai11) AnalyticsService.GetLearningTrend 难度调节:查询学习趋势 data-ana 就绪前返回默认趋势
data-ana (ai11) AnalyticsService.GetClassPerformance 备课工作流:班级整体学情 data-ana 就绪前降级跳过学情查询(degraded:true
iam (ai06) IamService.GetEffectiveDataScope(待 P4 补全ISSUE-07 多租户配额:查询用户 DataScope iam RPC 未就绪时降级为"仅按 user_id 配额,不按 school_id"

端口content gRPC 50054 / data-ana 50055 / iam 50052port-allocation.md §5。注意 02-architecture-design.md §1.1/§1.2 mermaid 图误标为 3005/3006/3002HTTP 端口),应以 50054/50055/50052 为准。

2.2 Kafka 事件订阅(异步)

ai 是无状态服务P5 不消费任何 Kafka 事件01/02 §5.1 明确)。原 contract 列出的 content 事件订阅已删除(与设计文档矛盾,见 ISSUE-05.5)。

P6+ 评估可消费事件(待 coord 仲裁,非 P5 范围):

Topic Event 发布方 用途 评估阶段
edu.content.question.events QuestionEvent content (ai09) 题目查重:避免 AI 生成与已有重复 P6+
edu.iam.user.events UserEvent iam (ai06) 角色变更:主动失效 DataScope 缓存 P6+

2.3 HTTP 调用(外部)

被调用方 Method.Path 用途 mock 策略
LLM ProviderOpenAI/Anthropic/百川/Ollama POST /v1/chat/completions 调用大模型生成内容 开发期使用本地 mock server 返回固定 ChatResponse不消耗真实 token

多 Provider 通过 ProviderFailoverChain 故障切换OpenAI → Anthropic → 百川 → 本地 Ollama熔断器连续 3 次失败触发 60s 熔断。


§3 就绪信号

3.1 我依赖的上游就绪标志

  • ai.proto 升级 v1 完整版6 RPC + 字段扩展)—— coordISSUE-03
  • events.proto 补 AIUsageEvent message —— coordISSUE-04
  • ai 用量事件 topic 命名裁决 —— coordISSUE-02
  • content gRPC 50054 启用ai09—— 知识点维度 + 题库检索 + 入库
  • data-ana gRPC 50055 启用ai11可选—— 学生薄弱点(可降级独立运行)
  • iam GetEffectiveDataScope RPC P4 补全ai06 + coordISSUE-07可降级
  • LLM Provider API key 配置(人类决策者)

3.2 我的就绪标志(供下游消费)

  • ai gRPC 50058 启用HealthService.Check 返回 SERVING
  • AiService.Chat / StreamChat 可调用(含流式响应)
  • AiService.GenerateQuestion / StreamGenerateQuestion 可调用
  • AiService.GenerateLessonPlan 可调用P5 补全)
  • AiService.OptimizeExpression 可调用
  • ai 用量事件 topic 可发布(供 data-ana 统计 AI 用量)

端口50058port-allocation.md §3/§5/§7 权威源2026-07-09 coord 仲裁"50058 让给 ai")。注意 matrix.md §2/§8 仍写 50057待 coord 同步ISSUE-01


§4 Mock 策略

4.1 我提供的 mock

在 ai 真实服务就绪前为下游teacher-bff提供以下 mock

  • gRPC mock:使用 grpc-mock 拦截 50058 端口
    • AiService.Chat 返回固定 ChatResponsecontent="这是 AI 助手的模拟回复"
    • AiService.StreamChat 返回固定流3 个 ChatChunk最后一个 done=true
    • AiService.GenerateQuestion 返回固定 GeneratedQuestionquestion/answer/explanation
    • AiService.GenerateLessonPlan 返回固定 LessonPlanResponseworkflow_id + 3 个题目)
    • AiService.StreamGenerateQuestion 返回固定流2 个题目逐字 chunk
    • AiService.OptimizeExpression 返回固定 OptimizedExpression
  • Kafka mockai 就绪前不发布真实 AIUsageEventdata-ana 仪表盘 AI 用量显示"暂无数据"

4.2 我消费的 mock

在真实上游就绪前ai 使用以下 mock

  • LLM Provider mock:本地启动 mock serverPOST /v1/chat/completions 返回固定 JSON不消耗真实 token不产生费用
  • content 知识点:内置固定知识点表(数学 20 个知识点 + 前置依赖关系),不依赖 content gRPC
  • data-ana 薄弱点内置固定学生薄弱点2 个 weak_points不依赖 data-ana gRPC
  • iam DataScope:内置固定 DataScopeSCHOOL 级),不依赖 iam GetEffectiveDataScope
  • 事件订阅P5 不订阅任何事件,无 mock 需要

§5 契约待裁决项汇总

以下字段待 coord 裁决后最终定稿ai12 当前按建议方案先行实现。

待裁决项 ISSUE ai12 建议方案 影响章节
ai gRPC 端口50057 vs 50058 ISSUE-01 50058port-allocation.md 已定,待 matrix 同步) §1.1 / §3.2
ai 用量事件 topic 命名 ISSUE-02 edu.ai.usage §1.4
ai.proto P5 目标 RPC 数6 vs 8 ISSUE-03 6 RPC查询/确认用 HTTP §1.1
events.proto 补 AIUsageEvent ISSUE-04 按 02-architecture-design.md §3.3 schema §1.4
备课工作流 TemporalP6 决策点) ISSUE-06 P5 用 BackgroundTasks + RedisP6 评估 Temporal §2.1(无影响)
iam GetEffectiveDataScope P4 补全 ISSUE-07 确认 P4 已补全;未补全则降级 §2.1
proto package 命名(全局) ISSUE-08 待 coord 裁定是否迁移 edu.<domain>.v1 §1.1
响应信封 ActionState 整改 ISSUE-09 P5 整改degraded 作为 error.details 子字段 §1.2