VectorStore(向量数据库)¶
tRPC-Python-Agent 框架通过 LangchainKnowledge 支持多种向量数据库后端。向量数据库(VectorStore)用于存储文本的向量化表示(Embedding),并基于向量相似度进行高效检索,是构建 RAG(检索增强生成)应用的核心组件。本文档介绍如何在框架中接入和使用以下向量数据库:
PGVector¶
安装依赖¶
pip install -qU langchain-postgres
使用¶
创建 PGVector 对象并构造 LangchainKnowledge:
from trpc_agent_sdk.server.knowledge.langchain_knowledge import LangchainKnowledge
def _build_pgvector_knowledge() -> LangchainKnowledge:
"""Build knowledge with PGVector vectorstore"""
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_postgres import PGVector
config = get_pgvector_config()
# 初始化 Embedding 模型,将文本转化为向量表示
embedder = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")
# 创建 PGVector 实例;use_jsonb=True 使用 JSONB 格式存储元数据,支持结构化过滤
vectorstore = PGVector(
embeddings=embedder,
collection_name=config["collection_name"],
connection=config["connection"],
use_jsonb=True,
)
text_loader = TextLoader(KNOWLEDGE_FILE, encoding="utf-8")
# chunk_size 和 chunk_overlap 控制文档分块粒度,影响检索精度
text_splitter = RecursiveCharacterTextSplitter(separators=["\n"], chunk_size=10, chunk_overlap=0)
# 将各组件组装为 LangchainKnowledge,统一管理文档加载、分割、向量化和检索
return LangchainKnowledge(
prompt_template=rag_prompt,
document_loader=text_loader,
document_transformer=text_splitter,
embedder=embedder,
vectorstore=vectorstore,
)
说明:确保启动了具有 pgvector 扩展的 PostgreSQL 数据库。连接参数通过环境变量配置,详见 examples/knowledge_with_vectorstore/agent/config.py 中的 get_pgvector_config()。
如何从文档构建向量数据库¶
如果是知识库已在PGVector上构建好,则可跳过此部分,直接进行检索即可。否则,可以按如下步骤进行构建。我们支持如下方式:
1) 使用LangchainKnowledge成员方法create_vectorstore_from_document构建向量数据库
# examples/knowledge_with_vectorstore/run_agent.py
from agent.tools import rag
# 从文档创建向量数据库(如知识库已构建好,可跳过此步骤)
await rag.create_vectorstore_from_document()
2) 使用PGVector成员方法add_documents添加数据到向量数据库
以下为简单示例:
from langchain_core.documents import Document
docs = [
Document(
page_content="there are cats in the pond",
metadata={"id": 1, "location": "pond", "topic": "animals"},
),
Document(
page_content="ducks are also found in the pond",
metadata={"id": 2, "location": "pond", "topic": "animals"},
),
Document(
page_content="fresh apples are available at the market",
metadata={"id": 3, "location": "market", "topic": "food"},
),
]
# 将文档添加到向量数据库,ids 用于去重和后续更新
vectorstore.add_documents(docs, ids=[doc.metadata["id"] for doc in docs])
3) 直接使用PGVector的类方法from_documents构建向量数据库
from langchain_community.document_loaders import TextLoader
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_text_splitters import CharacterTextSplitter
from langchain_postgres import PGVector
from agent.config import get_pgvector_config
config = get_pgvector_config()
# 加载并分割文档
loader = TextLoader("test.txt", encoding="utf-8")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
embedder = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")
# from_documents 一步完成向量化 + 写入数据库,返回可查询的 vectorstore 实例
vectorstore = PGVector.from_documents(
documents=docs,
embedding=embedder,
collection_name=config["collection_name"],
connection=config["connection"],
use_jsonb=True,
)
如何使用向量数据库进行检索¶
1) 使用LangchainKnowledge的成员方法search
# examples/knowledge_with_vectorstore/agent/tools.py
async def simple_search(query: str):
"""Search the knowledge base for relevant documents"""
metadata = {
'assistant_name': 'test',
'runnable_config': {},
}
# 构造 Agent 上下文,timeout 设置检索超时(毫秒)
ctx = new_agent_context(timeout=3000, metadata=metadata)
# 将查询文本封装为 SearchRequest
sr: SearchRequest = SearchRequest()
sr.query = Part.from_text(text=query)
# 执行向量相似度检索,返回按相关性排序的文档列表
search_result: SearchResult = await rag.search(ctx, sr)
if len(search_result.documents) == 0:
return {"status": "failed", "report": "No documents found"}
# 取相似度最高的首条文档
best_doc = search_result.documents[0].document
return {"status": "success", "report": f"content: {best_doc.page_content}"}
2) 使用PGVector的成员方法similarity_search
results = vectorstore.similarity_search(
query="LangChain provides abstractions to make working with LLMs easy",
k=2, # 返回 Top-K 条最相似结果
filter=[{"term": {"metadata.source.keyword": "tweet"}}], # 基于元数据进行过滤
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
如何使用向量数据库创建检索器¶
使用PGVector的成员方法as_retriever获取检索器
# search_type="mmr" 使用最大边际相关性算法,兼顾相关性与多样性
retriever = vectorstore.as_retriever(search_type="mmr", search_kwargs={"k": 1})
retriever.invoke("kitty")
参考文档¶
Elasticsearch¶
安装依赖¶
pip install -qU langchain-elasticsearch
使用¶
创建 ElasticsearchStore 对象并构造 LangchainKnowledge(完整代码见 examples/knowledge_with_vectorstore/agent/tools.py):
def _build_elasticsearch_knowledge() -> LangchainKnowledge:
"""Build knowledge with Elasticsearch vectorstore"""
from langchain_elasticsearch import ElasticsearchStore
from langchain_huggingface import HuggingFaceEmbeddings
config = get_elasticsearch_config()
embedder = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")
# 创建 ElasticsearchStore 实例,通过 es_api_key 进行身份认证
vectorstore = ElasticsearchStore(
es_url=config["es_url"],
index_name=config["index_name"],
embedding=embedder,
es_api_key=config["es_api_key"],
)
text_loader = TextLoader(KNOWLEDGE_FILE, encoding="utf-8")
text_splitter = RecursiveCharacterTextSplitter(separators=["\n"], chunk_size=10, chunk_overlap=0)
# 组装 LangchainKnowledge,与 PGVector 用法一致,仅 vectorstore 后端不同
return LangchainKnowledge(
prompt_template=rag_prompt,
document_loader=text_loader,
document_transformer=text_splitter,
embedder=embedder,
vectorstore=vectorstore,
)
说明:连接参数通过环境变量配置,详见 examples/knowledge_with_vectorstore/agent/config.py 中的 get_elasticsearch_config()。
如何从文档构建向量数据库¶
如果是知识库已在Elasticsearch上构建好,则可跳过此部分,直接进行检索即可。否则,可以按如下步骤进行构建。我们支持如下方式:
1) 使用LangchainKnowledge成员方法create_vectorstore_from_document构建向量数据库
# examples/knowledge_with_vectorstore/run_agent.py
from agent.tools import rag, get_create_vectorstore_kwargs
# Elasticsearch 需要传递额外连接参数,由 get_create_vectorstore_kwargs() 自动生成
await rag.create_vectorstore_from_document(**get_create_vectorstore_kwargs())
get_create_vectorstore_kwargs() 对于 Elasticsearch 返回如下参数:
def get_create_vectorstore_kwargs() -> dict:
"""Return extra kwargs for create_vectorstore_from_document based on vectorstore type"""
vstore_type = get_vectorstore_type()
# ...
elif vstore_type == "elasticsearch":
config = get_elasticsearch_config()
# 这些参数会传递给 LangchainKnowledge.create_vectorstore_from_document()
return {
"es_url": config["es_url"],
"index_name": config["index_name"],
"es_api_key": config["es_api_key"],
}
2) 使用ElasticsearchStore成员方法add_documents构建向量数据库
import uuid
from agent.tools import rag
async def create_vectorstore_from_document():
# 异步加载原始文档
documents = await rag.document_loader.aload()
# 将文档按配置的分割策略切分为小块
documents = await rag.document_transformer.atransform_documents(documents)
# 为每个文档块生成唯一 ID,确保可去重和更新
uuids = [str(uuid.uuid4()) for _ in range(len(documents))]
# 异步将文档块向量化并写入向量数据库
added_ids = await rag.vectorstore.aadd_documents(documents=documents, ids=uuids)
return added_ids
3) 直接使用ElasticsearchStore的类方法from_documents构建向量数据库
from langchain_community.document_loaders import TextLoader
from langchain_elasticsearch import ElasticsearchStore
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_text_splitters import CharacterTextSplitter
from agent.config import get_elasticsearch_config
config = get_elasticsearch_config()
# 加载并分割文档
loader = TextLoader("test.txt", encoding="utf-8")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
embedder = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")
# from_documents 一步完成向量化 + 写入 Elasticsearch,返回可查询的 vectorstore 实例
vectorstore = ElasticsearchStore.from_documents(
documents=docs,
embedding=embedder,
es_url=config["es_url"],
index_name=config["index_name"],
es_api_key=config["es_api_key"],
)
如何使用向量数据库进行检索¶
1) 使用LangchainKnowledge的成员方法search
# examples/knowledge_with_vectorstore/agent/tools.py
async def simple_search(query: str):
"""Search the knowledge base for relevant documents"""
metadata = {
'assistant_name': 'test',
'runnable_config': {},
}
# 构造 Agent 上下文,timeout 设置检索超时(毫秒)
ctx = new_agent_context(timeout=3000, metadata=metadata)
# 将查询文本封装为 SearchRequest
sr: SearchRequest = SearchRequest()
sr.query = Part.from_text(text=query)
# 执行向量相似度检索,返回按相关性排序的文档列表
search_result: SearchResult = await rag.search(ctx, sr)
if len(search_result.documents) == 0:
return {"status": "failed", "report": "No documents found"}
# 取相似度最高的首条文档
best_doc = search_result.documents[0].document
return {"status": "success", "report": f"content: {best_doc.page_content}"}
2) 使用ElasticsearchStore的成员方法similarity_search
results = vectorstore.similarity_search(
query="LangChain provides abstractions to make working with LLMs easy",
k=2, # 返回 Top-K 条最相似结果
filter=[{"term": {"metadata.source.keyword": "tweet"}}], # 基于元数据进行过滤
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
3) 设置检索策略:使用ElasticsearchStore的类方法from_documents,通过参数strategy设置检索策略
from langchain_elasticsearch import DenseVectorStrategy
from agent.config import get_elasticsearch_config
config = get_elasticsearch_config()
vectorstore = ElasticsearchStore.from_documents(
documents=docs,
embedding=embedder,
es_url=config["es_url"],
index_name=config["index_name"],
es_api_key=config["es_api_key"],
strategy=DenseVectorStrategy(), # 使用稠密向量检索策略,也可选 SparseVectorStrategy 等
)
docs = vectorstore.similarity_search(
query="What did the president say about Ketanji Brown Jackson?", k=10
)
说明:更多检索策略详见LangChain Elasticsearch Retrieval Strategies
如何使用向量数据库创建检索器¶
1) 使用ElasticsearchStore的成员方法as_retriever获取检索器
# similarity_score_threshold 仅返回相似度高于阈值的结果,过滤低质量匹配
retriever = vectorstore.as_retriever(
search_type="similarity_score_threshold", search_kwargs={"score_threshold": 0.2}
)
retriever.invoke("Stealing from the bank is a crime")
2) 使用ElasticsearchRetriever的类方法from_es_params创建检索器
from langchain_elasticsearch import ElasticsearchRetriever
# 自定义向量查询函数,返回 Elasticsearch 原生 KNN 查询 DSL
def vector_query(search_query: str) -> Dict:
vector = embeddings.embed_query(search_query) # 使用与索引时相同的 Embedding 模型
return {
"knn": {
"field": dense_vector_field,
"query_vector": vector,
"k": 5, # 返回最相似的 5 条结果
"num_candidates": 10, # 候选集大小,越大精度越高但性能越低
}
}
# 通过 ES 原生参数创建检索器,body_func 允许完全自定义查询逻辑
vector_retriever = ElasticsearchRetriever.from_es_params(
index_name=index_name,
body_func=vector_query,
content_field=text_field,
url=es_url,
)
vector_retriever.invoke("foo")
说明:更多类型的检索器详见LangChain Elasticsearch Retriever
参考文档¶
Tencent Cloud VectorDB(腾讯云向量数据库)¶
安装依赖¶
pip3 install tcvectordb langchain-community
使用¶
创建 TencentVectorDB 对象并构造 LangchainKnowledge:
def _build_tencentvdb_knowledge() -> LangchainKnowledge:
"""Build knowledge with Tencent Cloud VectorDB"""
from langchain_community.vectorstores.tencentvectordb import (
ConnectionParams,
IndexParams,
TencentVectorDB,
)
config = get_tencentvdb_config()
connection_params = ConnectionParams(
url=config["url"],
key=config["key"],
username=config["username"],
timeout=20,
)
# dimension 需与所用 Embedding 模型的输出维度一致
index_params = IndexParams(dimension=768, replicas=0)
# 腾讯云向量数据库支持服务端内置 Embedding,无需外部 Embedding 模型,因此传 None
embeddings = None
vectorstore = TencentVectorDB(
embedding=embeddings,
connection_params=connection_params,
index_params=index_params,
database_name=config["database_name"],
collection_name=config["collection_name"],
t_vdb_embedding=config["t_vdb_embedding"], # 指定服务端内置的 Embedding 模型
)
text_loader = TextLoader(KNOWLEDGE_FILE, encoding="utf-8")
text_splitter = RecursiveCharacterTextSplitter(separators=["\n"], chunk_size=10, chunk_overlap=0)
# embedder 传 None,因为向量化由腾讯云服务端完成
return LangchainKnowledge(
prompt_template=rag_prompt,
document_loader=text_loader,
document_transformer=text_splitter,
embedder=None,
vectorstore=vectorstore,
)
说明:连接参数通过环境变量配置,详见 examples/knowledge_with_vectorstore/agent/config.py 中的 get_tencentvdb_config()。
如何从文档构建向量数据库¶
如果是知识库已在腾讯云向量数据库上构建好,则可跳过此部分,直接进行检索即可。否则,可以按如下步骤进行构建。我们支持如下方式:
1) 使用LangchainKnowledge成员方法create_vectorstore_from_document构建向量数据库
# examples/knowledge_with_vectorstore/run_agent.py
from agent.tools import rag, get_create_vectorstore_kwargs
# 腾讯云向量数据库需要传递额外连接参数,由 get_create_vectorstore_kwargs() 自动生成
await rag.create_vectorstore_from_document(**get_create_vectorstore_kwargs())
get_create_vectorstore_kwargs() 对于腾讯云向量数据库返回如下参数:
def get_create_vectorstore_kwargs() -> dict:
"""Return extra kwargs for create_vectorstore_from_document based on vectorstore type"""
vstore_type = get_vectorstore_type()
if vstore_type == "tencentvdb":
from langchain_community.vectorstores.tencentvectordb import (
ConnectionParams,
IndexParams,
)
config = get_tencentvdb_config()
# 这些参数会传递给 LangchainKnowledge.create_vectorstore_from_document()
# 用于在腾讯云服务端创建向量数据库集合
return {
"embeddings": None,
"connection_params": ConnectionParams(
url=config["url"],
key=config["key"],
username=config["username"],
timeout=20,
),
"index_params": IndexParams(dimension=768, replicas=0),
"database_name": config["database_name"],
"collection_name": config["collection_name"],
"t_vdb_embedding": config["t_vdb_embedding"],
}
2) 直接使用TencentVectorDB的类方法from_documents构建向量数据库
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores.tencentvectordb import (
ConnectionParams,
TencentVectorDB,
)
from langchain_text_splitters import CharacterTextSplitter
from agent.config import get_tencentvdb_config
config = get_tencentvdb_config()
loader = TextLoader("test.txt", encoding="utf-8")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
conn_params = ConnectionParams(
url=config["url"],
key=config["key"],
username=config["username"],
timeout=20,
)
# 使用服务端内置 Embedding,无需本地 Embedding 模型
embeddings = None
vector_db = TencentVectorDB.from_documents(
docs,
embeddings=embeddings,
connection_params=conn_params,
t_vdb_embedding=config["t_vdb_embedding"], # 指定服务端 Embedding 模型名称
)
说明:from_documents间接调用from_text接口,支持传递更多的接口参数(如数据库名、connection名等),详见from_texts接口定义:
def from_texts(
cls,
texts: List[str],
embedding: Embeddings,
metadatas: Optional[List[dict]] = None,
connection_params: Optional[ConnectionParams] = None,
index_params: Optional[IndexParams] = None,
database_name: str = "LangChainDatabase",
collection_name: str = "LangChainCollection",
drop_old: Optional[bool] = False,
collection_description: Optional[str] = "Collection for LangChain",
meta_fields: Optional[List[MetaField]] = None,
t_vdb_embedding: Optional[str] = "bge-base-zh",
**kwargs: Any,
) -> TencentVectorDB:
3) 使用TencentVectorDB的类方法add_texts往向量数据库中插入数据
# 若未指定文档id,则会随机生成。可通过 ids: Optional[List[str]]参数指定
vector_db.add_texts(["Ankush went to Princeton"])
如何使用向量数据库进行检索¶
1) 使用LangchainKnowledge成员方法search
# examples/knowledge_with_vectorstore/agent/tools.py
async def simple_search(query: str):
"""Search the knowledge base for relevant documents"""
metadata = {
'assistant_name': 'test',
'runnable_config': {},
}
# 构造 Agent 上下文,timeout 设置检索超时(毫秒)
ctx = new_agent_context(timeout=3000, metadata=metadata)
# 将查询文本封装为 SearchRequest
sr: SearchRequest = SearchRequest()
sr.query = Part.from_text(text=query)
# 执行向量相似度检索,返回按相关性排序的文档列表
search_result: SearchResult = await rag.search(ctx, sr)
if len(search_result.documents) == 0:
return {"status": "failed", "report": "No documents found"}
# 取相似度最高的首条文档
best_doc = search_result.documents[0].document
return {"status": "success", "report": f"content: {best_doc.page_content}"}
2) 使用TencentVectorDB的成员方法similarity_search
query = "What did the president say about Ketanji Brown Jackson"
docs = vector_db.similarity_search(query)
print(docs[0].page_content)
参考文档¶
完整示例¶
完整示例可见 knowledge_with_vectorstore,支持 PGVector、Elasticsearch、腾讯云向量数据库三种后端。
示例运行步骤:
- 在 examples/knowledge_with_vectorstore/.env 中配置环境变量,设置
VECTORSTORE_TYPE=tencentvdb并填写腾讯云向量数据库连接参数:
VECTORSTORE_TYPE=tencentvdb
TENCENT_VDB_URL=http://10.0.X.X
TENCENT_VDB_KEY=your_key_here
TENCENT_VDB_USERNAME=root
TENCENT_VDB_DATABASE=LangChainDatabase
TENCENT_VDB_COLLECTION=LangChainCollection
TENCENT_VDB_EMBEDDING=bge-base-zh
- 准备知识库文档
默认使用项目下的 test.txt 作为知识库文档。你可以替换为自己的文档,或通过 KNOWLEDGE_FILE 环境变量指定路径:
echo "shenzhen weather: sunny
guangzhou weather: rain
shanghai weather: cloud" > test.txt
- 运行示例
cd examples/knowledge_with_vectorstore/
python3 run_agent.py
程序会自动从文档构建向量数据库,然后 Agent 接收查询后调用 simple_search 工具进行向量检索,结合检索结果生成回答。