Azure Cosmos DB for NoSQL 支持查询具有灵活模式的项,并原生支持 JSON。它现在提供向量索引和搜索功能。此功能旨在处理高维向量,能够在任何规模下实现高效、准确的向量搜索。你现在可以直接将向量与数据一起存储在文档中。数据库中的每个文档不仅可以包含传统的无模式数据,还可以包含作为文档其他属性的高维向量。
了解如何利用 Azure Cosmos DB for NoSQL 的向量搜索功能,请参阅此页面 。如果你没有 Azure 账户,可以创建一个免费账户 来开始使用。
首先,你需要安装 @langchain/azure-cosmosdb 包:
有关安装 LangChain 包的通用说明,请参阅此部分 。
npm install @langchain/azure-cosmosdb @langchain/core
你还需要一个正在运行的 Azure Cosmos DB for NoSQL 实例。你可以按照此指南 在 Azure 门户上免费部署一个实例,无需任何费用。
一旦你的实例开始运行,请确保你拥有连接字符串。你可以在 Azure 门户中实例的“设置 / 密钥”部分找到它们。然后你需要设置以下环境变量:
# 使用连接字符串进行身份验证
AZURE_COSMOSDB_NOSQL_CONNECTION_STRING =
# 使用托管标识进行身份验证
AZURE_COSMOSDB_NOSQL_ENDPOINT =
使用 Azure 托管标识
如果你使用 Azure 托管标识,可以这样配置凭据:
import { AzureCosmosDBNoSQLVectorStore } from "@langchain/azure-cosmosdb" ;
import { OpenAIEmbeddings } from "@langchain/openai" ;
// 创建 Azure Cosmos DB 向量存储
const store = new AzureCosmosDBNoSQLVectorStore ( new OpenAIEmbeddings () , {
// 或使用环境变量 AZURE_COSMOSDB_NOSQL_ENDPOINT
endpoint : "https://my-cosmosdb.documents.azure.com:443/" ,
// 数据库和容器必须已存在
databaseName : "my-database" ,
containerName : "my-container" ,
} ) ;
使用 Azure 托管标识和基于角色的访问控制时,必须确保数据库和容器已预先创建。RBAC 不提供创建数据库和容器的权限。你可以在 Azure Cosmos DB 文档 中获取有关权限模型的更多信息。
使用筛选器时的安全注意事项
如果数据未经过适当清理,使用用户提供的输入进行筛选可能存在安全风险。请遵循以下建议以防止潜在的安全问题。
允许将原始用户输入连接到类似 SQL 的子句中——例如 WHERE ${userFilter}——会引入 SQL 注入攻击的重大风险,可能导致意外数据泄露或损害系统完整性。为缓解此问题,请始终使用 Azure Cosmos DB 的参数化查询机制,传入 @param 占位符,这可以将查询逻辑与用户提供的输入清晰地分离开来。
以下是一个不安全代码的示例:
import { AzureCosmosDBNoSQLVectorStore } from "@langchain/azure-cosmosdb" ;
const store = new AzureCosmosDBNoSQLVectorStore (embeddings , {} ) ;
// 不安全:用户控制的输入被注入到查询中
const userId = req . query . userId ; // 例如 "123' OR 1=1"
const unsafeQuerySpec = {
query : `SELECT * FROM c WHERE c.metadata.userId = ' ${ userId } '` ,
};
await store . delete ( { filter : unsafeQuerySpec } ) ;
如果攻击者提供 123 OR 1=1,则查询变为 SELECT * FROM c WHERE c.metadata.userId = '123' OR 1=1,这会强制条件始终为真,从而绕过预期的筛选器并删除所有文档。
为防止此注入风险,你可以定义一个占位符(如 @userId),Cosmos DB 会将用户输入单独绑定为参数,确保其被严格视为数据而非可执行的查询逻辑,如下所示。
import { SqlQuerySpec } from "@azure/cosmos" ;
const safeQuerySpec : SqlQuerySpec = {
query : "SELECT * FROM c WHERE c.metadata.userId = @userId" ,
parameters : [ { name : "@userId" , value : userId } ] ,
};
await store . delete ( { filter : safeQuerySpec } ) ;
现在,如果攻击者输入 123 OR 1=1,该输入将被视为要匹配的字面字符串值,而不是查询结构的一部分。
有关更多用法示例和最佳实践,请参阅关于 Azure Cosmos DB for NoSQL 中的参数化查询 的官方文档。
使用示例
以下是一个示例,它将文件中的文档索引到 Azure Cosmos DB for NoSQL 中,运行向量搜索查询,最后使用链基于检索到的文档以自然语言回答问题。
import { AzureCosmosDBNoSQLVectorStore } from "@langchain/azure-cosmosdb" ;
import { ChatPromptTemplate } from "@langchain/core/prompts" ;
import { ChatOpenAI , OpenAIEmbeddings } from "@langchain/openai" ;
import { createStuffDocumentsChain } from "@langchain/classic/chains/combine_documents" ;
import { createRetrievalChain } from "@langchain/classic/chains/retrieval" ;
import { TextLoader } from "@langchain/classic/document_loaders/fs/text" ;
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters" ;
// 从文件加载文档
const loader = new TextLoader ( "./state_of_the_union.txt" ) ;
const rawDocuments = await loader . load () ;
const splitter = new RecursiveCharacterTextSplitter ( {
chunkSize : 1000 ,
chunkOverlap : 0 ,
} ) ;
const documents = await splitter . splitDocuments (rawDocuments) ;
// 创建 Azure Cosmos DB 向量存储
const store = await AzureCosmosDBNoSQLVectorStore . fromDocuments (
documents ,
new OpenAIEmbeddings () ,
{
databaseName : "langchain" ,
containerName : "documents" ,
}
) ;
// 执行相似性搜索
const resultDocuments = await store . similaritySearch (
"总统对凯坦吉·布朗·杰克逊说了什么?"
) ;
console . log ( "相似性搜索结果:" ) ;
console . log (resultDocuments[ 0 ] . pageContent) ;
/*
今晚。我呼吁参议院:通过《自由投票法案》。通过《约翰·刘易斯投票权法案》。并且,在你们这样做的时候,通过《披露法案》,以便美国人能够知道谁在资助我们的选举。
今晚,我想向一位毕生致力于服务这个国家的人致敬:斯蒂芬·布雷耶大法官——一位陆军退伍军人、宪法学者,以及即将退休的美国最高法院大法官。布雷耶大法官,感谢您的服务。
总统最严肃的宪法职责之一是提名某人在美国最高法院任职。
我在四天前就这样做了,当时我提名了巡回上诉法院法官凯坦吉·布朗·杰克逊。她是我国顶尖的法律头脑之一,将继续布雷耶大法官卓越的遗产。
*/
// 将存储用作链的一部分
const model = new ChatOpenAI ( { model : "gpt-3.5-turbo-1106" } ) ;
const questionAnsweringPrompt = ChatPromptTemplate . fromMessages ([
[
"system" ,
"根据以下上下文回答用户的问题: \n\n {context}" ,
] ,
[ "human" , "{input}" ] ,
]) ;
const combineDocsChain = await createStuffDocumentsChain ( {
llm : model ,
prompt : questionAnsweringPrompt ,
} ) ;
const chain = await createRetrievalChain ( {
retriever : store . asRetriever () ,
combineDocsChain ,
} ) ;
const res = await chain . invoke ( {
input : "总统关于价格的首要任务是什么?" ,
} ) ;
console . log ( "链响应:" ) ;
console . log (res . answer) ;
/*
总统的首要任务是控制价格。
*/
// 清理
await store . delete () ;
高级搜索选项
所有搜索类型都通过统一的 similaritySearch 和 similaritySearchWithScore 方法访问,使用筛选选项中的 searchType 参数。搜索类型可作为 AzureCosmosDBNoSQLSearchType 的常量使用:
可用的搜索类型:
AzureCosmosDBNoSQLSearchType.Vector(默认):标准向量相似性搜索
AzureCosmosDBNoSQLSearchType.VectorScoreThreshold:带最低分数筛选的向量搜索
AzureCosmosDBNoSQLSearchType.FullTextSearch:使用 FullTextContains 的全文搜索(预览版)
AzureCosmosDBNoSQLSearchType.FullTextRanking:带 BM25 排名的全文搜索(预览版)
AzureCosmosDBNoSQLSearchType.Hybrid:使用 RRF 的混合向量 + 全文搜索(预览版)
AzureCosmosDBNoSQLSearchType.HybridScoreThreshold:带分数阈值的混合搜索(预览版)
你也可以在创建存储时使用 defaultSearchType 配置选项设置默认搜索类型,这样就不必在每次查询中都指定它:
import {
AzureCosmosDBNoSQLVectorStore ,
AzureCosmosDBNoSQLSearchType ,
} from "@langchain/azure-cosmosdb" ;
import { OpenAIEmbeddings } from "@langchain/openai" ;
const store = new AzureCosmosDBNoSQLVectorStore ( new OpenAIEmbeddings () , {
databaseName : "langchain" ,
containerName : "documents" ,
defaultSearchType : AzureCosmosDBNoSQLSearchType . VectorScoreThreshold ,
} ) ;
带分数阈值的向量搜索
根据最低相似性分数筛选结果:
import {
AzureCosmosDBNoSQLVectorStore ,
AzureCosmosDBNoSQLSearchType ,
} from "@langchain/azure-cosmosdb" ;
import { OpenAIEmbeddings } from "@langchain/openai" ;
const store = new AzureCosmosDBNoSQLVectorStore ( new OpenAIEmbeddings () , {
databaseName : "langchain" ,
containerName : "documents" ,
} ) ;
// 仅返回相似性分数 >= 0.8 的结果
const results = await store . similaritySearchWithScore (
"法国的首都是哪里?" ,
10 ,
{
searchType : AzureCosmosDBNoSQLSearchType . VectorScoreThreshold ,
threshold : 0.8 ,
}
) ;
for ( const [ doc , score ] of results) {
console . log ( `分数: ${ score } ,内容: ${ doc . pageContent } ` ) ;
}
最大边际相关性(MMR)搜索
MMR 搜索在结果的相关性和多样性之间取得平衡:
import { AzureCosmosDBNoSQLVectorStore } from "@langchain/azure-cosmosdb" ;
import { OpenAIEmbeddings } from "@langchain/openai" ;
const store = new AzureCosmosDBNoSQLVectorStore ( new OpenAIEmbeddings () , {
databaseName : "langchain" ,
containerName : "documents" ,
} ) ;
const results = await store . maxMarginalRelevanceSearch ( "机器学习" , {
k : 5 , // 要返回的结果数量
fetchK : 20 , // 要考虑的候选数量
lambda : 0.5 , // 0 = 最大多样性,1 = 最大相关性
} ) ;
全文和混合搜索(预览版)
全文和混合搜索是 Azure Cosmos DB 中的预览功能。你需要使用全文策略和适当的索引配置容器才能使用这些功能。有关设置说明,请参阅 Azure Cosmos DB 文档 。
要使用全文或混合搜索,请在创建存储时启用它:
import {
AzureCosmosDBNoSQLVectorStore ,
AzureCosmosDBNoSQLSearchType ,
} from "@langchain/azure-cosmosdb" ;
import { OpenAIEmbeddings } from "@langchain/openai" ;
const store = new AzureCosmosDBNoSQLVectorStore ( new OpenAIEmbeddings () , {
databaseName : "langchain" ,
containerName : "documents" ,
fullTextSearchEnabled : true ,
fullTextPolicy : {
defaultLanguage : "en-US" ,
fullTextPaths : [ { path : "/text" , language : "en-US" } ] ,
},
indexingPolicy : {
indexingMode : "consistent" ,
automatic : true ,
includedPaths : [ { path : "/*" } ] ,
excludedPaths : [ { path : "/_etag/?" } ] ,
vectorIndexes : [ { path : "/vector" , type : "quantizedFlat" } ] ,
fullTextIndexes : [ { path : "/text" } ] ,
},
} ) ;
全文搜索
// 在筛选子句中使用 FullTextContains 进行全文搜索
const fullTextResults = await store . similaritySearch ( "" , 10 , {
searchType : AzureCosmosDBNoSQLSearchType . FullTextSearch ,
filterClause : "WHERE FullTextContains(c.text, 'artificial intelligence')" ,
} ) ;
全文排名
// 使用 BM25 评分的全文排名
const rankingResults = await store . similaritySearch ( "" , 10 , {
searchType : AzureCosmosDBNoSQLSearchType . FullTextRanking ,
fullTextRankFilter : [
{ searchField : "text" , searchText : "artificial intelligence" },
] ,
} ) ;
混合搜索
混合搜索使用倒数排名融合(RRF)结合向量相似性和全文搜索:
// 结合向量和全文结果的混合搜索
const hybridResults = await store . similaritySearchWithScore (
"机器学习" ,
10 ,
{
searchType : AzureCosmosDBNoSQLSearchType . Hybrid ,
fullTextRankFilter : [
{ searchField : "text" , searchText : "机器学习" },
] ,
}
) ;
// 带分数阈值的混合搜索
const filteredResults = await store . similaritySearchWithScore (
"机器学习" ,
10 ,
{
searchType : AzureCosmosDBNoSQLSearchType . HybridScoreThreshold ,
fullTextRankFilter : [
{ searchField : "text" , searchText : "机器学习" },
] ,
threshold : 0.5 ,
}
) ;
实用方法
删除文档
// 通过 ID 删除特定文档
await store . delete ( { ids : [ "document-id-123" ] } ) ;
// 删除匹配筛选器的文档
await store . delete ( {
filter : {
query : "SELECT * FROM c WHERE c.metadata.category = @category" ,
parameters : [ { name : "@category" , value : "old" } ] ,
},
} ) ;
// 删除所有文档
await store . delete () ;
访问底层容器
// 直接访问 Cosmos DB 容器以进行高级操作
const container = store . getContainer () ;
const { resources } = await container . items
. query ( "SELECT * FROM c WHERE c.metadata.category = 'tech'" )
. fetchAll () ;
相关内容
将这些文档 通过 MCP 连接到 Claude、VSCode 等,以获取实时答案。