一个中文任务名引发的跨平台故障
一个中文任务名引发的跨平台故障
一个定时任务插件,到点本该正常触发一个 Agent 会话,却在任务名改成中文之后,整条链路报出一个让人摸不着头脑的错误:TRANSPORT。单看这个字段,大家第一反应都是“网络传输断了”,于是去查代理、查超时、查对端是否在线,查了半天一无所获——因为问题从头到尾就不是网络。
这篇文章记录我修复的一个真实故障:中文任务名是如何一路变成跨平台请求里的字节问题、最终被系统标成 TRANSPORT 的。细节以实际项目为准,但它揭示的“编码链路”问题在跨平台、跨字节编码的对接里非常典型。
一、现象:报错叫 TRANSPORT,根因却在编码
故障表现为:创建定时任务时,任务标题是中文;到点触发时,宿主要求用“真实 Agent 会话”去执行 prompt。结果这些中文任务名被一路带进了会话标识里,在把请求发到模型服务时,被系统在请求层拦下,抛出一个被归类为 TRANSPORT 的错误。
TRANSPORT 这个名字有极强的误导性——它让人以为问题出在“传输层”。但翻到真正抛错的地方,是对端在解析请求头时,遇到了一个非 ASCII 的字节序列,它按字节串(ByteString)去解析时失败了。换句话说:传输层根本没出问题,是请求里带了一个它无法接受的字节串。
那个非 ASCII 的东西,就是中文任务名被写进会话 ID 之后留下的痕迹。
定位时我把 TRANSPORT 这个错误名先放一边,去翻了真正抛错的那一层日志,看到的是“请求头里有一个无法按字节串解析的值”。顺着这个值往上追,发现它来自会话 ID,而会话 ID 来自任务标题。整条链路就清楚了:标题(中文)→ 会话 ID(带中文)→ 请求头(字节串解析失败)→ 报成 TRANSPORT。 问题在“编码链路”,不在“传输链路”。
二、诱因:把“给人看的名字”当成了“内部 ID”
问题的源头很隐蔽:实现里,任务有一个“标题”(给人看的中文),会话又有一个内部 session id。最省事的写法,是让两者共用同一个字段——标题是什么,session id 就是什么。这样界面好看、逻辑也简单。
但内部 ID 的用途和标题完全不同:它要进 URL、进请求头、进各种需要严格 ASCII 的协议边界。一旦塞进中文,就突破了这些边界对字节的限制。中文在 UTF-8 里是多字节的,请求头按 ASCII/ByteString 解析时就会炸。
所以根因不是“网络”,而是把一个展示字段错误地复用了成协议字段。展示名允许任意字符,内部标识必须被严格约束。
三、修复:把“展示名”和“内部 ID”彻底解耦
正确的修法不是“以后别用中文”——那只是绕过,不是修复。这也是我在主页里写“没有停在‘改成英文绕过去’”的原因。绕过去,等哪天用户用了个别的特殊字符,故障会原样回来。
我的做法是:会话 ID 只允许 ASCII。 中文不再写入 session id,而是单独作为展示标题存在;内部标识由一套只含 ASCII 的规则生成,保证它无论进 URL、进请求头还是进其他协议边界都安全。
这一步的实质是:分清“给人看的字段”和“给机器用的字段”,让它们各自遵守自己的字符集约束,而不是共用同一个值去省事。展示层可以随便花哨,协议层必须保守。
四、回归测试:把“中文标题 → ASCII session id”钉死
光改代码不够,得把这条规则写进测试,防止以后谁又“顺手”把标题写回 ID。
这个项目有一条行为级 E2E,用的是假 host,无需完整的 DSH 运行时也能跑。覆盖项里就专门有一条:“中文标题 → ASCII session id”。也就是说,创建一个中文标题的任务,断言生成出来的内部会话 ID 是纯 ASCII,而不是中文原文。
这比口头约定可靠得多:只要有人把规则改回去,测试立刻变红,也就能在发布前拦住,而不是等用户踩到才报障。
五、遗留与兼容:老数据也要给出路
修复还有一个绕不开的点:已经生成的旧会话,其 ID 里可能已经带了非 ASCII。 打开它们时,仍可能触发 TRANSPORT。如果没有兼容策略,用户会遇到“明明更新了,老任务还是坏”的困惑。
处理方式是:不强行改历史数据(改了会破坏会话绑定),而是在文档里明确说明——旧会话如果 ID 含非 ASCII,请用新版本重新「立即执行」生成新会话;同时把这条作为一个已知限制写清楚。这样用户拿到的是一个“知道该怎么处理”的版本,而不是一个“看起来修了其实暗坑还在”的版本。
六、可复用结论
TRANSPORT这类错误名会骗人:先看抛错位置的字节约束,别急着查网络。- 内部 ID 只允许 ASCII 是对协议边界的尊重;展示名另存,两者解耦。
- 修复应针对“编码链路”,而不是“这次别用中文”这种绕行。
- 用一条“中文输入 → ASCII 输出”的回归用例把规则钉住。
- 老数据要给出迁出路径,并把已知限制写进文档,别让用户在暗坑里猜。
一次跨平台故障,最后落在“字节字符串”上,而不是“网络”上——这本身就是个提醒:报错信息说“哪里出了问题”,未必是“真正出问题的地方”。顺着编码链路去看,比对着错误名去猜,要快得多。