perf(vision): 图片 URL 的「取回 + 内联」按内容哈希 memo(协同 H1:每回合重复付费/取回)
- 起因(Android 注册的成本项 H1):`resolveImages` 每回合都跑,而 `inlineImageSrc` 对 `data:` 短路、 对 **URL 每回合重新取回并内联** ⇒ ① 同一张图反复网络 I/O;② 来源一旦失效则该回合解析失败, 而 loop 保留原消息不中断回合 ⇒ **模型这轮静默看不到图** - 修法:按**内容哈希**记忆「URL → data URI」结果(有界 + 并发安全,独立小文件承载); **失败不写缓存**(不把坏结果钉住,第二次仍可重试);命中即不再发起网络请求 - **来源失效不再静默**:取回失败产生可诊断信号(含主机与原因,**不含图片内容/凭据**),回合照旧继续 - 复核:vision 包 build/vet/测试绿(含 `-race`);断言覆盖「同一 URL 连续解析 → 上游只被取回 1 次且结果逐字节相同」 「内容变化不被旧缓存命中」「失败不写缓存且第二次仍重试」「容量上限生效」,以及既有断言 (非图片 `ErrNotImage` / SSRF 被拒 / 长度预检)不回归;变异反证已还原
This commit is contained in:
1 parent
b65fe05635
commit
94b882f4d9
5 files changed
+682
-8
No files matched your search
@@ -26,17 +26,22 @@ type MessageResolver struct {
|
||||
router *Router
|
||||
info ModelInfoProvider
|
||||
invoke ToolInvoker
|
||||
cache *imageCache
|
||||
}
|
||||
|
||||
// NewMessageResolver 构造一个 MessageResolver。router 决定
|
||||
// 分层;info 报告主模型的视觉能力;invoke 运行一个已注册的 vision/OCR
|
||||
// 工具。invoke 为 nil 时任何工具路由都会失败(此时图像被保留),
|
||||
// 因此没有工具的解析器会降级到主模型路径。
|
||||
//
|
||||
// 解析器自带一个按内容哈希 memo 化的取回缓存:解析器在接线处构造一次并
|
||||
// 长期复用,同一 URL 图因此只在首个回合真正取回一次(见 cache.go)。
|
||||
func NewMessageResolver(router *Router, info ModelInfoProvider, invoke ToolInvoker) *MessageResolver {
|
||||
return &MessageResolver{
|
||||
router: router,
|
||||
info: info,
|
||||
invoke: invoke,
|
||||
cache: newImageCache(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +82,10 @@ func (r *MessageResolver) resolveImage(ctx context.Context, imageURL string) (mo
|
||||
// 取回并内联为 data: URI——云 provider 取不到自部署的局域网地址
|
||||
// (如 http://192.168.x.x:10942/api/v1/files/…),Anthropic 协议更是
|
||||
// 只接受 base64 data: URI(model/anthropic_encode.go 会拒绝裸 URL)。
|
||||
// 取回失败时返回错误,由 loop 保留原消息(该轮不因此中断)。
|
||||
src, err := inlineImageSrc(ctx, imageURL)
|
||||
// 取回失败时返回结构化错误(带来源主机与原因),由 loop 记录一条
|
||||
// 可诊断的 WARN 并保留原消息(该轮不因此中断);失败不进缓存,
|
||||
// 下一回合会照常重试,因此不会「永久看不到图」。
|
||||
src, err := inlineImageCached(ctx, r.cache, imageURL)
|
||||
if err != nil {
|
||||
return model.Content{}, err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user