Análisis
Los LLMs que pueden seguir instrucciones bien pueden ser asignados a la tarea de producir información en un formato dado.
Este enfoque depende de diseñar buenas indicaciones y luego analizar la salida de los LLMs para que puedan extraer información de manera efectiva.
Aquí, utilizaremos Claude, que es bueno siguiendo instrucciones. Ver Modelos Antropicos.
from langchain_anthropic.chat_models import ChatAnthropic
model = ChatAnthropic(model_name="claude-3-sonnet-20240229", temperature=0)
Consejo: Todas las mismas consideraciones para la calidad de extracción se aplican al enfoque de análisis. Revisa las pautas para la calidad de extracción.
Este tutorial está diseñado para ser simple, ¡pero generalmente debería incluir ejemplos de referencia para exprimir el rendimiento!
Uso de PydanticOutputParser
El siguiente ejemplo utiliza el PydanticOutputParser
incorporado para analizar la salida de un 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):
"""Información sobre una persona."""
name: str = Field(..., description="El nombre de la persona")
height_in_meters: float = Field(
..., description="La altura de la persona expresada en metros."
)
class People(BaseModel):
"""Información de identificación sobre todas las personas en un texto."""
people: List[Person]
parser = PydanticOutputParser(pydantic_object=People)
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Responde a la consulta del usuario. Envuelve la salida en etiquetas `json`\n{format_instructions}",
),
("human", "{query}"),
]
).partial(format_instructions=parser.get_format_instructions())
Echemos un vistazo a la información que se enviará al modelo
query = "Anna tiene 23 años y mide 1.83 metros de altura"
print(prompt.format_prompt(query=query).to_string())
Sistema: Responde a la consulta del usuario. Envuelve la salida en etiquetas `json`
La salida debe estar formateada como una instancia JSON que cumpla con el esquema JSON abajo.
Como ejemplo, para el esquema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
el objeto {"foo": ["bar", "baz"]} es una instancia bien formateada del esquema. El objeto {"properties": {"foo": ["bar", "baz"]}} no está bien formateado.
Aquí está el esquema de salida:
{"description": "Información de identificación sobre todas las personas en un texto.", "properties": {"people": {"title": "People", "type": "array", "items": {"$ref": "#/definitions/Person"}}}, "required": ["people"], "definitions": {"Person": {"title": "Person", "description": "Información sobre una persona.", "type": "object", "properties": {"name": {"title": "Nombre", "description": "El nombre de la persona", "type": "string"}, "height_in_meters": {"title": "Altura En Metros", "description": "La altura de la persona expresada en metros.", "type": "number"}}, "required": ["name", "height_in_meters"]}}}
Humano: Anna tiene 23 años y mide 1.83 metros de altura
chain = prompt | model | parser
chain.invoke({"query": query})
People(people=[Person(name='Anna', height_in_meters=1.83)])
Análisis Personalizado
Es fácil crear un mensaje personalizado y un analizador con LangChain
y LCEL
.
¡Puedes usar una función sencilla para analizar la salida del 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 Persona(BaseModel):
"""Información sobre una persona."""
nombre: str = Field(..., description="El nombre de la persona")
altura_en_metros: float = Field(
..., description="La altura de la persona expresada en metros."
)
class Personas(BaseModel):
"""Información de identificación sobre todas las personas en un texto."""
personas: List[Persona]
prompt = ChatPromptTemplate.from_messages(
[
(
"sistema",
"Responde a la consulta del usuario. Genera tu respuesta como un JSON que coincida con el esquema dado: ```json\n{schema}\n```. "
"Asegúrate de envolver la respuesta en las etiquetas ```json y ```",
),
("humano", "{consulta}"),
]
).partial(schema=Personas.schema())
def extraer_json(mensaje: AIMessage) -> List[dict]:
"""Extrae el contenido JSON de una cadena donde el JSON está incrustado entre las etiquetas ```json y ```.
Parámetros:
text (str): El texto que contiene el contenido JSON.
Retorna:
list: Una lista de cadenas JSON extraídas.
"""
texto = mensaje.content
patron = r"```json(.*?)```"
coincidencias = re.findall(patron, texto, re.DOTALL)
try:
return [json.loads(coincidencia.strip()) for coincidencia in coincidencias]
except Exception:
raise ValueError(f"No se pudo analizar: {mensaje}")
query = "Anna tiene 23 años y mide 1.83 metros de altura"
print(prompt.format_prompt(query=query).to_string())
Sistema: Responde a la consulta del usuario. Genera tu respuesta como un JSON que coincida con el esquema dado: \`\`\`json
{'title': 'Personas', 'description': 'Información de identificación sobre todas las personas en un texto.', 'type': 'object', 'properties': {'personas': {'title': 'Personas', 'type': 'array', 'items': {'$ref': '#/definitions/Persona'}}}, 'required': ['personas'], 'definitions': {'Persona': {'title': 'Persona', 'description': 'Información sobre una persona.', 'type': 'object', 'properties': {'nombre': {'title': 'Nombre', 'description': 'El nombre de la persona', 'type': 'string'}, 'altura_en_metros': {'title': 'Altura En Metros', 'description': 'La altura de la persona expresada en metros.', 'type': 'number'}}, 'required': ['nombre', 'altura_en_metros']}}}
\`\`\`. Asegúrate de envolver la respuesta en las etiquetas \`\`\`json y \`\`\`
Humano: Anna tiene 23 años y mide 1.83 metros de altura
cadena = prompt | modelo | extraer_json
cadena.invoke({"consulta": query})
[{'personas': [{'nombre': 'Anna', 'altura_en_metros': 1.83}]}]
Otras Bibliotecas
Si estás interesado en extraer usando un enfoque de análisis, echa un vistazo a la biblioteca Kor. Está escrita por uno de los mantenedores de LangChain
y ayuda a crear un mensaje que tiene en cuenta ejemplos, permite controlar los formatos (por ejemplo, JSON o CSV) y expresa el esquema en TypeScript. ¡Parece funcionar muy bien!