修复涵盖 6 大类问题: 1. api-gateway - 路径前缀剥离 /api 而非 /api/v1,保留下游 /v1/ controller 前缀 - JWKS URL 默认值修复 - publicPaths 白名单对齐 /v1/iam/* 2. iam - iam.module.ts exports 补充 PermissionCacheService 和 IamRepository - main.ts resolveProtoPath() 多路径探测 proto 文件 3. core-edu - app.module.ts AuthMiddleware 全局注册 4. BFF 层 GraphQL 端点(teacher-bff / parent-bff / student-bff) - teacher-bff: mock dataScope OWN→SELF 对齐 GraphQL enum;WHATWG Request header .get() 提取 - parent-bff: handleNodeRequestAndResponse 不存在 → 直接 yoga(req,res);WHATWG Request header .get() 提取 - student-bff: auth.resolver 移除 ActionState 信封返回扁平对象;WHATWG Request header .get() 提取 5. ai - Kafka 事务降级 + 10s 超时 - gRPC 拦截器降级 - dev mode 禁用事务模式 6. 前端 + 共享包 - teacher-portal: MF 插件条件实例化 + transpilePackages + extensionAlias - ui-components: error-boundary.tsx 添加 use client - ui-tokens: tailwind-theme.css 移除 @layer base - shared-ts: 导出从源码改为 dist 编译产物;OutboxModule global:true 7. infra - .gitignore 补充 keys/ *.pem *.key secrets/ 排除规则 - infra/init-sql/02-all-services-schema.sql 36 张表 DDL 验证结果: - TS typecheck: 19 个 workspace 项目全部通过 - Go vet + Ruff: 通过 - 15 服务全部启动成功 - 3 个 BFF GraphQL 端点 + 4 个前端页面全部 200 - Gateway → iam → core-edu 端到端链路验证通过 AI identity: trae-main(集成测试修复会话)
AI 网关服务
版本:1.0(P5 完整实现) 端口:HTTP 3008 + gRPC 50058 定位:D6 智能洞察领域 · 生成子域(Python/FastAPI,严格无状态)
职责
统一封装 LLM 调用(多模型路由 + 故障切换 + 熔断 + 限流 + 成本控制),提供:
- 聊天:非流式 + SSE 流式
- 题目生成:非流式 + 流式 + 评估三道防线(RuleValidator + LLMJudge + QualityGate)
- 表达优化:文字清晰度/简洁度/语气优化
- 备课工作流:4 步编排(分析学情 → 推荐知识点 → 生成题目 → 教师审核入库)
通过 gRPC 查询 content 题库与 data-ana 学情数据。通过 Kafka 发布 AIUsageEvent 供 data-ana 统计。
技术栈
- Python 3.12 + FastAPI 0.115
- Pydantic 2 + pydantic-settings(12-factor 配置)
- grpc.aio(gRPC server 8 RPC + client 拦截器)
- aiokafka(用量事件发布,事务性 + 幂等,派生数据豁免 Outbox)
- Jinja2 + YAML(Prompt 模板渲染)
- redis(限流令牌桶 + 用量记录 + 工作流状态存储)
- OpenTelemetry(HTTP + gRPC 链路追踪)
- prometheus-client + structlog(指标 + 结构化日志)
架构分层
HTTP 端点(/v1/ai 前缀,ActionState 信封)
↓
PermissionGuard(权限校验)→ RateLimiter(三维度令牌桶)
↓
Service 层(ChatService / QuestionService / ExpressionService / LessonPlanWorkflowService)
↓
LLM ProviderFailoverChain(4 适配器 + CircuitBreaker)
↓
LLM Provider(OpenAI / Anthropic / Baichuan / LocalOllama)
gRPC server(端口 50058,8 RPC,interceptor 链)
↓
AiServicer(proto ↔ domain 模型转换)
↓
Service 层(同 HTTP)
备课工作流:FastAPI BackgroundTasks + Redis 状态存储(24h TTL)
安全层:PIIRedactor + InputSanitizer + OutputModerator
用量:UsageRecorder(Redis)→ KafkaProducer → edu.ai.usage topic
开发
# 安装依赖
uv sync
# 启动开发服务(dev_mode=true 跳过 OTel exporter)
DEV_MODE=true uv run uvicorn src.ai.main:app --reload --port 3008
# Lint
uv run ruff check src/
# 测试
uv run pytest
HTTP API
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| GET | /healthz | — | liveness |
| GET | /readyz | — | readiness(含 LLM/gRPC/Provider 状态) |
| GET | /metrics | — | Prometheus 指标 |
| POST | /v1/ai/chat | ai:chat | 非流式聊天 |
| POST | /v1/ai/chat/stream | ai:chat | 流式聊天(SSE) |
| POST | /v1/ai/generate/question | ai:question:generate | 生成题目 |
| POST | /v1/ai/generate/question/stream | ai:question:generate | 流式生成题目(SSE) |
| POST | /v1/ai/optimize/expression | ai:expression:optimize | 优化表达 |
| POST | /v1/ai/lesson-plan/generate | ai:lesson:generate | 启动备课工作流 |
| GET | /v1/ai/lesson-plan/status/{workflow_id} | — | 查询工作流状态 |
| POST | /v1/ai/lesson-plan/confirm/{workflow_id} | ai:lesson:confirm | 教师确认入库 |
所有业务响应统一使用 ActionState 信封:{success, data, error:{code, message, details?, traceId?}}
降级采用方案 B(总裁裁决 §2.6):success=true + error=null + data 内 degraded=true + degraded_reason
gRPC API(端口 50058,8 RPC)
| RPC | 请求 | 响应 |
|---|---|---|
| Chat | ChatRequest | ChatResponse |
| StreamChat | ChatRequest | stream ChatChunk |
| GenerateQuestion | GenerateQuestionRequest | GeneratedQuestion |
| StreamGenerateQuestion | GenerateQuestionRequest | stream GeneratedQuestionChunk |
| OptimizeExpression | OptimizeExpressionRequest | OptimizedExpression |
| GenerateLessonPlan | GenerateLessonPlanRequest | LessonPlanResponse |
| GetLessonPlanStatus | GetLessonPlanStatusRequest | LessonPlanStatus |
| ConfirmLessonPlan | ConfirmLessonPlanRequest | ConfirmResult |
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
| http_port | 3008 | HTTP 端口 |
| grpc_port | 50058 | gRPC 端口 |
| dev_mode | false | 开发模式(跳过 OTel + 权限校验) |
| openai_api_key | — | OpenAI API 密钥 |
| anthropic_api_key | — | Anthropic API 密钥 |
| baichuan_api_key | — | 百川 API 密钥 |
| ollama_base_url | — | 本地 Ollama 地址 |
| llm_provider_priority | openai,anthropic,baichuan,local_ollama | Provider 故障切换顺序 |
| redis_url | redis://localhost:6379/0 | Redis 连接 |
| kafka_bootstrap_servers | localhost:9092 | Kafka 连接 |
| kafka_ai_usage_topic | edu.ai.usage | 用量事件 topic |
| otel_endpoint | http://localhost:4318 | OpenTelemetry OTLP 端点 |
限流(三维度)
| 维度 | 限制 | 算法 |
|---|---|---|
| user | 10 req/min | Redis Lua 令牌桶 |
| IP | 30 req/min | Redis Lua 令牌桶 |
| school | 100 req/min | Redis Lua 令牌桶 |
Redis 不可用时降级放行(记录警告)。
错误码
前缀 AI_*,完整 21 个错误码见 02-architecture-design.md §6.2。