一个被忽视的问题:MySQL 解决不了的语义检索
假设你在做一个 AI 日记本应用,用户问:"我哪几天的日记心情比较好?"
如果你把日记存在 MySQL 里,你会怎么查?SELECT * FROM diary WHERE content LIKE '%开心%'?这种关键词匹配根本不靠谱。用户可能写的是"今天很愉快"、"心情不错"、"感觉很棒",这些表达心情好的方式千变万化,关键词匹配会漏掉大量结果。
再换个场景:用户问"我做过什么户外活动?",日记里可能写的是"去公园散步"、"周末爬山"、"海边跑步"。这些内容在语义上都属于户外活动,但用 SQL 的 LIKE 查询,你得写一堆 OR 条件,还不一定能覆盖全。
这就是传统关系型数据库在 AI 应用中的根本局限:它只能做精确匹配和关键词匹配,无法理解语义。
而 AI Agent 的核心能力恰恰是理解自然语言、进行语义推理。当用户用自然语言提问时,系统需要从知识库中找出"语义相关"的内容,而不是"关键词相关"的内容。这就是为什么几乎所有 AI Agent 产品都会用到向量数据库。
向量数据库解决的核心问题
向量数据库的本质是:把文本转换成高维向量,通过向量之间的距离来衡量语义相似度。
举个直观的例子:
scss
"今天很开心" → [0.23, 0.87, -0.45, ..., 0.61] (1024维向量)
"心情愉快" → [0.25, 0.89, -0.43, ..., 0.59] (1024维向量)
"天气很好" → [0.71, 0.12, 0.88, ..., -0.34] (1024维向量)
前两句话语义相近,它们的向量在高维空间中距离很近(余弦相似度接近 1)。第三句话语义不同,向量距离就远。
这样,当用户问"我哪几天心情比较好"时:
- 把问题转成向量
- 在向量数据库中找距离最近的 Top K 个向量
- 返回对应的日记内容
整个过程完全基于语义,不依赖关键词。
MySQL vs Milvus:职责分工而非替代关系
很多人会问:既然向量数据库这么强,是不是可以替代 MySQL?
答案是不能,也不应该。它们解决的是不同层面的问题。
以 AI 日记本为例:
MySQL 负责的场景:
- 查询日记列表(按日期排序、分页)
- 根据 ID 精确查询某篇日记
- 统计用户写了多少篇日记
- 按标签筛选日记(精确匹配)
Milvus 负责的场景:
- "我哪几天心情比较好?"(语义检索)
- "我做过什么户外活动?"(语义检索)
- "帮我找找关于学习的日记"(语义检索)
实际工程中的做法是:MySQL 和 Milvus 双写。
用户写日记
↓
同时写入 MySQL(结构化数据 + 精确查询)
↓
同时写入 Milvus(向量化数据 + 语义检索)
这样既能做精确查询,又能做语义检索。删除和更新时也要同步操作两个数据库。
Milvus 的数据组织方式
在开始写代码之前,先理解 Milvus 的数据结构。它和 MySQL 很像,但有些关键差异:
sql
MySQL: Milvus:
Database Database
└─ Table └─ Collection
└─ Row └─ Entity
主要区别在于:
- Collection 需要定义 Schema:类似 MySQL 的表结构,但必须包含一个向量字段
- 向量字段需要建索引:用于快速检索,这是向量数据库的核心
- 使用前需要 Load Collection:把数据加载到内存,才能查询
一个典型的 Schema 长这样:
javascript
{
collection_name: 'ai_diary',
fields: [
{ name: 'id', data_type: DataType.VarChar, is_primary_key: true },
{ name: 'vector', data_type: DataType.FloatVector, dim: 1024 }, // 核心
{ name: 'content', data_type: DataType.VarChar },
{ name: 'date', data_type: DataType.VarChar },
{ name: 'mood', data_type: DataType.VarChar },
{ name: 'tags', data_type: DataType.Array }
]
}
这里有几个关键点:
1. 向量维度必须和 Embedding 模型一致
如果你用的 Embedding 模型输出 1024 维向量,Schema 里的 dim 就必须是 1024。不匹配会报错。
2. 向量字段必须建索引
javascript
await client.createIndex({
collection_name: 'ai_diary',
field_name: 'vector',
index_type: IndexType.IVF_FLAT,
metric_type: MetricType.COSINE, // 余弦相似度
params: { nlist: 1024 }
});
metric_type 决定了如何计算向量距离。常用的有:
COSINE:余弦相似度,适合文本语义检索(推荐)L2:欧氏距离,适合图像检索IP:内积,适合推荐系统
对于文本语义检索,余弦相似度是默认选择,因为它只关注方向,不关注向量长度。
3. 其他字段是元数据
content、date、mood、tags 这些字段不参与向量检索,但会在检索结果中返回。它们的作用是:
- 提供给大模型作为上下文
- 用于业务逻辑(比如按日期过滤)
- 展示给用户
环境准备:用 Docker 跑 Milvus
Milvus 本地开发最简单的方式是用 Docker Compose。
前置条件:
- 安装 Docker Desktop(www.docker.com/)
- 确保
docker命令可用
启动 Milvus:
bash
# 1. 创建目录
mkdir milvus-data && cd milvus-data
# 2. 下载配置文件
# 从 https://github.com/milvus-io/milvus/releases 下载
# milvus-standalone-docker-compose.yml
# 3. 启动服务
docker compose -f milvus-standalone-docker-compose.yml up -d
启动后,Milvus 会运行在 localhost:19530。可以通过健康检查接口验证:
bash
curl http://localhost:9091/healthz
# 返回 OK 表示服务正常
在 Docker Desktop 中可以看到运行的容器,包括:
milvus-standalone:核心服务milvus-minio:对象存储milvus-etcd:元数据存储
实战:插入数据到 Milvus
现在开始写代码。我们用 Node.js 来操作 Milvus。
初始化项目:
bash
mkdir milvus-test && cd milvus-test
npm init -y
pnpm install @zilliz/milvus2-sdk-node @langchain/openai dotenv
配置文件 .env:
env
OPENAI_API_KEY=sk-xxx
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL_NAME=qwen-plus
EMBEDDINGS_MODEL_NAME=text-embedding-v3
插入数据的完整流程(src/insert.mjs):
javascript
import "dotenv/config";
import { MilvusClient, DataType, MetricType, IndexType } from '@zilliz/milvus2-sdk-node';
import { OpenAIEmbeddings } from "@langchain/openai";
const COLLECTION_NAME = 'ai_diary';
const VECTOR_DIM = 1024;
// 初始化 Embedding 模型
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: process.env.EMBEDDINGS_MODEL_NAME,
configuration: { baseURL: process.env.OPENAI_BASE_URL },
dimensions: VECTOR_DIM
});
// 连接 Milvus
const client = new MilvusClient({ address: 'localhost:19530' });
async function main() {
await client.connectPromise;
// 步骤1:创建 Collection
await client.createCollection({
collection_name: COLLECTION_NAME,
fields: [
{ name: 'id', data_type: DataType.VarChar, max_length: 50, is_primary_key: true },
{ name: 'vector', data_type: DataType.FloatVector, dim: VECTOR_DIM },
{ name: 'content', data_type: DataType.VarChar, max_length: 5000 },
{ name: 'date', data_type: DataType.VarChar, max_length: 50 },
{ name: 'mood', data_type: DataType.VarChar, max_length: 50 },
{ name: 'tags', data_type: DataType.Array, element_type: DataType.VarChar, max_capacity: 10, max_length: 50 }
]
});
// 步骤2:创建向量索引
await client.createIndex({
collection_name: COLLECTION_NAME,
field_name: 'vector',
index_type: IndexType.IVF_FLAT,
metric_type: MetricType.COSINE,
params: { nlist: 1024 }
});
// 步骤3:加载 Collection 到内存
await client.loadCollection({ collection_name: COLLECTION_NAME });
// 步骤4:准备日记数据
const diaries = [
{
id: 'diary_001',
content: '今天天气很好,去公园散步了,心情愉快。',
date: '2026-01-10',
mood: 'happy',
tags: ['生活', '散步']
},
{
id: 'diary_002',
content: '今天工作很忙,完成了一个重要项目,很有成就感。',
date: '2026-01-11',
mood: 'excited',
tags: ['工作', '成就']
}
];
// 步骤5:向量化并插入
const diaryData = await Promise.all(
diaries.map(async (diary) => ({
...diary,
vector: await embeddings.embedQuery(diary.content)
}))
);
const result = await client.insert({
collection_name: COLLECTION_NAME,
data: diaryData
});
console.log(`插入了 ${result.insert_cnt} 条记录`);
}
main();
这段代码的关键点:
- 创建 Collection 时必须指定完整 Schema:包括所有字段的类型、长度限制
- 向量字段的维度必须匹配:这里是 1024,和 Embedding 模型输出一致
- 必须先建索引再加载:否则查询会很慢
- 插入前要向量化 :
content字段通过 Embedding 模型转成vector
运行后,数据就插入到 Milvus 了。你可以用 Attu(Milvus 的 GUI 工具)来可视化查看。
语义检索:Milvus 的核心能力
插入数据后,我们来做语义检索。
查询代码(src/query.mjs):
javascript
import "dotenv/config";
import { MilvusClient, MetricType } from '@zilliz/milvus2-sdk-node';
import { OpenAIEmbeddings } from "@langchain/openai";
const COLLECTION_NAME = 'ai_diary';
const VECTOR_DIM = 1024;
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: process.env.EMBEDDINGS_MODEL_NAME,
configuration: { baseURL: process.env.OPENAI_BASE_URL },
dimensions: VECTOR_DIM
});
const client = new MilvusClient({ address: 'localhost:19530' });
async function main() {
await client.connectPromise;
const query = '我想看看关于户外活动的日记';
const queryVector = await embeddings.embedQuery(query);
const searchResult = await client.search({
collection_name: COLLECTION_NAME,
vector: queryVector,
limit: 2,
metric_type: MetricType.COSINE,
output_fields: ['id', 'content', 'date', 'mood', 'tags']
});
searchResult.results.forEach((item, index) => {
console.log(`${index + 1}. [相似度: ${item.score.toFixed(4)}]`);
console.log(` 内容: ${item.content}`);
console.log(` 日期: ${item.date}`);
console.log(` 心情: ${item.mood}\n`);
});
}
main();
检索流程解析:
- 把查询文本向量化 :
embeddings.embedQuery(query) - 在 Milvus 中搜索:找出向量距离最近的 Top K 条记录
- 返回元数据 :通过
output_fields指定要返回的字段
运行结果示例:
ini
1. [相似度: 0.8923]
内容: 周末和朋友去爬山,天气很好,心情也很放松。
日期: 2026-01-12
心情: relaxed
2. [相似度: 0.8654]
内容: 今天天气很好,去公园散步了,心情愉快。
日期: 2026-01-10
心情: happy
注意,用户问的是"户外活动",但日记里写的是"爬山"、"散步"。Milvus 通过语义理解,准确找到了相关内容。
关键参数说明:
limit:返回 Top K 个最相似的结果metric_type:距离度量方式,COSINE 表示余弦相似度output_fields:指定返回哪些字段,不指定则只返回 id 和 score
完整 RAG 流程:从检索到生成
现在把 Milvus 接入完整的 RAG 流程,实现一个真正能回答问题的 AI 日记助手。
RAG 流程(src/rag.mjs):
javascript
import "dotenv/config";
import { MilvusClient, MetricType } from '@zilliz/milvus2-sdk-node';
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
const COLLECTION_NAME = 'ai_diary';
const VECTOR_DIM = 1024;
// 初始化大模型
const model = new ChatOpenAI({
temperature: 0.7,
model: process.env.MODEL_NAME,
apiKey: process.env.OPENAI_API_KEY,
configuration: { baseURL: process.env.OPENAI_BASE_URL }
});
// 初始化 Embedding 模型
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: process.env.EMBEDDINGS_MODEL_NAME,
configuration: { baseURL: process.env.OPENAI_BASE_URL },
dimensions: VECTOR_DIM
});
const client = new MilvusClient({ address: 'localhost:19530' });
// 检索相关日记
async function retrieveRelevantDiaries(question, k = 2) {
const queryVector = await embeddings.embedQuery(question);
const searchResult = await client.search({
collection_name: COLLECTION_NAME,
vector: queryVector,
limit: k,
metric_type: MetricType.COSINE,
output_fields: ['id', 'content', 'date', 'mood', 'tags']
});
return searchResult.results;
}
// RAG 回答问题
async function answerDiaryQuestion(question) {
console.log(`问题: ${question}\n`);
// 1. 检索相关日记
const retrievedDiaries = await retrieveRelevantDiaries(question, 2);
if (retrievedDiaries.length === 0) {
return '抱歉,我没有找到相关的日记内容。';
}
// 2. 打印检索到的日记
console.log('【检索到的相关日记】');
retrievedDiaries.forEach((diary, i) => {
console.log(`\n[日记 ${i + 1}] 相似度: ${diary.score.toFixed(4)}`);
console.log(`日期: ${diary.date}`);
console.log(`内容: ${diary.content}`);
});
// 3. 构建上下文
const context = retrievedDiaries
.map((diary, i) => `[日记 ${i + 1}]\n日期: ${diary.date}\n心情: ${diary.mood}\n内容: ${diary.content}`)
.join('\n\n');
// 4. 构建 Prompt
const prompt = `你是一个温暖贴心的 AI 日记助手。基于用户的日记内容回答问题。
请根据以下日记内容回答问题:
${context}
用户问题: ${question}
回答要求:
1. 结合日记内容给出详细、温暖的回答
2. 可以总结多篇日记的内容,找出共同点
3. 用第一人称"你"来称呼日记的作者
4. 回答要有同理心,让用户感到被理解
AI 助手的回答:`;
// 5. 调用大模型生成回答
console.log('\n【AI 回答】');
const response = await model.invoke(prompt);
console.log(response.content);
return response.content;
}
async function main() {
await client.connectPromise;
await answerDiaryQuestion("我最近做了什么让我感到快乐的事情?");
}
main();
RAG 流程的三个关键步骤:
- Retrieve(检索):把用户问题向量化,从 Milvus 检索相关日记
- Augment(增强):把检索到的日记内容拼接到 Prompt 中
- Generate(生成):大模型基于上下文生成回答
运行效果示例:
makefile
问题: 我最近做了什么让我感到快乐的事情?
【检索到的相关日记】
[日记 1] 相似度: 0.8756
日期: 2026-01-10
内容: 今天天气很好,去公园散步了,心情愉快。
[日记 2] 相似度: 0.8621
日期: 2026-01-11
内容: 今天工作很忙,完成了一个重要项目,很有成就感。
【AI 回答】
从你的日记来看,最近有两件事让你感到快乐:
一是 1月10日那天,你去公园散步,享受了好天气,心情很愉快。这种亲近自然的时刻总是能让人放松和开心。
二是 1月11日,你完成了一个重要的工作项目,获得了满满的成就感。这种通过努力达成目标的喜悦是很珍贵的。
看得出来,你既懂得享受生活中的小确幸,也能从工作中获得满足感,这是很好的平衡状态。
这就是完整的 RAG 流程。大模型不是凭空回答,而是基于从 Milvus 检索到的真实日记内容来生成回答。
更新和删除:完整的 CRUD 操作
除了插入和查询,实际应用中还需要更新和删除数据。
更新数据(src/update.mjs):
javascript
import "dotenv/config";
import { MilvusClient } from '@zilliz/milvus2-sdk-node';
import { OpenAIEmbeddings } from "@langchain/openai";
const COLLECTION_NAME = 'ai_diary';
const VECTOR_DIM = 1024;
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: process.env.EMBEDDINGS_MODEL_NAME,
configuration: { baseURL: process.env.OPENAI_BASE_URL },
dimensions: VECTOR_DIM
});
const client = new MilvusClient({ address: 'localhost:19530' });
async function main() {
await client.connectPromise;
// Milvus 通过 upsert 实现更新
const updateId = 'diary_001';
const updatedContent = {
id: updateId,
content: '今天下了一整天的雨,心情很糟糕。工作上遇到了很多困难。',
date: '2026-01-10',
mood: 'sad',
tags: ['生活', '工作']
};
// 重新向量化
const vector = await embeddings.embedQuery(updatedContent.content);
const updateData = { ...updatedContent, vector };
await client.upsert({
collection_name: COLLECTION_NAME,
data: [updateData]
});
console.log(`✓ 已更新日记: ${updateId}`);
}
main();
更新的关键点:
- 使用
upsert方法:如果 id 存在则更新,不存在则插入 - 必须重新向量化:因为内容变了,向量也要重新生成
- 需要 Embedding 模型:更新和插入一样,都要向量化
删除数据(src/delete.mjs):
javascript
import "dotenv/config";
import { MilvusClient } from '@zilliz/milvus2-sdk-node';
const COLLECTION_NAME = 'ai_diary';
const client = new MilvusClient({ address: 'localhost:19530' });
async function main() {
await client.connectPromise;
// 1. 删除单条数据
await client.delete({
collection_name: COLLECTION_NAME,
filter: `id == "diary_005"`
});
console.log('✓ 已删除单条记录');
// 2. 批量删除
const deleteIds = ['diary_002', 'diary_003'];
const idsStr = deleteIds.map(id => `"${id}"`).join(', ');
await client.delete({
collection_name: COLLECTION_NAME,
filter: `id in [${idsStr}]`
});
console.log('✓ 已批量删除记录');
// 3. 条件删除
await client.delete({
collection_name: COLLECTION_NAME,
filter: `mood == "sad"`
});
console.log('✓ 已按条件删除记录');
}
main();
删除的关键点:
- 不需要 Embedding 模型:删除是根据 id 或其他字段,不涉及向量
- 使用 filter 表达式 :支持
==、in、>、<等操作符 - 可以批量删除 :通过
id in [...]或条件表达式
关键参数与配置说明
在实际使用中,有几个参数需要特别注意:
1. 向量维度(dim)
必须和 Embedding 模型输出维度一致。常见的维度:
- OpenAI text-embedding-3-small: 1536
- OpenAI text-embedding-3-large: 3072
- 阿里云 text-embedding-v3: 1024
2. 检索数量(limit)
也就是 Top K,决定返回多少条最相似的结果。选择建议:
- 太小(k=1):可能漏掉重要信息
- 太大(k>10):引入噪音,增加 token 消耗
- 推荐范围:k=2~5
3. 距离度量(metric_type)
COSINE:余弦相似度,文本语义检索首选L2:欧氏距离,适合图像、音频IP:内积,适合推荐系统
4. 索引类型(index_type)
IVF_FLAT:平衡精度和速度,适合中小规模数据(< 100万)HNSW:高精度,适合对召回率要求高的场景IVF_PQ:高压缩比,适合大规模数据(> 1000万)
对于大多数 AI Agent 应用,IVF_FLAT + COSINE 是默认推荐组合。
常见误区与实战建议
误区 1:认为向量数据库可以替代关系型数据库
向量数据库擅长语义检索,但不擅长:
- 复杂的关联查询(JOIN)
- 事务处理(ACID)
- 精确的数值范围查询
正确做法是 MySQL + Milvus 双写,各司其职。
误区 2:忽略向量维度的一致性
Schema 定义的 dim 必须和 Embedding 模型输出维度完全一致,否则插入时会报错。建议把维度定义为常量,统一管理。
误区 3:不建索引就查询
没有索引的向量查询会退化为暴力搜索,性能极差。必须先 createIndex 再 loadCollection。
误区 4:每次查询都重新连接数据库
Milvus 客户端应该复用,不要每次查询都 new MilvusClient()。建议在应用启动时初始化一次,全局复用。
误区 5:忽略相似度阈值
检索结果的 score 表示相似度(0~1),并不是所有结果都真正相关。建议:
- 设置阈值(如 0.7),过滤掉低相似度结果
- 如果所有结果都低于阈值,告诉用户"没有找到相关内容"
实战建议 1:合理设计 Schema
除了必需的 id 和 vector,根据业务需求添加元数据字段:
- 时间戳:用于按时间过滤
- 分类标签:用于分类检索
- 来源信息:标记数据来源
这些字段在检索时可以通过 filter 参数进行过滤。
实战建议 2:批量操作提升性能
插入和查询都支持批量操作:
javascript
// 批量插入
await client.insert({
collection_name: COLLECTION_NAME,
data: [diary1, diary2, diary3, ...] // 一次插入多条
});
// 批量查询(多个问题)
const queries = ['问题1', '问题2', '问题3'];
const queryVectors = await Promise.all(
queries.map(q => embeddings.embedQuery(q))
);
批量操作可以显著减少网络开销。
实战建议 3:使用 Attu 可视化调试
Attu 是 Milvus 官方的 GUI 工具,可以:
- 查看所有 Collection 和数据
- 手动执行向量检索
- 查看索引状态和性能指标
开发阶段强烈建议安装:github.com/zilliztech/...
实战建议 4:监控向量化成本
Embedding 模型调用是有成本的:
- 插入 1000 条日记 = 1000 次 Embedding 调用
- 每次查询 = 1 次 Embedding 调用
建议:
- 批量向量化时使用
embedDocuments()而非循环调用embedQuery() - 缓存常见查询的向量
- 选择性价比高的 Embedding 模型
向量数据库在 AI Agent 中的典型应用
理解了 Milvus 的基本用法后,我们来看看它在 AI Agent 中的实际应用场景。
1. 知识库检索
企业内部文档、产品手册、技术文档等,用户用自然语言提问,系统从知识库中检索相关内容。
arduino
用户:"如何配置 VPN?"
↓ 向量化
↓ Milvus 检索
↓ 找到《VPN 配置指南》相关章节
↓ 放入 Prompt
↓ 大模型生成回答
2. 长期记忆
AI Agent 需要记住用户的偏好、历史对话、个人信息等。这些记忆存在 Milvus 中,需要时检索出来。
arduino
用户:"推荐一家餐厅"
↓ 检索用户历史记忆
↓ 找到"用户喜欢川菜"、"对海鲜过敏"
↓ 结合记忆生成推荐
3. 代码检索
在大型代码库中,根据功能描述找到相关代码片段。
bash
开发者:"找到处理用户登录的代码"
↓ 向量化查询
↓ Milvus 检索代码向量
↓ 返回 auth/login.ts、middleware/auth.ts 等文件
4. 多模态检索
不仅是文本,图像、音频也可以向量化后存入 Milvus,实现"以图搜图"、"以音搜音"。
性能与扩展性考虑
数据规模与索引选择:
- < 10万条 :
IVF_FLAT,精度高,速度快 - 10万 ~ 100万条 :
IVF_FLAT或HNSW - > 100万条 :
IVF_PQ,牺牲部分精度换取存储和速度
查询性能优化:
- 预加载 Collection :
loadCollection()把数据加载到内存,查询更快 - 合理设置 nlist :IVF 索引的聚类中心数量,通常设为
sqrt(数据量) - 使用 filter 减少搜索范围:先按条件过滤,再做向量检索
javascript
await client.search({
collection_name: COLLECTION_NAME,
vector: queryVector,
filter: 'date >= "2026-01-01"', // 先过滤
limit: 5
});
生产环境部署:
- 本地开发:Docker Compose(单机模式)
- 生产环境:Kubernetes 集群部署(分布式模式)
- 云服务:Zilliz Cloud(Milvus 官方云服务)
与其他向量数据库的对比
市面上还有其他向量数据库,如 Pinecone、Weaviate、Qdrant 等。为什么选 Milvus?
Milvus 的优势:
- 开源免费:可以本地部署,数据完全掌控
- 性能强劲:支持十亿级向量检索,毫秒级响应
- 生态成熟:LangChain、LlamaIndex 等主流框架都有集成
- 功能完整:支持多种索引、距离度量、混合检索
适用场景:
- 企业内部部署,对数据安全有要求
- 大规模数据(百万级以上)
- 需要高度定制化
如果是小规模原型验证,也可以考虑 Pinecone(云服务,开箱即用)或 Chroma(轻量级,适合本地开发)。
总结:向量数据库是 AI Agent 的基础设施
回到文章开头的问题:为什么 AI Agent 离不开向量数据库?
核心原因有三个:
- 语义理解是 AI 的本质能力:用户用自然语言交互,系统必须理解语义而非关键词
- 知识检索是 RAG 的基础:大模型需要外部知识支撑,向量检索是最有效的方式
- 长期记忆需要语义索引:AI Agent 要记住用户偏好和历史,语义检索比精确匹配更智能
Milvus 在这个链路中的位置:
用户输入(自然语言)
↓
Embedding 模型(向量化)
↓
Milvus(语义检索)
↓
检索结果(相关知识)
↓
大模型(生成回答)
实际工程中的最佳实践:
- MySQL + Milvus 双写:精确查询用 MySQL,语义检索用 Milvus
- 合理设计 Schema:除了向量,添加必要的元数据字段
- 选对索引和距离度量:文本检索用 IVF_FLAT + COSINE
- 设置相似度阈值:过滤低质量检索结果
- 批量操作提升性能:减少网络开销和 Embedding 调用次数
从这篇文章你应该掌握:
- 向量数据库解决的核心问题:语义检索
- Milvus 的数据组织方式:Database → Collection → Entity
- 完整的 CRUD 操作:插入、查询、更新、删除
- RAG 流程的实现:检索 → 增强 → 生成
- 关键参数的选择:维度、Top K、距离度量、索引类型
向量数据库不是可选项,而是 AI Agent 的必备基础设施。就像 Web 应用离不开 MySQL,AI Agent 离不开 Milvus。
如果你在做 AI Agent 相关的项目,Milvus 是一项值得写进简历的技能。围绕它可以聊很多:知识库构建、记忆系统设计、RAG 优化、混合检索策略等。
现在就开始动手实践吧,从一个简单的 AI 日记本开始,逐步理解向量检索的威力。
相关资源:
- Milvus 官方文档:milvus.io/docs
- Attu GUI 工具:github.com/zilliztech/...
- Milvus Node.js SDK:github.com/milvus-io/m...
- 本文示例代码:[GitHub 仓库链接]