|
| 1 | +# SPX-Algorithm:构建多模态搜索服务的一些心得 |
| 2 | + |
| 3 | +## 写在前面 |
| 4 | + |
| 5 | +也是快到结营阶段了,关于我在实训营期间负责的 SPX-Algorithm 这个项目模块的设计思路,想着写个分享记录一下这段时间的心得体会。这个项目说起来其实就是个图文搜索服务,但做下来发现里面还挺有意思的,尤其是在架构设计和工程实践方面踩了不少坑,也有一些收获。 |
| 6 | + |
| 7 | +## 项目背景和定位 |
| 8 | + |
| 9 | +SPX-Algorithm本质上是一个图像搜索推荐模块。用户输入文本描述,系统从图片库里找出最相关的结果。听起来简单,但实际做起来发现挑战不少。 |
| 10 | + |
| 11 | +传统的图片搜索主要靠标签匹配,但这种方式局限性很明显。图片的标签往往不够丰富,用户的表达又很灵活。所以我的目标很明确:用AI来理解文本和图片的语义,让搜索更智能。 |
| 12 | + |
| 13 | +## 整体架构思路 |
| 14 | + |
| 15 | +经过一段时间的摸索,最终采用了分层架构设计: |
| 16 | + |
| 17 | +```text |
| 18 | +API层 ← 对外接口,简洁易用 |
| 19 | +协调层 ← 编排各种算法模块 |
| 20 | +服务层 ← 图文匹配 + 重排序 |
| 21 | +数据层 ← 向量存储 + 用户反馈数据存储 |
| 22 | +``` |
| 23 | + |
| 24 | +### 为什么选择分层架构? |
| 25 | + |
| 26 | +1. **职责清晰**:每一层只关心自己的事情,降低耦合 |
| 27 | +2. **易于扩展**:加新功能时只需要在对应层面改动 |
| 28 | +3. **便于测试**:每层都可以独立测试和调试 |
| 29 | +4. **未来团队协作**:不同人可以专注不同层面的开发 |
| 30 | + |
| 31 | +## 核心模块设计 |
| 32 | + |
| 33 | +### 图文匹配服务 |
| 34 | + |
| 35 | +这是算法实现的核心模块,负责理解用户查询并召回相关图片。 |
| 36 | + |
| 37 | +选择CLIP模型主要是因为它能把文本和图片映射到同一个语义空间。我们用的是OpenCLIP的ViT-B-32,512维向量输出。这个选择是经过权衡的: |
| 38 | + |
| 39 | +- 效果足够好,能理解复杂的语义关系 |
| 40 | +- 推理速度快,满足线上服务需求 |
| 41 | +- 社区成熟,资料多坑少 |
| 42 | + |
| 43 | +向量存储用的Milvus,主要看中它对大规模向量检索的优化。 |
| 44 | + |
| 45 | +### 重排序服务 |
| 46 | + |
| 47 | +图文匹配召回的结果虽然相关,但排序质量还有提升空间。这时候就需要重排序来精调。 |
| 48 | + |
| 49 | +我们采用 LTR 的思路,基于用户的真实反馈来训练排序模型。整个设计围绕"用户反馈闭环"展开: |
| 50 | + |
| 51 | +1. **反馈收集**:用户每次搜索后的点击行为都会被记录下来 |
| 52 | +2. **训练数据构建**:从点击行为中提取pairwise训练样本,被选中的图片作为正样本,未选中的作为负样本 |
| 53 | +3. **模型训练**:使用神经网络学习用户偏好模式 |
| 54 | +4. **在线重排序**:训练好的模型对搜索结果进行重新排序 |
| 55 | + |
| 56 | +这种设计的好处是能够持续学习用户偏好,越用越准。但也有挑战,比如冷启动问题、反馈噪声处理等。 |
| 57 | + |
| 58 | +### 搜索协调器 |
| 59 | + |
| 60 | +为了统一管理多个算法服务,我们设计了SearchCoordinator。它的作用是编排整个搜索流程: |
| 61 | + |
| 62 | +1. 调用图文匹配服务进行粗排召回 |
| 63 | +2. 如果启用了重排序,调用重排序服务进行细排 |
| 64 | +3. 返回最终的排序结果 |
| 65 | + |
| 66 | +这个设计让我们能够灵活控制算法流程,比如可以随时开关重排序功能,方便做A/B测试。 |
| 67 | + |
| 68 | +## API设计理念 |
| 69 | + |
| 70 | +在接口设计上,我们遵循了"对外简洁,对内丰富"的原则,主要分为三类接口: |
| 71 | + |
| 72 | +### 资源管理接口 (`/v1/resource/`) |
| 73 | + |
| 74 | +- `POST /add`:添加单个资源 |
| 75 | +- `POST /batch`:批量添加资源 |
| 76 | +- `POST /search`:基于文本的语义搜索 |
| 77 | +- `POST /match`:基于图片的语义搜索 |
| 78 | + |
| 79 | +### 用户反馈接口 (`/v1/feedback/`) |
| 80 | + |
| 81 | +- `POST /submit`:提交用户点击反馈 |
| 82 | +- `GET /stats`:查看反馈统计信息 |
| 83 | +- `GET /recent`:获取最近的反馈数据 |
| 84 | +- `POST /train`:触发模型训练 |
| 85 | +- `GET /model/status`:查看模型状态 |
| 86 | +- `POST /model/enable|disable`:启用/禁用重排序 |
| 87 | + |
| 88 | +### 内部调试接口 (`/v1/internal/`) |
| 89 | + |
| 90 | +- 向量数据管理:查看、搜索向量数据 |
| 91 | +- 资源管理:列表查询、删除操作 |
| 92 | +- 数据库状态:详细的系统状态信息 |
| 93 | + |
| 94 | +这样设计的好处是业务方使用简单(只需要关心resource接口),反馈收集独立成模块(便于数据科学团队使用),同时我们内部有足够的工具来监控和调试系统。 |
| 95 | + |
| 96 | +## 踩过的坑和解决方案 |
| 97 | + |
| 98 | +### SVG处理问题 |
| 99 | + |
| 100 | +我们的图片库有很多SVG格式的图片,但CLIP模型只能处理位图。最初直接用Pillow转换,发现效果很差——SVG的矢量信息丢失了。 |
| 101 | + |
| 102 | +后来改用CairoSVG来处理,质量明显提升。 |
| 103 | + |
| 104 | +这个经历让我意识到:**看似简单的问题往往有很多细节**。 |
| 105 | + |
| 106 | +### 向量存储优化 |
| 107 | + |
| 108 | +最初我们把所有向量数据都放在内存里,随着数据量增长很快就撑不住了。 |
| 109 | + |
| 110 | +迁移到Milvus后,发现索引类型的选择很关键。我们试了IVF、HNSW等几种索引,最终选择HNSW是因为它在我们的数据规模下召回率和速度表现最均衡。 |
| 111 | + |
| 112 | +### 重排序特征设计 |
| 113 | + |
| 114 | +重排序模块我们改了好几版。最初用10维手工特征,包括余弦相似度、欧氏距离、向量模长等。后来发现CLIP向量已经归一化了,模长特征基本没用。 |
| 115 | + |
| 116 | +最终改成了神经网络方案,用1500多维的丰富特征,包括原始向量、统计特征等。虽然维度高了很多,但信息保留更完整。 |
| 117 | + |
| 118 | +### 配置管理混乱 |
| 119 | + |
| 120 | +项目初期配置管理比较随意,开发、测试、生产环境的配置经常搞混。后来统一用dataclass重新设计了配置系统,按环境分离,清爽了很多。 |
| 121 | + |
| 122 | +## 一些工程实践心得 |
| 123 | + |
| 124 | +### 日志和监控 |
| 125 | + |
| 126 | +每个关键模块都加了详细的日志,包括: |
| 127 | + |
| 128 | +- 请求响应时间 |
| 129 | +- 数据库操作耗时 |
| 130 | +- 搜索结果统计 |
| 131 | +- 异常情况记录 |
| 132 | + |
| 133 | +这些数据在出问题时特别有用,能快速定位根因。 |
| 134 | + |
| 135 | +### 错误处理 |
| 136 | + |
| 137 | +对于算法服务来说,容错很重要。我们的策略是: |
| 138 | + |
| 139 | +- 单个服务出错不影响整体功能 |
| 140 | +- 重排序失败时返回粗排结果 |
| 141 | +- 向量服务异常时走降级逻辑 |
| 142 | + |
| 143 | +### 测试策略 |
| 144 | + |
| 145 | +除了常规的单元测试,我们还设计了端到端的功能测试。特别是对于机器学习模块,我们会构造一些已知结果的测试用例,确保算法逻辑正确。 |
| 146 | + |
| 147 | +## 未来的一些想法 |
| 148 | + |
| 149 | +1. **多模态融合**:除了CLIP,考虑加入其他视觉理解能力 |
| 150 | +2. **个性化搜索**:结合用户历史行为做个性化排序 |
| 151 | +3. **特征学习**:让模型能更好地适应用户偏好 |
| 152 | +4. **效果评估**:建立更完善的线上效果评估体系 |
| 153 | + |
| 154 | +## 总结 |
| 155 | + |
| 156 | +做SPX-Algorithm这个项目最大的收获是:**好的架构设计比炫酷的算法更重要**。 |
| 157 | + |
| 158 | +技术选型要务实,不要为了用新技术而用新技术。我们选择CLIP、Milvus这些相对成熟的方案,主要考虑的是稳定性和可维护性。 |
| 159 | + |
| 160 | +工程实践要细致,很多看起来简单的问题往往有很多坑。配置管理、错误处理、日志监控这些"脏活累活"往往决定了系统能不能稳定运行。 |
| 161 | + |
| 162 | +最后,用户反馈闭环很重要。我们通过收集用户的真实行为数据来持续优化算法效果,这比闭门造车要有效得多。 |
| 163 | + |
| 164 | +希望这些分享对大家有用。如果有问题欢迎交流讨论! |
0 commit comments