目录
[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 实现“删”与“改”)
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 会删除旧集合,生产环境请慎用