从单体到 AI 搜索:一个电商搜索系统的进化

2026-08-28 21:280 条评论193 次阅读

从单体到 AI 搜索:一个电商搜索系统的进化


开篇:11 年,五代架构,一套搜索

2026 年回看,我第一次接手电商搜索后端,是在一台 Solr Master-Slave 集群面前。

那是 2016 年,我刚入职某电商公司不久,接手了上一个人留下的「搜索服务」。单机 Solr + 单体 Java Service,索引按天跑全量,宕机一次全站搜索瘫痪一次。那个架构朴素到今天回想起来都有点感动:没有 Kafka,没有微服务,连 Nginx 都得自己配。

谁能想到,11 年后,这个团队同一套业务跑在五套完全不同的架构上:Solr Cloud 分布式、微服务化、平台化多路召回,最后一路演进到 Search Agent——基于 Gemma 微调模型 + LangGraph 编排的会话式商品搜索。上线后电商会话搜索转化率比传统关键词搜索提升约 22%,用户平均交互 3.2 轮。

这篇文章,我想把这条路完整地讲一遍。不是为了炫技,是因为搜索系统这 11 年的演进,几乎,就是过去十年整个互联网后端架构演进史的一个缩影。每一代架构背后,都是同一个业务问题被同一群工程师用当时能找到的最优解重新回答一遍。

五代架构速览:

代次 形态 核心解决 关键数据
第一代 单体 + Solr MS 把搜索做出来 单机房、日导数据
第二代 大数据分布式 数据量爆炸 TB 级、24h 全量
第三代 微服务化 服务隔离 + 团队并行 交付周期 -60%
第四代 双塔 + 多路召回 + 平台化 召回覆盖 + 效果提升 CTR 2.2% → 2.7%
第五代 Search Agent 会话式搜索 转化率 +22%

下面我们一代一代讲。


第一代:单体服务 + Solr Master-Slave(2016 早期)

刚接手那会儿,整个搜索链路就是这么简单:

Sqoop
按天全量

replicate

MySQL
商品库

Solr Master

Solr Slave

Java 单体服务
查 Solr 索引

返回给前端

没有 Kafka,没有 Spark,没有 Redis 缓存。Java Service 直接打 Solr Slave,索引按天凌晨跑一次 Sqoop 全量同步。

这一代解决了「把搜索做出来」的问题。代价是三个:

  • 数据延迟极高:凌晨跑的全量,意味着白天改的商品信息,要等第二天才能被搜到。运营经常一脸懵:明明上新了,怎么搜不到?
  • 宕机风险极高:单体服务 + 单 Solr Slave,宕机一次全站搜索直接挂。Master 挂了还有 Slave 顶上,Slave 挂了就完了。线上最怕半夜告警。
  • 运维成本高:每次 Solr 索引需要重建,全量数据从 Sqoop 拉过来再灌进 Solr,重建一次几个小时,中间还要保证服务可用。

这是所有"初代架构"的通病:用最少的组件跑通业务,把工程债先记下来,回头再还。

我自己在那段时间也顺手还了一笔:写了个定时脚本监控 Solr 索引文档数,少于阈值就告警;写了个简单的 fallback 方案,当 Solr Slave 出问题,直接降级查 MySQL LIKE。这两个补丁现在看很粗糙,但当时真的救过几次急。


第二代:大数据分布式架构(2017-2019)

业务量起来之后,第一代架构撑不住了。日均 PV 从百万级跳到千万级,商品库从百万条涨到亿级,全量同步的时间窗口越来越紧,单体服务也开始扛不住高并发。

第二代的核心思路是:把数据链路和服务链路彻底解耦

服务侧

实时增量链路

离线全量链路

Sqoop

MapReduce

MapReduce

Canal/Binlog

MySQL 商品库

HBase
Main Field

Hive
Item Wide Table

Solr Cloud 集群

Kafka

Spark Streaming

Java Service × N 节点

Nginx 负载均衡

前端搜索接口

几个关键设计:

离线全量:MySQL → Sqoop → HBase → MapReduce → Hive(Item Wide Table)→ MapReduce → Solr Cloud。这条链路是上一代 Sqoop→Solr 的"分布式版本",每一步都为了解决数据量大、字段多的痛点。Hive 宽表是关键设计——把所有需要的字段在 Hive 里打宽,下游 MR 直接消费,不再每次 join。

实时增量:MySQL 通过 Binlog/Canal 进 Kafka,Spark Streaming 消费 Kafka 消息,实时构建增量索引写入 Solr Cloud。这是从「T+1」到「近实时」的关键一跃——商品上新、库存变化、价格调整,几秒内就能搜到。

服务多节点:Java Service 水平扩多节点,前端 Nginx 做负载。单体服务被拆成了"可水平扩展的无状态服务",单机挂了不影响全局。

第二代解决了三个问题:

指标 第一代 第二代
数据延迟 T+1 天 增量端到端 < 30 秒
全量耗时 数小时 TB 级日处理、< 24h
容量上限 百万商品 / 数千 QPS 亿级商品 / 数万 QPS

但代价也很明显——架构复杂度爆炸

组件从 4 个涨到 12 个(Hadoop 全家桶),每加一个组件,运维负担就翻倍。Spark Streaming 的 checkpoint、Hive 的元数据、Solr Cloud 的 shard 均衡、Kafka 的 topic 规划……任何一个出问题都得排查半天。

印象最深的一次:Spark Streaming 在 Kafka 消费时遇到了反压(backpressure)问题,任务积压越来越严重,Solr 索引延迟从 30 秒飙到 10 分钟。原因是一个 Kafka partition 的 offset 没提交,叠加 Spark 的 window 配置不合理。我们当时专门为这个写了 Spark-Kafka 自定义插件来控制消费节奏。

另外 Solr Cloud 的稳定性也出过大事——某次 Master 节点宕机,集群选举新 Master 过程中有几秒钟的不可用。最坏的时候,因为 Solr 插件热部署机制有问题,重启插件直接让整个 Collection 索引重建,半夜里惊出一身冷汗。

但这一代架构带来一个重要副产品:团队从"运维单体应用"成长为"运维分布式系统"。这一波踩坑经验,后来在第三代、第四代都用得上。


第三代:微服务化(2019-2020)

第二代架构跑起来后,新问题来了:搜索代码在快速膨胀,一个 jar 包里塞了 Query 理解、召回、过滤、排序、AB 实验、日志……改动一次要全量发版,团队一旦超过 5 个人就开始互相踩脚。

微服务化是必然。我把搜索链路按职责拆成了四个微服务(再加一个"没拆"的):

搜索接入层

Nginx

API Gateway

Query 理解服务
分词/类目预测/实体识别

召回服务
Solr/Redis 查询

数据平台层
Redis 平台 / Solr 平台

排序服务
单点部署

返回搜索结果

四个微服务:Query 理解、召回、数据平台(Redis 平台 + Solr 平台)。一个"故意没微服务化"的:排序。

为什么排序没拆出来? 因为排序对响应延迟极度敏感(必须 100ms 内完成),拆成微服务会引入额外的网络开销(RPC 调用),在当时团队规模下,性价比不高。我们选择让它继续作为一个本地服务嵌入在召回服务的调用链路里。这是当时一个理性的妥协。

微服务化带来的好处立竿见影:

  • 交付周期缩短 60%:原来发版要全量回归,现在每个服务可以独立发版、独立灰度。
  • 团队并行:每个小组负责一个服务,代码冲突大幅减少。
  • 故障隔离:某个服务出问题不会拖垮整条链路,熔断 + 降级终于有用武之地。

但微服务不是银弹,它带来了新的复杂度——服务治理。

我们不得不补齐一整套基础设施:

  • 注册中心(Eureka / Consul)
  • 配置中心(动态配置下发)
  • API Gateway(统一入口、限流、鉴权)
  • 链路监控(请求 trace 跨服务追踪)
  • 熔断降级(Hystrix 这一代当时很火)

每一项都是新组件、新运维、新坑。这是最容易"过度工程化"的一代——很多团队在这里被新组件拖垮,原本单体撑得住的业务,微服务化后反而出更多事故。

我们的经验是:微服务化必须跟着业务规模和团队规模走。5 人团队硬上 10 个微服务是灾难,20 人团队还死守单体也是灾难。


第四代:双塔模型 + 多路召回 + 平台化(2021-2024)

第三代架构跑了一两年后,新的业务问题出现了。

随着商品数量继续增长(亿级 → 十亿级 SKU)、用户搜索习惯从"精确关键词"变成"模糊描述"("适合女生的笔记本电脑")、长尾 query 占比上升——传统基于 Solr 的关键词召回开始显得力不从心。

最直观的体现:搜索覆盖率(搜出的相关商品占应该被搜出的比例)长期徘徊不前,CTR 提升到了瓶颈。

这一代我们做的事情,本质上是把搜索从"关键词匹配"升级为"语义匹配 + 平台化"

基础设施层

Azkaban 调度

Solr 搜索引擎

ES 评估报表

Hive 数仓

Redis 缓存/实时特征

Mapreduce 离线

Kafka 消息队列

Spark Streaming 实时

数据层

特征中心
加工 / 回流 / 审计 / 清洗

AI 模型
压缩蒸馏 · 训练 · 数据集

商品索引系统
全量索引 · Embedding 全量 · ETL

服务层

商品搜索业务服务

Query 理解系统
类目预测 · 实体识别
Query 改写 · Term weight · Embedding

keyword 处理
分词 · Stemming · 停词 · 短语

Mapreduce 多路结果融合

Kafka 商品精排

Embedding 召回

Exact Match 召回

精排
LTR 粗排 + GBDT/深度学习

工具层

人工干预
Query / 排序干预

模型结果辅助

评估系统
AB 评估 / 模型版本

整个搜索被重新梳理为三个清晰的子系统:

Query 理解系统:从原来简单的分词+同义词,扩展到完整的语义理解——类目预测("iPhone 15"是手机类目)、实体识别("ThinkPad X1"是品牌型号)、Query 改写("笔记本电脑 女生"→"轻薄本 高颜值")、Term weight(不同关键词权重不同)、Embedding(把 query 变成向量)。

多路召回系统:抛弃"单一 Solr 召回"路线,引入多路并发召回 + 结果融合

  • Embedding 召回(语义相似度)
  • Exact Match 召回(关键词精确匹配)
  • 新品召回(专门兜底冷启动商品)
  • 个性化协同召回(结合用户行为)

多路结果通过 Redis 做融合,最终送到排序层。

排序系统:粗排用 LTR(Learning to Rank)做初筛,精排用 GBDT 或者深度学习模型做最终排序。千亿级候选商品的精准流量分发,这是搜索效果的最后一公里。

这一代的效果是颠覆性的:

指标 第三代 第四代
召回覆盖率 基线 多路融合后 +35%
CTR 2.2% 2.7%
长尾 query 效果 明显不佳 大幅改善
Redis + Solr 平台 P99 100+ ms < 80 ms

第四代也是平台化最重要的一代。我们把 Redis 集群、Solr 集群、AI 模型训练、特征中心、数据 ETL 等基础能力抽象成独立平台,每个平台有自己的 Owner 和 SLA:

CI/CD

Jenkins

K8S

Sonar

Docker Hub

GitLab

数据运维与监控

Search Portal

Logx

Grafana

Alerta

大数据基础设施

Hive

Kafka

Redis Cluster

Solr Cluster

ETL

Presto

MapReduce

Spark

HDFS

Azkaban/AirFlow

数据平台层

ML Platform

Redis Platform

Solr Platform

综合个性化排序平台

Recommend Engine

Sponsored

个性化产品排序系统

综合业务中台

Search DashBoard

BI Portal

业务服务层

WWW Search

B2B Search

Mobile Search

Event Sales Store

Product Finder

PC Builder

平台化的核心收益不是"看起来高大上",而是让搜索团队可以专注做搜索本身。Redis 集群扩容?找 Redis 平台 Owner。Solr 调优?找 Solr 平台 Owner。模型训练?找 ML 平台 Owner。搜索工程师不再需要是一个 Hadoop 专家、Solr 专家、Redis 专家的合体。

这一代最让我有成就感的是一个生产事故。某次大促前夜,Varnish 缓存层负载严重倾斜(部分节点 QPS 是其他节点的 10 倍),按当时的设计会拖垮整个搜索入口。我们紧急做了一轮重写,把负载均衡算法从 round-robin 改成了基于实时 QPS 的加权均衡,凌晨上线,效果立竿见影,扛住了整个大促。


第五代:AI Search Agent(2025-2026)

2025 年下半年,搜索团队遇到了一个新的业务命题:用户开始习惯用自然语言描述需求,而不是输入关键词

"我想给妈妈买一台适合看视频、续航长、不太贵的手机"——这种 query 用传统关键词匹配基本无法处理:里面没有明确的品牌型号,"不太贵"是模糊语义,"适合妈妈"是用户画像。

我们决定做一件事:让搜索变成对话

这就是第五代——AI Search Agent。

MCP 平台

意图理解 + DSL

多轮对话
上下文理解

工具调用

工具调用

工具调用

用户 Query
自然语言

Search Agent
基于 Gemma 微调

多路召回
关键词 + 语义 + 类目

商品候选

记忆系统
Milvus + bge-m3

结构化检索结果
+ 个性化推荐

工具 1

工具 2

工具 7000+

第五代的核心设计:

意图理解层:基于 Gemma 微调模型,把用户的自然语言 query 解析为结构化 DSL(Domain Specific Language)。支持多轮上下文理解——用户第一轮说"我想买个手机",第二轮说"屏幕大点的",模型必须理解"大点的"指的是手机屏幕。

商品召回层:接收 DSL 并执行多路召回(关键词 + 语义 + 类目)。这一层复用了第四代的整套召回基础设施,没有重造轮子,这是 Agent 架构能快速落地的重要原因。

Agent 编排层:基于 LangGraph 构建 ReAct 推理链路。Agent 知道什么时候该调用召回接口、什么时候该调用记忆系统、什么时候该生成最终回答。LangGraph 的状态机设计天然适合多轮对话的复杂控制流。

用户分析层:采集对话行为与点击反馈,驱动搜索效果的持续优化。Agent 不是上线就结束,它需要持续学习。

还有一个关键的辅助设施:MCP 平台。我们把公司内部 7000+ REST API 全部封装成 MCP 工具,让 Agent 可以像调用函数一样调用任何内部系统。从用户搜索延伸出去的"查库存、查物流、查活动"等操作,都通过 MCP 工具完成。MCP 平台让 Agent 从"只能搜索"进化成了"能完成整个购物流程的助手"

第五代上线的效果:

  • 会话式搜索转化率比传统关键词搜索 提升约 22%
  • 用户平均交互轮次 3.2 轮
  • 模糊 query(长尾、无明确关键词)的召回效果突破传统搜索的天花板

但 Search Agent 不是终点。我们正在做的下一件事是:把单 Agent 演化为多 Agent + 独立记忆系统——专门的 Agent 负责意图理解、专门的 Agent 负责召回、专门的 Agent 负责对话管理、各 Agent 之间通过 MCP 协议协同,记忆系统从"对话上下文"扩展为"长期用户偏好"(基于 Milvus + bge-m3 实现的独立记忆层)。

这就是搜索的下一站。


经验复盘:每一代架构解决了什么、付出了什么

回看五代演进,有几个反复出现的规律:

1. 每一代架构的诞生,都不是技术驱动,而是业务驱动。

第二代分布式不是 Hadoop 火了我们就要上 Hadoop,是商品库从百万级涨到亿级,单体 Solr 真的扛不住了。第四代多路召回不是 BERT 火了我们就要上 BERT,是长尾 query 的搜索效果长期不达预期。第五代 Search Agent 不是 LangGraph 火了我们就要上 LangGraph,是用户搜索行为从关键词迁移到了自然语言。

2. 每一代架构的代价,都比想象的大。

第一代到第二代,引入了 Hadoop 全家桶,运维负担翻了几倍。第二代到第三代,引入了微服务治理全套,链路监控、熔断降级、服务网格的坑一个接一个。第三代到第四代,AI 模型的训练、部署、在线推理又是一个全新的工程领域。每一代都在解决上一个问题的同时,制造了三个新问题。

3. 每一代架构都有"刻意没做的事"。

排序没微服务化、Agent 没用最新的闭源大模型、记忆系统暂未独立——这些"克制"往往是团队理性的体现。在工程领域,不做什么比做什么更难

4. 真正穿越五代都没变的东西,是业务理解本身。

Solr 换了、Hadoop 换了、微服务换了、LangGraph 上了——但"什么是好的搜索结果"这件事,11 年里没变过。Query 理解、召回、排序这条主线贯穿始终。任何一代如果脱离业务本质去追求技术时髦,都会走弯路。


写在最后

如果给刚入职那天接手 Solr Master-Slave 的自己一个建议,我会说:

别急着把它推翻。先把业务跑通,再回头优化架构。架构演进的最佳节奏,永远是"业务推一下,架构跟一步",而不是"架构先飞起来,等业务来追"。

11 年,五代架构,看起来是技术故事,本质上是一个业务和一个团队一起长大的故事

搜索这条路没有终点,下一代架构已经在路上。但不管走到哪一代,工程师能做的,永远是把当下能用的工具用到极致,然后准备好接住下一个变化。