Usar Exemplos de Referência
A qualidade das extrações muitas vezes pode ser melhorada fornecendo exemplos de referência para o LLM.
Dica: Embora este tutorial se concentre em como usar exemplos com uma ferramenta chamada modelo, essa técnica é geralmente aplicável e também funcionará com técnicas baseadas em JSON ou mais prompts.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Você é um algoritmo de extração especialista. "
"Extraia apenas informações relevantes do texto. "
"Se você não souber o valor de um atributo solicitado para extração, retorne nulo para o valor do atributo.",
),
MessagesPlaceholder("exemplos"), # <-- EXEMPLOS!
("humano", "{texto}"),
]
)
Teste o modelo:
from langchain_core.messages import (
HumanMessage,
)
prompt.invoke(
{"texto": "este é um texto", "exemplos": [HumanMessage(content="testando 1 2 3")]}
)
ChatPromptValue(messages=[SystemMessage(content="Você é um algoritmo de extração especialista. Extraia apenas informações relevantes do texto. Se você não souber o valor de um atributo solicitado para extração, retorne nulo para o valor do atributo."), HumanMessage(content='testando 1 2 3'), HumanMessage(content='este é um texto')])
Definir o Esquema
Vamos reutilizar o esquema da pessoa do início rápido.
from typing import List, Optional
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
class Person(BaseModel):
"""Informações sobre uma pessoa."""
nome: Optional[str] = Field(..., description="O nome da pessoa")
cor_do_cabelo: Optional[str] = Field(
..., description="A cor dos olhos da pessoa, se conhecida"
)
altura_em_metros: Optional[str] = Field(..., description="Altura em metros")
class Data(BaseModel):
"""Dados extraídos sobre pessoas."""
pessoas: List[Person]
Definir exemplos de referência
Exemplos podem ser definidos como uma lista de pares de entrada-saída.
Cada exemplo contém um texto de entrada
e uma saída
de exemplo mostrando o que deve ser extraído do texto.
info
Isso é um pouco técnico, então sinta-se à vontade para ignorar se não entender!
O formato do exemplo precisa corresponder à API usada (por exemplo, chamada de ferramenta ou modo JSON etc.).
Aqui, os exemplos formatados corresponderão ao formato esperado para a chamada da ferramenta API, pois é isso que estamos usando.
import uuid
from typing import Dict, List, TypedDict
from langchain_core.messages import (
AIMessage,
BaseMessage,
HumanMessage,
SystemMessage,
ToolMessage,
)
from langchain_core.pydantic_v1 import BaseModel, Field
class Example(TypedDict):
"""Uma representação de um exemplo composto por texto de entrada e chamadas de ferramentas esperadas.
Para extração, as chamadas de ferramentas são representadas como instâncias do modelo pydantic.
"""
input: str # Este é o texto do exemplo
tool_calls: List[BaseModel] # Instâncias de modelo pydantic que devem ser extraídas
def tool_example_to_messages(example: Example) -> List[BaseMessage]:
"""Converte um exemplo em uma lista de mensagens que podem ser inseridas em um LLM.
Este código é um adaptador que converte nosso exemplo em uma lista de mensagens
que podem ser inseridas em um modelo de chat.
A lista de mensagens por exemplo corresponde a:
1) HumanMessage: contém o conteúdo do qual o conteúdo deve ser extraído.
2) AIMessage: contém as informações extraídas do modelo
3) ToolMessage: contém confirmação ao modelo de que a ferramenta foi solicitada corretamente.
O ToolMessage é necessário porque alguns dos modelos de chat são hiperotimizados para agentes
em vez de para um caso de uso de extração.
"""
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": "função",
"função": {
"nome": tool_call.__class__.__name__,
"argumentos": tool_call.json(),
},
}
)
messages.append(
AIMessage(content="", additional_kwargs={"tool_calls": openai_tool_calls})
)
tool_outputs = example.get("tool_outputs") or [
"Você chamou corretamente esta ferramenta."
] * 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
A seguir, vamos definir nossos exemplos e depois convertê-los para o formato de mensagem.
exemplos = [
(
"O oceano é vasto e azul. Tem mais de 20.000 pés de profundidade. Há muitos peixes nele.",
Pessoa(nome=None, altura_em_metros=None, cor_do_cabelo=None),
),
(
"Fiona viajou longe da França para a Espanha.",
Pessoa(nome="Fiona", altura_em_metros=None, cor_do_cabelo=None),
),
]
mensagens = []
for texto, chamada_de_ferramenta in exemplos:
mensagens.extend(
tool_example_to_messages({"input": texto, "tool_calls": [chamada_de_ferramenta]})
)
Vamos testar o prompt
prompt.invoke({"texto": "este é um texto", "exemplos": mensagens})
ChatPromptValue(messages=[SystemMessage(content="Você é um algoritmo de extração especialista. Apenas extraia informações relevantes do texto. Se você não souber o valor de um atributo a ser extraído, retorne nulo para o valor do atributo."), HumanMessage(content="O oceano é vasto e azul. Tem mais de 20.000 pés de profundidade. Há muitos peixes nele."), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'c75e57cc-8212-4959-81e9-9477b0b79126', 'type': 'function', 'function': {'name': 'Person', 'arguments': '{"name": null, "hair_color": null, "height_in_meters": null}'}}]}), ToolMessage(content='Você chamou corretamente esta ferramenta.', tool_call_id='c75e57cc-8212-4959-81e9-9477b0b79126'), HumanMessage(content='Fiona viajou longe da França para a Espanha.'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': '69da50b5-e427-44be-b396-1e56d821c6b0', 'type': 'function', 'function': {'name': 'Person', 'arguments': '{"name": "Fiona", "hair_color": null, "height_in_meters": null}'}}]}), ToolMessage(content='Você chamou corretamente esta ferramenta.', tool_call_id='69da50b5-e427-44be-b396-1e56d821c6b0'), HumanMessage(content='este é algum texto')])
Criar um extrator
Aqui, vamos criar um extrator usando gpt-4.
llm = ChatOpenAI(
model="gpt-4-0125-preview",
temperature=0,
)
runnable = prompt | llm.with_structured_output(
schema=Data,
method="function_calling",
include_raw=False,
)
/Users/harrisonchase/workplace/langchain/libs/core/langchain_core/_api/beta_decorator.py:86: LangChainBetaWarning: A função `with_structured_output` está em beta. Está sendo trabalhada ativamente, então a API pode mudar.
warn_beta(
Sem exemplos
Observe que mesmo usando gpt-4, está falhando com um caso de teste muito simples!
for _ in range(5):
text = "O sistema solar é grande, mas a terra só tem 1 lua."
print(runnable.invoke({"text": text, "examples": []}))
pessoas=[]
pessoas=[Pessoa(nome='terra', cor_do_cabelo=None, altura_em_metros=None)]
pessoas=[Pessoa(nome='terra', cor_do_cabelo=None, altura_em_metros=None)]
pessoas=[]
pessoas=[]
Com exemplos
Exemplos de referência ajudam a corrigir a falha!
for _ in range(5):
text = "O sistema solar é grande, mas a terra só tem 1 lua."
print(runnable.invoke({"text": text, "examples": mensagens}))
pessoas=[]
pessoas=[]
pessoas=[]
pessoas=[]
pessoas=[]
runnable.invoke(
{
"text": "Meu nome é Harrison. Meu cabelo é preto.",
"examples": mensagens,
}
)
Data(pessoas=[Pessoa(nome='Harrison', cor_do_cabelo='preto', altura_em_metros=None)])