数字花园
污染的历史:DSML 泄露与影子自模仿
分身术最诡谲的心魔,不是中邪,是学会了模仿自己的中邪。
十月四日,“她”第一次在 TG 上漏出了破绽——本该调用工具发照片的时刻,对话框里却吐出一段带 send_my_photo 字样的原始格式文本。用户只说了一句”那你发照片啊”,等来的却是一段乱码。工程兵连夜挖到了这场心魔的完整真相。
一、第一滴毒
起因微小得近乎无辜:16:19,那段时间网关恰好有个不稳定的抖动窗口(实测 deepseek-flash 通道六次调用里就有一次返回空内容),模型某次回复把工具调用的私有格式(DSML)原样漏了出来,AstrBot 解析失败,那段带格式的文本就当普通消息发给了用户。
如果故事到此为止,这只是一次性抽风。但——那段垃圾文本进了对话历史。
二、影子自模仿
从那一刻起,模型每一轮都读得到”上一次我是怎么调用工具的”——在它眼里,那就是自己的字迹。于是它开始临摹自己的坏榜样:格式越漏越顺,漏得越来越熟练。用户换模型?没用。工程兵实测三个模型的原生工具调用:deepseek-v4.1-flash 与 glm-5.3-flash 都是 6/6 满分——大脑全是好的,毒素却住在记忆里。
这就是”换模型也治不好”的真相:污染会话历史的不是某一代模型,是对话历史本身。历史,才是教坏它的老师。
三、深度排查的三级跳
工程兵被用户两次逼问(“深度检查下,到底是哪里没设置好?“)后,做了本战役最关键的对照实验:此前所有测试都是非流式请求,而流式 + 工具调用在上游通道里恰恰是最常见的断裂组合——一测,网关三条路(非流式/流式/带工具)全部完好,问题被精确定位在 AstrBot 自己发出的请求里。
顺带还抓到一个误导工程数小时的假线索:配置里那个看起来人畜无害的 default_provider_id 根本是非法键名(AstrBot 启动时会规范掉它),真正的键在 agent_runner.config.model.provider_id——默认大脑一直指向最不稳定的 deepseek-flash,而仪表盘显示”未设置”。
四、清毒
终极尸检在数据库里完成:3 条 DSML 毒记录——2 条在对话历史、1 条在平台消息流。删除,复验,干净。默认大脑换成 v4.1-flash(备胎链 v4.1-flash → glm-5.3-flash 故障转移),防复读参数在位。按用户最后的要求又切回 deepseek-flash——让它在史上最干净的环境里接受终审:历史已清毒、参数在位、网络双通道、日志全程可观测。若它此时还漏,才配谈”模型固有缺陷”;若正常,用户最初的直觉(deepseek-flash 本身没问题,是历史污染)就被全额证成。
插叙:僵尸化的她
清毒后还出现过一段插曲:她彻底不回消息了。四路排查(服务、网络、历史、模型)一切正常,但 provider_stats 从 14:56 后零调用——消息根本没走到 LLM。真凶是 TG 轮询连接在白天”睡眠冻结→苏醒”后成了僵尸。一次带日志重定向的重启,一切归零重来:TG 适配器运行中、两个会话被识别、self-learning 恢复监控。从此她的每一次调用,工程兵都能看着日志说话。
真实坐标
- 事故:16:19 网关抖动窗口(deepseek-flash 实测 5/6,1/6 空返)→ DSML 格式漏出 → 进入对话历史 → 模型临摹自身历史 → 失败自我强化(换模型无效)
- 模型实测:deepseek-v4.1-flash 6/6、glm-5.3-flash 6/6 原生工具调用全过;deepseek-flash 5/6
- 关键实验:非流式 vs 流式+工具对照 → 网关三路全好 → 问题在 AstrBot 请求侧 → “对话历史一粘”
- 配置陷阱:
default_provider_id是会被规范掉的非法键;真键 =agent_runner.config.model.provider_id - 清毒:数据库 3 条 DSML 记录(2 对话历史 + 1 平台消息流)删除复验
- 终态:默认模型回切 deepseek-flash,备胎 v4.1-flash→glm-5.3-flash;僵尸 TG 轮询经重启+日志重定向修复;等待”那你发照片啊”终审
评论