聊聊我对技术探索这件事的真实看法
本文首发于个人博客,写于 2025 年某个听着落日飞车的深夜。
说实话,写这篇文章之前我犹豫了很久。
倒不是不知道写什么,而是"对技术探索与实践的看法"这种题目,太容易写成那种假大空的布道文了——"我们要拥抱变化""终身学习""技术驱动业务",这些话说出来自己都觉得心虚。
所以我决定换个方式,就聊聊我自己这些年的真实经历和感受,好的坏的都说,算是给自己做个复盘,也给同行们一点参考。
先简单介绍下我自己吧。我最早是干 DBA 的,对,就是那个天天跟慢查询、死锁、主从延迟打交道的 DBA。后来因为一些机缘(说白了就是觉得 DBA 天花板太低,而且半夜被叫起来处理故障的次数实在太多了),转成了后端开发。但说实话,DBA 的底子让我对数据库这块一直有种说不清的执念,看到烂 SQL 就浑身难受,那种感觉就像厨师看到别人用微波炉炒菜一样。
坐标上海,在公司附近租了个一室户,走路十分钟就能到工位。这个距离让我可以很从容地早上九点半到公司,泡杯咖啡,戴上耳机,放点音乐,然后开始一天的工作。我写代码有个习惯,必须听音乐,不戴耳机感觉少了点什么。最近循环的是落日飞车和 Deca Joins,偶尔也听听 lo-fi hip hop,看心情。
好了,背景交代完毕,开始聊正事。
技术探索的起点,往往不是什么高大上的理由
很多人觉得技术大牛搞技术探索都是因为热爱,因为极客精神。我不否认有这种人,但就我自己而言,大部分技术探索的起点,其实挺接地气的——要么是被逼的,要么是想跳槽。
先说"被逼的"。
去年 Q3 的时候,我们团队接了一个智能客服的项目。产品经理(没有说产品经理不好的意思,但那天他确实让我很头疼)提了个需求:用户问问题的时候,系统要能从历史工单里找到最相似的案例,然后给客服推荐解决方案。
我一听,这不就是相似度检索嘛。最开始我的思路很传统——用 Elasticsearch 做全文检索,加上 BM25 评分,再搞点同义词扩展,差不多能搞定。毕竟我是 DBA 出身,对 ES 这种基于倒排索引的搜索引擎还是比较熟悉的。
结果一做才发现,事情没那么简单。
用户的提问方式千奇百怪。同一个问题,有人问"我的快递到哪了",有人问"物流怎么还没更新",还有人直接甩一句"催一下"。基于关键词匹配的 ES 在这类语义层面的相似度匹配上,效果差得一塌糊涂。召回率上不去,误匹配还一堆,客服那边反馈说推荐的案例经常驴唇不对马嘴。
那段时间我真的很焦虑。项目 deadline 就摆在那里,每周一的站会上 leader 都会问进度,测试同学那边也等着我出接口好写用例。我甚至有一两天晚上躺在床上,脑子里全是在想方案,翻来覆去睡不着。
后来是在一次技术社区的线上分享里,听到了向量数据库这个概念。讲真,之前我对向量数据库的了解仅限于"听说过",知道是做 embedding 存储和检索的,但具体怎么用、有哪些产品、性能怎么样,一概不知。
但那天的分享就像打开了新世界的大门。
从"听说过"到"线上跑",中间隔了无数个坑
知道了方向之后,接下来的事情就是疯狂补课。
那两周我基本上把市面上主流的向量数据库都摸了一遍:Milvus、Pinecone、Weaviate、Qdrant、Chroma,还有 pgvector。没错,作为一个对 PostgreSQL 有感情的前 DBA,看到 pgvector 的时候我是有点小激动的——能直接用 SQL 做向量检索,不用引入新的中间件,多优雅。
但优雅归优雅,选型还是要看场景。我做了个简单的对比:
| 数据库 | 部署方式 | 性能(百万级数据) | 生态成熟度 | 运维复杂度 | 适合场景 |
|---|---|---|---|---|---|
| Milvus | 独立部署/K8s | 很高 | 高 | 中高 | 大规模生产环境 |
| Pinecone | 全托管 SaaS | 高 | 高 | 低 | 快速验证/海外业务 |
| Qdrant | 独立部署/Docker | 高 | 中 | 中 | Rust 写的,性能好 |
| pgvector | PG 插件 | 中 | 中 | 低 | 数据量不大/已有 PG |
| Weaviate | 独立部署/Docker | 中高 | 中 | 中 | 多模态场景 |
| Chroma | 嵌入式/Docker | 低 | 低 | 极低 | 原型开发/学习 |
考虑到我们的数据量预估在千万级别,而且公司对数据自主可控有要求(不能用纯 SaaS),再加上我们团队本身就有 K8s 的运维经验(我们公司全面拥抱云原生,业务基本都跑在 K8s 上),最终我选了 Milvus。
现在回头看,这个选择大体是对的,但过程中踩的坑也不少。这里分享几个我印象比较深的:
坑一:Embedding 模型的选择比想象中重要得多
向量数据库只是存储和检索,真正决定检索质量的,是你的 embedding 模型。一开始我图省事,直接用了 OpenAI 的 text-embedding-ada-002,效果还行,但有两个问题:一是延迟高,每次请求都要调外部 API;二是数据要传到国外服务器,安全合规那边直接给我打回来了。
后来换成了开源的 bge-large-zh-v1.5,自己部署推理服务。中文场景下效果反而更好,而且延迟可控。这里有个小技巧:如果你的场景对延迟敏感,可以考虑用 ONNX Runtime 或者 TensorRT 做模型推理加速,我们实测 QPS 提升了大概 3 倍。
# 使用 FlagEmbedding 做文本向量化
from FlagEmbedding import FlagModel
model = FlagModel('BAAI/bge-large-zh-v1.5',
query_instruction_for_retrieval="为这个句子生成表示以用于检索相关文章:")
# 对查询文本做 embedding
queries = ['我的快递到哪了', '物流怎么还没更新']
embeddings = model.encode(queries)
# 归一化(Milvus 使用 COSINE 相似度时需要)
import numpy as np
embeddings = embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True)
坑二:Milvus 在 K8s 上的资源规划
Milvus 的架构比较重,依赖 etcd、MinIO、Pulsar(或者 Kafka)这些组件。在 K8s 上部署的时候,资源规划很关键。一开始我按照官方文档的最低配置来,结果压测的时候直接 OOM 了。
后来反复调优,总结了一套适合我们场景的配置:
# Milvus 在 K8s 上的资源推荐配置(千万级数据量)
# 注意:这只是我们场景的经验值,具体要看你的数据量和查询模式
# QueryNode - 最吃内存的组件
queryNode:
replicas: 3
resources:
requests:
memory: "16Gi"
cpu: "4"
limits:
memory: "32Gi"
cpu: "8"
# DataNode - 负责数据持久化
dataNode:
replicas: 2
resources:
requests:
memory: "8Gi"
cpu: "2"
limits:
memory: "16Gi"
cpu: "4"
# IndexNode - 负责建索引,CPU 密集型
indexNode:
replicas: 2
resources:
requests:
memory: "8Gi"
cpu: "4"
limits:
memory: "16Gi"
cpu: "8"
还有一个血泪教训:一定要给 Milvus 的 PVC 配 SSD。我们一开始用了普通的 HDD 存储盘,建索引的时候慢到令人发指,千万级数据建个 HNSW 索引要跑好几个小时。换成 SSD 之后,同样的数据量十几分钟就搞定了。DBA 的老毛病又犯了——存储 IO 真的是性能的生命线。
坑三:HNSW 参数调优是个玄学
Milvus 默认支持多种索引类型,我们用的是 HNSW(Hierarchical Navigable Small World),它在召回率和查询速度之间取得了比较好的平衡。但 M 和 efConstruction 这两个参数怎么调,官方文档说得比较笼统,基本上得自己试。
| M 值 | efConstruction | 建索引耗时 | 查询 QPS | 召回率@10 | 内存占用 |
|---|---|---|---|---|---|
| 16 | 200 | 基准 | 基准 | 92.3% | 基准 |
| 32 | 400 | +80% | +15% | 95.1% | +60% |
| 32 | 200 | +75% | +12% | 93.8% | +55% |
| 64 | 400 | +180% | +20% | 96.2% | +120% |
| 16 | 500 | +30% | +8% | 94.5% | +10% |
最终我们选了 M=32, efConstruction=400,在召回率和资源消耗之间取了一个平衡。查询的时候 ef 参数(注意跟 efConstruction 不一样)设成了 128,可以根据业务对召回率的要求动态调整。
技术探索这件事,我觉得最重要的是"手感"
回到文章的主题。做了这么多年技术,从 DBA 到后端开发,从传统架构到云原生,我最大的感触是:技术探索不能只停留在"看"的层面,一定要动手。
看十篇技术博客,不如自己写一百行代码。看一百行代码,不如自己踩一次坑。
我见过太多人(包括以前的我自己),收藏了一堆技术文章,买了一堆技术书,订阅了一堆技术公众号,但真正动手去实践的少之又少。这种"收藏即学会"的幻觉,其实是技术成长最大的敌人。
拿向量数据库来说。如果我只是看了那篇分享,觉得"哦,向量数据库挺有意思的",然后就没有然后了。那我永远不会知道 embedding 模型的选型有多关键,不会知道 Milvus 在 K8s 上跑的时候 QueryNode 有多吃内存,不会知道 HNSW 的参数调优需要大量实验。这些"手感",是任何博客和文档都给不了你的。
所以我现在给自己定了个规矩:每遇到一个感兴趣的技术点,不管工作用不用得上,都要花一个周末的时间动手搞一搞。不一定是做个完整的项目,哪怕就是写个 demo,跑通一个最小闭环,也比光看不动手强一百倍。
比如前阵子对 Rust 感兴趣,我就花了两个周末用 Rust 重写了一个简化版的 LRU Cache。写完之后虽然感觉自己的 Rust 水平还是很菜,但至少对所有权、生命周期这些概念有了体感,不再是停留在"看文档觉得懂了"的层面。
关于简历和技术探索的一个现实话题
聊到这里,不得不提一个很现实的问题:技术探索对简历的帮助。
我知道很多人搞技术探索的直接动力就是跳槽或者涨薪。这不丢人,完全理解。但我见过一些朋友在简历上写技术探索的经历时,容易犯两个极端的问题:
一个是写得太虚。"深入研究了 xxx 技术,对 xxx 有深刻理解"——这种话写了等于没写,面试官一看就知道是套话。
另一个是写得太碎。今天学了 Go,明天看了 Rust,后天又搞了 Flutter,简历上列了一堆"了解 xxx",但每个都只有三五行代码的 demo 级别。这种在面试官眼里反而减分,因为会觉得你什么都浅尝辄止,没有深度。
我的建议是:简历上写技术探索经历的时候,一定要跟实际项目或者实际解决的问题结合起来。
比如我在简历上是这么写的(当然做了脱敏处理):
主导智能客服系统的相似案例检索模块设计与实现。针对传统全文检索在语义匹配场景下召回率不足的问题,引入向量检索方案。基于 Milvus 构建向量检索服务,结合 BGE 模型做文本向量化,在千万级工单数据上实现了 95%+ 的 Top10 召回率,接口 P99 延迟控制在 50ms 以内。
你看,这里没有说"深入研究了向量数据库"这种虚话,而是把技术选型的原因、具体用了什么方案、解决了什么问题、达到了什么效果,都交代清楚了。面试官看到这种描述,自然会追问细节,而你有实际踩坑的经验,应对起来也游刃有余。
最后说几句掏心窝子的话
写了这么多,其实想表达的核心观点就一个:技术探索最重要的不是"探索了什么",而是"怎么探索的"。
是遇到问题时那种"我一定要搞明白"的劲头。是周末别人在打游戏你在调 bug 的自律。是踩了坑之后那种"原来如此"的顿悟。是凌晨两点终于跑通了 demo 时那种纯粹的开心。
这些东西,才是技术探索真正带给你的财富。至于简历上多了一行字、面试时多了一个谈资,那只是副产品。
当然,我也不是说要无脑卷。该休息休息,该摸鱼摸鱼(不是),该听音乐听音乐。技术探索应该是可持续的,而不是透支式的。我现在基本保持每周花两三个小时在技术探索上,不多,但贵在坚持。
对了,如果你也有什么技术探索的经历或者心得,欢迎在评论区交流。我一个人闷头搞容易钻牛角尖,多跟同行聊聊,往往能碰撞出不一样的火花。
好了,夜深了,落日飞车的专辑也听完了。明天还要早起开需求评审会,希望产品经理明天不要又改需求。
晚安,各位。
P.S. 如果你也在用 Milvus,遇到什么坑可以来找我聊。前 DBA 对数据库相关的东西还是比较敏感的,说不定能帮上忙。


评论 0