技术背景介绍
老铁们,今天我们聊聊如何从无结构文本中提取结构化信息。这不仅仅是将自然语言处理应用于真实场景,还涵盖了如何利用工具实现这一目标。相较于之前的静态方法,由于LLMs(大型语言模型)如ChatGPT的出现,信息提取变得更加灵活和动态。
原理深度解析
我们用的是LangChain,一个开源库,支持各种语言模型的集成和调用。LangChain特别适合处理多步骤、多调用的复杂操作。其核心在于定义一个清晰的信息提取schema,通过Pydantic来规范化数据,并使用支持工具调用的模型来实现。
两个最佳实践:
- 文档化属性和schema:这是为了帮助LLM理解我们期望提取的信息,从而提高提取质量。
- 避免强迫LLM生成信息:通过使用Optional字段,允许模型在不确定答案时输出None。
实战代码演示
接下来我们进入实操环节,看看如何实现这个信息提取链。
首先,我们定义一个schema来提取个人信息:
from typing import Optional
from langchain_core.pydantic_v1 import BaseModel, Field
class Person(BaseModel):
"""Information about a person."""
name: Optional[str] = Field(default=None, description="The name of the person")
hair_color: Optional[str] = Field(default=None, description="The color of the person's hair if known")
height_in_meters: Optional[str] = Field(default=None, description="Height measured in meters")
接着,我们创建一个信息提取器:
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(
[
(
"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.",
),
("human", "{text}"),
]
)
from langchain_mistralai import ChatMistralAI
llm = ChatMistralAI(model="mistral-large-latest", temperature=0)
runnable = prompt | llm.with_structured_output(schema=Person)
现在我们测试一下:
text = "Alan Smith is 6 feet tall and has blond hair."
result = runnable.invoke({"text": text})
print(result)
这波操作可以说是相当丝滑,模型甚至能将提到的身高从英尺转换为米。
优化建议分享
建议在信息提取过程中使用LangSmith进行日志跟踪,这样可以帮助我们分析每一步调用结果,提高调试效率。
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="..."
在Jupyter Notebook中可以这么操作:
import getpass
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()
补充说明和总结
在实际应用中,可能需要提取多个实体,如下:
from typing import List
class Data(BaseModel):
people: List[Person]
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."
result = runnable.invoke({"text": text})
print(result)
对于多实体的提取,模型允许输出空列表,这样可以更灵活处理没有信息的情况。
今天的技术分享就到这里,希望对大家有帮助。开发过程中遇到问题也可以在评论区交流~