集成 Vector Search 与 LlamaIndex
本教程演示如何将 TiDB 的 vector search 功能与 LlamaIndex 集成。
前置条件
完成本教程,你需要:
- 已安装 Python 3.8 或更高版本。
- 已安装 Jupyter Notebook。
- 已安装 Git。
- 一个 TiDB 集群。
如果你还没有 TiDB 集群,可以按如下方式创建:
- (推荐)参考 创建 TiDB Cloud Starter 集群 创建属于你自己的 TiDB Cloud 集群。
- 参考 部署本地测试 TiDB 集群 或 部署生产环境 TiDB 集群 创建 v8.4.0 或更高版本的本地集群。
快速开始
本节将提供将 TiDB Vector Search 与 LlamaIndex 集成以进行语义检索的分步指南。
步骤 1. 新建 Jupyter Notebook 文件
在项目根目录下,新建一个名为 integrate_with_llamaindex.ipynb 的 Jupyter Notebook 文件:
touch integrate_with_llamaindex.ipynb
步骤 2. 安装所需依赖
在你的项目目录下,运行以下命令安装所需的依赖包:
pip install llama-index-vector-stores-tidbvector
pip install llama-index
在 Jupyter Notebook 中打开 integrate_with_llamaindex.ipynb 文件,并添加以下代码以导入所需包:
import textwrap
from llama_index.core import SimpleDirectoryReader, StorageContext
from llama_index.core import VectorStoreIndex
from llama_index.vector_stores.tidbvector import TiDBVectorStore
步骤 3. 配置环境变量
根据你选择的 TiDB 部署方式配置环境变量。
对于 TiDB Cloud Starter 集群,按以下步骤获取集群连接串并配置环境变量:
进入 Clusters 页面,点击目标集群名称进入集群概览页。
点击右上角的 Connect,弹出连接对话框。
确认连接对话框中的配置与你的操作环境一致。
- Connection Type 设置为
Public。 - Branch 设置为
main。 - Connect With 设置为
SQLAlchemy。 - Operating System 与你的环境一致。
- Connection Type 设置为
点击 PyMySQL 标签页,复制连接串。
配置环境变量。
本文档以 OpenAI 作为嵌入模型提供方为例。在此步骤中,你需要提供上一步获取的连接串和你的 OpenAI API key。
运行以下代码配置环境变量。你将被提示输入连接串和 OpenAI API key:
# 使用 getpass 在终端安全地输入环境变量。 import getpass import os # 从 TiDB Cloud 控制台复制你的连接串。 # 连接串格式: "mysql+pymysql://<USER>:<PASSWORD>@<HOST>:4000/<DB>?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true" tidb_connection_string = getpass.getpass("TiDB Connection String:") os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
本文档以 OpenAI 作为嵌入模型提供方为例。在此步骤中,你需要提供 TiDB 集群的连接串和你的 OpenAI API key。
运行以下代码配置环境变量。你将被提示输入连接串和 OpenAI API key:
# 使用 getpass 在终端安全地输入环境变量。
import getpass
import os
# 连接串格式: "mysql+pymysql://<USER>:<PASSWORD>@<HOST>:4000/<DB>?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true"
tidb_connection_string = getpass.getpass("TiDB Connection String:")
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
以 macOS 为例,集群连接串如下:
TIDB_DATABASE_URL="mysql+pymysql://<USERNAME>:<PASSWORD>@<HOST>:<PORT>/<DATABASE_NAME>"
# 例如: TIDB_DATABASE_URL="mysql+pymysql://root@127.0.0.1:4000/test"
你需要根据自己的 TiDB 集群修改连接串中的参数。如果你在本地运行 TiDB,<HOST> 默认为 127.0.0.1。初始 <PASSWORD> 为空,因此首次启动集群时可以省略该字段。
各参数说明如下:
<USERNAME>:连接 TiDB 集群的用户名。<PASSWORD>:连接 TiDB 集群的密码。<HOST>:TiDB 集群的主机地址。<PORT>:TiDB 集群的端口号。<DATABASE>:你要连接的数据库名称。
步骤 4. 加载示例文档
步骤 4.1 下载示例文档
在你的项目目录下,新建目录 data/paul_graham/,并从 run-llama/llama_index GitHub 仓库下载示例文档 paul_graham_essay.txt。
!mkdir -p 'data/paul_graham/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'
步骤 4.2 加载文档
使用 SimpleDirectoryReader 类从 data/paul_graham/paul_graham_essay.txt 加载示例文档。
documents = SimpleDirectoryReader("./data/paul_graham").load_data()
print("Document ID:", documents[0].doc_id)
for index, document in enumerate(documents):
document.metadata = {"book": "paul_graham"}
步骤 5. 嵌入并存储文档向量
步骤 5.1 初始化 TiDB 向量存储
以下代码会在 TiDB 中创建一个名为 paul_graham_test 的表,该表已针对向量检索进行了优化。
tidbvec = TiDBVectorStore(
connection_string=tidb_connection_url,
table_name="paul_graham_test",
distance_strategy="cosine",
vector_dimension=1536,
drop_existing_table=False,
)
执行成功后,你可以在 TiDB 数据库中直接查看和访问 paul_graham_test 表。
步骤 5.2 生成并存储嵌入向量
以下代码会解析文档,生成嵌入向量,并将其存储到 TiDB 向量存储中。
storage_context = StorageContext.from_defaults(vector_store=tidbvec)
index = VectorStoreIndex.from_documents(
documents, storage_context=storage_context, show_progress=True
)
预期输出如下:
Parsing nodes: 100%|██████████| 1/1 [00:00<00:00, 8.76it/s]
Generating embeddings: 100%|██████████| 21/21 [00:02<00:00, 8.22it/s]
步骤 6. 执行向量检索
以下代码基于 TiDB 向量存储创建查询引擎,并执行语义相似度检索。
query_engine = index.as_query_engine()
response = query_engine.query("What did the author do?")
print(textwrap.fill(str(response), 100))
预期输出如下:
The author worked on writing, programming, building microcomputers, giving talks at conferences,
publishing essays online, developing spam filters, painting, hosting dinner parties, and purchasing
a building for office use.
步骤 7. 使用元数据过滤器进行检索
为了优化检索结果,你可以使用元数据过滤器,仅返回符合过滤条件的最近邻结果。
使用 book != "paul_graham" 过滤器查询
以下示例会排除 book 元数据字段为 "paul_graham" 的结果:
from llama_index.core.vector_stores.types import (
MetadataFilter,
MetadataFilters,
)
query_engine = index.as_query_engine(
filters=MetadataFilters(
filters=[
MetadataFilter(key="book", value="paul_graham", operator="!="),
]
),
similarity_top_k=2,
)
response = query_engine.query("What did the author learn?")
print(textwrap.fill(str(response), 100))
预期输出如下:
Empty Response
使用 book == "paul_graham" 过滤器查询
以下示例仅返回 book 元数据字段为 "paul_graham" 的文档:
from llama_index.core.vector_stores.types import (
MetadataFilter,
MetadataFilters,
)
query_engine = index.as_query_engine(
filters=MetadataFilters(
filters=[
MetadataFilter(key="book", value="paul_graham", operator="=="),
]
),
similarity_top_k=2,
)
response = query_engine.query("What did the author learn?")
print(textwrap.fill(str(response), 100))
预期输出如下:
The author learned programming on an IBM 1401 using an early version of Fortran in 9th grade, then
later transitioned to working with microcomputers like the TRS-80 and Apple II. Additionally, the
author studied philosophy in college but found it unfulfilling, leading to a switch to studying AI.
Later on, the author attended art school in both the US and Italy, where they observed a lack of
substantial teaching in the painting department.
步骤 8. 删除文档
从索引中删除第一个文档:
tidbvec.delete(documents[0].doc_id)
检查文档是否已被删除:
query_engine = index.as_query_engine()
response = query_engine.query("What did the author learn?")
print(textwrap.fill(str(response), 100))
预期输出如下:
Empty Response