Ejemplos de referencia
La calidad de las extracciones a menudo se puede mejorar al proporcionar ejemplos de referencia al LLM.
Consejo: Aunque este tutorial se centra en cómo usar ejemplos con una herramienta que llama al modelo, esta técnica es generalmente aplicable y también funcionará con técnicas basadas en JSON o en el prompt.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
(
"sistema",
"Eres un algoritmo de extracción experto. "
"Solo extrae información relevante del texto. "
"Si no conoces el valor de un atributo solicitado para extraer, devuelve nulo para el valor del atributo.",
),
MessagesPlaceholder("ejemplos"), # <-- ¡EJEMPLOS!
("humano", "{texto}"),
]
)
Probar la plantilla:
from langchain_core.messages import (
HumanMessage,
)
prompt.invoke(
{"texto": "este es un texto", "ejemplos": [HumanMessage(content="prueba 1 2 3")]}
)
ChatPromptValue(mensajes=[SystemMessage(contenido="Eres un algoritmo de extracción experto. Solo extrae información relevante del texto. Si no conoces el valor de un atributo solicitado para extraer, devuelve nulo para el valor del atributo."), HumanMessage(contenido='prueba 1 2 3'), HumanMessage(contenido='este es un texto')])
Definir el esquema
Reutilicemos el esquema de persona del inicio rápido.
from typing import List, Optional
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
class Persona(BaseModel):
"""Información sobre una persona."""
nombre: Optional[str] = Field(..., descripcion="El nombre de la persona")
color_ojos: Optional[str] = Field(
..., descripcion="El color de los ojos de la persona si se conoce"
)
altura_en_metros: Optional[str] = Field(..., descripcion="Altura en METROS")
class Datos(BaseModel):
"""Datos extraídos sobre personas."""
personas: List[Persona]
Definir ejemplos de referencia
Los ejemplos se pueden definir como una lista de pares de entrada-salida.
Cada ejemplo contiene un texto de entrada
y una salida
que muestra lo que se debe extraer del texto.
info
Esto es un poco complicado, ¡así que si no lo entiendes, siéntete libre de ignorarlo!
El formato del ejemplo debe coincidir con la API utilizada (por ejemplo, llamada a la herramienta o modo JSON, etc.).
Aquí, los ejemplos formateados coincidirán con el formato esperado para la API de llamada a la herramienta, ya que es lo 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):
"""Una representación de un ejemplo que consiste en texto de entrada y llamadas de herramienta esperadas.
Para la extracción, las llamadas de herramienta se representan como instancias del modelo pydantic.
"""
input: str # Este es el texto de ejemplo
tool_calls: List[BaseModel] # Instancias del modelo pydantic que deben ser extraídas
def tool_example_to_messages(example: Example) -> List[BaseMessage]:
"""Convertir un ejemplo en una lista de mensajes que se pueden alimentar a un LLM.
Este código es un adaptador que convierte nuestro ejemplo en una lista de mensajes
que se pueden alimentar a un modelo de chat.
La lista de mensajes por ejemplo corresponde a:
1) HumanMessage: contiene el contenido del cual debe extraerse el contenido.
2) AIMessage: contiene la información extraída del modelo
3) ToolMessage: contiene la confirmación al modelo de que se solicitó correctamente una herramienta.
El ToolMessage es necesario porque algunos de los modelos de chat están hiper-optimizados para agentes
en lugar de para un caso de uso de extracción.
"""
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 [
"Has llamado correctamente a esta herramienta."
] * 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 continuación, vamos a definir nuestros ejemplos y luego convertirlos al formato de mensaje.
examples = [
(
"El océano es vasto y azul. Tiene más de 20,000 pies de profundidad. Hay muchos peces en él.",
Persona(nombre=None, altura_en_metros=None, color_de_cabello=None),
),
(
"Fiona viajó lejos de Francia a España.",
Persona(nombre="Fiona", altura_en_metros=None, color_de_cabello=None),
),
]
mensajes = []
for texto, llamada_herramienta in ejemplos:
mensajes.extend(
tool_example_to_messages({"input": texto, "tool_calls": [llamada_herramienta]})
)
Probemos el comando
prompt.invoke({"text": "este es un poco de texto", "ejemplos": mensajes})
ChatPromptValue(messages=[SystemMessage(content="Eres un algoritmo de extracción experto. Solo extrae información relevante del texto. Si no conoces el valor de un atributo que se te pide extraer, devuelve null como valor del atributo."), HumanMessage(content="El océano es vasto y azul. Tiene más de 20,000 pies de profundidad. Hay muchos peces en él."), 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='Has llamado correctamente a esta herramienta.', tool_call_id='c75e57cc-8212-4959-81e9-9477b0b79126'), HumanMessage(content='Fiona viajó lejos de Francia a España.'), 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='Has llamado correctamente a esta herramienta.', tool_call_id='69da50b5-e427-44be-b396-1e56d821c6b0'), HumanMessage(content='este es algún texto')])
Crear un extractor
Aquí, crearemos un extractor utilizando gpt-4.
llm = ChatOpenAI(
model="gpt-4-0125-preview",
temperature=0,
)
ejecutable = 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: La función `with_structured_output` está en beta. Se está trabajando activamente en ella, por lo que el API puede cambiar.
warn_beta(
Sin ejemplos
¡Observa que aunque estamos utilizando gpt-4, falla con un caso de prueba muy simple!
for _ in range(5):
texto = "El sistema solar es grande, ¡pero la Tierra solo tiene 1 luna!"
print(ejecutable.invoke({"texto": texto, "ejemplos": []}))
gente=[]
gente=[Persona(nombre='Tierra', color_de_cabello=None, altura_en_metros=None)]
gente=[Persona(nombre='Tierra', color_de_cabello=None, altura_en_metros=None)]
gente=[]
gente=[]
Con ejemplos
¡Los ejemplos de referencia ayudan a solucionar el fallo!
for _ in range(5):
texto = "El sistema solar es grande, ¡pero la Tierra solo tiene 1 luna!"
print(ejecutable.invoke({"texto": texto, "ejemplos": mensajes}))
gente=[]
gente=[]
gente=[]
gente=[]
gente=[]
ejecutable.invoke(
{
"texto": "Mi nombre es Harrison. Tengo el cabello negro.",
"ejemplos": messages,
}
)
Datos(personas=[Persona(nombre='Harrison', color_de_cabello='negro', altura_en_metros=None)])