从零搭建 AI 日记本:Milvus 向量数据库 + RAG 实战
用 Milvus 给 LLM 装上"记忆",实现语义搜索和智能问答。本文带你从连接数据库到完整的 RAG 管线,代码来自
demo/src/下的真实实现。
一、为什么 Agent 需要向量数据库?
传统 Web 应用把数据存在 MySQL 里,靠 id 或 LIKE 关键字做增删改查。但 AI Agent 面对的是语义级别的需求:
sql
❌ SQL: SELECT * FROM diary WHERE content LIKE '%开心%'
✅ 语义: "我最近心情比较好的日记有哪些?"
LIKE 只能做字符串匹配------"愉快""高兴""happy"都搜不到,而语义搜索能理解这些词表达的是同一种情绪。
Agent 把知识、记忆放在向量数据库中,做语义检索------这就是 RAG(检索增强生成)的基础设施。
ini
Agent = LLM + Memory + Tool + RAG + MCP + Skills
↑
向量数据库(Milvus)
二、Milvus 是什么?
Milvus 是一款开源向量数据库,专为海量高维向量数据设计。它解决的核心问题是:如何在百万级向量中,毫秒级找到最相似的 Top-K?
对比传统数据库:
| MySQL | Milvus | |
|---|---|---|
| 存什么 | 结构化数据(int, varchar) | 高维向量(float\[\]) |
| 怎么查 | WHERE id = 1 / LIKE '%关键词%' |
向量相似度(余弦距离) |
| 索引 | B+Tree | IVF_FLAT / HNSW |
| 典型场景 | 订单、用户、商品 | 语义搜索、推荐、图像检索 |
Zilliz Cloud 是基于 Milvus 的全托管云服务,免去自建集群的运维成本。本文使用 Zilliz Cloud 的 Serverless 实例。
三、第一步:连接数据库,创建 Collection
3.1 连接 Zilliz Cloud
js
import { MilvusClient } from '@zilliz/milvus2-sdk-node';
const client = new MilvusClient({
address: process.env.MILVUS_ADDRESS, // 云服务地址
token: process.env.MILVUS_TOKEN // API Key
});
const health = await client.checkHealth();
// { isHealthy: true } → 连接成功
Milvus 是 C/S 架构,客户端通过 gRPC 与服务端通信。checkHealth() 是连接后的第一个操作,确认集群状态正常。
3.2 创建 Collection(相当于 MySQL 的 Table)
js
await client.createCollection({
collection_name: 'AI_Dairy',
fields: [
{ name: 'id', data_type: DataType.VarChar, max_length: 50, is_primary_key: true },
{ name: 'vector', data_type: DataType.FloatVector, dim: 1024 },
{ 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 }
]
});
Collection 的 Schema 比 MySQL 灵活------可以在插入数据时动态添加字段,但生产环境建议显式定义。核心字段是 vector(1024 维浮点向量),这是语义搜索的基础。
3.3 创建索引
js
await client.createIndex({
collection_name: 'AI_Dairy',
field_name: 'vector',
index_type: IndexType.IVF_FLAT,
metric_type: MetricType.COSINE
});
没有索引时,每次查询都要把库里所有向量和查询向量逐一算相似度(O(n))。索引就像图书馆的分类系统------先缩小范围再精排:
图书检索类比:
无索引 → 每本书翻一遍
IVF_FLAT → 文学馆 → 小说 → 科幻 → 找到《三体》
四、第二步:向量化并写入数据
4.1 文本转向量(Embedding)
LLM 只能处理数字。Embedding 模型把文本映射到高维向量空间,语义相近的文本向量距离也更近:
js
import { OpenAIEmbeddings } from '@langchain/openai';
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: 'text-embedding-v3', // 阿里云 DashScope
configuration: { baseURL: process.env.OPENAI_BASE_URL },
dimensions: 1024
});
const getEmbedding = async (text) => {
return await embeddings.embedQuery(text); // "今天很开心" → [0.12, -0.34, ...] (1024维)
};
这里用阿里云的 text-embedding-v3,通过 OpenAI 兼容接口调用。LangChain 的 OpenAIEmbeddings 封装了调用细节。
4.2 批量写入日记
js
const diaryContents = [
{ 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(
diaryContents.map(async (diary) => ({
...diary,
vector: await getEmbedding(diary.content) // 每条的 content → 向量
}))
);
const result = await client.insert({ collection_name: 'AI_Dairy', data: diaryData });
console.log(`${result.insert_cnt} 条记录成功插入`);
对比 MySQL 的 INSERT INTO ... VALUES (...),Milvus 的插入同样简单------给 JSON 就行,不用写 SQL。Promise.all 并发调用 Embedding API,5 条的向量化总耗时 = max(单次耗时),而非累加。
五、第三步:语义搜索
向量入库后,就可以用自然语言搜日记了:
js
const query = '我想看看关于户外活动的日记';
const queryVector = await getEmbedding(query); // 查询也要向量化
const result = await client.search({
collection_name: 'AI_Dairy',
vector: queryVector,
limit: 2,
metric_type: MetricType.COSINE, // 余弦相似度
output_fields: ['id', 'content', 'date', 'mood', 'tags']
});
// 输出:
// 1. [Score]: 0.8734 --- diary_003: 周末和朋友去爬山,天气很好...
// 2. [Score]: 0.7652 --- diary_001: 今天天气很好,去公园散步了...
整个过程:
css
用户问题 "户外活动"
→ Embedding 模型 → [0.23, -0.45, ...]
→ Milvus 索引检索(IVF_FLAT + COSINE)
→ 返回 Top-2 最相似日记
查询里没有出现"爬山""散步"这些词,但向量相似度能理解"户外活动"和它们语义相关。这就是向量数据库相比 LIKE 关键字的质变。
六、第四步:RAG ------ 让 LLM 基于日记回答问题
单独检索出日记还不够,最终目标是让 LLM 像真人一样回答。这就进入 RAG 的完整管线:
用户问题 → Embedding → Milvus 检索 → 拼入 Prompt → LLM 生成回答
6.1 检索模块
js
async function retrieveRelevantDiaries(question, k = 2) {
const queryVector = await getEmbedding(question);
const result = await client.search({
collection_name: 'AI_Dairy',
vector: queryVector,
limit: k,
metric_type: MetricType.COSINE,
output_fields: ['id', 'content', 'date', 'mood', 'tags']
});
return result.results;
}
6.2 生成模块
js
const model = new ChatOpenAI({
temperature: 0.1, // 低温度 = 更稳定的回答
model: 'qwen-plus', // 阿里云
apiKey: process.env.OPENAI_API_KEY,
configuration: { baseURL: process.env.OPENAI_BASE_URL }
});
async function answerDiaryQuestion(question, k = 2) {
const diaries = await retrieveRelevantDiaries(question, k);
// 把检索结果拼成上下文
const context = diaries.map((d, i) => `
[日记 ${i + 1}]
日期: ${d.date} 心情: ${d.mood} 标签: ${d.tags?.join(',')}
内容: ${d.content}
`).join('\n\n----\n\n');
const prompt = `你是一个温暖、贴心的 AI 日记助手。请根据以下日记内容回答:
${context}
用户问题:${question}
回答要求:
1. 结合日记内容给出详细、温暖的回答
2. 可以总结多篇日记,找出共同点或趋势
3. 用第二人称"你"来称呼作者
4. 有同理心,让用户感到被理解
AI 助手的回答:`;
const response = await model.invoke(prompt);
return response.content;
}
6.3 运行效果
js
await answerDiaryQuestion('我最近做了什么让我开心的事情?', 2);
// ================================================================================
// 问题:我最近做了什么让我开心的事情?
// ================================================================================
// 检索相关日记
// 日记1 相似度: 0.8521 --- 今天天气很好,去公园散步了,心情愉快。
// 日记2 相似度: 0.7834 --- 晚上做了一顿丰盛的晚餐,尝试了新菜谱。家人都说很好吃。
//
// [AI 回答]
// 最近你做了几件让人开心的事情呢!1 月 10 号那天天气很好,你去公园散步,
// 看到了很多花开了,享受了春天的美好。还有一天晚上,你尝试了新菜谱,
// 做了一顿丰盛的晚餐,家人都很喜欢------这种被认可的感觉一定很温暖吧!
// 看起来你是个懂得在生活中寻找小确幸的人~
RAG 管网线完整跑通了: 用户的自然语言问题 → 向量检索 → 拼入 Prompt → LLM 生成带上下文的温暖回复。
七、总结
一条主线串起全部知识点:
markdown
传统数据库(MySQL)
→ 无法做语义搜索
→ 引入向量数据库(Milvus)
→ Embedding 模型把文本转为向量
→ 向量入库 + 建索引(IVF_FLAT)
→ 用户问题向量化 → 相似度检索
→ 检索结果拼入 Prompt
→ LLM 生成基于真实日记的回答(RAG)
Milvus 和 MySQL 不是替代关系,而是互补:
- MySQL 管结构化数据:用户表、订单表、日记的 CRUD
- Milvus 管语义数据:知识检索、记忆搜索、推荐匹配
这就是 Agent 记忆系统的核心基础设施。Cursor、Claude Code 等产品背后,都是同一套"向量数据库 + RAG"的逻辑------只是工程规模更大,知识库更复杂。
本文涉及的源文件:demo/src/main.mjs、demo/src/index.mjs、demo/src/query.mjs、demo/src/rag.mjs
技术栈:Milvus / Zilliz Cloud · LangChain · OpenAI Embeddings · 阿里云 DashScope