客户 I · 漳州
问工厂,被报了泉州门店;要杉木,被说“不支持”
9 月 30 日傍晚,销售 A的新好友。首触发出两分钟,他就开口:“柜体 用 杉木 柜门 用 海洋板 / 报价多少”——材料、价格都想好了,是很具体的买家。这一场里 AI 答错了两件事,两件同样要紧:
① 工厂 / 地址:他问“你们工厂在哪里?”,程序没经过模型,直接发了一段“泉州有三家店……”的门店模板;他说“我还以为你们漳州有厂”,AI 答“咱们漳州没有厂”。事实是:工厂就在漳州漳浦,漳州龙文区也有门店。
② 杉木:AI 第一句就说“柜体用杉木我们这边不支持”;他第二次说“柜体我们还是想做杉木生态板”,没人接。事实是:知识库里写着柜体可以换同品牌杉木芯(每平方加 50),销售人工接手后发的也正是杉木芯板的图。
两件事的底子相同:该用的那份资料其实排上了,但喂给模型的“产品知识”只有 1500 字,关键那一行被截在外面;模型没看到,就自己说成了“没有”。而发送前没有任何一道检查会拦“我们不支持 / 没有厂”这种话。截至 9-30 晚,这两处都还没修。
完整聊天记录与逐句来源标注
紫色 = 程序发的(AI 代回或固定模板),绿色 = 销售人工发的,灰黄边 = 客户。红框是本案两处核心错误。来源:消息表(库里的消息记录)、调用记录(llm_call_provenance)、Langfuse 输入(这一轮真实喂给模型的全部内容和模型原话)、运营截图(库里没有,主会话转述)。
运营截图标题栏带客户备注编号和手机号,页面不放截图本身,聊天内容全部用文字还原。
一页看懂:两个问题,一样要紧
他一共问了两件事:工厂在哪、柜体能不能用杉木。这两件我们都能给他满意的答案,结果两件都答成了“没有”。
问工厂,先被报了泉州门店,再被说“漳州没有厂”
客户问:“你们工厂在哪里?”“我还以为你们漳州有厂”。
我们答:先是泉州三家门店的地址(固定模板,没经过模型),再是“咱们漳州没有厂”。
事实:工厂在漳州漳浦——知识库原话是“客户问‘你们工厂在哪’直接答,这是工厂直供的实锤”;漳州龙文区居然之家二楼还有门店。
后果:他是冲着“漳州有厂、工厂直供”来的,我们亲手把这张最硬的牌扔了;他说“都很远”,差点就走了。
要杉木柜体,被说“不支持”;第二次说,没人接
客户问:“柜体 用 杉木 柜门 用 海洋板 / 报价多少”,后来又说“柜体我们还是想做 杉木生态板”。
我们答:“柜体用杉木我们这边不支持”;第二次,程序发的门店模板和下一轮 AI 都没接这句。
事实:知识库写着柜体可以换同品牌杉木芯(每平方 +50),也有杉木芯的生态板和 SPC 杉木芯柜门。销售人工接手后发的就是杉木芯板的图。
后果:客户先被告知“不行”,自己又追问了两次;最后要靠销售人工补救。
客户发了个小表情,AI 回“您发的图我没收到”
读屏把表情认成了“[图片]”,模型照着“客户发了张图我们看不到”去回。影响不大,但放在这一串错答后面,更像机器。详见第 04 节。
问题一:问“工厂在哪”,答成了门店,又说“漳州没有厂”
这一问经过了两道程序:18:05 走的是“门店固定模板”,没经过模型;18:10 走的是模型。两道各错一次。
“在哪里”三个字,把“工厂在哪里”送进了门店模板
已坐实程序判断“客户是不是在问门店”,用的是 customerAsksStoreNow(wecom-chat src/lib/wecom/weixin-client-context.ts:686–689)。它的第二段正则里有一个光秃秃的“在哪里”——不管问的是店、是工厂、还是别的什么在哪里,都算问门店。拿这条正则实跑“你们工厂在哪里?”,命中的就是“在哪里”。
命中后,storeTopicOf 判“门店话题进行中”,回复入口(src/app/api/wecom/chat/reply/route.ts:5116–5122)直接走“确定性门店回复”:cityLocationReply → storeListingForCity,按客户城市把门店清单原样列出来,整个过程不叫模型。所以这一轮调用记录里没有 AI 代回,只有一条画像抽取。
同一个问题,程序里两处口径不一样
已坐实同一套门店代码里,决定“要不要附到店地址卡”的判据 OWN_LOCATION_RE(src/lib/wecom/store-visit-cards.ts:250–251)本来就把“工厂”排除了——拿同一句实跑,它命中“工厂”、判“不是问店”。但 customerAsksStoreNow 只在第一段借用了这个判据,第二段那串关键词自己单干,没有排除“工厂”。一处说“这不是问店”,另一处说“这是问店”,后者先生效。
城市是从备注猜的,而备注写错了
已坐实客户当时没说过自己在哪,程序按备注前缀认城市:「闽C」=泉州(src/lib/wecom/windows-customer-name.ts 的车牌表:闽 A 福州、C 泉州、D 厦门、E 漳州……)。按现有规则这一步没算错,但备注本身错了——销售后来改成了「闽E」(漳州)。就算前面两条都没错、真该报门店,这一轮也会报成泉州的店。
18:10“漳州没有厂”:工厂资料排上了,但“工厂地点:漳浦”那一行被截掉
已坐实知识库里有一份《工厂直供定位与核心话术》(39dd8d39),最后一行写着:“工厂地点:漳浦(客户问‘你们工厂在哪’直接答,这是工厂直供的实锤)。”这一轮它排在第二,也进了提示——但只进了前半截:
原文只有 236 字,本来放得下;但喂给模型时,门店工作台确认过的一批要点(知识元素)被拼进了正文,文档变长,剩下的 270 字就够不着最后一行了。模型看到了“工厂直供”,却没看到工厂在哪;而门店清单里明明白白列着“漳州:龙文区居然之家二楼”,却没有“漳州有厂”——它就说成了“漳州没有厂”。
证据:18:10 那轮 Langfuse 输入(“产品知识”块正好 1500 字,门店清单 1230 字 + 工厂资料 270 字,全文无“漳浦”);知识库 39dd8d39 原文;截断规则见src/lib/llm.ts:708(上限 1500 字)与 :814。发送前删了两句,剩下没头没尾的半句
已坐实模型原话比实发多两句:“最近的门店在泉州”“我先让设计师线上出个方案”。前一句被门店检查删掉——删得对(漳州本地就有门店,不该替客户认定“最近在泉州”);后一句也被删了。删完剩下“您要是考虑做,您看合适再定”。今天 18:34 合并的删句修复(#1822)只认“您要是……,”后面什么都不剩的情况;这句后面还跟着“您看合适再定”,不算悬空,照样会发出去。
对比:调用记录 replyText(模型原话)vs 消息表正文(实发)。哪句被哪条规则删、以及“现有删句规则盖不到这种形状,要另立判据”,是开发会话里确认的(主会话转述)。为什么门店地址修了十几轮,这一处还漏
已坐实9-24 以来那一组地址修复(#1737 #1743 #1753 #1757 #1760 #1761 #1762 #1763 #1788 #1819,见门店地址报错合集)管的全是门店:门店清单统一解析、有店城市全测、说错城市转人工……“工厂”不在门店清单里,这些检查都看不见它。在 wecom-chat 的个微回复代码里搜“工厂”,除了上面那条到店卡排除,没有任何一处在核对“工厂在哪”的说法。
“我们没有厂”这种否认句,没有任何检查拦
已坐实见第 05 节“共同根”第 ③ 条。
39dd8d39《工厂直供定位与核心话术》、79777dff《全国门店地址清单》)里都写着。问题二:要杉木柜体,被说“不支持”;第二次说,没人接
知识库里至少四份资料写着杉木:柜体可以换同品牌杉木芯、生态板就是杉木基材、柜门有 SPC 杉木芯款。模型一份都没看到完整的那行,就说了“不支持”。
客户一问价,价目表被钉到最前面,把 1500 字额度一口吃光;杉木那行在截断点之后
已坐实客户这句里有“报价”两个字,触发了“问价必进通道”(src/lib/llm.ts:727–731、:768):先把最相关的 2 份价格资料钉到“产品知识”最前面。排第一的是《2026 报价清单·江浙沪深京全档位》(57ebb374,原文 1932 字)。个微这条通道最多放 3 份(:2484),总共 1500 字(:708)——这一份单独就超了,于是从中间截断,后面的资料一份也进不来。
模型看到的:海洋板有(“不怕水的糯米板/海洋板配置”)、ENF 多层有、首触也说“ENF 级多层实木板任选”——唯独没有杉木。于是它答:“柜门用海洋板可以做”,“柜体用杉木不支持”。它不是乱编,是拿着一份被截掉关键行的资料,推出了一个错的结论。
证据:17:59 那轮 Langfuse 输入(“产品知识”块正好 1500 字,末尾停在“配置:18mm 多层柜”;整份提示里“杉木”只出现在客户原话里);知识库 57ebb374 原文。截掉的资料不记账,后台看起来像“一份都没检到”
已坐实代码规定:一份资料被截断时,正文照样塞进去,但不记进 knowledge_doc_ids(src/lib/llm.ts:814–818:“Partial fit: include the slice but DON'T claim the id”)。所以这一轮调用记录里 knowledge_doc_ids = []、knowledgeRel = {},看上去像“检索是空的”。本案最初的排查就是这么读的;打开 Langfuse 输入才发现资料其实在,只是被截了。
素材库那 3 段也没有杉木
已坐实另一套检索(素材库,相似度门槛 0.5、最多 4 段、900 字,src/lib/kb/retrieve.ts:25–29)这一轮喂了 3 段,都是“②ENF 级实木多层 · 同色卡欧松柜门(低配档)”海报的说明(江浙沪深京 528 / 其他地区 498),没有一段提到杉木。素材库里其实有 14 份资料的正文片段带“杉木”(比如兔宝宝杉木细木工板的检测报告),这一轮一份都没排上。为什么没排上,需要用同一句话重算相似度才知道——本页不调向量接口,没验成。
“不确定就去核实”的规则在,没管住
已坐实这一轮提示的第一段人设里就写着:“始终以有大有小已经确认的品牌知识和报价规则为准……不确定就明确说去核实,不能编造。”(src/lib/weixin-persona.ts:56)规则有,没管住——模型没觉得自己“不确定”。
嫌疑同一份提示里还有一段门店补充要求:“实打实跟客户讲,能做的说能做、做不了的直说做不了。”模型以为杉木“做不了”,这句可能正好把它推向“直说不支持”。验证方法:用这一轮的原始输入,分别①补上被截掉的杉木那行、②去掉这句“直说做不了”,各重放若干次,看“不支持”的比例变不变。本页不调模型,没做。
第二次说杉木,两道程序都没接
已坐实“柜体我们还是想做 杉木生态板”这句,是客户在我方 18:05 门店模板生成的那十几秒里发的。代码只把“我方最后一个气泡之后”的话算作新消息,这句被模板气泡压在上面,当轮就漏了(所以说它“被门店模板吞掉”不准确:模板那一轮根本没收到它)。18:10 下一轮,“连发补漏”把它捡了回来(消息编号前缀 wcml_),模型这次看到了,但只答了“漳州有没有厂”,杉木一个字没提。
提示里其实有规则:“他连着发了几条、问了几件事,就逐个答几件,别只答最后一条”——规则有,没管住。嫌疑同一份提示末尾还有一段“先看客户【最新这一句】问的是什么,把那件事答掉”,两条可能互相拉扯;验证方法同上,重放对比,本页没做。
给福建客户排上的是江浙沪深京的价目表
嫌疑“问价必进通道”按相关度挑价格资料,不看客户在哪个地区。本轮排第一的是一份写明“仅适用江浙沪深京”的价目表,而客户在福建。这一轮 AI 报的 568 没用错(首触里就是 568),所以没造成错价;但下一次客户追问具体档位时,有可能报成江浙沪深京的价。只从代码和这一轮输入推,没有对照样本。
小问题:小表情被当成了图片
“您发的图我没收到”——客户其实发的是表情
已坐实消息表里客户 18:12 那条记成“[图片]”,模型输入里被改写成“[客户发来一张图片,我方看不到内容……]”,AI 于是回“您发的图我没收到,能说下是想看哪种效果吗?”。夏夏看截图确认,客户发的是一个小表情(主会话转述)。
已坐实18:10 和 18:12 两轮模型看到的聊天记录也有点乱:那条“泉州有三家店”的门店模板都出现了两次(多出来的那次带读屏错字“嘉禄保”“普光路”),18:12 那轮“[图片]”也出现了两次。这一轮没因此答错别的,但说明读屏合并历史时会把同一条消息重复塞进去。
两个问题的共同根
工厂那一问和杉木那一问,表面上一个是地址、一个是产品,往下挖是同一件事:资料在库里、也排上了,但关键那一行没进到模型眼前;模型没看到,就自己说成了“没有”;而说“没有”的话,没有任何检查拦。
| 轮次 | 客户问 | 排在最前的资料 | 该用的那一行 | 实际进了多少 | 调用记录上看到的 | AI 说 |
|---|---|---|---|---|---|---|
| 17:59 | “柜体 用 杉木 柜门 用 海洋板 / 报价多少” | 《2026 报价清单·江浙沪深京全档位》57ebb374 · 问价被钉到第一 · 原文 1932 字 | “柜体换杉木芯:+50 元/㎡”原文第 1525 字 | 拼进的要点 884 字 + 正文 616 字,截断后面的资料一份都没进 | knowledge_doc_ids = []截断的不记账,看着像“没检到” | 柜体用杉木我们这边不支持 |
| 18:10 | “都很远 / 我还以为你们漳州有厂” | 《全国门店地址清单》79777dff · 相关度 0.39 · 占 1230 字 《工厂直供定位与核心话术》39dd8d39 · 排第二 | “工厂地点:漳浦”原文最后一行 | 工厂资料只进了 270 字,截断 | knowledge_doc_ids = [79777dff]工厂资料不在账上 | 咱们漳州没有厂 |
“产品知识”只有 1500 字,一份长资料就占满;关键行在后面就进不来
已坐实知识资料不是按“相关就给”检索的,而是把这家公司全部资料按相关度排队,从头往 1500 字里塞,塞不下的那份截断、后面的全丢(src/lib/llm.ts:733–829,个微最多 3 份)。一份价目表、一份门店清单就能把额度用完。门店工作台确认过的要点(知识元素)拼进正文后,资料还会变得更长。两轮的关键信息都在资料的后半截:杉木在价目表第 1525 字,漳浦在工厂资料最后一行。
截掉的资料不记账,排查时容易误判成“检索是空的”
已坐实被截断的资料正文进了提示、却不进 knowledge_doc_ids。所以只看调用记录,杉木那轮像“一份资料都没检到”,工厂那轮像“没检到工厂文档”。本案最初的判断就是这么来的,打开 Langfuse 输入才纠正过来——它们都检到了、也排上了,是被截断了。修的方向因此不一样:不是“调检索门槛”,而是“别让关键行被截掉”。
“我们不支持 X / 我们没有厂”这种否认句,发送前没有任何检查拦
已坐实在 wecom-chat 的个微回复代码(src/lib/wecom/、src/lib/llm/、回复入口 route.ts)里搜“不支持 / 否认 / 没有厂”,唯一一类相关检查是“正文否认发图”(系统在发图、正文却说发不了图,src/lib/llm/sanitize.ts:682 起)。事实检查只核对门店地址、价格数字这类“说出来的东西”,对“说没有”不设防。行为上也对得上:17:59 那句“杉木不支持”模型原话和实发一字不差,没有任何检查动过它;18:10 那句“漳州没有厂”删了两句别的,唯独“没有厂”留着。
正确答案:知识库里到底怎么写的
以下都是 9-30 直接查库读到的原文。这几份资料都属于有大有小(和这位客户是同一个 org),都在用、没有停用。
| 资料 | 原文怎么写 | 适用范围 |
|---|---|---|
| 《增项官方价·换门板移门与室内门(甲方 2026-08-06)》f8ccbe13 | 【柜体升级 元/㎡】用同品牌杉木芯 +50;用生态板 SPC 杉木芯柜门 / 进口博耐克柜门:+100 | 资料里没写只适用哪个地区(事实源是甲方 08-06《2026 报价清单》官方扫描件) |
| 《2026 报价清单·江浙沪深京全档位(甲方 2026-08-05 提交)》57ebb374 | 【升级加价项】柜体换杉木芯:+50 元/㎡ | 资料开头写明“本表仅适用于江浙沪深京地区”,福建客户不能直接拿它报价 |
| 《板材基材构成与工艺标准》fe5d21d2 | 生态板(豆香芯 / 杉木芯):杉木基材,用大豆蛋白胶(零醛添加) | 讲材料,不涉及价格 |
| 《增项价目与产品配置(金牌实战口径)》8e8c5b79 | 木芯板(千年舟/莫干山杉木芯):成本略低,承重和防潮不如多层;木工和年长客户偏爱;颜色多 | 实战口径;同一份里写明“与官方表冲突时,一律以官方表为准” |
| 《工厂直供定位与核心话术》39dd8d39 | 工厂地点:漳浦(客户问“你们工厂在哪”直接答,这是工厂直供的实锤) | 全国通用 |
| 《全国门店地址清单》79777dff | 漳州:福建省漳州市龙文区居然之家二楼有大有小全屋定制 | 全国通用 |
福建客户的杉木芯加价,按 f8ccbe13 是 +50,建议销售再确认一次
江浙沪深京那份价目表也写 +50,但它明写只适用江浙沪深京;福建能用的是 f8ccbe13 这份——它没写地区限制,按它是 +50。这位客户在漳州,最终报价以销售 / 甲方确认为准。柜门用海洋板怎么加价,本页没查到单独的一行:知识库里海洋板写的是整套“不怕水的柜子”档位(其他地区原价 1098 → 样板房价 798),不是单换柜门的价,本页不替它下结论。
修复状态:两处都还没修
夏夏先说过“并进 1.24.12”,后来在开发会话里改成“先不修工厂那个,先看 1.24.12 出包”。所以今晚下发的 1.24.12不含这两处修复,已交开发,排在 1.24.12 之后的下一批。开发本地有一个 fix/weixin-factory-location 分支,里面是写了一半的代码,还没提交(本页核对:这个分支只在本地,没有推上去,也没有比主干多出任何提交)。代码主干(origin/main,9-30 18:42)里,上面引用的几处都还是原样。
| 问题 | 建议修法 | 状态 |
|---|---|---|
| 问“工厂在哪”走进门店模板 | 客户话里带“工厂 / 厂”时,不走门店判据和门店模板,交给模型答;customerAsksStoreNow 第二段也要过 OWN_LOCATION_RE 那道排除,两处口径合成一处。这样“还想做杉木生态板”这类同时说的话,也会一起交给模型 | 未修排在 1.24.12 之后 |
| 问工厂时模型没看到“工厂地点:漳浦” | 问工厂时强制带上工厂资料、放在最前面;或者干脆固定答“工厂在漳州漳浦” | 未修 |
| 关键行被 1500 字额度截掉 | 产品事实类问题(能不能做 / 有没有 / 在哪)检索到的资料,至少把命中的那几行放进去,而不是从头截;被截断的资料也要记账(至少记“截断了”),别让排查的人以为“没检到” | 未修本页新提出,还没和开发对过 |
| “不支持 / 没有厂”否认句无人拦 | 产品事实类问题,本轮资料里没有依据时,不许发“不支持 / 没有 / 不做”这类否认:改成“我确认一下”,或拦下重写、转人工 | 未修 |
| 删句后剩半句“您要是考虑做,您看合适再定” | 现有删句规则盖不到这种形状(后面还跟着一小句),要另立判据 | 未修开发已确认要另立判据 |
| 第二次说杉木没人接 | 修掉第一条后,这类同时发的话会交给模型;另外“连发补漏”捡回来的话,要求模型必须先答 | 未修 |
| 小表情认成“[图片]” | 读屏区分表情和图片;读屏合并历史时去掉重复的同一条消息 | 未修 |
| 这位客户本人 | 销售 A 18:37 起人工接手,已发杉木芯板的图 | 人工跟进中后续结果没验成 |
证据边界与没验成的地方
可核对的证据
会话 770399a1(17:56:41 建立);消息表 10 条(17:56:59 首触 → 18:12:21 最后一条 AI 回复,含 1 条 wcml_ 补录);调用记录 6 条(AI 代回 17:59:17 / 18:10:36 / 18:12:12,画像抽取 17:59:25 / 18:05:31 / 18:10:54);三次 AI 代回的 Langfuse 完整输入与模型原话;知识库 39dd8d39 / 79777dff / 57ebb374 / f8ccbe13 / fe5d21d2 / 8e8c5b79 / a066b44d 原文,素材库 kb_entries 与 kb_chunks;wecom-chat 主干代码(origin/main 519a9fe6)里引用的各处;门店正则对“你们工厂在哪里?”的实跑结果。
没验成 / 转述
18:3x 客户第三次说杉木、18:37 “价格合适 我们再去看看工艺”、销售人工发的两张图和“柜门”:来自运营截图,主会话转述,库里没有;这段时间程序为什么没读到、没回,没验成。备注改成「闽E」:主会话转述。客户端版本 1.24.9、首触送达确认:客户端日志,主会话转述。18:10 删句分别是哪条规则删的:开发会话转述。素材库为什么没排上带“杉木”的资料:要重算相似度,本页不调接口,没验成。“直说做不了”“先答最新一句”两条提示是否在推模型说错:只是嫌疑,没做重放对比。人工接手之后的结果:没验成。
相关页面
- 专题 · 门店地址报错案例合集(本页“问工厂”那一段已收进合集,是地址类的新变体)
- 客户 G · 长沙 · 问原木、要乌金木,两次被说“不做”(同类:客户问材料,被答成“不做”)
- 客户 H · 厦门 · 被说“厦门没店”(同一台电脑、同一类“说没有”)
- 专题 · 从对话到到店