直接解析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)])
自定义解析
使用 LangChain
和 LCEL
很容易创建自定义提示和解析器。
你可以使用一个简单的函数来解析模型的输出!
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 中表达模式。似乎非常好用!