从零搭建 AI 日记助手:Milvus 向量数据库 + RAG 实战

从零搭建 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 条记录成功插入。

流程很简单:

flowchart LR A[原始日记文本] --> B[text-embedding-v3] B --> C[1024维向量] C --> D[Milvus Collection] E[结构化字段<br/>日期/心情/标签] --> D

此时,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']
})

这里发生的事情:

  1. 用户输入自然语言 "我想看看关于户外活动的日记"
  2. Embedding 模型把它变成 1024 维向量
  3. Milvus 在向量空间中找最接近的 2 个向量(余弦相似度)
  4. 返回对应日记的全部结构化字段

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 架构

flowchart TD A[用户提问] --> B[Embedding 向量化] B --> C[Milvus 向量检索] C --> D[取回 Top-K 相关日记] D --> E[拼接 Context + Prompt] E --> F[LLM 生成回答] F --> G[返回给用户]

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 回答的几个亮点:

  1. 结合了具体日记内容:提到了"公园散步"和"做晚餐"两个具体事件
  2. 有情感温度:不是冷冰冰的摘要,而是像朋友的对话
  3. 用"你"称呼:让用户感觉 AI 在对自己说话
  4. 有总结提炼:最后一句点出了两个事件的共同主题

这就是 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.mjsindex.mjsquery.mjs / rag.mjs


8. 扩展方向

这个 Demo 只是起点,还有很多方向值得探索:

  • 时间过滤:搜索时加入日期范围条件,比如"上个月的快乐日记"
  • 混合搜索 :结合向量相似度 + 结构化过滤(mood = 'happy'),提高召回精度
  • 对话记忆:加入对话历史,让 AI 助手记住刚才聊了什么,实现多轮对话
  • 增量更新:每天自动同步新日记,保持数据库最新
  • 多模态:日记中的图片用 CLIP 模型向量化,实现"搜图片"的功能

9. 结语

从 4 维的玩具向量到 1024 维的真实语义向量,从简单的相似搜索到完整的 RAG 对话------这 4 个文件串起了向量数据库应用开发的核心链路。

如果你也想动手试试,关键就三步:

  1. 注册 Zilliz Cloud(有免费额度)
  2. 接入任一 OpenAI 兼容的 Embedding 和 Chat 模型(阿里、百度、本地都行)
  3. 跑通 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)
相关推荐
zguigo1 小时前
结合苍穹外卖对redis进行总结和教学
后端
玉宇夕落1 小时前
Milvus向量数据库和cs bs架构学习
后端
Larcher1 小时前
别再搞混了!一文讲透 AI Workflow 和 Agent 的本质区别
javascript·人工智能·后端
瀛川1 小时前
microVM 技术解析:面向多租户 Serverless 与 AI Agent 的微虚拟机架构
后端·云原生
Conan在掘金2 小时前
鸿蒙报错速查:装对象字量禁 as Object 编译炸,根因 + 真解法
后端
IT_陈寒2 小时前
Python的finally居然不等同于Go的defer,差点坑惨我
前端·人工智能·后端
会编程的土豆2 小时前
功能详解 01 · 用户注册:从表单到数据库一行
开发语言·数据库·后端·mysql·golang
Ivanqhz2 小时前
Rust collect() 浅析
开发语言·后端·rust
卷无止境2 小时前
python进阶:类方法与静态方法的分野,classmethod 和 staticmethod 到底该怎么选
后端·python