方案 B 把整条链路跑在云电脑一个常驻 Python loop 里:截屏 VL 读客户消息 → 调 Vercel chatReply 出「小艳」回复 → GUI 逐字打字发送 → 回写 DB。绕开方案 A 的企微 API 可信 IP / ICP 卡点。本报告汇总首个真实案例、0→1 逻辑、首发统计、已遇 badcase 及优化进展、下一步清单。
外部微信好友(Gustavo@微信),咨询大户型报价。全程由「小艳」自动代回,无人工介入。展示了报价、户型识别、业务边界拒单(不做别墅)、地区套近乎、要实拍图推进等能力;也暴露了本日修复的 badcase(回复被切成多条气泡)。
设计原则:GUI I/O 留云电脑,大脑 / DB / Langfuse / 成本全留 TS。云电脑只做「看屏 + 打字」,不碰企微 API(故无可信 IP / ICP 约束)。机器对机器鉴权走专属 WECOM_CHAT_SECRET。
chatReply。Langfuse trace / 成本注入都在这。status='sent'(显式失败:只在真发出后才记)。chatReply() @ src/lib/llm.ts,端点 src/app/api/wecom/chat/reply/route.ts(经 worker /wecom/chat/reply 中转)。qwen/qwen3-235b-a22b-2507(代码 CHAT_DEFAULT / env LLM_CHAT_MODEL),走 OpenRouter。qwen/qwen3-vl-30b-a3b-instruct(env AKKE_OCR_MODEL),走 OpenRouter,云电脑本地调,负责 detect_unread + read_open_conversation。PERSONA @ llm.ts)。stage=nurture(跳过破冰)。系统 prompt 由 PM 在 Langfuse 编辑:dm.nurture.system(本通道)/ dm.ice_break.system / dm.decision.system。loadOrgContext(品牌/报价/decision_rules)+ 跨会话 customer_profile。sanitizeReply / extractLeakedToolCalls 清理 tool-call 协议字节 + 舞台指示。诚实前置:方案 B 6-29 才联调验通、6-30 才首次真发,目前是早期小样本、且含内部测试会话,不是规模化数据。下列为 DB 真实计数(channel=wecom_chat),非估算。规模统计从本周起累积。
Gustavo/Gustavo @微信/Gustavo@微信)、阿江 3 个 → 去重后真实主体约 5–6 个。此重复即 badcase #5(身份=显示名),已在下节列明。按本日(含数据里暴露的)实际问题分类。#1–#4 本日已改并部署到云电脑;#5–#6 已定位、待做。
| 类别 | 现象 | 根因 | 优化方式 | 进展 |
|---|---|---|---|---|
| #1 回复切碎 发送层 |
一条回复被切成多条气泡(如「我们不做别墅哈,」单独一条),无上限 | 回复文案里的 \n 换行,在 GUI 打字时被企微当成 Enter=发送,几条完全看 LLM 换行数 |
按换行切段、封顶 3 条,超出并进第 3 条(空格连、不丢内容),逐段显式打字+发送 | 已修 |
| #2 VL 误判发送方 读取层 |
客户明明发了新消息(靠左灰气泡),loop 判成「最新一条是自己发的」跳过、不回,且卡死循环跳过 | 「谁发的」100% 靠一次 VL 看截图,prompt 没讲清左右/颜色规则;本主题自己=蓝、客户=灰,易看歪 | VL prompt 加明确规则:靠左灰白=customer / 靠右蓝绿=self,按左右位置判、别只看颜色;右侧空白则 ok=false | 已修 |
| #3 点击没命中 读取层 |
点「顶部会话」偶尔没点开,read 对着空列表把发送方误判成 self | 单次点击+固定等待,点击漂/渲染慢时读到空白,无重试直接跳过 | 开会话失败重试一次(重点+多等 2s 再读),仍失败才跳过;只在发送前、不会重发 | 已修 |
| #4 无法诊断 可观测 |
出问题时看不清 VL 到底看到了啥(读/未读两步截图互相覆盖) | 两次截图共用同一文件名 _wecom.png,后者覆盖前者 |
分开存名:_wecom_list.png(未读检测)/ _wecom_read.png(读会话),事后可复盘 |
已修 |
| #5 身份=显示名 数据/记忆 |
同一客户建多个会话:Gustavo ×3、阿江 ×3(名字带不带「@微信」「 @微信」空格差异) | V1 身份键 = VL 读出的显示名(无稳定 userid);VL 每次读名字有细微差异 → 撞不上唯一键 → 重复建会话,历史/记忆碎片化、有串台风险 | 规划:显示名归一化(去空格/去「@微信」后缀再匹配)作过渡;根治=拿稳定 external_userid。先做归一化脚本合并现有重复 | 待做 |
| #6 无红点漏触发 触发层 |
正与客户聊天、会话开着时客户秒回 → 企微不弹红点 → loop 不处理,漏接 | 触发完全靠 detect_unread 的红色未读小红点;会话聚焦时消息即时已读、无小红点 |
规划:除红点外,主动看一眼当前打开会话最底是不是客户新消息(指纹幂等去重防重发) | 待做 |
C:\akke-wecom\wecom_reply_loop.py 覆盖 + 重启 loop。坐标/密钥都在 .env,覆盖 .py 不影响校准。#1–#4 已于 2026-07-01 部署验证(Select-String 4 项全在)。_wecom_read.png 抽查。git pull。measure_wecom_coords.py 重标坐标。