从零搭建 AI 日记助手:Milvus 向量数据库 + RAG 实战
本文将带你一步步用 Milvus 向量数据库、LangChain 和 OpenAI 兼容接口,构建一个能"读懂你日记"的 AI 助手------你可以用自然语言向它提问,它会从你过往的日记中检索相关内容,并给出温暖贴心的回答。 源码在结尾
1. 项目概述
你有没有想过,如果日记里的内容能被 AI "回忆"起来,会是什么体验?
比如你问一句 "我最近做了什么让我感到快乐的事?",AI 能翻出你的日记,找到那些快乐的片段,然后像朋友一样告诉你------这就是我们这个小项目的核心目标。
整个项目只有 4 个文件,由浅入深地展示了:
| 文件 | 功能 | 核心概念 |
|---|---|---|
main.mjs |
最简 Demo:连接 Milvus + 插入数据 + 相似搜索 | 向量数据库基本操作 |
index.mjs |
数据入库:Embedding 向量化 + Schema 设计 | 结构化数据存储 |
query.mjs |
语义搜索:自然语言查询日记 | 向量相似度检索 |
rag.mjs |
RAG 对话:检索增强生成,AI 助手回答 | LLM + 向量检索 |
让我们按这个递进顺序,一步步拆解它的实现原理。
2. 环境准备
2.1 依赖
项目使用三个核心依赖:
json
{
"dependencies": {
"@zilliz/milvus2-sdk-node": "最新版", // Milvus Node.js SDK
"@langchain/openai": "^1.5.5", // LangChain OpenAI 封装
"dotenv": "最新版" // 环境变量管理
}
}
2.2 基础设施
- 向量数据库:Zilliz Cloud(全托管 Milvus 服务),无需本地部署,开箱即用
- Embedding 模型 :
text-embedding-v3(通过阿里云 DashScope 的 OpenAI 兼容接口) - 对话模型 :
qwen-plus(同上接口)
env
# .env 配置
OPENAI_API_KEY=your-api-key
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL_NAME=qwen-plus
EMBEDDINGS_MODEL_NAME=text-embedding-v3
MILVUS_ADDRESS=https://xxx.serverless.ali-cn-hangzhou.cloud.zilliz.com.cn
MILVUS_TOKEN=your-milvus-token
重点是 OPENAI_BASE_URL 指向了阿里云的兼容接口,这意味着你不需要 OpenAI 的 API Key,用国产大模型就能跑通整个流程。
3. 第一步:你好,Milvus(main.mjs)
先来看最简化的入门示例,理解向量数据库的核心操作逻辑。
3.1 连接数据库
javascript
import { MilvusClient } from '@zilliz/milvus2-sdk-node'
const client = new MilvusClient({
address: ADDRESS, // Zilliz Cloud 地址
token: TOKEN // API Key 认证
})
const checkHealth = await client.checkHealth()
// 链接成功,集群状态正常。
Zilliz Cloud 提供了 Serverless 的全托管服务,无需操心集群维护,连上就能用。
3.2 创建 Collection 与索引
javascript
const COLLECTION_NAME = 'test'
const DIMENSION = 4 // 向量维度
await client.createCollection({
collection_name: COLLECTION_NAME,
dimension: DIMENSION,
auto_id: true
})
await client.createIndex({
collection_name: COLLECTION_NAME,
field_name: 'vector',
index_type: IndexType.AUTOINDEX,
metric_type: MetricType.COSINE
})
Collection 类似于关系数据库中的"表",但它的核心字段是向量(vector)。
为什么要建索引?
没有索引时,每次查询都要把库里所有向量和查询向量逐一计算相似度------O(n) 的复杂度,数据量一大就慢得没法用。这就好比你要在图书馆找一本《三体》,没有索引的话每一本都得翻一遍;有了索引就像按"文学馆 → 小说 → 科幻"的分类快速缩小范围。
Milvus 支持多种索引类型:
IVF_FLAT(聚簇索引,毫秒级查询)、AUTOINDEX(自动选择最优索引)等。这里用AUTOINDEX让系统替我们做选择。
相似度计算方式 选用了 COSINE(余弦相似度),衡量的是两个向量"方向"上的接近程度,特别适合文本语义相似度计算。
3.3 插入与搜索
javascript
import 'dotenv/config';
import {
MilvusClient, // C/S B/S
MetricType, // 相似度求方法
IndexType,
DataType // 字段数据类型约束
} from '@zilliz/milvus2-sdk-node';
import {
OpenAIEmbeddings
} from '@langchain/openai';
const ADDRESS = process.env.MILVUS_ADDRESS;
// api key
const TOKEN = process.env.MILVUS_TOKEN;
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: ADDRESS,
token: TOKEN
})
const getEmbedding = async (text) => {
const result = await embeddings.embedQuery(text);
return result;
}
async function main() {
console.log('正在连接 zilliz cloud....')
const checkHealth = await client.checkHealth();
if (!checkHealth.isHealthy) {
console.error('连接失败', checkHealth.reasons);
return ;
}
console.log('链接成功, 集群状态正常。')
await client.createCollection({
collection_name: COLLECTION_NAME,
fields: [
// diary_01
{
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
},
]
});
console.log('collection created');
console.log('create index...');
await client.createIndex({
collection_name: COLLECTION_NAME,
field_name: 'vector',
index_type: IndexType.IVF_FLAT,
metric_type: MetricType.COSINE
})
}
main()
.catch(console.error)
几条核心心得:
- 插入像写 JSON:不需要预定义严格的 Schema,比传统 SQL 灵活得多
- 搜索是"语义"的:不是精确匹配,而是"找最像的",这是向量数据库的本质区别
当然,这里的 4 维向量只是教学用途。真正的语义搜索,需要靠 Embedding 模型把文本变成高维向量------这就是下一步要做的。
4. 第二步:让 AI 读懂日记(index.mjs)
index.mjs 实现了一个真实的场景:把日记存入向量数据库,每条日记都携带丰富的结构化信息和语义向量。
4.1 设计 Schema
javascript
const 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 },
]
这是一张结构完整的"日记表":
| 字段 | 类型 | 说明 |
|---|---|---|
id |
VarChar(50) | 主键,如 diary_001 |
vector |
FloatVector(1024) | 核心字段------Embedding 后的语义向量 |
content |
VarChar(5000) | 日记正文 |
date |
VarChar(50) | 日期 |
mood |
VarChar(50) | 心情标签,如 happy, excited |
tags |
ArrayVarChar | 标签数组,如 ['生活', '散步'] |
这里的关键设计是:既有向量字段用于语义搜索,又保留了原始的结构化字段(日期、心情、标签)。这让后续的查询既可以"搜意思相近的",也可以精确过滤"某一天的"或"心情为 happy 的"。
4.2 文本向量化
javascript
import { OpenAIEmbeddings } from '@langchain/openai'
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: 'text-embedding-v3',
configuration: { baseURL: process.env.OPENAI_BASE_URL },
dimensions: 1024
})
const getEmbedding = async (text) => {
const result = await embeddings.embedQuery(text)
return result // number[],长度 = 1024
}
LangChain 的 OpenAIEmbeddings 封装得很好------只需配置 baseURL 就能对接任何 OpenAI 兼容接口。一条日记经过 embedQuery() 就变成了一个 1024 维的浮点数数组,捕捉了整段文本的语义信息。
4.3 批量入库
javascript
const diaryContents = [
{ id: 'diary_001', content: '今天天气很好,去公园散步了...', mood: 'happy', tags: ['生活', '散步'] },
{ id: 'diary_002', content: '今天工作很忙,完成了一个重要的项目里程碑...', mood: 'excited', tags: ['工作', '成就'] },
// ... 共 5 条日记
]
const diaryData = await Promise.all(
diaryContents.map(async (diary) => ({
...diary,
vector: await getEmbedding(diary.content) // 日记正文 → 1024维向量
}))
)
const insertResult = await client.insert({
collection_name: COLLECTION_NAME,
data: diaryData
})
// 5 条记录成功插入。
流程很简单:
此时,5 条日记的"语义指纹"已经存入了 Milvus,随时可以被搜索唤醒。
5. 第三步:用自然语言搜索日记(query.mjs)
有了数据,下一步自然是查 。query.mjs 展示了语义搜索的魔力。
5.1 核心逻辑
javascript
const query = '我想看看关于户外活动的日记'
const queryVector = await getEmbedding(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']
})
这里发生的事情:
- 用户输入自然语言
"我想看看关于户外活动的日记" - Embedding 模型把它变成 1024 维向量
- Milvus 在向量空间中找最接近的 2 个向量(余弦相似度)
- 返回对应日记的全部结构化字段
5.2 输出效果
yaml
QUERY: 我想看看关于户外活动的日记
Found 2 results:
1. [Score: 0.8523]
ID: diary_003
Date: 2026-01-12
Mood: relaxed
Tags: 户外, 朋友
Content: 周末和朋友去爬山,天气很好,心情也很放松。享受大自然的感觉真好。
2. [Score: 0.6120]
ID: diary_001
Date: 2026-01-10
Mood: happy
Tags: 生活, 散步
Content: 今天天气很好,去公园散步了,心情愉快。看到了很多花开了,春天真美好。
注意------我们没有写任何关键词匹配逻辑 ,也没有用 SQL 的 LIKE '%户外%'。向量搜索自动理解了"户外活动"和"爬山"、"散步"之间的语义关联。
这就是向量搜索的核心价值:搜的是"意思",而不是"字面"。
6. 第四步:AI 日记助手------RAG 完整实现(rag.mjs)
最后一步,也是最精彩的一步:把检索 和生成 结合起来,打造一个真正能"对话"的 AI 日记助手。这就是当前大模型应用中最热门的范式------RAG(Retrieval-Augmented Generation,检索增强生成)。
6.1 RAG 架构
6.2 检索阶段
javascript
async function retrieveRelevantDiaries(question, k = 2) {
const queryVector = await getEmbedding(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
}
和 query.mjs 中的搜索完全一致------把用户问题向量化,在 Milvus 中找到最相关的日记。
6.3 生成阶段
这一步是 RAG 的灵魂------如何把检索到的日记"喂"给 LLM,让它生成高质量回答。
javascript
const context = retrievedDiaries.map((diary, i) => `
[日记${i + 1}]
日期:${diary.date}
心情:${diary.mood}
标签:${diary.tags}
内容:${diary.content}
`)
const prompt = `你是一个贴心的AI日记助手。基于用户的日记内容回答问题,用亲切自然的语言。
${context}
用户问题:${question}
回答要求:
1. 如果日记中有相关信息,请结合日记内容给出详细温暖的回答
2. 可以总结多篇日记的内容,找出共同点或趋势
3. 如果日记中没有相关信息,请温和告知用户
4. 用第一人称"你"来称呼日记的作者
5. 回答要有同理心,让用户感到被理解和关心
AI助手的回答:`
这个 Prompt 设计有几个值得注意的细节:
| 要点 | 说明 |
|---|---|
| 明确的角色设定 | "贴心的AI日记助手"------定了调子,决定了语气风格 |
| 用"你"称呼用户 | 这个人称转换很关键,LLM 知道它在对日记作者本人说话 |
| 5 条回答要求 | 覆盖了"有信息"、"无信息"、"多篇总结"等边界情况 |
| 同理心要求 | 让 AI 不只是"陈述事实",而是"共情回应" |
接着调用 LLM:
javascript
const model = new ChatOpenAI({
temperature: 0.1, // 低温度,确保回答稳定可控
model: 'qwen-plus',
apiKey: process.env.OPENAI_API_KEY,
configuration: { baseURL: process.env.OPENAI_BASE_URL }
})
const response = await model.invoke(prompt)
console.log(response.content)
temperature: 0.1 的选择很讲究------在 RAG 场景下,我们希望 LLM 忠实于检索到的上下文,而不是天马行空地发挥。
6.4 实际效果
运行 rag.mjs,输入问题 "我最近做了什么让我感到快乐的事":
markdown
================================================================================
问题: 我最近做了什么让我感到快乐的事
================================================================================
检索相关日记
[检索到 diary_001: 公园散步, diary_005: 做晚餐]
[AI 回答]
最近你经历了不少快乐的事呢!首先是1月10号那天,你趁着好天气去公园散了步,
看到盛开的花朵,感受到了春天的美好,心情也变得格外愉快。
还有1月13号晚上,你下厨做了一顿丰盛的晚餐,还大胆尝试了新菜谱,家人都说
很好吃------那种被认可的成就感,一定让你心里暖暖的吧!
看起来,无论是亲近大自然还是为家人付出,都能给你带来真实的快乐呢。🌸
注意 AI 回答的几个亮点:
- 结合了具体日记内容:提到了"公园散步"和"做晚餐"两个具体事件
- 有情感温度:不是冷冰冰的摘要,而是像朋友的对话
- 用"你"称呼:让用户感觉 AI 在对自己说话
- 有总结提炼:最后一句点出了两个事件的共同主题
这就是 RAG 的力量------LLM 提供了流畅的表达能力,向量数据库提供了准确的"记忆"能力,两者结合,效果远超各自的单独使用。
7. 技术要点总结
7.1 向量数据库 vs 传统数据库
| 特性 | 传统数据库 (MySQL) | 向量数据库 (Milvus) |
|---|---|---|
| 查询方式 | 精确匹配 WHERE = |
相似度搜索 ORDER BY cosine_distance |
| 索引原理 | B-Tree / Hash | IVF / HNSW / 图索引 |
| 适用场景 | 结构化精确查询 | 非结构化语义搜索 |
| 典型操作 | SELECT * WHERE name LIKE '%关键词%' |
search(vector, limit=5) |
7.2 RAG 的核心优势
传统 LLM: 用户问题 → LLM → 回答(可能编造、过时、或不知道)
RAG: 用户问题 → 检索相关知识 → LLM + 知识 → 回答(有据可查)
RAG 解决了 LLM 的三大痛点:
- 幻觉问题:回答基于检索到的真实数据,大大减少编造
- 知识时效:知识存在外部数据库里,更新数据不需要重新训练
- 领域知识:私有日记、企业文档等 LLM 没见过的东西也能回答
7.3 文件依赖关系
erlang
main.mjs (独立,最简 Demo)
index.mjs (独立,数据入库脚本)
query.mjs (依赖 index.mjs 入库的数据)
rag.mjs (依赖 index.mjs 入库的数据,比 query 多了 LLM 生成环节)
建议的运行顺序:main.mjs → index.mjs → query.mjs / rag.mjs
8. 扩展方向
这个 Demo 只是起点,还有很多方向值得探索:
- 时间过滤:搜索时加入日期范围条件,比如"上个月的快乐日记"
- 混合搜索 :结合向量相似度 + 结构化过滤(
mood = 'happy'),提高召回精度 - 对话记忆:加入对话历史,让 AI 助手记住刚才聊了什么,实现多轮对话
- 增量更新:每天自动同步新日记,保持数据库最新
- 多模态:日记中的图片用 CLIP 模型向量化,实现"搜图片"的功能
9. 结语
从 4 维的玩具向量到 1024 维的真实语义向量,从简单的相似搜索到完整的 RAG 对话------这 4 个文件串起了向量数据库应用开发的核心链路。
如果你也想动手试试,关键就三步:
- 注册 Zilliz Cloud(有免费额度)
- 接入任一 OpenAI 兼容的 Embedding 和 Chat 模型(阿里、百度、本地都行)
- 跑通 RAG 流程------一旦看到 AI 用你的数据回答问题的那一刻,你会明白向量数据库的真正价值。
代码量不大,但每个文件都说明白了一个核心概念。希望这篇文章能帮你在向量数据库和 RAG 的探索之路上少走一些弯路。Happy coding! 🚀
10.代码
index.mjs
javascript
import 'dotenv/config';
import {
MilvusClient, // C/S B/S
MetricType, // 相似度求方法
IndexType,
DataType // 字段数据类型约束
} from '@zilliz/milvus2-sdk-node';
import {
OpenAIEmbeddings
} from '@langchain/openai';
const ADDRESS = process.env.MILVUS_ADDRESS;
// api key
const TOKEN = process.env.MILVUS_TOKEN;
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: ADDRESS,
token: TOKEN
})
const getEmbedding = async (text) => {
const result = await embeddings.embedQuery(text);
return result;
}
async function main() {
console.log('正在连接 zilliz cloud....')
const checkHealth = await client.checkHealth();
if (!checkHealth.isHealthy) {
console.error('连接失败', checkHealth.reasons);
return ;
}
console.log('链接成功, 集群状态正常。')
// await client.createCollection({
// collection_name: COLLECTION_NAME,
// fields: [
// // diary_01
// {
// 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
// },
// ]
// });
// console.log('collection created');
// console.log('create index...');
// await client.createIndex({
// collection_name: COLLECTION_NAME,
// field_name: 'vector',
// index_type: IndexType.IVF_FLAT,
// metric_type: MetricType.COSINE
// })
console.log('loading collection');
await client.loadCollection({
collection_name: COLLECTION_NAME
});
console.log('collection loaded')
const diaryContents = [
{
id: 'diary_001',
content: '今天天气很好,去公园散步了,心情愉快。看到了很多花开了,春天真美好。',
date: '2026-01-10',
mood: 'happy',
tags: ['生活', '散步']
},
{
id: 'diary_002',
content: '今天工作很忙,完成了一个重要的项目里程碑。团队合作很愉快,感觉很有成就感。',
date: '2026-01-11',
mood: 'excited',
tags: ['工作', '成就']
},
{
id: 'diary_003',
content: '周末和朋友去爬山,天气很好,心情也很放松。享受大自然的感觉真好。',
date: '2026-01-12',
mood: 'relaxed',
tags: ['户外', '朋友']
},
{
id: 'diary_004',
content: '今天学习了 Milvus 向量数据库,感觉很有意思。向量搜索技术真的很强大。',
date: '2026-01-12',
mood: 'curious',
tags: ['学习', '技术']
},
{
id: 'diary_005',
content: '晚上做了一顿丰盛的晚餐,尝试了新菜谱。家人都说很好吃,很有成就感。',
date: '2026-01-13',
mood: 'proud',
tags: ['美食', '家庭']
}
];
console.log('Generating embeddings...');
const diaryData = await Promise.all(
diaryContents.map(async( diary) => ({
...diary,
vector: await getEmbedding(diary.content)
}))
);
const insertResult = await client.insert({
collection_name: COLLECTION_NAME,
data: diaryData
})
console.log(insertResult.insert_cnt, "条记录成功插入。");
}
main()
.catch(console.error)
query.mjs
javascript
import 'dotenv/config'
import {
MilvusClient, // C/S架构 B/S架构
MetricType, //求相似度的方法类型,是cos 还是sin
IndexType,
DataType, //字段数据类型约束
} from '@zilliz/milvus2-sdk-node'
import {
OpenAIEmbeddings
} from '@langchain/openai'
//云端向量数据库地址
const ADDRESS = process.env.MILVUS_ADDRESS
//云端数据库KEY
const TOKEN = process.env.MILVUS_TOKEN
const COLLECTION_NAME = 'ai_dairy';
const VECTOR_DIM = 1024
//创建embedding llm实例
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: process.env.EMBEDDING_MODEL_NAME,
configuration: {
baseURL: process.env.OPENAI_BASE_URL,
},
dimensions: VECTOR_DIM,
})
//连接远程数据库
const databaseclient = new MilvusClient({
address: ADDRESS,
token: TOKEN,
})
//向量化方法
const getEmbedding = async (text) => {
const result = await embeddings.embedQuery(text);
return result;
}
async function main() {
try {
console.log('Connected to Milvus...')
// await databaseclient.connectPromise;//连接Milvus (SDK 会自动连接,不需要手动调用)
const query = '我想看看关于户外活动的日记'
console.log(`QUERY:${query}`);
const queryVector = await getEmbedding(query);
const searchResult = await databaseclient.search({
collection_name: COLLECTION_NAME,
vector: queryVector,
limit: 2,
metric_type: MetricType.COSINE,
output_fields: ['id', 'content', 'date', 'mood', 'tags']
})
console.log(`Found ${searchResult.results.length}result`);
searchResult.results.forEach((item, index) => {
console.log(`${index + 1}.[Score:${item.score.toFixed(4)}]`);
console.log(`
ID:${item.id};
Date:${item.date};
Mood:${item.mood};
Tags:${item.tags?.join(",")}
Content:${item.content}
`)
})
} catch (err) {
}
}
main()
.catch(console.error)
rag.mjs
javascript
import 'dotenv/config'
import {
MilvusClient, // C/S架构 B/S架构
MetricType, //求相似度的方法类型,是cos 还是sin
IndexType,
DataType, //字段数据类型约束
} from '@zilliz/milvus2-sdk-node'
import {
OpenAIEmbeddings
} from '@langchain/openai'
//云端向量数据库地址
const ADDRESS = process.env.MILVUS_ADDRESS
//云端数据库KEY
const TOKEN = process.env.MILVUS_TOKEN
const COLLECTION_NAME = 'ai_dairy';
const VECTOR_DIM = 1024
//创建embedding llm实例
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: process.env.EMBEDDING_MODEL_NAME,
configuration: {
baseURL: process.env.OPENAI_BASE_URL,
},
dimensions: VECTOR_DIM,
})
//连接远程数据库
const databaseclient = new MilvusClient({
address: ADDRESS,
token: TOKEN,
})
//向量化方法
const getEmbedding = async (text) => {
const result = await embeddings.embedQuery(text);
return result;
}
async function main() {
try {
console.log('Connected to Milvus...')
// await databaseclient.connectPromise;//连接Milvus (SDK 会自动连接,不需要手动调用)
const query = '我想看看关于户外活动的日记'
console.log(`QUERY:${query}`);
const queryVector = await getEmbedding(query);
const searchResult = await databaseclient.search({
collection_name: COLLECTION_NAME,
vector: queryVector,
limit: 2,
metric_type: MetricType.COSINE,
output_fields: ['id', 'content', 'date', 'mood', 'tags']
})
console.log(`Found ${searchResult.results.length}result`);
searchResult.results.forEach((item, index) => {
console.log(`${index + 1}.[Score:${item.score.toFixed(4)}]`);
console.log(`
ID:${item.id};
Date:${item.date};
Mood:${item.mood};
Tags:${item.tags?.join(",")}
Content:${item.content}
`)
})
} catch (err) {
}
}
main()
.catch(console.error)