一架梯子,一头程序猿,仰望星空!
使用LangChain提取结构化数据 > 内容正文

解析


直接解析LLM返回的数据

前面的章节基于大模型(LLM)的函数/工具调用特性实现数据提取,那么如果你使用的LLM不支持函数调用特性,我们可以基于提示词指令要求LLM返回指定格式的数据,然后通过代码转换LLM返回的文本数据。本章主要基于这个思路讲解如何提取结构化的数据。

在这里,我们将使用 Claude模型,使用OpenAI模型也类似,创建不同的模型对象即可

定义模型

from langchain_anthropic.chat_models import ChatAnthropic

model = ChatAnthropic(model_name="claude-3-sonnet-20240229", temperature=0)

使用 PydanticOutputParser

以下示例使用内置的 PydanticOutputParser 来解析聊天模型的输出。

from typing import List, Optional

from langchain.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field, validator

# 定义我们需要提取的数据格式
class Person(BaseModel):
    """关于一个人的信息。"""

    name: str = Field(..., description="人的姓名")
    height_in_meters: float = Field(
        ..., description="以米为单位表示的人的身高"
    )


class People(BaseModel):
    """文本中所有人的身份信息。"""

    people: List[Person]


# 定义Python对象解析器,负责将LLM返回的文本内容,转成指定的Python对象
parser = PydanticOutputParser(pydantic_object=People)

# 定义提示词模板,这里通过get_format_instructions函数,把我们希望模型返回的格式,拼接到提示词中
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "回答用户的查询。将输出内容放入 `json` 标记中\n{format_instructions}",
        ),
        ("human", "{query}"),
    ]
).partial(format_instructions=parser.get_format_instructions())

让我们看看发送给模型的信息

query = "安娜今年 23 岁,身高 6 英尺"
print(prompt.format_prompt(query=query).to_string())
System: 回答用户的查询。将输出内容放入 `json` 标记中
输出应该格式化为符合以下 JSON 模式的 JSON 实例。

举个例子,对于模式 {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
对象 {"foo": ["bar", "baz"]} 是模式的格式良好的实例。而对象 {"properties": {"foo": ["bar", "baz"]}} 则格式不良好。

下面是输出模式:
{"description": "文本中所有人的身份信息。", "properties": {"people": {"title": "People", "type": "array", "items": {"$ref": "#/definitions/Person"}}}, "required": ["people"], "definitions": {"Person": {"title": "Person", "description": "关于一个人的信息。", "type": "object", "properties": {"name": {"title": "Name", "description": "人的姓名", "type": "string"}, "height_in_meters": {"title": "Height In Meters", "description": "以米为单位表示的人的身高", "type": "number"}}, "required": ["name", "height_in_meters"]}}}

Human: 安娜今年 23 岁,身高 6 英尺

下面调用模型测试

chain = prompt | model | parser
chain.invoke({"query": query})

返回结果

People(people=[Person(name='安娜', height_in_meters=1.83)])

自定义解析

使用 LangChainLCEL 很容易创建自定义提示和解析器。

你可以使用一个简单的函数来解析模型的输出!

import json
import re
from typing import List, Optional

from langchain_anthropic.chat_models import ChatAnthropic
from langchain_core.messages import AIMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field, validator


class Person(BaseModel):
    """关于一个人的信息。"""

    name: str = Field(..., description="人的姓名")
    height_in_meters: float = Field(
        ..., description="以米为单位表示的人的身高。"
    )


class People(BaseModel):
    """文本中所有人的识别信息。"""

    people: List[Person]


prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "回答用户的查询。将您的答案输出为符合给定模式的 JSON:```json\n{schema}\n```。"
            "确保将答案用 ```json 和 ``` 标记起来",
        ),
        ("human", "{query}"),
    ]
).partial(schema=People.schema())


def extract_json(message: AIMessage) -> List[dict]:
    """从包含在 ```json 和 ``` 标记之间的字符串中提取 JSON 内容。

    参数:
        text (str):包含 JSON 内容的文本。

    返回:
        list:提取出的 JSON 字符串列表。
    """
    text = message.content
    pattern = r"```json(.*?)```"

    matches = re.findall(pattern, text, re.DOTALL)

    try:
        return [json.loads(match.strip()) for match in matches]
    except Exception:
        raise ValueError(f"解析失败:{message}")
query = "Anna 今年 23 岁,身高 6 英尺"
print(prompt.format_prompt(query=query).to_string())
系统:回答用户的查询。将您的答案输出为符合给定模式的 JSON:\`\`\`json
{'title': 'People', 'description': '文本中所有人的识别信息。', 'type': 'object', 'properties': {'people': {'title': 'People', 'type': 'array', 'items': {'$ref': '#/definitions/Person'}}}, 'required': ['people'], 'definitions': {'Person': {'title': 'Person', 'description': '关于一个人的信息。', 'type': 'object', 'properties': {'name': {'title': 'Name', 'description': '人的姓名', 'type': 'string'}, 'height_in_meters': {'title': 'Height In Meters', 'description': '以米为单位表示的人的身高。', 'type': 'number'}}, 'required': ['name', 'height_in_meters']}}}
\`\`\`。确保将答案用 \`\`\`json 和 \`\`\` 标记起来
用户:Anna 今年 23 岁,身高 6 英尺
chain = prompt | model | extract_json
chain.invoke({"query": query})
[{'people': [{'name': 'Anna', 'height_in_meters': 1.83}]}]

其他库

如果你想使用解析方法进行提取,请查看 Kor 库。它是由 LangChain 维护者之一编写的,可帮助制作考虑示例的提示,允许控制格式(例如 JSON 或 CSV),并在 TypeScript 中表达模式。似乎非常好用!



关联主题