LlamaIndex 实战 Milvus 向量数据库:从 CRUD 到 智能检索

目录

[1. 为什么选择 LlamaIndex + Milvus?](#1. 为什么选择 LlamaIndex + Milvus?)

[2. 核心代码实战](#2. 核心代码实战)

[2.1 依赖安装](#2.1 依赖安装)

[2.2 导包与配置](#2.2 导包与配置)

[2.3 解决 Windows 下的 Asyncio 痛点](#2.3 解决 Windows 下的 Asyncio 痛点)

[2.4 增加操作](#2.4 增加操作)

[2.5 实现"查" 并解决"乱匹配"问题](#2.5 实现“查” 并解决“乱匹配”问题)

[2.6 实现"删"与"改"](#2.6 实现“删”与“改”)

3.运行效果展示

4.避坑指南总结


1. 为什么选择 LlamaIndex + Milvus?

  • LlamaIndex :当前最火的 LLM 数据框架,能轻松把你的私有数据(PDF、Word、数据库)变成大模型能读懂的索引。

  • Milvus :高性能的开源向量数据库,适合存储海量 Embedding 数据。


2. 核心代码实战

在此之前,请确保安装了milvus的相关组件。这里我们采用Docker来进行快速启动。

2.1 依赖安装

pip install llama-index llama-index-vector-stores-milvus pymilvus


2.2 导包与配置

里我们使用 OpenAI 格式的接口(例如智谱 GLM-4 或 DeepSeek),你需要填入自己的 API Key。

python 复制代码
import asyncio
from llama_index.core import (
    VectorStoreIndex, 
    Document, 
    StorageContext, 
    Settings,
)
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.postprocessor import SimilarityPostprocessor # 关键组件:用于过滤低分结果

# === 配置部分 ===
MILVUS_URI = "http://localhost:19530"
COLLECTION_NAME = "csdn_demo_crud"
EMBEDDING_DIM = 2048 # 注意:必须与 embedding 模型维度一致!

# 初始化 Embedding 模型 (这里以 GLM 为例)
try:
    # 假设你有 config.py 存储密钥,或者直接写字符串
    from example.zy0108.config import config 
    Settings.embed_model = OpenAIEmbedding(
        model_name="embedding-3",
        api_key=config.GLM_API_KEY, 
        api_base="https://open.bigmodel.cn/api/paas/v4",
    )
except Exception as e:
    print("配置模型失败,请检查 API Key")

2.3 解决 Windows 下的 Asyncio 痛点

初学者在 Windows 运行 LlamaIndex + Milvus 常遇到 ConnectionConfigException 或 RuntimeError: no running event loop 。这是因为 Windows 的事件循环策略与 Milvus 的异步库有冲突。

解决方案:封装一个智能的获取 Store 的函数。

python 复制代码
async def _init_store_async(overwrite: bool):
    """实际执行初始化的异步函数"""
    return MilvusVectorStore(
        uri=MILVUS_URI,
        collection_name=COLLECTION_NAME,
        dim=EMBEDDING_DIM,
        overwrite=overwrite # True=重建集合, False=使用现有
    )

def get_vector_store(overwrite: bool = False):
    """
    【核心技巧】智能获取 Milvus 实例
    自动判断当前是否有 EventLoop,解决 Windows 同步/异步环境兼容性问题
    """
    try:
        # 场景1: 如果已经在 Loop 中 (如 Jupyter 或 其他异步函数内部)
        loop = asyncio.get_event_loop()
        return loop.run_until_complete(_init_store_async(overwrite))
    except RuntimeError:
        # 场景2: 如果是普通脚本运行,没有 Loop,则新建一个
        return asyncio.run(_init_store_async(overwrite))

2.4 增加操作

将文本转为 Vector 并存入 Milvus。

python 复制代码
def create_and_insert():
    print("\n=== 1. CREATE & INSERT (增) ===")
    
    # 准备数据
    documents = [
        Document(text="LlamaIndex 是一个用于构建 LLM 应用的数据框架。", metadata={"category": "AI"}),
        Document(text="Milvus 是一个高性能的向量数据库。", metadata={"category": "DB"}),
        Document(text="Python 是一种广泛使用的编程语言。", metadata={"category": "Lang"})
    ]
    
    # 获取 Store (overwrite=True 表示清空旧数据,重新开始)
    vector_store = get_vector_store(overwrite=True)
    
    # 创建 StorageContext
    storage_context = StorageContext.from_defaults(vector_store=vector_store)
    
    # 这一步会自动调用 Embedding 模型,计算向量并存入 Milvus
    index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
    
    print(f"成功插入 {len(documents)} 条数据。")
    return index

2.5 实现"查" 并解决"乱匹配"问题

新手常见坑 :问"西瓜",Milvus 却返回"Python"。 原因 :向量检索默认返回 Top-K(距离最近的),哪怕最近的也很远。 解法 :使用 SimilarityPostprocessor 设置阈值。

要注意的是,相似度的阈值需要自己进行测试,不同模型生成的向量,阈值可能不同。测试方法可以,将完全相同的文本得到的分数作为最接近的。比如"Milvus 是一个高性能的向量数据库"。我们搜索:Milvus 是一个高性能的向量数据库。以这个输出作为最高的阈值,比如"Milvus 是一个高性能的向量数据库",我们搜索:milvus,以这个输出作为我们匹配的一个阈值。

python 复制代码
def query_data(query_text: str):
    print(f"\n=== 2. RETRIEVE (查): '{query_text}' ===")
    
    # 连接现有集合 (overwrite=False)
    vector_store = get_vector_store(overwrite=False)
    index = VectorStoreIndex.from_vector_store(vector_store=vector_store)
    
    # 1. 先检索 (Top 1)
    retriever = index.as_retriever(similarity_top_k=1)
    nodes = retriever.retrieve(query_text)
    
    # 2. 【关键】后处理:过滤掉相似度低于 0.4 的结果
    # 0.4 是个经验值,不同模型可能不同,建议自己测试
    processor = SimilarityPostprocessor(similarity_cutoff=0.4)
    results = processor.postprocess_nodes(nodes)
    
    if not results:
        print("未找到相关结果 (相似度过低,已过滤)。")
    else:
        for res in results:
            print(f"找到匹配:\n  - 内容: {res.get_text()}\n  - 分数: {res.score}")
            return res.node.ref_doc_id 

2.6 实现"删"与"改"

删 :通过 doc_id 删除。

改 :向量库通常不支持直接 Update。标准做法是 先删后增 。

python 复制代码
def delete_data(doc_id: str):
    print(f"\n=== 3. DELETE (删): Doc ID '{doc_id}' ===")
    vector_store = get_vector_store(overwrite=False)
    vector_store.delete(ref_doc_id=doc_id)
    print("删除成功。")

3.运行效果展示

在 if name == "main": 中调用上述函数:

python 复制代码
if __name__ == "__main__":
    # 1. 插入数据
    create_and_insert()
    
    # 2. 测试无关问题 (验证过滤器)
    # 问: "你知道什么是西瓜吗" -> 库里只有 AI/DB/Python 知识
    # 预期输出: 未找到相关结果
    query_data("你知道什么是西瓜吗")
    
    # 3. 测试相关问题
    # 问: "什么是 LlamaIndex?"
    # 预期输出: 找到匹配,分数 > 0.4
    query_data("什么是 LlamaIndex?")

相关截图:


4.避坑指南总结

(1)Windows 异步报错 : 不要直接在全局用 MilvusVectorStore ,务必用 asyncio.run 或 loop.run_until_complete 包裹初始化过程。
(2)维度不匹配 : EMBEDDING_DIM 必须和你的模型输出一致(OpenAI text-embedding-3-small 默认 1536,智谱可能不同,务必确认)。
(3)乱匹配 : 一定要加 SimilarityPostprocessor ,否则只要库里有数据,随便问什么都会有返回。
**(4)覆盖数据 :**初始化时 overwrite=True 会删除旧集合,生产环境请慎用

相关推荐
玖日大大1 天前
Milvus 深度解析:开源向量数据库的技术架构、实践指南与生态生态
数据库·开源·milvus
薛定谔的猫19823 天前
LlamaIndex(二)加载本地数据
llamaindex
薛定谔的猫19823 天前
LlamaIndex(一)初见
llama·llamaindex
长路 ㅤ   3 天前
Milvus向量库Java对接使用指南
milvus·向量数据库·索引优化·混合搜索·ann搜索
福大大架构师每日一题5 天前
milvus v2.6.8 发布:搜索高亮上线,性能与稳定性全面跃升,生产环境强烈推荐升级
android·java·milvus
Clarence Liu7 天前
Milvus学习(1) 架构和部署
学习·架构·milvus
托尼吴8 天前
milvus 向量数据库学习笔记-基础认识
数据库·学习·milvus
liuc03178 天前
调用embedding生成向量并存储到milvus中,进行查询
embedding·milvus
西柚小萌新10 天前
【大模型:RAG】--向量数据库Milvus详解2
数据库·milvus