Análise
LLMs capazes de seguir bem as instruções podem ser encarregados de produzir informações em um formato específico.
Essa abordagem depende do design de boas instruções e, em seguida, analisa a saída dos LLMs para extrair informações de forma eficiente.
Aqui, vamos usar o Claude, que é ótimo em seguir instruções! Veja modelos antropicos.
from langchain_anthropic.chat_models import ChatAnthropic
model = ChatAnthropic(model_name="claude-3-sonnet-20240229", temperature=0)
Dica: Todas as mesmas considerações para qualidade de extração se aplicam à abordagem de análise. Reveja as diretrizes para qualidade de extração.
Este tutorial tem a intenção de ser simples, mas geralmente deve incluir exemplos de referência para obter melhor desempenho!
Usando PydanticOutputParser
O exemplo a seguir usa o PydanticOutputParser
integrado para analisar a saída de um modelo de chat.
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):
"""Informações sobre uma pessoa."""
name: str = Field(..., description="O nome da pessoa")
height_in_meters: float = Field(
..., description="A altura da pessoa expressa em metros."
)
class People(BaseModel):
"""Informações de identificação de todas as pessoas em um texto."""
people: List[Person]
parser = PydanticOutputParser(pydantic_object=People)
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Responda à consulta do usuário. Envie a saída entre tags `json`\n{format_instructions}",
),
("human", "{query}"),
]
).partial(format_instructions=parser.get_format_instructions())
Vamos ver quais informações são enviadas para o modelo.
query = "Anna tem 23 anos e tem 1,83 metros de altura"
print(prompt.format_prompt(query=query).to_string())
Sistema: Responda à consulta do usuário. Envie a saída entre tags `json`
A saída deve ser formatada como uma instância JSON que esteja de acordo com o esquema JSON abaixo.
Como exemplo, para o esquema {"properties": {"foo": {"title": "Foo", "description": "uma lista de strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
o objeto {"foo": ["bar", "baz"]} é uma instância bem formatada do esquema. O objeto {"properties": {"foo": ["bar", "baz"]}} não está bem formatado.
Aqui está o esquema de saída:
{"description": "Informações de identificação de todas as pessoas em um texto.", "properties": {"people": {"title": "Pessoas", "type": "array", "items": {"$ref": "#/definitions/Person"}}}, "required": ["people"], "definitions": {"Person": {"title": "Pessoa", "description": "Informações sobre uma pessoa.", "type": "object", "properties": {"name": {"title": "Nome", "description": "O nome da pessoa", "type": "string"}, "height_in_meters": {"title": "Altura em Metros", "description": "A altura da pessoa expressa em metros.", "type": "number"}}, "required": ["name", "height_in_meters"]}}}
Usuário: Anna tem 23 anos e tem 1,83 metros de altura
chain = prompt | model | parser
chain.invoke({"query": query})
People(people=[Person(name='Anna', height_in_meters=1.83)])
Análise Personalizada
É fácil criar um prompt e um analisador personalizado com LangChain
e LCEL
.
Você pode usar uma função simples para analisar a saída do modelo!
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):
"""Informações sobre uma pessoa."""
name: str = Field(..., description="O nome da pessoa")
height_in_meters: float = Field(
..., description="A altura da pessoa expressa em metros."
)
class People(BaseModel):
"""Informações de identificação sobre todas as pessoas em um texto."""
people: List[Person]
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Responda à consulta do usuário. Produza sua resposta como JSON que corresponda ao esquema fornecido: ```json\n{schema}\n```. "
"Certifique-se de envolver a resposta em tags ```json e ```",
),
("human", "{query}"),
]
).partial(schema=People.schema())
def extract_json(message: AIMessage) -> List[dict]:
"""Extrai o conteúdo JSON de uma string onde o JSON está incorporado entre as tags ```json e ```.
Parâmetros:
text (str): O texto contendo o conteúdo JSON.
Retorna:
list: Uma lista de strings JSON extraídas.
"""
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"Falha ao analisar: {message}")
query = "Anna tem 23 anos e mede 1,83 metros de altura"
print(prompt.format_prompt(query=query).to_string())
System: Responda à consulta do usuário. Produza sua resposta como JSON que corresponda ao esquema fornecido: \`\`\`json
{'title': 'People', 'description': 'Informações de identificação sobre todas as pessoas em um texto.', 'type': 'object', 'properties': {'people': {'title': 'Pessoas', 'type': 'array', 'items': {'$ref': '#/definitions/Person'}}}, 'required': ['people'], 'definitions': {'Person': {'title': 'Pessoa', 'description': 'Informações sobre uma pessoa.', 'type': 'object', 'properties': {'name': {'title': 'Nome', 'description': 'O nome da pessoa', 'type': 'string'}, 'height_in_meters': {'title': 'Altura Em Metros', 'description': 'A altura da pessoa expressa em metros.', 'type': 'number'}}, 'required': ['name', 'height_in_meters']}}}
\`\`\`. Certifique-se de envolver a resposta em \`\`\`json e \`\`\`
Humano: Anna tem 23 anos e mede 1,83 metros de altura
chain = prompt | model | extract_json
chain.invoke({"query": query})
[{'people': [{'name': 'Anna', 'height_in_meters': 1.83}]}]
Outras Bibliotecas
Se estiver procurando por uma abordagem de extração usando um analisador, confira a biblioteca Kor. Foi escrita por um dos mantenedores do LangChain
e ajuda a criar um prompt que leva em conta exemplos, permite controlar formatos (por exemplo, JSON ou CSV) e expressa o esquema em TypeScript. Parece funcionar muito bem!