客户 H · 厦门
「你们这店在哪呀?」——我们说厦门没店,同一句里又给了厦门的地址
9 月 29 日下午,销售 A加上了这位新好友。程序 14:54 扫到他时没读出聊天区,首触没发,同一秒却把他登记进了召回——所以他收到的程序第一条,是一条召回加两张活动图。10 分钟后他发来一条语音,微信转成文字是:“你们这店在哪呀?”这是想来看店的信号。AI 31 秒后回:“厦门这边暂时没有我们的实体店……最近的在泉州、漳州或福州。门店在厦门市思明区台北路海西金谷广场T1-11楼。”前半句说没店,后半句给了厦门的店。事实是:厦门海西金谷广场就是有大有小总部门店,门店清单第一条就是它。模型不是自己乱说的,是系统在提示里明确告诉它“厦门没有实体门店,绝不许说有”——系统读门店清单时把厦门那一行读丢了。截至 9-29 16:36,他没有再回。
完整聊天记录与逐句来源标注
时间为北京时间。来源标注:消息表(库里的消息记录)、召回任务(召回任务表)、客户端日志(销售 A那台电脑的运行日志)、Langfuse 输入(这一轮真实喂给模型的全部内容和模型原话)、运营截图(运营 9/29 现场截图,库里没有)。写着“推断”的是根据几条证据判断的,写着“没验成”的是取证没拿到。
聊天截图来自运营 9/29 现场截图,截图标题栏带客户备注编号和手机号,页面不放截图本身。
用户背景与核心需求
他是销售主动加的新好友,只开口说了一句:店在哪。这是想来看实物的信号,而他所在的城市恰好有我们的总部门店。
他在哪
备注以「闽D」开头,按备注推断在厦门。他自己没说过。系统也是按这个前缀认的:模型输入里写着“客户所在城市已识别为「厦门」”。
怎么加上的
销售 A加的他,申请里写了一段活动话术(568 元/㎡、每平方补贴 300)。这段话术是销售手写的,属于推断,理由见聊天记录第 2 条。
他关心什么
“你们这店在哪呀?”——他想知道能不能去店里看。没问价格、没问材料,直接问店,是这个阶段最接近到店的一句。
我们能不能满足他
能,而且很近。门店清单第一条就是厦门:思明区台北路海西金谷广场 T1-11 楼,有大有小总部。对一个厦门客户来说,这是最好接的一个问题。
未知信息
面积、户型、装修到哪一步、预算、什么时候方便来,全都不知道。召回里问了“装修进行到哪一步了”,他没答这个,直接问了店。
完整转化时间线
加上后直到 14:54 才被程序扫到;首触没发,召回先到;召回后 10 分钟他问店;31 秒后收到一条自相矛盾的回答;之后没有下文。
销售加上了他,申请里带了一段活动话术
来自运营截图。14:26–14:40 销售在用电脑,程序一直让开,没有发任何东西。
运营看到截图,决定照常让程序发首触
申请话术只是加好友时带的一句,不算我们正式打过招呼。
程序扫到他:聊天区没读出来,首触先搁 15 分钟
客户端记“首触待确认,15 分钟后再判”。
同一秒,他被登记进了召回
服务端 14:55 建任务并当场派单。库里没有首触记录,9-29 上午刚上线的“首触后召回要冷却”认不出他是新好友。
召回:活动配置参考 + 两张图
这是程序发给他的第一条。结尾问了一句“装修进行到哪一步了”。
语音:“你们这店在哪呀?”
召回后 10 分钟,他第一次开口,问的是店。
系统在提示里告诉模型:厦门没有实体门店
同时算出“厦门不在服务覆盖范围,远程服务费约 100 元”。这两条都是错的:系统读门店清单时把厦门那一行读丢了。
AI 31 秒回:厦门没店……门店在厦门海西金谷广场
模型照系统的话说了“厦门没店、最近在泉州漳州福州,我给您发地址过去”;发送前检查把“发地址”换成了厦门地址卡,前半句没动,于是一条消息里既说没店、又给了厦门的店。
没有再回
运营已建议销售 A人工补一句更正,是否已发没验成。
每个阶段是怎么推进的
| 阶段 | 我方动作 | 客户顾虑 | 结果信号 | 来源 |
|---|---|---|---|---|
| 加好友 | 销售发申请,附活动话术(568 元/㎡) | — | 加上了 | 运营截图(话术出处为推断) |
| 首触 | 没发:聊天区两次没读出来,先搁 15 分钟 | — | — | 客户端日志 |
| 召回第 1 轮 | 活动配置参考 + 问装修进度 + 两张图 | — | 10 分钟后开口 | 召回任务 + 消息表 + 客户端日志 |
| 问门店 | — | 店在哪、能不能去看 | 到店意向 | 消息表(语音转文字) |
| AI 作答 | “厦门没有实体店,最近在泉州漳州福州” + 厦门总部地址和导航 | — | 没有再回 | AI 代回 + Langfuse 输入 + 客户端日志 |
来源判定依据:该会话只有 1 条 AI 代回调用记录(15:09:50),对应消息表 15:10:10 那条回复;召回那条有召回任务对应;申请话术库里没有、当时程序在让开,按销售加好友时写的处理。
核心卡点
一条消息里,既说没店,又给了店
从客户这边看:先听到“厦门暂时没有实体店,最近的在泉州、漳州或福州”,接着又是“门店在厦门市思明区……”。到底有没有?在哪家?他得自己猜。对一个正想来看店的人,这一句把最好接的问题答砸了。
“你们这店在哪呀?”
召回后 10 分钟主动问店,是到店意向。他在厦门,总部就在厦门——本来一句“厦门有的,就在海西金谷广场总部”就能顺势约时间。
新好友的第一条程序消息是召回
他收到的是“这是这次样板房活动的配置参考……您家现在装修进行到哪一步了”,没有自我介绍、没有首触那段完整的活动说明。好在销售加他时的申请话术已经带了活动价,这一处对他的影响不算大。
地址卡本身是对的
发送前补上的那段地址——思明区台北路海西金谷广场 T1-11 楼,外加高德导航——是真的,也是离他最近的店。问题出在它前面那句“没店”没被拿掉。
技术卡点:厦门那一行被读丢了
每条都标了证据等级:成立(有记录直接证明)/ 嫌疑(有迹象、没坐实)/ 没验成(取证没拿到)。第 01–03 条是这次的根因,已坐实。
模型是照系统的指令答的:系统告诉它“厦门没有实体门店”
成立:那一轮喂给模型的提示里,系统自动加了一块:“【客户所在城市已识别为「厦门」 · 这个城市没有实体门店(清单里查过了,确实没有)】⛔ 绝不许说厦门有店 …… ✅ 先如实说‘厦门这边暂时没有我们的实体店’ …… 有实体店的城市是:泉州、漳州、宁德、福安、福州、长沙、苏州、昆山、莆田、上海、成都、天津”。另一块还算出“客户所在城市(厦门)不在服务覆盖范围 · 最近服务点漳州约 60 公里 · 远程服务费约 100 元”。而同一份提示里的门店清单,第一条就是厦门。模型没有乱编,它是在两份互相打架的材料里,照着口气更硬的那一块答的。
为什么系统认定厦门没店:清单标题和厦门粘在了同一行
成立:拼进提示的门店清单里,其他城市都是一城一行,只有厦门那一行长这样:
- 【全国门店地址清单】厦门:厦门市思明区台北路海西金谷广场T1-11楼(有大有小总部)
程序(wecom-chat 仓 src/lib/llm.ts 里的 buildStoreDirectory)按“冒号前面是城市名”来读,读出来的城市名是“【全国门店地址清单】厦门”,和“厦门”对不上;列“有店城市”的那一步又按长度把这个怪名字过滤掉了。拿同一段输入按代码逻辑复刻一遍,得到的有店城市正好是提示里那 12 个,一字不差。
同一份清单被 5 处各自解析,读法不一样,所以正文和地址卡打架
成立:当时这份门店清单在 5 个地方各读各的:给模型的门店块、按省份收窄清单、发送前的事实检查、远程服务费、到店地址卡。前三类(门店块 / 事实检查 / 远程费)都把厦门丢了;到店地址卡那处读法宽松,没丢。于是模型按“没店”写正文,发送前又按“有店”补了厦门地址卡——同一条消息里两种说法。更糟的是:事实检查也丢了厦门,意味着就算模型答对了“厦门有店 + 地址”,真地址也会被当成编造删掉。
影响面:所有被认成厦门的客户问店,都会被告知没店
成立:只要客户被认成厦门、又问到门店,就会走进这条路:被告知没店,还可能被报远程费。这块“没店也要给确定说法”的提示是 9-22 为修杭州编地址才加的;按备注「闽D」认厦门的城市识别是 9-28 前后加的。两者单看都没错,叠在一起,厦门客户就走进了一条没人测过的错路。本案这一轮模型没有提远程费,但提示里已经算好了“约 100 元”。
9-22 以来第三次门店地址出错,底子是同一个
成立:
| 日期 | 城市 | 客户听到的 | 表面原因 |
|---|---|---|---|
| 9-22 | 杭州(测试号) | “杭州有的!地址在杭州市区合作装企展厅” | 清单里没有杭州,模型自己推成有店 |
| 9-24 | 天津(客户 C) | 被报了漳州门店地址 | 没认出城市 + 提示词里写死了漳州区名当例子 |
| 9-29 | 厦门(本案) | “厦门没店” + 厦门地址 | 清单格式让厦门被读丢 |
三次表面原因各不相同,共同的底子有三层:① 同一份门店清单在多处各自解析,谁读错了都没人发现;② 每扩大一次“认得出客户城市”的范围,就有一批城市的客户走进没测过的路径;③ 没有“每个城市都问一遍”的测试。近 30 天个微 AI 消息全量核对:707 条里 87 条涉及门店 / 地址 / 远程费,查出的问题正好就是这三起(杭州 4 条、天津 1 条、厦门 1 条),没有别的漏网。盲区:只能核对备注带车牌前缀的客户,没有前缀的客户在哪个城市,核对不了。
新好友“首触没读出来”,同一秒又被登记进召回
成立:客户端日志 14:54:49 同一秒里有两条:一条说“聊天区两次都没读出来,15 分钟后再判首触”,一条说“登记召回”。首触那边在等,召回那边已经排上了。服务端建任务时库里没有首触记录,9-29 10:57 刚上线的 #1730(首触过的人第一轮召回要冷却)按规则放行。结果新好友收到的程序第一条是召回。召回那一步主读图模型两次请求失败、按备用档下结论,对“登记召回”这个判断有没有影响,没验成。
提示里还有一句“系统会自动附到店指引,你只写一句接话”
成立:同一轮提示的另一块写着:“客户这一轮在问门店位置……系统会在你这句话后面自动附上完整的到店指引……你这句只写一句简短自然的接话”。一块说“会自动附厦门地址”,一块说“厦门没店、绝不许报地址”,模型两头都照顾了:先说没店,再说“我给您发地址过去”。嫌疑:这两块互相矛盾,本身就会诱发自相矛盾的回答——这是从输入原文推的,没有单独做对照实验。
模型看到的聊天记录不全
成立:模型输入里只有召回那段话、一个“[图片]”(实际发了 2 张)和客户这句;销售加好友时那段申请话术不在里面。本案里这一点没有直接造成错误,但模型不知道客户已经看过 568 的活动价。
本案暴露的问题,现在修到哪了
本案对话发生在这些改动之前,页面上的原话不会因此改变。
| 问题 | 怎么修的 | PR | 状态 |
|---|---|---|---|
| 厦门那一行被读丢 | 读清单前先去掉行首的“【……】”标题;加兜底:正文说某城市没店、却附了这个城市的地址卡 → 不发,转人工 | #1737(服务端) | 已上线 · 部署探针 /api/status 返回 commit=dffefc0(已亲自核对) |
| 同一份清单 5 处各自解析;没有全城市测试 | 新建唯一的门店清单解析口(store-directory),5 处全部改读它;一致性检查只留一个出口(说有店城市没店 / 客户城市有店却只报别城地址 / 有店城市提远程费 → 不发,转人工);全城市测试进 CI:13 个有店城市 × 3 种问法 + 5 个只有服务点的城市 + 3 个都没有的城市,城市名单从生产清单快照读;车牌映射表单独测试;门店清单单独放进提示,不会被 1500 字上限截掉;每天 08:30 自动巡检(/api/cron/store-directory-check),有问题推告警。验收:杭州 / 天津 / 厦门三起原样重放各 3 次全部答对;30 天回放门店相关 23 轮没有新增错误;撤掉修复后测试立刻变红;全量 5480 个测试通过 | #1743(服务端) | 已上线 · 9-29 17:04 部署探针 /api/status 返回 commit=fcb3272,包含 #1743 合并提交 51b3c15b(已亲自核对) |
| 知识库门店清单过时 / 兜底话术会开空头支票 | 天津店更新为“天津市河西区尖山街道解放南路475号 居然之家(河西珠江友谊店)”(楼层未提供);清单末句“帮您查下最近的门店、把准确地址发您”改为“如实说暂时没有实体店 + 有店城市名单 + 本地有师傅对接” | 知识库 | 已写入知识库 |
| 新好友首触没读出来,同一秒又被登记召回 | — | — | 未修 · 已提给开发,攒进下一个客户端版本 |
| 本案客户本人 | 建议销售 A人工补一句更正(见下方复盘) | — | 待确认是否已发 |
案例复盘:做对什么,还能改什么
做得好的地方
召回发出后 10 分钟他就开口,而且问的是店,说明活动价和配置图起了作用。AI 31 秒就回了,没有编价格、没有乱承诺;补上的厦门地址和导航是真的,也是离他最近的店。系统在提示里还特意交代了“不许说帮您查一下”这类空头支票,这一条模型照做了。
可以优化的地方
新好友收到的程序第一条是召回,不是首触:召回那段话以“这是这次样板房活动的配置参考”开头,对第一次说话的人来说没头没尾。好在申请话术已经带了活动价。另外,他回了“店在哪”却没答“装修进行到哪一步”,下一句本该顺势约时间、再补问进度。
这条链路最伤的一处
对一个就在总部城市、主动问店的客户,我们说了“没店”。这不是模型的错,是系统读门店清单时把厦门读丢了,又用最硬的口气(“清单里查过了,确实没有”“绝不许说有”)让模型照说;而另一处读对了清单,补上了厦门地址,于是一条消息自己打自己的脸。更要紧的是,这已经是9-22 以来第三次门店地址出错,三次的底子一样:清单多处各读各的、扩城市不测、没有全城市测试。
更合理的推进方式
他问“你们这店在哪呀?”时,一句话答准:“厦门有的!就在思明区台北路海西金谷广场 T1-11 楼,是我们总部门店,您方便哪天过来看看?”再附导航。现在最要紧的一步:由销售 A人工补一句——“不好意思刚才说岔了,厦门有的,就是海西金谷广场总部门店,您方便哪天过来看看?”这句已建议给运营,是否已发没验成,待确认。
后续优化建议
今天就把这句更正发出去
销售 A人工补一句“厦门有的,就在海西金谷广场总部”,顺势约到店时间。发没发由运营回看聊天窗口确认。
一份清单只许一个地方解析
#1743 把 5 处改成读同一个解析口。上线后要看行为:拿一个被认成厦门的会话问一次店,确认答“有”并给对地址。
每个有店城市都问一遍
以后每扩大一次“认得出客户城市”的范围(加车牌前缀、加城市别名),新增城市都要进全城市测试,别让一批客户先替我们踩坑。
回查这段时间被认成厦门的客户
9-28 前后到 #1737 上线之间,被认成厦门、问过店或被报过远程费的客户,逐个看要不要人工补一句。近 30 天核对只查出本案 1 条,但核对只覆盖备注带车牌前缀的客户。
首触没确认的新好友先别召回
客户端“首触待确认”和“登记召回”不能在同一轮里同时成立;首触还在等的人,召回也要等。已提给开发。
同一轮提示别出现两块互相打架的指令
“会自动附到店指引”和“这个城市没店”不该同时出现;拼提示时发现矛盾就只留一块,或者直接转人工。
证据边界与待补充信息
可核对的证据
消息表 3 条(09-29 14:59:24 召回、15:09:39 客户、15:10:10 AI 代回);召回任务 1 条(14:55:18 建立并领取、14:59:24 发出,第 1 天第 1 轮,配图两张);调用记录 2 条(1 次 AI 代回,含模型原话;1 次画像抽取,结果为空);这一轮 AI 代回的 Langfuse 完整输入与输出(含“厦门没有实体门店”那一块、门店清单原文、远程费那一块、到店指引那一块);销售 A那台电脑的客户端运行日志(14:26–14:40 让开、14:54:49 首触待确认与登记召回、14:59:24 召回发出、回复改写事件);运营 9/29 现场截图(聊天窗口最上方的申请话术与添加提示);服务端 #1737 部署探针(commit=dffefc0);近 30 天个微 AI 消息门店相关全量核对(707 条 / 87 条相关)。
仍需补充
销售 A有没有人工补发更正(没验成);#1743 上线后真实客户问店的实际回复(上线已核对,行为待下一位问店客户验证);窗口最上方那段话是销售手写的申请话术(按日志和模板推断,没向本人确认);“厦门”是按备注「闽D」推断的,没经客户确认;语音原音没听,转写是否有错字没验成;召回那一步读图模型两次失败对“登记召回”判断有没有影响(没验成);近 30 天核对的盲区是备注不带车牌前缀的客户。