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 会删除旧集合,生产环境请慎用

相关推荐
高铭杰3 天前
LlamaIndex实用入门案例(可执行)
agent·llvm·rag·llamaindex
领航猿1号4 天前
Langchain 1.0.2 从入门到精通(含基础、RAG、Milvus、Ollama、MCP、Agents)
langchain·agent·milvus·rag·mcp·langchain 1.0
Knight_AL5 天前
Docker 部署 Milvus 并连接现有 MinIO 对象存储
docker·eureka·milvus
码农阿豪5 天前
基于Milvus与混合检索的云厂商文档智能问答系统:Java SpringBoot全栈实现
java·spring boot·milvus
GeminiJM5 天前
亿级向量检索:Elasticsearch vs. Milvus,性能鸿沟与架构抉择
elasticsearch·架构·milvus
福大大架构师每日一题7 天前
milvus v2.6.9 发布:支持主键搜索、段重开机制、日志性能全面提升!
android·java·milvus
Lkygo10 天前
milvus快速入门(包含图片搜索)
milvus
molaifeng10 天前
告别大模型幻觉:深度解析 RAG 文档切割艺术与 Milvus 高性能实战
milvus·rag
storyseek12 天前
关于Milvus向量数据库的基础
数据库·milvus
Zilliz Planet13 天前
熠智AI+Milvus:从Embedding 到数据处理、问题重写,电商AI客服架构怎么搭?
人工智能·架构·embedding·milvus