# AI 回复三态开关(REQ-坐席-010)— 工程师续载清单 > 创建于 2026-08-04 18:5x > 用途:寇豆码在 429 重启后无需重读架构文档,直接据此清单补完剩余 3 件。 ## 权威需求/设计(先读) - PRD:`docs/01-产品文档/04-坐席工作台/PRD-REQ-坐席-010-AI回复三态开关.md` - 技术方案(含 5 任务、行号、Mermaid):`docs/02-技术文档/技术方案-REQ-坐席-010-AI回复三态开关.md` - Mermaid 图:`docs/02-技术文档/architecture/REQ-坐席-010-{class-diagram,sequence-diagram}.mermaid` ## 已落盘(**不要重写**) ### T01 数据层 - ✓ `src/backend/app/constants/ai_reply_mode.py`(62 行) - ✓ `src/backend/app/models/conversation.py` line 231 新增 `ai_reply_mode: Mapped[str]` - ✓ `src/backend/app/schemas/conversation.py` line 359 ConversationResponse 加 `ai_reply_mode` ### T02 门控内核 - ✓ `src/backend/app/services/ai_reply_gate.py`(163 行,6 函数:resolve_mode / conversation_mode / _normalize_status / can_ai_auto_reply_path_a / can_ai_auto_reply_path_b / agent_mirror_enabled / agent_dedicated_message) - ✓ `src/backend/tests/test_ai_reply_gate.py`(51 项参数化断言全过 2026-08-04 18:59) ### T03 路径 A - ✓ `src/backend/app/services/message_router.py` line 187 接入 `can_ai_auto_reply_path_a` - ✓ L399 `_push_agent_dedicated_message` + L567 调用(b 态专属推送) - ✓ imports constants/ai_reply_gate ### T02.5 设置 API - ✓ `src/backend/app/api/conversations.py` line 400 PUT `/api/conversations/{conversation_id}/ai-reply-mode` - ✓ 含广播 `ai_reply_mode_changed` WS 事件 - ✓ `src/backend/app/services/session_service.py` 已加 `set_ai_reply_mode` ### T04 路径 B(**含接单后停 AI 缺口修复**) - ✓ `src/backend/app/api/h5.py` line 946 接 `can_ai_auto_reply_path_b`(门控在 create_task 之前 ✅) - ✓ `src/backend/app/api/ws.py` line 478 同上 - ✓ `src/backend/app/tasks/h5_ai_task.py` 4 处坐席广播点(L540/817/970/1684)已接 `agent_mirror_enabled` - ✓ 2 处 `_push_agent_dedicated_message` 调用(L567/855) ## 仍需补完(3 件) ### 1. Alembic 058 迁移(最简单,可立刻做) - 文件:`src/backend/alembic/versions/058_add_ai_reply_mode.py`(仿 057 幂等写法:`sa.inspect(bind)` 守卫) - `down_revision = '057_troubleshooting_templates'` - 字段:`ai_reply_mode = sa.Column("ai_reply_mode", sa.String(20), nullable=False, server_default="employee_only")` - 存量自动套用 server_default,无需数据回填 ### 2. 前端 T05(5 子项) #### 2a. `src/frontend-agent/src/components/chat/ai-assist/AiReplyModeSwitch.vue` - 🤖 图标按钮(复用 `.tb-btn` 样式)+ `el-popover` 内 `el-radio-group` 三态单选 - 三个值:`employee_only` / `employee_and_agent` / `off`,显示中文文案 - 选中即调 `setAiReplyMode` API - 当前态高亮(a 正常色 / b 高亮 / off 置灰) #### 2b. `src/frontend-agent/src/components/chat/ReplyBox.vue` - 在 `.toolbar-left` 之后、`.tb-sep` 之后、`` 之前插入 `` - 与 4 个主动 AI 按钮(💡🎚️🖌️🔄)以 `.tb-sep` 分隔,视觉独立 #### 2c. `src/frontend-agent/src/api/`(或现有 api 模块) - `setAiReplyMode(conversationId, mode)` → PUT `/api/conversations/{conversation_id}/ai-reply-mode` #### 2d. conversation store(找已有 conversation store,按 conversationId 存当前 mode) - action 存 + getter 取;切会话读各自值 #### 2e. WS 监听 `ai_reply_mode_changed`(**不复用** `conversation_updated`,新增独立 handler) - payload: `{conversation_id, ai_reply_mode}` - 多端同步:收到事件 → 更新 store ### 3. 修正技术方案文档(按 B 口径) **用户最终澄清**(2026-08-04 15:47): > a 态(employee_only)= AI 只对员工消息/选择作进一步回复;坐席端**仍按现状能看到 AI 回复员工的消息**。 > 即:a 维持现状镜像;b 在 a 基础上**额外**推专属;off 全关。 修正 `docs/02-技术文档/技术方案-REQ-坐席-010-AI回复三态开关.md`: - "推坐席"小节:明确 `agent_mirror_enabled = (mode != "off")`(a/b 都镜像) - "专属坐席消息"小节:`agent_dedicated_message = (mode == "employee_and_agent")`(仅 b 推) - 说明当前实现(h5_ai_task.py + message_router.py 的 _push_agent_dedicated_message)已与本修正口径一致 ## 完成后自测 1. 跑后端:`pytest tests/test_ai_reply_gate.py` → 期望 51/51 2. 跑前端:`pnpm vue-tsc --noEmit`(仅 AiReplyModeSwitch.vue 范围无新增错) 3. **全局一致性审查 IS_PASS: YES/NO** 重点核对: - 字段 `ai_reply_mode`(不要写成 aiReplyMode / reply_scope) - WS 事件 `ai_reply_mode_changed`(不要复用 conversation_updated) - 端点路径 `/api/conversations/{conversation_id}/ai-reply-mode` - 4 个广播点全部已接 `agent_mirror_enabled`(grep 确认) - 不动的 4 个 `broadcast_to_employees` 未被误改 ## 提交 ``` git add ... && git commit -m "feat(ai-reply-mode): REQ-坐席-010 三态开关完工 - T01 数据层 + alembic 058 - T02 门控内核 + 单测 - T03 路径 A + 坐席专属推送 - T04 路径 B + h5_ai_task 4 广播点收紧 + 接单后停 AI 缺口修复 - T05 前端 AiReplyModeSwitch + 集成 + WS 监听 - 修正技术方案文档'推坐席'小节按 B 口径" ``` 把 commit hash + 改动文件清单 + IS_PASS 结果回传主理人。