Files
Neo-ZQYY/docs/specs/P14-ai-dashscope-migration/requirements.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

19 KiB
Raw Blame History

需求文档 — P14AI 模块改造 — DashScope 迁移 + 调度器完善

简介

当前 AI 模块使用 openai SDK 的通用模型 APIchat.completions.create),但项目的 8 个 App 均为百炼控制台创建的智能体应用(各有独立 app_id)。通用模型 API 不接受 app_id,等于绕过了百炼控制台配置的 System Prompt、MCP 工具等全部能力。

本 spec 将 SDK 从 openai 切换到 dashscopeApplication API一步到位完成迁移同时修复调度器 asyncio 嵌套问题、打通事件触发链、新增熔断/限流/Token 预算控制,并完成相关数据库变更。

依赖

  • P5AI 集成层)— 现有 AI 模块基础架构、8 个 App 实现、缓存/对话服务
  • RNS1.4CHAT 对齐)— CHAT 路径迁移、SSE 端点、对话复用规则

来源文档

  • docs/prd/specs/P14-ai-dashscope-migration.md — PRD 主文档
  • docs/reports/2026-03-21__ai_module_issues.md — 18 个问题清单4 P0 / 6 P1 / 5 P2 / 3 P3

不在本 spec 范围

  • admin-web AI 监控后台P15
  • 全链路测试重建与历史回填P15
  • 多门店支持BACKLOG当前写死 2790685415443269
  • 消息队列替代 HTTP 触发(单独 PRD
  • Prompt 版本管理BACKLOG
  • 前端刷新机制(前端改动,不在本 spec

术语表

  • BackendFastAPI 后端应用,位于 apps/backend/
  • ETL:飞球 Connector ETL 管道,位于 apps/etl/connectors/feiqiu/
  • DashScope_Client:新的 DashScope Application API 客户端,替代现有 BailianClient
  • Application_APIdashscope.Application.call() 方法,百炼智能体应用的原生调用接口
  • App1:通用对话应用(流式,支持多轮 session_id
  • App2财务洞察应用单轮DWS 完成后预生成)
  • App3:维客线索应用(单轮,消费事件触发)
  • App4:关系分析应用(单轮,消费/任务事件触发)
  • App5:话术参考应用(单轮,依赖 App4 结果)
  • App6:备注分析应用(单轮,备注事件触发)
  • App7:客户分析应用(单轮,消费事件触发)
  • App8:维客线索整理应用(单轮,整合 App3/App6 线索)
  • session_id:百炼云端对话管理标识,格式 conv_{conversation_id}_{created_timestamp}
  • Circuit_Breaker:熔断器,按 app_id 独立计数,连续失败后暂停请求
  • Rate_Limiter:限流器,按用户/门店维度控制请求频率
  • Budget_TrackerToken 预算追踪器,按日/月聚合 token 消耗
  • Internal_AI_API:内部触发接口 POST /api/internal/ai/triggerETL 通过此接口触发 AI 调用链
  • DispatcherAI 事件调度与调用链编排器,位于 apps/backend/app/ai/dispatcher.py
  • ai_run_logsAI 运行记录表,记录每次 Application API 调用的输入/输出/耗时/token
  • ai_trigger_jobs:调度运行记录表,记录事件触发的调用链执行状态

需求

需求 1SDK 替换 — openai 切换到 dashscope Application API

用户故事: 作为后端开发者,我希望将 AI 客户端从 openai SDK 切换到 dashscope Application API以便 8 个百炼智能体应用能通过各自的 app_id 调用,使用百炼控制台配置的 System Prompt 和 MCP 工具。

验收标准

  1. THE DashScope_Client SHALL 使用 dashscope.Application.call() 替代 openai.AsyncOpenAI.chat.completions.create(),所有 8 个 App 通过各自的 app_id 参数调用 Application API
  2. THE DashScope_Client SHALL 使用 asyncio.to_thread() 包装同步的 Application.call() 方法,避免阻塞 FastAPI 事件循环
  3. WHEN App1 进行流式调用时THE DashScope_Client SHALL 在独立线程中消费 Application.call(stream=True) 返回的同步迭代器,通过 asyncio.Queue 桥接到 async generator逐 chunk 输出文本
  4. WHEN App2~8 进行单轮调用时THE DashScope_Client SHALL 通过 prompt 参数传入后端拼好的完整数据 JSON不使用 messages 数组
  5. THE DashScope_Client SHALL 保留指数退避重试机制:最多 3 次重试,间隔 1s → 2s → 4sHTTP 4xx 不重试5xx/超时/连接错误重试
  6. WHEN Application API 返回非合法 JSON 时THE DashScope_Client SHALL 纯重试(最大 3 次),不做本地解析修复
  7. THE Backend SHALL 在 pyproject.toml 中移除 openai 依赖,新增 dashscope 依赖

需求 2环境变量统一 — BAILIAN_* 迁移到 DASHSCOPE_*

用户故事: 作为运维人员,我希望环境变量从 BAILIAN_* 统一迁移到 DASHSCOPE_* 前缀,以便与 DashScope SDK 的命名规范保持一致。

验收标准

  1. THE Backend SHALL 废弃并删除以下环境变量:BAILIAN_API_KEYBAILIAN_BASE_URLBAILIAN_MODEL
  2. THE Backend SHALL 新增以下环境变量:DASHSCOPE_API_KEYDashScope API KeyDASHSCOPE_WORKSPACE_ID(百炼工作空间 ID可选
  3. THE Backend SHALL 将 8 个 App ID 环境变量从 BAILIAN_APP_ID_* 前缀重命名为 DASHSCOPE_APP_ID_* 前缀(DASHSCOPE_APP_ID_1_CHATDASHSCOPE_APP_ID_8_CONSOLIDATE
  4. THE Backend SHALL 更新 .env.env.template 文件,反映所有环境变量变更
  5. THE Backend SHALL 在启动时校验必需环境变量(DASHSCOPE_API_KEY 和 8 个 DASHSCOPE_APP_ID_*),缺失时立即报错,禁止静默回退空字符串

需求 3App1 对话管理 — session_id 云端 + 本地双轨

用户故事: 作为助教用户,我希望与 AI 助手的多轮对话能通过百炼 session_id 保持上下文连贯,同时本地持久化消息记录,以便在 session 过期后仍能恢复对话。

验收标准

  1. WHEN App1 创建新对话时THE Backend SHALL 生成 session_id格式 conv_{conversation_id}_{created_timestamp}),存储到 ai_conversations.session_id 字段
  2. WHEN App1 发送消息时THE DashScope_Client SHALL 携带 session_id 参数调用 Application API由百炼云端管理对话上下文
  3. THE DashScope_Client SHALL 通过 biz_params.user_prompt_params 传递用户信息:User_ID(用户 IDRole(角色)、Nickname(昵称)
  4. THE Backend SHALL 同时将每条消息写入本地 ai_messages 表,实现云端 + 本地双轨持久化
  5. IF session_id 过期(百炼返回 session 无效错误THEN THE Backend SHALL 从本地 ai_messages 加载最近 20 条历史消息,用 messages 数组(不带 session_id重新调用百炼并将百炼返回的新 session_id 更新到本地
  6. THE Backend SHALL 保持现有对话复用规则不变task 入口无时限复用、customer/coach 入口 3 天时限、general 入口始终新建

需求 4App2~8 单轮 Prompt 调用

用户故事: 作为后端开发者,我希望 App2~8 统一使用单轮 prompt 调用模式,以便简化调用逻辑并充分利用百炼控制台配置的 System Prompt。

验收标准

  1. THE Backend SHALL 为 App2~8 的每次调用使用 build_prompt() 函数拼好完整数据 JSON通过 Application.call(app_id=..., prompt=data_json) 传入
  2. THE Backend SHALL 不再为 App2~8 在代码中维护 System Prompt以百炼控制台配置为准
  3. THE Backend SHALL 不再为 App2~8 使用 messages 数组或 response_format 参数
  4. WHEN Application API 返回结果时THE Backend SHALL 解析 response.output.text 字段获取 JSON 内容,解析失败时按需求 1 第 6 条重试
  5. THE Backend SHALL 为每次 App2~8 调用记录 ai_run_logs(详见需求 10

需求 5熔断器

用户故事: 作为系统管理员,我希望 AI 调用具备熔断保护,以便在百炼服务异常时快速降级,避免无效请求堆积。

验收标准

  1. THE Circuit_Breaker SHALL 按 app_id 独立计数App1 熔断不影响 App2~8反之亦然
  2. WHEN 某个 app_id 连续 5 次调用失败时THE Circuit_Breaker SHALL 进入熔断状态,持续 60 秒内所有该 app_id 的请求直接返回降级响应
  3. WHEN 熔断 60 秒后THE Circuit_Breaker SHALL 进入半开状态,放行 1 个请求进行探测
  4. WHEN 半开状态的探测请求成功时THE Circuit_Breaker SHALL 关闭熔断,恢复正常调用
  5. WHEN 半开状态的探测请求失败时THE Circuit_Breaker SHALL 重新进入熔断状态,再等待 60 秒
  6. WHILE Circuit_Breaker 处于熔断状态THE Backend SHALL 对 App1 请求返回友好提示"AI 服务暂时不可用,请稍后重试",对 App2~8 后台任务记录 circuit_open 状态并跳过执行

需求 6限流

用户故事: 作为系统管理员,我希望 AI 调用具备限流保护,以便防止单个用户或门店过度消耗 AI 资源。

验收标准

  1. THE Rate_Limiter SHALL 对 App1 实施每用户每分钟 10 次的请求频率限制
  2. THE Rate_Limiter SHALL 对 App2~8 实施每门店每小时 100 次(合计)的请求频率限制
  3. WHEN 请求超过限流阈值时THE Rate_Limiter SHALL 对 App1 返回友好提示"请求过于频繁,请稍后再试",对 App2~8 后台任务记录 rate_limited 状态并跳过执行
  4. THE Rate_Limiter SHALL 使用内存计数器实现(单实例部署),不依赖外部 Redis

需求 7Token 预算控制

用户故事: 作为系统管理员,我希望 AI 调用具备 Token 预算控制,以便防止 API 费用失控。

验收标准

  1. THE Budget_Tracker SHALL 从 ai_run_logs.tokens_used 按日/月聚合计算已消耗 token 数
  2. THE Budget_Tracker SHALL 支持日预算上限(默认 100,000 tokens和月预算上限默认 2,000,000 tokens
  3. WHEN 日预算或月预算超限时THE Backend SHALL 对 App1 用户对话返回友好提示"AI 服务今日额度已用完,请明天再试"
  4. WHEN 日预算或月预算超限时THE Backend SHALL 对 App2~8 后台任务跳过执行,记录 budget_exceeded 状态到 ai_run_logs
  5. THE Budget_Tracker SHALL 在每次 AI 调用前检查预算,调用后更新 token 消耗记录

需求 8调度器 asyncio 修复

用户故事: 作为后端开发者,我希望修复 dispatcher.py 中的 asyncio 嵌套问题,以便事件处理器在 FastAPI 事件循环中正常工作,不再因 asyncio.run() 嵌套而报错。

验收标准

  1. THE Dispatcher SHALL 移除所有 asyncio.run()asyncio.new_event_loop() 调用
  2. THE Dispatcher SHALL 将所有事件处理器入口改为 async def,使用 asyncio.create_task() 发起后台异步任务
  3. THE Dispatcher SHALL 使用 asyncio.wait_for() 实现超时控制,替代同步超时机制
  4. THE Dispatcher SHALL 确保事件处理器在 FastAPI lifespan 中注册后,能在已有事件循环中正常执行调用链

需求 9事件触发链打通

用户故事: 作为系统管理员,我希望消费事件、备注事件、任务分配事件能正确触发对应的 AI 调用链,以便 AI 分析结果能自动生成,无需人工干预。

验收标准

  1. WHEN ETL DWS 任务完成后发送消费事件时THE Dispatcher SHALL 执行调用链App3 → App8 → App7无助教时或 App3 → App8 → App7 + App4 → App5有助教时
  2. WHEN 小程序助教提交备注时THE Dispatcher SHALL 执行调用链App6 → App8
  3. WHEN task_manager 自动分配任务时THE Dispatcher SHALL 执行调用链App4 → App5
  4. THE Dispatcher SHALL 在调用链中某步失败时记录错误日志,后续应用使用已有缓存继续执行,不中断整条链
  5. THE Dispatcher SHALL 将每次事件触发记录到 ai_trigger_jobs 表,包含事件类型、执行链、状态、耗时

需求 10ETL → 后端内部触发 API

用户故事: 作为 ETL 开发者,我希望 DWS 任务完成后能通过 HTTP 接口触发后端 AI 调用链,以便实现 ETL 与 AI 模块的自动联动。

验收标准

  1. THE Backend SHALL 实现 POST /api/internal/ai/trigger 端点,接受 JSON 请求体包含:event_type(事件类型)、connector_type(连接器类型,默认 feiqiu)、site_id(门店 IDmember_id(会员 ID可选payload(事件附加数据)
  2. THE Internal_AI_API SHALL 使用独立的 INTERNAL_API_TOKEN 环境变量进行认证,通过 HTTP Header Authorization: Internal-Token {token} 传递,不走 JWT
  3. IF 认证 token 缺失或不匹配THEN THE Internal_AI_API SHALL 返回 HTTP 401
  4. THE Internal_AI_API SHALL 将事件写入 ai_trigger_jobs 表后立即返回 { trigger_job_id, status: "pending" },调用链在后台异步执行
  5. THE Internal_AI_API SHALL 设计为连接器无关接口,connector_type 字段标识来源,为多平台扩展预留
  6. THE ETL SHALL 在 DWS 任务完成后通过 HTTP POST 调用 Internal_AI_API传递消费事件或 DWS 完成事件

需求 11App2 预生成

用户故事: 作为门店管理者我希望财务洞察App2在每日 DWS 数据刷新后自动预生成,以便打开页面时能立即看到最新分析结果,无需等待。

验收标准

  1. WHEN ETL 通过 Internal_AI_API 发送 event_type: "dws_completed" 事件时THE Dispatcher SHALL 触发 App2 预生成任务
  2. THE Dispatcher SHALL 为当前门店(site_id: 2790685415443269)生成 8 个时间维度的财务洞察:今日、昨日、本周、上周、本月、上月、本季、上季
  3. THE Dispatcher SHALL 将 App2 预生成结果写入 ai_cachecache_type: app2_finance),过期时间为当日 23:59:59
  4. THE Dispatcher SHALL 确保 App2 预生成每日调用量为 1 门店 × 8 维度 = 8 次

需求 12幂等与去重

用户故事: 作为系统管理员,我希望 AI 事件触发具备幂等去重能力,以便重复事件不会导致重复执行和资源浪费。

验收标准

  1. THE Dispatcher SHALL 对自动触发的事件按 (event_type, member_id, site_id, date) 进行去重,重复事件跳过执行并记录 skipped_duplicate 状态
  2. WHEN 手动重跑时(is_forced = trueTHE Dispatcher SHALL 允许强制执行,跳过去重检查,在 ai_trigger_jobs 中明确标记 is_forced
  3. THE Backend SHALL 对 App8 写入 member_retention_clue 业务表时实施强幂等:在事务中先 DELETE 再 INSERT同一 member 同一天只执行一次
  4. IF App8 幂等写入事务失败THEN THE Backend SHALL 自动回滚,记录错误到 ai_trigger_jobs.error_message

需求 13缓存策略

用户故事: 作为后端开发者,我希望 AI 缓存按 App 类型设置不同的过期时间和状态管理,以便缓存数据的新鲜度与业务需求匹配。

验收标准

  1. THE Backend SHALL 为每个 App 设置独立的缓存过期策略App2 当日 23:59:59、App3/App4/App5/App7/App8 为 7 天、App6 为 30 天
  2. THE Backend SHALL 在 ai_cache 表新增 status 字段,支持四种状态:valid(有效)、expired(已过期)、invalidated(手动失效)、generating(生成中)
  3. WHEN 写入新缓存前THE Backend SHALL 将 status 设为 generating,写入完成后更新为 valid,防止并发读取到不完整数据
  4. THE Backend SHALL 在查询缓存时仅返回 status = 'valid' 且未过期(expires_at > now()expires_at IS NULL)的记录
  5. THE Backend SHALL 对 App2~8 每个 App 保留最新 20,000 条 ai_cache 记录超限时清理最旧记录App1 对话记录不自动删除

需求 14数据库变更

用户故事: 作为后端开发者,我希望新增必要的数据库表和字段,以便支持 AI 运行日志、事件调度记录、session_id 管理和缓存状态管理。

验收标准

  1. THE Backend SHALL 在 biz schema 新增 ai_run_logs 表,包含字段:idBIGSERIAL PKsite_idBIGINT NOT NULLapp_typeVARCHAR(30))、trigger_typeVARCHAR(20))、member_idBIGINT 可空)、request_promptTEXT截断前 2000 字符)、response_textTEXTtokens_usedINTEGERlatency_msINTEGERstatusVARCHAR(20))、error_messageTEXTsession_idVARCHAR(100))、created_atTIMESTAMPTZfinished_atTIMESTAMPTZ
  2. THE Backend SHALL 在 biz schema 新增 ai_trigger_jobs 表,包含字段:idBIGSERIAL PKsite_idBIGINT NOT NULLevent_typeVARCHAR(30))、connector_typeVARCHAR(30) 默认 feiqiu)、member_idBIGINT 可空)、payloadJSONBstatusVARCHAR(20))、is_forcedBOOLEAN 默认 falseapp_chainVARCHAR(100))、started_atTIMESTAMPTZfinished_atTIMESTAMPTZerror_messageTEXTcreated_atTIMESTAMPTZ
  3. THE Backend SHALL 在 ai_conversations 表新增 session_id 字段VARCHAR(100)),用于存储百炼 session_id
  4. THE Backend SHALL 在 ai_cache 表新增 status 字段VARCHAR(20) 默认 validCHECK 约束限制为 valid/expired/invalidated/generating
  5. THE Backend SHALL 为 ai_run_logs 创建索引:(site_id, app_type)(created_at)(status)
  6. THE Backend SHALL 为 ai_trigger_jobs 创建索引:(site_id, event_type)、去重索引 (event_type, member_id, site_id, created_at::date) WHERE status NOT IN ('skipped_duplicate')、(status)
  7. THE Backend SHALL 编写迁移脚本 db/zqyy_app/migrations/YYYYMMDD_p14_ai_module.sql,包含所有 DDL 变更,并编写对应的回滚脚本

需求 15SSE 端点适配

用户故事: 作为助教用户,我希望 AI 对话的 SSE 流式端点能适配 DashScope Application API 的流式输出,以便继续获得逐字显示的对话体验。

验收标准

  1. THE Backend SHALL 适配 SSE 端点(POST /api/xcx/chat/stream),将 DashScope_Client 的 async generator 输出转换为 SSE 事件流
  2. THE Backend SHALL 保持现有 SSE 事件格式不变:event: message(逐 tokenevent: done(流结束)、event: error(错误)
  3. WHEN DashScope_Client 流式调用过程中发生错误时THE Backend SHALL 发送 event: error 事件并关闭连接,不导致客户端挂起
  4. THE Backend SHALL 在流式调用完成后记录 ai_run_logs,包含 token 消耗和响应耗时

需求 16AI 运行日志记录

用户故事: 作为系统管理员,我希望每次 AI 调用都有完整的运行日志,以便追踪调用状态、排查问题和统计 token 消耗。

验收标准

  1. THE Backend SHALL 在每次 Application API 调用前创建 ai_run_logs 记录status: pending),调用开始时更新为 running
  2. WHEN 调用成功时THE Backend SHALL 更新 ai_run_logs 状态为 success,记录 response_texttokens_usedlatency_msfinished_at
  3. WHEN 调用失败时THE Backend SHALL 更新 ai_run_logs 状态为 failed,记录 error_messagelatency_msfinished_at
  4. WHEN 调用超时时THE Backend SHALL 更新 ai_run_logs 状态为 timeout
  5. WHEN 预算超限跳过执行时THE Backend SHALL 创建 ai_run_logs 记录,状态为 budget_exceeded
  6. THE Backend SHALL 将 request_prompt 截断为前 2000 字符后存储,避免大 prompt 占用过多存储空间