如何进行“自我查询”检索
自我查询检索器顾名思义,能够自我查询。具体来说,对于任何自然语言查询,检索器都会使用 LLM 来编写结构化查询,然后将该结构化查询应用于其底层向量存储。这使得检索器不仅可以使用用户输入的查询与存储文档的内容进行语义相似性比较,还可以从用户查询中提取存储文档元数据的过滤器,并执行这些过滤器。
前往 集成 查看支持内置自我查询的向量存储的文档。
开始
为了演示,我们将使用一个内存中未优化的向量存储。在实际构建时,您应该将其替换为支持的生产就绪向量存储。
自我查询检索器要求您安装 peggy
包作为对等依赖项,我们还将在此示例中使用 OpenAI
- npm
- yarn
- pnpm
npm i peggy @langchain/openai @langchain/core
yarn add peggy @langchain/openai @langchain/core
pnpm add peggy @langchain/openai @langchain/core
我们创建了一组小型演示文档,其中包含电影摘要
import "peggy";
import { Document } from "@langchain/core/documents";
/**
* First, we create a bunch of documents. You can load your own documents here instead.
* Each document has a pageContent and a metadata field. Make sure your metadata matches the AttributeInfo below.
*/
const docs = [
new Document({
pageContent:
"A bunch of scientists bring back dinosaurs and mayhem breaks loose",
metadata: {
year: 1993,
rating: 7.7,
genre: "science fiction",
length: 122,
},
}),
new Document({
pageContent:
"Leo DiCaprio gets lost in a dream within a dream within a dream within a ...",
metadata: {
year: 2010,
director: "Christopher Nolan",
rating: 8.2,
length: 148,
},
}),
new Document({
pageContent:
"A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea",
metadata: { year: 2006, director: "Satoshi Kon", rating: 8.6 },
}),
new Document({
pageContent:
"A bunch of normal-sized women are supremely wholesome and some men pine after them",
metadata: {
year: 2019,
director: "Greta Gerwig",
rating: 8.3,
length: 135,
},
}),
new Document({
pageContent: "Toys come alive and have a blast doing so",
metadata: { year: 1995, genre: "animated", length: 77 },
}),
new Document({
pageContent: "Three men walk into the Zone, three men walk out of the Zone",
metadata: {
year: 1979,
director: "Andrei Tarkovsky",
genre: "science fiction",
rating: 9.9,
},
}),
];
创建我们的自我查询检索器
现在我们可以实例化我们的检索器。为此,我们需要预先提供有关我们的文档支持的元数据字段以及文档内容的简要描述的信息。
import { OpenAIEmbeddings, OpenAI } from "@langchain/openai";
import { FunctionalTranslator } from "@langchain/core/structured_query";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { SelfQueryRetriever } from "langchain/retrievers/self_query";
import type { AttributeInfo } from "langchain/chains/query_constructor";
/**
* We define the attributes we want to be able to query on.
* in this case, we want to be able to query on the genre, year, director, rating, and length of the movie.
* We also provide a description of each attribute and the type of the attribute.
* This is used to generate the query prompts.
*/
const attributeInfo: AttributeInfo[] = [
{
name: "genre",
description: "The genre of the movie",
type: "string or array of strings",
},
{
name: "year",
description: "The year the movie was released",
type: "number",
},
{
name: "director",
description: "The director of the movie",
type: "string",
},
{
name: "rating",
description: "The rating of the movie (1-10)",
type: "number",
},
{
name: "length",
description: "The length of the movie in minutes",
type: "number",
},
];
/**
* Next, we instantiate a vector store. This is where we store the embeddings of the documents.
* We also need to provide an embeddings object. This is used to embed the documents.
*/
const embeddings = new OpenAIEmbeddings();
const llm = new OpenAI();
const documentContents = "Brief summary of a movie";
const vectorStore = await MemoryVectorStore.fromDocuments(docs, embeddings);
const selfQueryRetriever = SelfQueryRetriever.fromLLM({
llm,
vectorStore,
documentContents,
attributeInfo,
/**
* We need to use a translator that translates the queries into a
* filter format that the vector store can understand. We provide a basic translator
* translator here, but you can create your own translator by extending BaseTranslator
* abstract class. Note that the vector store needs to support filtering on the metadata
* attributes you want to query on.
*/
structuredQueryTranslator: new FunctionalTranslator(),
});
测试它
现在,我们可以实际尝试使用我们的检索器!
我们可以提出诸如“哪些电影少于 90 分钟?”或“哪些电影的评分高于 8.5?”之类的问题。我们还可以提出诸如“哪些电影是喜剧或剧情片,时长不到 90 分钟?”之类的问题。检索器内部的翻译器会自动将这些问题转换为可用于检索文档的向量存储过滤器。
await selfQueryRetriever.invoke("Which movies are less than 90 minutes?");
[
Document {
pageContent: "Toys come alive and have a blast doing so",
metadata: { year: 1995, genre: "animated", length: 77 }
}
]
await selfQueryRetriever.invoke("Which movies are rated higher than 8.5?");
[
Document {
pageContent: "A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception"... 16 more characters,
metadata: { year: 2006, director: "Satoshi Kon", rating: 8.6 }
},
Document {
pageContent: "Three men walk into the Zone, three men walk out of the Zone",
metadata: {
year: 1979,
director: "Andrei Tarkovsky",
genre: "science fiction",
rating: 9.9
}
}
]
await selfQueryRetriever.invoke("Which movies are directed by Greta Gerwig?");
[
Document {
pageContent: "A bunch of normal-sized women are supremely wholesome and some men pine after them",
metadata: { year: 2019, director: "Greta Gerwig", rating: 8.3, length: 135 }
}
]
await selfQueryRetriever.invoke(
"Which movies are either comedy or drama and are less than 90 minutes?"
);
[
Document {
pageContent: "Toys come alive and have a blast doing so",
metadata: { year: 1995, genre: "animated", length: 77 }
}
]
下一步
现在您已经了解了如何使用 SelfQueryRetriever
根据原始问题生成向量存储过滤器。
接下来,您可以查看 当前支持自我查询的向量存储列表.