model / multimodal / tts / embedding 里所有「把 net/http 的 *url.Error 直接打进 错误串」的地方(M51 清单的 B1 组 17 处 + 清单外的同根因 2 处)统一改走 trace.URLCause:错误串只少一段地址,底层原因、哨兵分类、状态码、重试/降级判据 一字不动。 清单内(17): - model/openai.go: Chat / ChatStream 的 NewRequest、doRequest - model/anthropic.go: chatOnce / streamOnce 的 NewRequest、doRequest - multimodal/vision/adapter.go: ask 的 NewRequest、client.Do - multimodal/voice/cloud.go: postJSON 的 NewRequest、client.Do - multimodal/voice/dashscope.go: download(预签名 OSS 地址)与 dashscopePost 各两处 - voice/tts/client.go: unreachable(返回值与同一行日志的 err 字段都只留原因, 地址只由 redactURL(endpoint) 出现一次) - embedding/api.go: embedChunk 的 client.Do、newEmbeddingRequest 的 NewRequest 清单外同根因(2,均为 %w 形态,B1 清单按 %v 搜时漏掉): - voice/tts/client.go: speak 的 NewRequest 失败 - embedding/endpoint.go: normalizeEndpointURL 的 url.Parse 失败 测试:5 个新文件 18 个用例,逐处可变异打红(实测:把任一处的 URLCause 去掉 ⇒ 对应用例红);dashscope 预签名地址单独一条用例,并另有一条钉住 403 状态码仍在。
背景:入库前审查链路一直整条超时(日志每 ~20s 一条 WARN),异步那层 (含刚装好的 T1)从未成功跑过。 - 新增 endpoint.go:把「连接语义上不可靠」的回环别名规范化成 127.0.0.1 (localhost 大小写不敏感 / 0.0.0.0 / 空主机),只替换 Host,不碰 path / query / fragment / userinfo;显式 [::1] 与真实主机名逐字不动 - Embed 加独立短超时 DefaultRequestTimeout = 5s(远小于审查 20s 预算): 卡住的调用快速失败并走既有「降级到词项余弦」的路径,把预算留给 T1 - .env.example 示例地址 localhost -> 127.0.0.1(未注释行键数 69 -> 69,无增删) - 跨包测试钉住 5s 严格小于审查总预算 诚实边界(子代理实测,推翻了主代理原先的 IPv6 根因推断): - Go 客户端走 localhost 实测约 57ms、curl 约 0.2s ⇒「localhost -> ::1 等满 20s 预算」这条链不成立;更可能是单槽 llama.cpp 的吞吐/争用 (一批 64 条约 2.1~2.9s,审查 201 条约 8~10s,再叠 T1 8s 顶满预算) - 规范化在任何环境下都无害,5s 快速失败对这个真因对症;但真因 (容量/争用)需要另排切片,已记入工作小结