跳至主要内容

构建一个提取链

先决条件

本指南假设您熟悉以下概念

在本教程中,我们将构建一个链来从非结构化文本中提取结构化信息。

info

本教程仅适用于支持**函数/工具调用**的模型

设置

安装

要安装 LangChain,请运行

yarn add langchain @langchain/core

有关更多详细信息,请参阅我们的安装指南

LangSmith

您使用 LangChain 构建的许多应用程序都将包含多个步骤,并多次调用 LLM。随着这些应用程序变得越来越复杂,能够检查链或代理内部究竟发生了什么变得至关重要。最好的方法是使用LangSmith

在您通过上面的链接注册后,请确保设置您的环境变量以开始记录跟踪

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="..."

# Reduce tracing latency if you are not in a serverless environment
# export LANGCHAIN_CALLBACKS_BACKGROUND=true

模式

首先,我们需要描述我们想从文本中提取哪些信息。

我们将使用Zod 来定义一个提取个人信息的示例模式。

yarn add zod @langchain/core
import { z } from "zod";

const personSchema = z.object({
name: z.string().nullish().describe("The name of the person"),
hair_color: z
.string()
.nullish()
.describe("The color of the person's hair if known"),
height_in_meters: z.string().nullish().describe("Height measured in meters"),
});

在定义模式时,有两个最佳实践

  1. 记录**属性**和**模式**本身:此信息将发送到 LLM,并用于提高信息提取的质量。
  2. 不要强迫 LLM 编造信息!我们在上面对属性使用了.nullish(),允许 LLM 在不知道答案的情况下输出nullundefined
info

为了获得最佳性能,请充分记录模式,并确保模型在文本中没有要提取的信息时不会被迫返回结果。

提取器

让我们使用上面定义的模式创建一个信息提取器。

import { ChatPromptTemplate } from "@langchain/core/prompts";

// Define a custom prompt to provide instructions and any additional context.
// 1) You can add examples into the prompt template to improve extraction quality
// 2) Introduce additional parameters to take context into account (e.g., include metadata
// about the document from which the text was extracted.)
const prompt = ChatPromptTemplate.fromMessages([
[
"system",
`You are an expert extraction algorithm.
Only extract relevant information from the text.
If you do not know the value of an attribute asked to extract,
return null for the attribute's value.`,
],
// Please see the how-to about improving performance with
// reference examples.
// ["placeholder", "{examples}"],
["human", "{text}"],
]);

我们需要使用支持函数/工具调用的模型。

请查看文档以了解可以与此 API 一起使用的模型列表。

import { ChatAnthropic } from "@langchain/anthropic";

const llm = new ChatAnthropic({
model: "claude-3-sonnet-20240229",
temperature: 0,
});

const runnable = prompt.pipe(llm.withStructuredOutput(personSchema));

const text = "Alan Smith is 6 feet tall and has blond hair.";
await runnable.invoke({ text });
{ name: "Alan Smith", hair_color: "blond", height_in_meters: "1.83" }
info

提取是生成性的 🤯

LLM 是生成模型,因此它们可以做一些非常酷的事情,比如即使身高以英尺提供,也能正确提取以米为单位的身高!

我们可以看到 LangSmith 跟踪在这里

尽管我们使用变量名personSchema定义了模式,但 Zod 无法推断出这个名称,因此不会将其传递给模型。为了帮助 LLM 更好地理解你提供的模式代表什么,你也可以给传递给withStructuredOutput()的模式命名。

const runnableWithName = prompt.pipe(
llm.withStructuredOutput(personSchema, { name: "person" })
);

const text2 = "Alan Smith is 6 feet tall and has blond hair.";

await runnableWithName.invoke({ text: text2 });
{ name: "Alan Smith", hair_color: "blond", height_in_meters: "1.83" }

这在很多情况下可以提高性能。

多个实体

大多数情况下,你应该提取实体列表而不是单个实体。

这可以通过在 Zod 中嵌套模型轻松实现。

import { z } from "zod";

const person = z.object({
name: z.string().nullish().describe("The name of the person"),
hair_color: z
.string()
.nullish()
.describe("The color of the person's hair if known"),
height_in_meters: z.number().nullish().describe("Height measured in meters"),
});

const dataSchema = z.object({
people: z.array(person).describe("Extracted data about people"),
});
info

提取可能并不完美。请继续阅读了解如何使用参考示例来提高提取质量,并查看指南部分!

const peopleExtractionChain = prompt.pipe(llm.withStructuredOutput(dataSchema));
const text3 =
"My name is Jeff, my hair is black and i am 6 feet tall. Anna has the same color hair as me.";
await peopleExtractionChain.invoke({ text: text3 });
{
people: [
{ name: "Jeff", hair_color: "black", height_in_meters: 1.83 },
{ name: "Anna", hair_color: "black", height_in_meters: null }
]
}
提示

当模式能够提取多个实体时,它也允许模型在文本中没有相关信息时通过提供空列表来提取无实体

这通常是件好事!它允许在实体上指定必需属性,而无需强制模型检测该实体。

我们可以在这里看到 LangSmith 跟踪 here

下一步

现在你已经了解了使用 LangChain 进行提取的基础知识,你就可以继续学习其他操作指南。

  • 添加示例: 了解如何使用参考示例来提高性能。
  • 处理长文本: 如果文本不适合 LLM 的上下文窗口,你应该怎么做?
  • 使用解析方法: 使用基于提示的方法来提取,适用于不支持工具/函数调用的模型。

此页面是否有帮助?


你也可以在 GitHub 上留下详细的反馈 on GitHub.