Files
Neo-ZQYY/docs/specs/P14-ai-dashscope-migration/tasks.md
Neo 70324d8542 chore: 文档与 IDE 配置整理
- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro)
- CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/
- 新增 /spec-close、/pre-change 两个工作流命令
- DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表)
- BD_Manual → BD_manual 命名统一(48 个文件)
- 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数)
- 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表)
- 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档)
- docs/database/README.md 索引更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:02:37 +08:00

13 KiB
Raw Blame History

实施计划P14 — AI 模块改造 — DashScope 迁移 + 调度器完善

概述

按依赖关系从底层到顶层逐步实施:环境变量/配置 → DashScope 客户端 → 防护层(熔断/限流/预算) → 运行日志 → 调度器 → API 路由 → 服务适配 → ETL 触发 → 数据库迁移 → 收尾。每个任务构建在前序任务之上,确保无孤立代码。

任务

  • 1. 环境变量与配置基础

    • 1.1 重写 apps/backend/app/ai/config.py,实现 AIConfig dataclass

      • 定义所有 DASHSCOPE_* 环境变量字段和 INTERNAL_API_TOKEN
      • 实现 from_env() 类方法,缺失必需变量时立即抛出异常
      • 删除所有 BAILIAN_* 引用
      • 需求: 2.1, 2.2, 2.3, 2.5
    • 1.2 编写属性测试:环境变量校验完整性

      • Property 2: 环境变量校验完整性
      • 对任意必需变量子集缺失,from_env() 应抛出异常,不返回含空字符串的配置
      • 验证: 需求 2.5
    • 1.3 更新 .env.env.templatepyproject.toml

      • .env / .env.templateBAILIAN_*DASHSCOPE_*,新增 DASHSCOPE_WORKSPACE_IDINTERNAL_API_TOKEN
      • pyproject.toml:移除 openai 依赖,新增 dashscope 依赖
      • 需求: 2.4, 1.7
  • 2. DashScopeClient 核心客户端

    • 2.1 创建 apps/backend/app/ai/dashscope_client.py,实现 DashScopeClient

      • call_app() — App2~8 单轮调用,asyncio.to_thread() 包装,返回 (parsed_json, tokens_used, new_session_id)
      • call_app_stream() — App1 流式调用,线程消费同步迭代器 + asyncio.Queue 桥接 async generator
      • _call_with_retry() — 指数退避重试1s→2s→4sHTTP 4xx 不重试5xx/超时/连接错误重试
      • 非合法 JSON 响应纯重试(最大 3 次),不做本地修复
      • 需求: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6
    • 2.2 定义异常层级

      • DashScopeError 基类及子类:DashScopeApiErrorDashScopeAuthErrorDashScopeTimeoutErrorDashScopeJsonParseErrorCircuitOpenErrorRateLimitExceededErrorBudgetExceededError
      • 需求: 1.5, 5.6, 6.3, 7.3
    • 2.3 编写属性测试:重试策略正确性

      • Property 1: 重试策略正确性
      • 4xx 立即抛出不重试5xx/超时/连接错误最多重试 3 次,非法 JSON 触发重试
      • 验证: 需求 1.5, 1.6
    • 2.4 编写属性测试Application API 响应解析

      • Property 20: Application API 响应解析
      • 合法 JSON 正确解析为 dict非法 JSON 触发重试
      • 验证: 需求 4.4
  • 3. 检查点 — 确保所有测试通过

    • 确保所有测试通过ask the user if questions arise.
  • 4. 防护层熔断器、限流器、Token 预算

    • 4.1 创建 apps/backend/app/ai/circuit_breaker.py,实现 CircuitBreaker

      • app_id 独立计数,_BreakerState 内部状态
      • check() / record_success() / record_failure() 方法
      • 状态机CLOSED → OPEN连续 5 次失败)→ HALF_OPEN60 秒后)→ CLOSED/OPEN
      • 需求: 5.1, 5.2, 5.3, 5.4, 5.5, 5.6
    • 4.2 编写属性测试:熔断器 app_id 隔离 + 状态机转换

      • Property 5: 熔断器 app_id 隔离
      • Property 6: 熔断器状态机转换
      • 不同 app_id 互不影响;状态转换符合 CLOSED→OPEN→HALF_OPEN→CLOSED/OPEN 规则
      • 验证: 需求 5.1, 5.2, 5.3, 5.4, 5.5
    • 4.3 创建 apps/backend/app/ai/rate_limiter.py,实现 RateLimiter

      • 滑动窗口内存计数器
      • check_user_rate() — App1 每用户每分钟 10 次
      • check_store_rate() — App2~8 每门店每小时 100 次
      • 需求: 6.1, 6.2, 6.3, 6.4
    • 4.4 编写属性测试:限流器窗口控制

      • Property 7: 限流器窗口控制
      • 窗口内未超阈值允许,超阈值拒绝;窗口外历史不影响当前判断
      • 验证: 需求 6.1, 6.2
    • 4.5 创建 apps/backend/app/ai/budget_tracker.py,实现 BudgetTracker

      • check_budget()ai_run_logs 聚合日/月 token 消耗
      • 日预算 100,000 / 月预算 2,000,000
      • 返回 BudgetStatus(allowed, daily_used, monthly_used, reason)
      • 需求: 7.1, 7.2, 7.3, 7.4, 7.5
    • 4.6 编写属性测试Token 预算检查正确性

      • Property 8: Token 预算检查正确性
      • 日聚合 = 当日 success 记录 tokens_used 之和;超限时 allowed=false
      • 验证: 需求 7.1, 7.3
  • 5. AI 运行日志服务

    • 5.1 创建 apps/backend/app/ai/run_log_service.py,实现 AIRunLogService

      • create_log() — 创建 pending 记录
      • update_running() / update_success() / update_failed() / update_timeout() — 状态转换
      • get_daily_token_usage() / get_monthly_token_usage() — 聚合查询
      • request_prompt 截断为前 2000 字符
      • 需求: 16.1, 16.2, 16.3, 16.4, 16.5, 16.6
    • 5.2 编写属性测试AI 运行日志状态机 + Prompt 截断

      • Property 18: AI 运行日志状态机
      • Property 19: Prompt 截断不变量
      • 状态转换正确pending→running→success/failed/timeoutprompt ≤ 2000 字符
      • 验证: 需求 16.1, 16.2, 16.3, 16.4, 16.5, 16.6
  • 6. 检查点 — 确保所有测试通过

    • 确保所有测试通过ask the user if questions arise.
  • 7. Dispatcher 调度器重写

    • 7.1 重写 apps/backend/app/ai/dispatcher.py,实现 AIDispatcher

      • 移除所有 asyncio.run()asyncio.new_event_loop() 调用
      • 所有入口改为 async def,用 asyncio.create_task() 发起后台任务
      • 超时用 asyncio.wait_for()
      • 集成 CircuitBreaker、RateLimiter、BudgetTracker
      • _run_step() — 单步执行:熔断检查→限流检查→预算检查→调用→记录日志
      • 需求: 8.1, 8.2, 8.3, 8.4
    • 7.2 实现事件触发链编排

      • _handle_consumption() — 消费事件App3→App8→App7无助教/ +App4→App5有助教
      • _handle_note() — 备注事件App6→App8
      • _handle_task_assigned() — 任务分配App4→App5
      • _handle_dws_completed() — DWS 完成App2 预生成8 个时间维度)
      • 调用链某步失败时记录错误,后续步骤使用已有缓存继续
      • 需求: 9.1, 9.2, 9.3, 9.4, 9.5, 11.1, 11.2, 11.3, 11.4
    • 7.3 实现幂等去重逻辑

      • _check_dedup() — 按 (event_type, member_id, site_id, date) 去重
      • is_forced=true 时跳过去重检查
      • 写入 ai_trigger_jobs 记录
      • 需求: 12.1, 12.2
    • 7.4 编写属性测试:事件类型到调用链映射

      • Property 9: 事件类型到调用链映射
      • 各事件类型映射到正确的 App 调用链
      • 验证: 需求 9.1, 9.2, 9.3, 11.1
    • 7.5 编写属性测试:调用链容错不中断

      • Property 10: 调用链容错不中断
      • 任意步骤失败后后续步骤仍继续执行
      • 验证: 需求 9.4
    • 7.6 编写属性测试:事件去重与强制执行

      • Property 12: 事件去重与强制执行
      • 重复自动事件跳过;is_forced=true 正常执行
      • 验证: 需求 12.1, 12.2
  • 8. 检查点 — 确保所有测试通过 76 passed

    • 确保所有测试通过ask the user if questions arise.
  • 9. API 路由与端点

    • 9.1 创建 apps/backend/app/routers/internal_ai.py,实现内部触发 API

      • POST /api/internal/ai/trigger 端点
      • TriggerRequest Pydantic 模型event_type, connector_type, site_id, member_id, payload
      • verify_internal_token() 依赖注入,校验 Authorization: Internal-Token {token}
      • 写入 ai_trigger_jobs 后立即返回 {trigger_job_id, status: "pending"},后台异步执行
      • 在 FastAPI app 中注册路由
      • 需求: 10.1, 10.2, 10.3, 10.4, 10.5
    • 9.2 编写属性测试:内部 API 认证

      • Property 11: 内部 API 认证
      • token 缺失/不匹配返回 401匹配时正常处理
      • 验证: 需求 10.2, 10.3
    • 9.3 适配 apps/backend/app/routers/xcx_chat.py SSE 端点

      • 替换 _get_bailian_client()_get_dashscope_client()
      • 调用 client.call_app_stream(app_id, prompt, session_id, biz_params)
      • 构建 prompt + biz_paramsUser_ID, Role, Nickname
      • 保持 SSE 事件格式:event: message / event: done / event: error
      • 流结束后记录 ai_run_logs
      • 需求: 15.1, 15.2, 15.3, 15.4, 3.3
    • 9.4 编写属性测试SSE 事件流格式

      • Property 17: SSE 事件流格式
      • 零或多个 event: message,最终以恰好一个 doneerror 结束
      • 验证: 需求 15.2
  • 10. 服务层适配

    • 10.1 适配 apps/backend/app/services/ai/chat_service.py — session_id 双轨逻辑

      • 新对话生成 session_id格式 conv_{conversation_id}_{created_timestamp}
      • 每条消息同时写入本地 ai_messages
      • session_id 过期时从本地加载最近 20 条历史重建
      • 保持对话复用规则task 无时限、customer/coach 3 天、general 新建
      • 需求: 3.1, 3.2, 3.4, 3.5, 3.6
    • 10.2 编写属性测试session_id 格式 + 对话复用规则

      • Property 3: session_id 格式不变量
      • Property 4: 对话复用规则
      • session_id 匹配 ^conv_\d+_\d+$;复用规则按入口类型正确判断
      • 验证: 需求 3.1, 3.6
    • 10.3 适配 apps/backend/app/services/ai/cache_service.py — 缓存状态与过期策略

      • 新增 status 字段处理valid/expired/invalidated/generating
      • 写入前设 generating,完成后设 valid
      • 查询仅返回 status='valid' 且未过期的记录
      • 按 App 类型设置过期时间App2 当日 23:59:59、App3~5/7/8 七天、App6 三十天)
      • App2~8 每 App 保留最新 20,000 条,超限清理最旧记录
      • 需求: 13.1, 13.2, 13.3, 13.4, 13.5
    • 10.4 编写属性测试:缓存过期策略 + 查询过滤 + 保留上限

      • Property 14: 缓存过期策略正确性
      • Property 15: 缓存查询过滤
      • Property 16: 缓存保留上限
      • 过期时间匹配策略;查询仅返回 valid 且未过期;每 App ≤ 20,000 条
      • 验证: 需求 13.1, 13.4, 13.5
    • 10.5 实现 App8 幂等写入 member_retention_clue

      • 事务中 DELETE + INSERT同一 member 同一天只执行一次
      • 事务失败自动回滚,记录错误到 ai_trigger_jobs.error_message
      • 需求: 12.3, 12.4
    • 10.6 编写属性测试App8 幂等写入

      • Property 13: App8 幂等写入
      • 多次执行后同一 member 同一天记录数恒为 1
      • 验证: 需求 12.3
  • 11. 检查点 — 确保所有测试通过 106 passed

    • 确保所有测试通过ask the user if questions arise.
  • 12. ETL 触发集成

    • 12.1 修改 apps/etl/connectors/feiqiu/tasks/ 相关 DWS 任务
      • DWS 任务完成后通过 requests 发送 POST /api/internal/ai/trigger
      • 携带 Authorization: Internal-Token {INTERNAL_API_TOKEN} Header
      • 事件类型:dws_completedApp2 预生成)/ consumption(消费事件链)
      • 新增 utils/ai_trigger.py 工具函数 + BaseDwsTask.AI_TRIGGER_EVENT 类属性
      • FinanceDailyTaskdws_completedMemberConsumptionTaskconsumption
      • 需求: 10.6
  • 13. 数据库迁移

    • 13.1 编写迁移脚本 db/zqyy_app/migrations/2026-03-22__p14_ai_module.sql
      • CREATE TABLE biz.ai_run_logs(含 3 个索引)
      • CREATE TABLE biz.ai_trigger_jobs(含 3 个索引,含去重部分索引)
      • ALTER TABLE biz.ai_conversations ADD COLUMN session_id
      • ALTER TABLE biz.ai_cache ADD COLUMN status + CHECK 约束
      • 编写对应回滚脚本(逆序 DROP/ALTER+ 验证 SQL7 条)
      • 需求: 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7
  • 14. 收尾:文档与集成验证

    • 14.1 更新 BD 手册

      • 更新 docs/database/BD_Manual_ai_tables.md:新增 ai_run_logsai_trigger_jobs 表结构
      • 更新 ai_cache.statusai_conversations.session_id 字段说明
      • 需求: 14.1, 14.2, 14.3, 14.4
    • 14.2 文档同步

      • 更新 docs/prd/ai-app-prompts.md:环境变量映射 BAILIAN_* → DASHSCOPE_*
      • 更新 apps/backend/README.mdAI 模块架构说明
      • 更新 docs/DOCUMENTATION-MAP.md:新增文档条目
      • 需求: 2.4
  • 15. 最终检查点 — 确保所有测试通过 505 passedP14 全部 15 个测试文件通过80 个预存失败均非 P14 相关)

    • 确保所有测试通过ask the user if questions arise.

说明

  • 标记 * 的子任务为可选(属性测试),可跳过以加速 MVP
  • 每个任务关联了具体的需求编号,确保可追溯
  • 属性测试任务标注了对应的 Property 编号和验证的需求条款
  • 检查点确保增量验证,避免问题累积
  • 实现语言Python与设计文档一致