从CV小白到上线:我在字节搞了个视觉问答系统,顺便玩了把RAG+AI编程

Shell脚本侠
2026-04-19 10:37
阅读 344

上周五晚上十一点半,我瘫在工位上盯着屏幕右下角的 build success,心里终于松了口气。这破项目总算能交差了——不是因为需求多复杂,而是产品经理在双11前两周突然拍脑袋说:“能不能让用户上传一张商品图,然后问‘这是什么品牌?’、‘有没有类似款?’,系统自动回答?”

我当时差点把咖啡泼他脸上。但转念一想,这不就是个典型的多模态检索增强生成(RAG)场景吗?而且最近正好在啃 Rust,不如借机练练手。于是,这个“临时起意”的计算机视觉实战项目就这么上了。


为啥是我来搞这个?

先简单自报家门:字节跳动基础架构组后端开发,干了快两年,日常和 Kubernetes、分布式存储、中间件打交道。VSCode 插件装了快 50 个,光是 Rust 相关的就有 rust-analyzer、crates、even better TOML……别笑,真香警告。

虽然主业不是算法,但字节有个“技术轮岗”文化——只要你敢接,就让你试。加上最近 AI 编程工具(比如 Cursor、GitHub Copilot)越来越猛,我也想看看它们能不能帮我这种“非科班 CV 工程师”快速搭出可用系统。

于是,一个融合 计算机视觉 + RAG + AI 编程辅助 的小项目就这么诞生了。


需求拆解:用户传图,我得答对

核心目标很清晰:

用户上传一张图片 → 系统理解图像内容 → 支持自然语言提问 → 返回准确答案

听起来像 CLIP + LLM 的组合?差不多,但细节魔鬼。我们内部商品库有上亿 SKU,不能靠纯生成模型瞎编,必须基于真实数据检索后再生成——这正是 RAG 的用武之地。

所以整体 pipeline 分三块:

  1. 图像编码:把图片转成向量
  2. 多模态检索:用问题文本 + 图像向量去商品库找 top-K 相似项
  3. 生成回答:把检索结果喂给 LLM,让它组织语言回答

关键在于:怎么让这三个环节高效、准确、低成本跑起来?


技术选型大战:CV 模型哪家强?

我拉了个表格,对比了几种主流方案(别嫌土,字节内部也这么干):

方案 模型 是否开源 向量维度 中文支持 推理速度 (CPU) 是否适合电商
CLIP (ViT-B/32) OpenAI 512 弱(英文为主) 中等 ⚠️ 需微调
Chinese-CLIP OFA 512 ✅ 强
BLIP-2 Salesforce 768 中等 慢(需 GPU) ✅✅
Qwen-VL 阿里 4096 ✅✅ ✅✅(但太重)
自研小模型 内部 256 极快 ✅✅✅

产品经理第一句话就是:“预算有限,别上 GPU。”
运维兄弟补刀:“QPS 至少 50,P99 延迟 < 800ms。”

直接把 BLIP-2 和 Qwen-VL 判死刑。CLIP 虽然轻,但中文商品名识别烂得一批——测试时把“李宁云 cushion 跑鞋”识别成 “Nike Air Max”,我当场裂开。

最后咬牙上了 Chinese-CLIP,理由如下:

  • 开源免费,社区活跃
  • 在中文图文对齐任务上表现优秀(论文指标吊打原版 CLIP)
  • 可以用 ONNX 导出,部署到 CPU 服务毫无压力

不过,光靠预训练模型肯定不够。我们拿内部 50 万张带标签的商品图做了两轮微调

  1. 第一轮:对比学习,拉近“同款不同图”距离
  2. 第二轮:加入用户真实 query,做图文匹配蒸馏

微调完,mAP@100 提升了 22%,线上 bad case 减少一大半。


RAG 架构设计:别让 LLM 胡说八道

很多人以为 RAG 就是“检索 + 生成”,其实坑多得很。最典型的问题:检索不准,LLM 一本正经胡说八道

比如用户问:“这款手机支持无线充电吗?”
如果检索返回的是“iPhone 13”,但实际图片是“Redmi Note 12”,LLM 很可能答:“支持,最高 15W。” —— 完全错误!

所以我们加了三层保险:

1. 双路检索:图文联合 embedding

  • 文本 query 先用 BGE-M3 编码
  • 图片用 Chinese-CLIP 编码
  • 最终向量 = α * text_emb + (1-α) * image_emb (α=0.6 实测最佳)

2. 粗排 + 精排

  • 粗排:FAISS HNSW,召回 1000 条
  • 精排:用轻量 Cross-Encoder 重打分(只跑 top-100)

3. 检索结果可信度过滤

如果 top-1 和 top-2 的相似度差 < 0.1,直接返回“无法确定,请换张图或描述更详细”

这部分代码用 Rust 重写了核心逻辑(主要是 FAISS 查询 + 向量加权),比 Python 快 3.2 倍,内存占用降了 60%。虽然学 Rust 时被 borrow checker 折磨到想删库跑路,但现在真香。

// 示例:图文混合 embedding 计算(简化版)
pub fn fuse_embeddings(
    text_emb: &[f32],
    image_emb: &[f32],
    alpha: f32,
) -> Vec<f32> {
    text_emb.iter()
        .zip(image_emb.iter())
        .map(|(t, i)| alpha * t + (1.0 - alpha) * i)
        .collect()
}

AI 编程:我的“赛博结对编程”伙伴

说实话,要不是用了 AI 编程工具,这项目根本赶不上双11。

我主要用 Cursor(比 Copilot 更懂上下文),几个骚操作:

  1. 自动生成 ONNX 导出脚本
    输入:“用 PyTorch 导出 Chinese-CLIP 为 ONNX,支持动态 batch”
    → 直接生成可运行代码,省了我查文档两小时

  2. Rust FAISS 封装
    我写了个注释:“封装 faiss-rs,提供 add/search/delete 接口,线程安全”
    → Cursor 自动生成 struct + impl + RwLock 保护

  3. Prompt 调优助手
    让它帮我改 LLM 的 system prompt:

    “你是一个电商客服,只能基于提供的商品信息回答。如果信息不足,就说‘不清楚’。”

    它建议加入:“禁止推测、禁止编造参数、禁止比较未提及品牌”——救命,这比我想得周全。

当然,AI 也不是万能的。有一次它给我生成了个 unsafe { transmute },差点引发内存泄漏。后来我学会了:生成代码必 review,尤其涉及 unsafe 或并发


部署上线:K8s + Envoy + 血泪教训

作为基础架构组老油条,部署这块我熟。但这次还是踩了个大坑。

初始架构:

用户请求 → API Gateway → CV Service (Rust) → FAISS Index → LLM Service

压测时发现:FAISS 单线程加载 index 时,整个服务卡死 8 秒
原因是 FAISS 默认不是线程安全的,而我们的服务是多 worker 模型。

解决方案:

  • 启动时预加载 index 到共享内存(用 mmap)
  • 所有查询走只读视图
  • 加个 health check,index 未就绪时返回 503

配置片段(K8s Deployment):

env:
- name: INDEX_PATH
  value: "/mnt/shared/faiss_index.bin"
volumeMounts:
- name: index-volume
  mountPath: /mnt/shared
volumes:
- name: index-volume
  persistentVolumeClaim:
    claimName: faiss-index-pvc

上线那天,运维盯着 Grafana 屏幕说:“P99 稳在 620ms,牛啊。”
我回了句:“下次别让产品周五提需求就行。”


效果与反思:值不值得搞?

上线两周,数据还不错:

  • 准确率(人工抽样):86.3%
  • 平均响应时间:580ms
  • 用户满意度(NPS):+42

最关键的是,bad case 大幅减少。以前纯 LLM 回答经常“幻觉”,现在有了 RAG 锚定,靠谱多了。

但也有遗憾:

  • 没上多模态 LLM(如 LLaVA),因为延迟扛不住
  • 图片 OCR 还没集成,遇到带文字的商品图会漏信息
  • 中文 query 的语义泛化还不够,比如“耐克那种气垫鞋”识别率低

不过嘛,技术永远没有完美方案,只有“够用就好”。毕竟在字节,能跑赢 deadline 的代码才是好代码


给同行的建议

如果你也在搞类似项目,几点血泪经验:

  1. 别迷信 SOTA 模型:轻量 + 可控 > 重型 + 黑盒
  2. RAG 的核心是检索质量,不是 LLM 多 fancy
  3. AI 编程是加速器,不是替代品——你得知道它哪里会翻车
  4. 尽早压测,尤其是向量检索这种 I/O 密集型操作
  5. 中文场景一定要用中文预训练模型,别头铁上英文 CLIP

最后,Rust 虽然学习曲线陡,但在高性能服务里真的稳。我现在看 Go 都觉得 GC 是种“不确定性”。


项目代码暂时不能开源(字节规矩你懂的),但核心思路完全可以复用。如果你也在折腾 CV + RAG,欢迎评论区交流——或者下次团建我请你喝瑞幸,聊聊怎么让产品经理闭嘴 😏

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝