这是我在开发 My-Notion 项目时踩的另一个坑——迁移到Qdrant向量数据库后,本地 AI 对话慢得离谱,我花了好久优化代码,结果毫无效果。最后发现根本不是代码的问题,而是网络的问题。
问题现象
项目里有个 RAG 对话功能:用户提问 → 向量检索文档 → LLM 生成回答。本地开发时,每次对话要等 5-8 秒才开始出字,体验非常差。
我的第一反应是:代码写得有问题,性能需要优化。
错误的排查方向
于是我开始了一系列"优化":
1. 怀疑 RAG 检索太慢
以为是 Qdrant 向量检索耗时,于是加了日志:
const start = Date.now();
const results = await vectorStore.similaritySearch(query, k, minScore);
console.log(`[RAG] 检索耗时: ${Date.now() - start}ms`);
结果检索本身只要 200-400ms,不是瓶颈。
2. 怀疑 Embeddings 计算太慢
以为是文本向量化耗时,又加了日志:
const embStart = Date.now();
const embedding = await openai.embeddings.create({
model: EMB_MODEL,
input: query,
});
console.log(`[Embeddings] 耗时: ${Date.now() - embStart}ms`);
结果 Embeddings 要 1-2 秒,有点慢但也不是 5-8 秒的量级。
3. 怀疑 LLM 流式响应有延迟
以为是流式输出卡顿,检查了 SSE/NDJSON 的解析逻辑,甚至重写了 ReadableStream 的处理方式,还是没改善。
4. 怀疑 Convex 查询慢
以为是数据库查询拖后腿,检查了 Convex 的函数耗时面板,全都在 100ms 以内。
折腾了好几天,每个环节单独看都不慢,但整体就是慢。
真正的原因
直到有一天,我把项目部署到 Vercel 上测试,发现线上对话飞快——1-2 秒就开始出字,体验丝滑。
同样的代码,本地慢、线上快,问题只能出在网络上。
画一下请求链路就清楚了:
本地开发环境(中国)
用户提问
→ 本地 Next.js (localhost:3000)
→ 通义千问 API (中国,快 ✅)
→ Qdrant Cloud (美国,慢 ❌) ← 跨太平洋往返 ~300-500ms/次
→ Convex Cloud (美国,慢 ❌) ← 跨太平洋往返 ~200-300ms/次
线上环境 (Vercel,美国)
用户提问
→ Vercel Serverless (美国)
→ 通义千问 API (中国,有延迟但只一次)
→ Qdrant Cloud (美国,快 ✅) ← 同机房级别,~10-30ms
→ Convex Cloud (美国,快 ✅) ← 同区域,~20-50ms
一次 RAG 对话的完整链路中,至少有 3-4 次跨太平洋的网络请求:
- Embeddings 计算:本地 → 通义千问 API(国内,快)
- 向量检索:本地 → Qdrant Cloud(美国,慢)
- 文档内容获取:本地 → Convex Cloud(美国,慢)
- LLM 生成:本地 → 通义千问 API(国内,快)
其中第 2、3 步每次往返都要 300-500ms,3-4 次加起来就是 1-2 秒的纯网络延迟。再加上 LLM 本身的生成时间,体感就是 5-8 秒。
而线上环境,Vercel、Qdrant、Convex 都在美国,服务间通信延迟只有几十毫秒,所以飞快。
为什么会这样
原因很简单——我偷懒了。
Qdrant 官方提供了 Docker 本地部署方案,一条命令就能跑起来:
docker run -p 6333:6333 qdrant/qdrant
但为了省事,我直接用了 Qdrant Cloud 的免费集群,没有在本地搭 Qdrant。Convex 也是同理,直接用的云端实例。
本地开发时,所有请求都打到了美国的服务器,跨太平洋的物理距离(约 12000 公里)决定了光速延迟就不可能快:
理论最低延迟 = 2 × 距离 / 光速
= 2 × 12000km / 300000km/s
≈ 80ms(单次往返,理想情况)
实际延迟 = 200-500ms(经过多层路由和 CDN 节点)
一次 RAG 对话涉及 3-4 次这样的往返,纯网络开销就 1-2 秒。
怎么解决
方案 1:本地部署 Qdrant(推荐)
最直接的方案——把 Qdrant 跑在本地,消除跨洋延迟:
# Docker 一键启动
docker run -p 6333:6333 \
-v ./qdrant_storage:/qdrant/storage \
qdrant/qdrant
然后在 .env.local 中切换到本地地址:
- NEXT_PUBLIC_QDRANT_URL=https://your-cluster.us-east4.gcp.cloud.qdrant.io
+ NEXT_PUBLIC_QDRANT_URL=http://localhost:6333
本地 Qdrant 的向量检索延迟从 300-500ms 降到 5-15ms,体感提升非常明显。
方案 2:使用环境变量区分本地和线上
在代码中根据环境自动切换:
const QDRANT_URL = process.env.NODE_ENV === "development"
? "http://localhost:6333" // 本地开发用 Docker Qdrant
: process.env.NEXT_PUBLIC_QDRANT_URL; // 线上用 Qdrant Cloud
方案 3:给本地开发加网络延迟感知
如果暂时不想搭本地 Qdrant,至少要在开发时意识到网络延迟的存在,避免像我一样把时间浪费在"优化代码"上。
一个简单的办法是给关键请求加耗时日志,区分"网络耗时"和"处理耗时":
async function fetchWithTiming(url: string, options?: RequestInit) {
const start = Date.now();
const response = await fetch(url, options);
const elapsed = Date.now() - start;
console.log(`[Network] ${url} - ${elapsed}ms`);
return response;
}
看到网络耗时占了大头,就不会盲目优化代码逻辑了。
排查网络问题的方法论
这次踩坑让我总结了一套排查"慢"问题的思路:
1. 先区分是"网络慢"还是"计算慢"
加耗时日志,把每个环节的耗时拆开看:
[RAG] Embeddings: 1200ms ← 网络 + 计算
[RAG] 向量检索: 450ms ← 网络 + 查询
[RAG] 文档获取: 280ms ← 网络 + 查询
[RAG] LLM 生成: 3000ms ← 网络 + 生成
[RAG] 总耗时: 4930ms
如果某个环节的耗时远超预期,大概率是网络问题而不是代码问题。
2. 对比本地和线上的表现
同样的代码,本地慢、线上快 → 网络问题 本地慢、线上也慢 → 代码问题
这是最简单有效的判断方式。
3. 检查服务器的物理位置
| 你的位置 | 服务位置 | 预期延迟 |
|---|---|---|
| 中国 | 中国 | 10-50ms |
| 中国 | 美西 | 150-300ms |
| 中国 | 美东 | 250-500ms |
| 中国 | 欧洲 | 200-400ms |
| 美国 | 美国 | 10-50ms |
如果你的服务部署在不同区域,延迟就会叠加。
4. 用 ping 和 traceroute 验证
# 测试到 Qdrant 服务器的延迟
ping your-cluster.qdrant.io
# 查看网络路径
traceroute your-cluster.qdrant.io
如果 ping 延迟在 200ms+,基本就是跨洋链路了。
总结
这次踩坑最大的教训是:遇到性能问题,先排查网络,再优化代码。
我花了很久时间优化代码逻辑,结果毫无效果。而部署到线上后,同样的代码跑得飞快——因为线上环境的网络延迟只有本地的十分之一。
对于使用海外云服务的开发者(在国内开发,服务部署在 AWS/GCP 等海外区域),这个问题尤其常见。建议:
- 本地开发尽量用本地服务 — Qdrant、Redis、PostgreSQL 都有 Docker 一键部署方案
- 加耗时日志区分网络和计算 — 不要盲目优化代码
- 本地慢但线上快 → 优先怀疑网络 — 别像我一样走弯路
- CI/CD 环境和线上保持一致 — Vercel + Qdrant Cloud 都在美国,CI 构建时的网络延迟和线上一致,不会出现"本地没问题、线上有问题"的反转
本文基于 My-Notion 项目的真实踩坑经历撰写,项目是一个 AI 原生的个人版 Notion,欢迎 Star ⭐