LangChain之提取解析与结构化输出

news2024/9/9 6:17:05

提取解析与结构化输出

  • 提取结构化输出
    • 概述
    • 提取方式
  • 使用函数
    • 配置Schema模式、架构
    • 提取器
    • 执行
    • 多个实体
    • 使用create_extraction_chain
  • 使用输出解析器
  • 使用参考示例
    • 配置Schema模式、架构
    • 定义参考示例
    • 创建一个提取器
    • 执行测试
  • 提取解析输出指南

提取结构化输出

概述

从原始LLM生成结构化输出可能是非常困难的,尤其在需要特定格式时。但是LLM只需适当说明和示例,就可以快速适应提取任务。

对于大模型输出的结构化数据,是非常重要、非常有用的,例如可以有以下应用:

提取要插入数据库的结构化行

提取API参数

提取用户查询的不同部分,执行语义提取

提取方式

函数方式:

某些LLM可以调用函数来从LLM响应中提取任意实体,比解析器更通用。

解析方式:

输出解析器是用于结构化LLM响应的类,能精确提取在Schema中定义的列属性。

基于提示:

LLM可以很好地遵循指示,可以指示以所需格式生成文本,从而实现结构化数据的输出。

使用函数

需要使用支持函数/工具调用的模型来从文本中提取信息

配置Schema模式、架构

Pydantic是一个用于Python的数据验证和设置管理库。它允许创建具有自动验证的属性的数据类。

定义一个带有类型注释的属性的类,描述想要从文本中提取哪些信息

from typing import Optional

from langchain_core.pydantic_v1 import BaseModel, Field


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

    创建实体 Person 的文档字符串, 并作为模式 Person 的描述发送到 LLM,它可以帮助提高提取结果。

    注意:
     1. 每个字段都是“可选”——这允许模型拒绝提取它!
     2. 每个字段都有一个“描述”——该描述由LLM使用。

    良好的描述有助于改善提取结果。
    """
    name: Optional[str] = Field(default=None, description="人名")
    hair_color: Optional[str] = Field(default=None, description="头发的颜色")
    height_in_meters: Optional[str] = Field(default=None, description="身高以米为单位测量")

两种最佳实践:

记录属性和模式本身:此信息被发送到 LLM 并用于提高信息提取的质量。

请勿强行LLM编造信息!上面使用 Optional 作为属性,允许 LLM 在不知道答案时输出 None 。

提取器

使用定义的Schema模式创建一个信息提取器

from langchain_core.prompts import ChatPromptTemplate

# 定义自定义提示以提供说明和任何其他上下文。
# 1) 可以在提示模板中添加示例以提高提取质量
# 2) 引入额外的参数以考虑上下文(例如,包括从中提取文本的文档元数据)。
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "您是提取算法专家。只从文本中提取相关信息。如果您不知道要求提取的属性的值,返回 null 作为属性值。",
        ),
        ("human", "{text}"),
    ]
)

执行

from langchain_openai import ChatOpenAI
# 初始化大模型
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

# 返回格式化以匹配给定模式的输出的模型包装器
# with_structured_output API处于测试阶段,未来可能会改变。
runnable = prompt | llm.with_structured_output(schema=Person)

# 执行
text = "Alan Smith is 6 feet tall and has blond hair."
res = runnable.invoke({"text": text})
print(res)

执行输出结果如下:

name='Alan Smith' hair_color='blond' height_in_meters='1.83'

多个实体

在大多数情况下,应该提取实体列表而不是单个实体,这可以通过使用 pydantic 将模型相互嵌套来轻松实现。

from typing import Optional, List
from langchain_core.pydantic_v1 import BaseModel, Field


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

    创建实体 Person 的文档字符串, 并作为模式 Person 的描述发送到 LLM,它可以帮助提高提取结果。

    注意:
     1. 每个字段都是“可选”——这允许模型拒绝提取它!
     2. 每个字段都有一个“描述”——该描述由LLM使用。

    良好的描述有助于改善提取结果。
    """
    name: Optional[str] = Field(default=None, description="人名")
    hair_color: Optional[str] = Field(default=None, description="头发的颜色")
    height_in_meters: Optional[str] = Field(default=None, description="身高以米为单位测量")


class Data(BaseModel):
    """提取有关人员的数据。"""

    # 创建一个模型,以便我们可以提取多个实体。
    people: List[Person]


from langchain_core.prompts import ChatPromptTemplate

# 定义自定义提示以提供说明和任何其他上下文。
# 1) 可以在提示模板中添加示例以提高提取质量
# 2) 引入额外的参数以考虑上下文(例如,包括从中提取文本的文档元数据)。
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "您是提取算法专家。只从文本中提取相关信息。如果您不知道要求提取的属性的值,返回 null 作为属性值。",
        ),
        # Please see the how-to about improving performance with
        # reference examples.
        # MessagesPlaceholder('examples'),
        ("human", "{text}"),
    ]
)

from langchain_openai import ChatOpenAI

# 初始化大模型
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

# 返回格式化以匹配给定模式的输出的模型包装器
# with_structured_output API处于测试阶段,未来可能会改变。
runnable = prompt | llm.with_structured_output(schema=Data)

# 执行
text = "My name is Jeff, my hair is black and i am 6 feet tall. Anna has the same color hair as me."
res = runnable.invoke({"text": text})
print(res)

执行输出结果如下:

people=[
Person(name='Jeff', hair_color='black', height_in_meters='1.83'), 
Person(name='Anna', hair_color='black', height_in_meters=None)
]

使用create_extraction_chain

OpenAI函数是一种提取的方式。定义一个模式,指定从LLM输出中提取的属性,然后使用create_extraction_chainOpenAI函数调用来提取所需模式。

from langchain.chains import create_extraction_chain
from langchain_openai import ChatOpenAI

# 模式
schema = {
	# 人的属性
    "properties": {
        "name": {"type": "string"},
        "height": {"type": "integer"},
        "hair_color": {"type": "string"},
    },
    # 允许模型只返回的属性
    "required": ["name", "height"],
}

# 输入
inp = """亚历克斯身高 5 英尺。克劳迪娅比亚历克斯高 1 英尺,并且跳得比他更高。克劳迪娅是黑发女郎,亚历克斯是金发女郎。"""

# 初始化大模型
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo")
# 构建链
chain = create_extraction_chain(schema, llm)
# 执行
res = chain.invoke(inp)
print(res)
{'input': '亚历克斯身高 5 英尺。克劳迪娅比亚历克斯高 1 英尺,并且跳得比他更高。克劳迪娅是黑发女郎,亚历克斯是金发女郎。', 
'text': [
{'name': '亚历克斯', 'height': 5}, 
{'name': '克劳迪娅', 'height': 1, 'hair_color': '黑发'}
]}

使用输出解析器

使用输出解析器实现提取解析与结构化输出,输出解析器是帮助结构化语言模型响应的类。

from typing import Optional, List
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field


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

    创建实体 Person 的文档字符串, 并作为模式 Person 的描述发送到 LLM,它可以帮助提高提取结果。

    注意:
     1. 每个字段都是“可选”——这允许模型拒绝提取它!
     2. 每个字段都有一个“描述”——该描述由LLM使用。

    良好的描述有助于改善提取结果。
    """
    name: Optional[str] = Field(default=None, description="人名")
    hair_color: Optional[str] = Field(default=None, description="头发的颜色")
    height_in_meters: Optional[str] = Field(default=None, description="身高以米为单位测量")


class Data(BaseModel):
    """提取有关人员的数据。"""

    people: List[Person]


from langchain_core.prompts import PromptTemplate
from langchain_openai import OpenAI

query = """亚历克斯身高 5 英尺。克劳迪娅比亚历克斯高 1 英尺,并且跳得比他更高。克劳迪娅是黑发女郎,亚历克斯是金发女郎。"""

# 设置解析器 + 将指令注入提示模板。
parser = PydanticOutputParser(pydantic_object=Data)

# 提示
prompt = PromptTemplate(
    template="回答用户查询。\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()},
)
# 格式化提示
promptValue = prompt.format_prompt(query=query)

# 初始化大模型并执行
llm = OpenAI(temperature=0)
output = llm.invoke(promptValue.to_string())
# 执行输出解析
res = parser.parse(output)
print(res)
people=[
Person(name='Alex', hair_color='Blonde', height_in_meters='1.524'), 
Person(name='Claudia', hair_color='Black', height_in_meters='1.8288')
]

使用参考示例

可以通过提供的参考示例来提高提取的质量LLM。

配置Schema模式、架构

定义一个带有类型注释的属性的类,描述想要从文本中提取哪些信息

from typing import List, Optional

from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI


class Person(BaseModel):
    """有关一个人的信息。"""
    name: Optional[str] = Field(..., description="人名")
    hair_color: Optional[str] = Field(..., description="眼睛的颜色")
    height_in_meters: Optional[str] = Field(..., description="身高(米)")


class Data(BaseModel):
    """提取有关人员的数据。"""
    people: List[Person]

定义参考示例

示例可以定义为输入-输出对的列表。每个示例都包含一个示例input文本和一个output 显示应从文本中提取内容的示例。

import uuid
from typing import List, TypedDict

from langchain_core.messages import (
    AIMessage,
    BaseMessage,
    HumanMessage,
    ToolMessage,
)
from langchain_core.pydantic_v1 import BaseModel


class Example(TypedDict):
    """由文本输入和预期工具调用组成的示例表示.

    对于提取,工具调用被表示为 pydantic 模型的实例。
    """

    input: str  # 这是示例文本
    tool_calls: List[BaseModel]  # 应提取的 pydantic 模型实例


def tool_example_to_messages(example: Example) -> List[BaseMessage]:
    """将示例转换为可以输入 LLM 的消息列表。

    此代码是一个适配器,它将我们的示例转换为消息列表 可以将其输入聊天模型中。

    每个示例的消息列表对应于:
    1) HumanMessage:包含应从中提取内容的内容。
    2)AIMessage:包含从模型中提取的信息
    3) ToolMessage:包含对模型的确认,表明模型正确地请求了工具。

    ToolMessage 是必需的,因为某些聊天模型针对代理进行了超级优化 而不是用于提取用例。
    """
    messages: List[BaseMessage] = [HumanMessage(content=example["input"])]
    openai_tool_calls = []
    for tool_call in example["tool_calls"]:
        openai_tool_calls.append(
            {
                "id": str(uuid.uuid4()),
                "type": "function",
                "function": {
                    "name": tool_call.__class__.__name__,
                    "arguments": tool_call.json(),
                },
            }
        )
    messages.append(
        AIMessage(content="", additional_kwargs={"tool_calls": openai_tool_calls})
    )
    tool_outputs = example.get("tool_outputs") or ["You have correctly called this tool."] * len(openai_tool_calls)
    for output, tool_call in zip(tool_outputs, openai_tool_calls):
        messages.append(ToolMessage(content=output, tool_call_id=tool_call["id"]))
    return messages

定义示例,然后将它们转换为消息格式。

examples = [
    (
        "海洋广阔而蔚蓝。它的深度超过 20,000 英尺。里面有很多鱼。",
        Person(name=None, height_in_meters=None, hair_color=None),
    ),
    (
        "菲奥娜从法国长途跋涉来到西班牙。她是 1.75 米高,而且她的眼睛是深色的。",
        Person(name="菲奥娜", height_in_meters=1.75, hair_color="深色"),
    ),
]

messages = []
for text, tool_call in examples:
    messages.extend(
        tool_example_to_messages({"input": text, "tool_calls": [tool_call]})
    )

创建一个提取器

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

# 定义自定义提示以提供说明和任何其他上下文。
# 1) 可以在提示模板中添加示例以提高提取质量
# 2) 引入额外的参数以考虑上下文(例如,包括从中提取文本的文档元数据)。
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "您是提取算法专家。只从文本中提取相关信息。如果您不知道要求提取的属性的值,返回 null 作为属性值。",
        ),
        MessagesPlaceholder("examples"),
        ("human", "{text}"),
    ]
)

text = "Jack来自美国,他1.75 米高"
res = prompt.invoke({"text": text, "examples": messages})
# print(res)

执行测试

初始化大模型,创建执行链

llm = ChatOpenAI(
    model="gpt-4-0125-preview",
    temperature=0,
)
runnable = prompt | llm.with_structured_output(
    schema=Data,
    method="function_calling",
    include_raw=False,
)

向LLM输入语句,测试添加参考示例对输出结果的影响

print(runnable.invoke({"text": "太阳系很大,但地球只有1个月亮。", "examples": []}))

print(runnable.invoke({"text": "太阳系很大,但地球只有1个月亮。", "examples": messages}))

print(runnable.invoke({"text": "Jack来自美国,他1.75 米高", "examples": messages}))

从执行日志可知,添加参考示例后,模型输出回答的更好

people=[Person(name='Earth', hair_color='Blue', height_in_meters='1')]
people=[Person(name='太阳系', hair_color=None, height_in_meters=None)]
people=[Person(name='Jack', hair_color='null', height_in_meters='1.75')]

提取解析输出指南

提取结果的质量取决于许多因素,参考以下建议,帮助从模型中获得最佳性能

将模型温度设置为 0 

改进提示。提示应该准确、切题

记录架构:确保记录架构以便为 LLM 提供更多信息

提供参考例子!各种示例都可以提供帮助,包括不应提取任何内容的示例。
如果您有很多示例,请使用检索器来检索最相关的示例

具有最佳可用 LLM/聊天模型(例如 gpt-4、claude-3 等)的基准

如果架构非常大,请尝试将其分解为多个较小的架构,运行单独的提取并合并结果

确保架构允许模型拒绝提取信息。如果没有的话,模特就会被强制补信息

添加验证/更正步骤(要求 LLM 更正或验证提取结果)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1962363.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4.1.1、操作系统的概述

操作系统的作用:通过资源管理提高计算机系统的效率;改善人机界面向用户提供友好的工作环境。 操作系统的特征:并发性、共享性、虚拟性、不确定性。 操作系统的功能:进程管理、存储管理、文件管理、设备管理、作业管理。 操作系统的分类:批处理操作系统、分时操作系统(轮流使…

美股:苹果选择谷歌芯片支持人工智能技术

最近的研究报告显示,苹果公司在其新一代人工智能工具和功能套件中选择依赖谷歌设计的芯片,而非市场领导者 Nvidia。这一决定引发了业界的关注,尤其是考虑到Nvidia在人工智能处理器市场的主导地位。 谷歌云的TPU在苹果的AI基础设施中发挥关键作…

计算机再过几年会没落?

大部分人卷的计算机:Java web 实际上的计算机:web,图形学,Linux系统开发,一系列嵌入式开发,数据库,高性能服务器,中间件开发,三维建模,网络安全,…

vue2 封装弹框组件

安装 element-ui npm install element-ui --save ---force main.js 导入 import Vue from vue; import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css; import App from ./App.vue; Vue.use(ElementUI); new Vue({ el: #app, render: h > h(Ap…

Minio、MySQL、Redis、Milvus 安装

CPU:2核↑,内存:4GB↑ 开发工具:eclipse-jee、MySQL Workbench、MobaXterm、Redis Insight... 操作系统:CentOS Stream 9(生产环境)、Windos 11 Ubuntu 22.04.3(开发环境&#xf…

使用 Kibana 和 Vega 构建高级可视化

作者:来自 Carly Richmond 为了解释在 Kibana 中构建 Vega 可视化的基础知识,我将使用此 GitHub 存储库中的 2 个示例。具体来说,我将介绍: 使用 Elasticsearch 聚合进行数据采购轴和标记事件和信号(例如工具提示和更…

工具使用备忘录

npm npm是node包管理工具。yarn是npm的替代品,看起来使用更加广泛。cnpm是中国镜像。 cnpm安装时,曾经出现过错误。不进行安全验证后运行成功。 目前在WSL上可以全局使用cnpm 当时解决的方案是将报错信息copy下来,直接看通义千问的结果。 …

时间序列中多维度、多变量、多元、多尺度

目录 多尺度 多维度 多变量 多元 区别 举例: 多尺度 多尺度时间序列分析是指在不同的时间尺度上对数据进行分析。例如,某些现象可能在短期内表现出一种模式,而在长期内表现出另一种模式。多尺度分析可以帮助我们捕捉这些不同时间尺度上…

北斗RTK高精度定位系统介绍

北斗RTK高精度定位系统是一种高精度、高可靠、高效率的定位系统。它采用北斗卫星导航系统,结合实时动态差分RTK技术,能够实现亚米级的定位准确度,适用于石油化工、工厂、工地、园区、环卫等领域。 北斗RTK的核心技术是RTK技术,即实…

C++ | string

前言 本篇博客讲解c中的string类的使用(常用接口) 💓 个人主页:普通young man-CSDN博客 ⏩ 文章专栏:C_普通young man的博客-CSDN博客 ⏩ 本人giee:普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见📝 &#x1f389…

在 Elasticsearch 中实现采集自动扩展

作者:来自 Elastic Pooya Salehi, Henning Andersen, Francisco Fernndez Castao 正确调整 Elasticsearch 集群的大小并不容易。集群的最佳大小取决于集群正在经历的工作负载,而工作负载可能会随着时间的推移而变化。自动扩展会自动调整集群大小以适应工…

【JavaScript】详解JavaScript语法

文章目录 一、变量和数据类型二、运算符三、条件语句四、循环语句五、函数六、对象和数组七、ES6新特性八、实际应用案例 JavaScript是一门广泛应用于Web开发的编程语言。掌握JavaScript语法是成为前端开发者的第一步。本文将详细介绍JavaScript的基本语法,包括变量…

“Assistants“ has no attribute “files“ in openAI assistants

题意:在 OpenAI 的助手(assistants)中,“Assistants” 没有 “files” 这个属性。 问题背景: assistant_file client.beta.assistants.files.create(assistant_id st.session_state.assistant_id,file_id st.sessi…

2024年最佳骨传导耳机推荐:五款不容错过的选择!

作为音乐爱好者的我,也一直在寻找一款好的骨传导耳机,听音乐对我来说不仅仅是一种消遣方式,更多是一种对生活、工作上压力和困难的舒缓,所以今天给大家推荐几款骨传导耳机。今天推荐这几款骨传导耳机都是比较有性价比,…

Oracle VM VirtualBox 异常退出,如何解决??

🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收…

向量数据库性能测试工具(VectorDBBench.com)性价比排名

排名 向量数据库(不同硬件配置) 价格/性能比 QP$(每百万次查询所花费的价格)中型数据集, OpenAI 无标量过滤 QP$(每百万次查询所花费的价格)中型数据集, OpenAI 低标量过滤 QP$(每百万次查询所花费的价格)中型数据集, OpenAI 高标量过滤 QP$(每百万次查询所花费的价…

Linux系统之ftp服务配置

(1)查看vsftpd服务软件是否安装。 若缺少相关软件请使用yum方式安装相关软件。 (2)关闭防火墙和selinux保护。 (3)设置匿名访问。 vim /etc/vsftpd/vsftpd.conf 并通过ftp的方式在共享文件夹中创建名为“…

生成式 AI 时代的数据库:Databend 与大模型的融合探索

生成式人工智能(Generative AI)近年来快速崛起,从图像生成、自然语言处理到个性化推荐系统,生成式 AI 的应用范围越来越广泛。在这其中,数据可以说是企业在生成式 AI 时代取得成功的关键,每个公司都能访问相…

python100day(31-35) 玩转Linux操作系统

目录 玩转Linux操作系统操作系统发展史没有操作系统(手工操作)批处理系统分时系统和实时系统通用操作系统 Linux概述Linux系统优点Linux系统发行版本基础命令实用程序文件和文件夹操作管道和重定向别名文本处理 用户管理文件系统文件和路径目录结构访问权…

MVC三层框架

什么是MVC : Model模型 view视图 Controller控制器 早先架构: 用户直接访问控制层,控制层就可以直接操作数据库 弊端:程序十分臃肿,不利于维护 servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理…