召回率从13%涨到50%,Recall@5从13%涨到80%。同一周,我的智能体端到端答完的问题,从10次里2次,掉到10次里1次,再掉到10次里0次。
每一个组件指标都在说我在赢。产品却在死。
![]()
这不是段子,是一个数据分析智能体的真实翻车记录。它跑在银行和经济时间序列的数据湖上,你用大白话提问,它找到对应的序列,建表、派生列、跑变点分析、画图。智能体从头到尾看不到数据本身,它看到的是一个目录,一行一个可度量指标,带名称、单位、频率、覆盖范围。它负责挑,数据库负责算。
这个目录有 55,532 条。这个数字就是整个故事的钥匙。
关键词匹配的荒诞现场
数据迁移期间,语义检索被关掉了。检索退化成关键词匹配,而关键词匹配要求你问题里的每一个词都出现在标签里。你搜"inflation"(通胀),返回的是一条资产负债表调整项——因为消费者价格指数的正式名字叫"Consumer Price Index",里面根本没有"inflation"这个词。
于是有了那组对比:改造前 recall@1 = 13%,recall@5 = 13%;改造后 recall@1 = 50%,recall@5 = 80%。
然后我跑了端到端场景。检索改造前,10次里2次跑完。改造后,10次里1次。我以为是噪声,又优化了一次检索,再跑:10次里0次。
模型到底在干什么
每一个失败的运行长得都一样。搜目录,再搜,一轮里搜12次、17次、23次——却一次都没调用那个真正建表的工具。
最直观的解读是犹豫:面对55,532个选项,它下不了决心。我沿着这个方向想了三套理论,已经开始动手修第二套。
然后我打开了推理轨迹,读了模型对自己说的话。
"第一次搜索返回了8个候选,但输出是空的(只有'8 candidates, best to worst:',后面没有列表)。让我换个词再搜一次。"
"奇怪。搜索结果被截断了。"
它不是拒绝做决定。它是在寻找被从脚下抽走的证据。
那行代码
上下文管理有一条规则:最近三条工具结果原样保留,更早的折叠成第一行。
而一条搜索结果长这样:第一行是表头"8 candidates, best to worst:",下面才是候选列表。这条规则保留了表头,删掉了列表。
模型看到的是"8 candidates, best to worst:",冒号后面空空如也,于是判断这次搜索什么都没返回,再搜一次。
一轮搜到十次时:总提示词8,646字符(约2,161 token),工具结果占窗口30%,候选ID只看得见80个里的18个,78%被删掉了。窗口才用了30%。这条规则为了省下1,800个字符,正在摧毁这一轮的工作记忆。
为什么检索变好反而更糟
检索变好,意味着第一次搜索就能给出像样的候选。像样的候选会诱使模型再搜一次做对比。而第三次之后的每一次搜索,都会再删掉一条结果。
- 检索差 → 模型早早放弃 → 搜索次数少 → 删除少
- 检索好 → 模型愿意探索 → 搜索次数多 → 好候选被删光
优化一个组件,通过一个两个组件都不拥有的机制,拖垮了整个系统。Recall@1 在杀死产品的同时,一直在诚实地变好。
同样的错误我还写在了另外两个地方:一个800字符的摘要上限,会在第五个候选处悄悄截断列表;一个按最旧优先填充的候选池,会把最新一次搜索刚找到的东西丢掉。这三处在写下时对当时的目录都是正确的——那时候只有13条。目录涨了四千倍,没有一处被重新审视。
修好它靠的不是更聪明的模型
不是更聪明的模型,不是更好的提示词。三处改动,全都关于"给模型看什么":
- 折叠的结果保留内容,而不是保留标签
- 每次搜索都重新陈述本轮累积的候选池,最新的排最前
- 结果按目录结构分组,而不是返回一个扁平的排序列表
前后对比:跑完三轮的运行从0/10变成9/10;建表的轮次从约7/30变成29/30;每轮发现性调用从12次降到2次。
整个修复过程中,检索质量没有变。Recall 还是50%/80%。分组改变的是呈现,不是排序——而呈现自始至终才是那个卡脖子的约束。
"GDP, Nominal · Türkiye——这个标题下196行中的一行"是一个可判定的选择。同一行放在扁平列表里,就不是。
行业标准解法反手捅了一刀
面对"模型不知道这类问题在这里是怎么被回答的",教科书答案是建一个已验证查询库:把问答对作为范例注入。Snowflake 就是这么做的。我照做了。
只用分组结果时,10次跑完9次。加上已验证查询库后,变成10次跑完3次,再变成5次。它在十次里干掉了六次。
一半的伤害,原因六周前就写在我自己的接口契约里:系统提示词不得包含族列表或序列ID。看过提示词里ID的模型,会自己发明它的变体。而我的范例里,恰恰带着它们解析到的那些族的ID。我读过那个文件。我还是把它发出去了。
另一半更简单:有了分组结果,模型已经能看出匹配聚集在哪里。一个抽象范例反而给了它多余的东西去推理。Snowflake 需要查询库,是因为它的语义模型被限制在32K token,没法展示整个目录。而我可以。同一个问题的两个解法,互相打架。
想告诉一周前的自己三件事
第一,去读模型对自己说的话。关于"犹豫"的三轮理论推演,被一次打开推理轨迹的运行全部终结。模型一直用大白话在描述这个bug。
第二,组件指标可以一路上涨,而系统正在死掉。Recall 在整段窗口里单调上升,产品在同一段窗口里归零。
第三,写下时正确的规则,不会因为数据规模涨了四千倍就自动保持正确。那三处上下文规则,没有一处是错的——它们只是属于一个只有13条目录的世界。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.