Utiliser des exemples de référence
La qualité des extractions peut souvent être améliorée en fournissant des exemples de référence au LLM.
Astuce : Bien que ce tutoriel se concentre sur l'utilisation d'exemples avec un modèle appelant, cette technique est généralement applicable et fonctionnera également avec des techniques basées sur JSON ou des invites.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
(
"système",
"Vous êtes un algorithme d'extraction expert. "
"Extraites uniquement les informations pertinentes du texte. "
"Si vous ne connaissez pas la valeur d'un attribut demandé "
"à extraire, retournez null pour la valeur de l'attribut.",
),
MessagesPlaceholder("exemples"), # <-- EXEMPLES !
("humain", "{text}"),
]
)
Essayez le modèle :
from langchain_core.messages import (
MessageHumaine,
)
prompt.invoke(
{"text": "Ceci est un texte", "exemples": [MessageHumaine(contenu="test 1 2 3")]}
)
ChatPromptValue(messages=[SystemMessage(content="Vous êtes un algorithme d'extraction expert. Extraites uniquement les informations pertinentes du texte. Si vous ne connaissez pas la valeur d'un attribut demandé à extraire, retournez null pour la valeur de l'attribut."), HumanMessage(content='test 1 2 3'), HumanMessage(content='Ceci est un texte')])
Définir le schéma
Réutilisons le schéma de personne du guide de démarrage rapide.
from typing import List, Optional
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
class Personne(BaseModel):
"""Informations sur une personne."""
nom: Optional[str] = Field(..., description="Le nom de la personne")
couleur_des_cheveux: Optional[str] = Field(
..., description="La couleur des yeux de la personne si connue"
)
taille_en_mètres: Optional[str] = Field(..., description="Taille en MÈTRES")
class Donnees(BaseModel):
"""Données extraites sur les personnes."""
personnes: List[Personne]
Définir des exemples de référence
Les exemples peuvent être définis comme une liste de paires entrée-sortie.
Chaque exemple contient un texte d'entrée
et une sortie
indiquant ce qui doit être extrait du texte.
info
C'est un peu technique, donc n'hésitez pas à ignorer si vous ne comprenez pas!
Le format de l'exemple doit correspondre à l'API utilisée (par exemple, appel d'outil ou mode JSON, etc.).
Ici, les exemples formatés correspondront au format attendu pour l'API d'appel d'outil, car c'est ce que nous utilisons.
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):
"""Une représentation d'un exemple composé d'une entrée texte et des appels d'outil attendus.
Pour l'extraction, les appels d'outil sont représentés sous forme d'instances de modèle pydantic.
"""
input: str # Ceci est le texte de l'exemple
tool_calls: List[BaseModel] # Instances de modèle pydantic qui doivent être extraites
def tool_example_to_messages(example: Example) -> List[BaseMessage]:
"""Convertir un exemple en une liste de messages pouvant être introduits dans un LLM.
Ce code est un adaptateur qui convertit notre exemple en une liste de messages
qui peuvent être introduits dans un modèle de chat.
La liste de messages par exemple correspond à:
1) HumanMessage: contient le contenu à partir duquel le contenu doit être extrait.
2) AIMessage: contient les informations extraites du modèle
3) ToolMessage: contient la confirmation au modèle que le modèle a demandé un outil correctement.
Le ToolMessage est nécessaire car certains modèles de chat sont hyper-optimisés pour les agents
plutôt que pour un cas d'utilisation d'extraction.
"""
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 [
"Vous avez appelé cet outil correctement."
] * 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
Ensuite, définissons nos exemples et convertissons-les en format de message.
exemples = [
(
"L'océan est vaste et bleu. Il fait plus de 20 000 pieds de profondeur. Il y a beaucoup de poissons dedans.",
Personne(nom=None, taille_en_mètres=None, couleur_de_cheveux=None),
),
(
"Fiona a voyagé loin de la France à l'Espagne.",
Personne(nom="Fiona", taille_en_mètres=None, couleur_de_cheveux=None),
),
]
messages = []
for texte, appel_outil in exemples:
messages.extend(
tool_example_to_messages({"input": texte, "tool_calls": [appel_outil]})
)
Testons la requête
prompt.invoke({"texte": "voici un texte", "exemples": messages})
ChatPromptValue(messages=[SystemMessage(content="Tu es un algorithme d'extraction expert. Extrait uniquement les informations pertinentes du texte. Si tu ne connais pas la valeur d'un attribut demandé à extraire, renvoie null pour la valeur de l'attribut."), HumanMessage(content="L'océan est vaste et bleu. Il fait plus de 20 000 pieds de profondeur. Il y a beaucoup de poissons dedans."), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'c75e57cc-8212-4959-81e9-9477b0b79126', 'type': 'function', 'function': {'name': 'Personne', 'arguments': '{"nom": null, "couleur_de_cheveux": null, "taille_en_metres": null}'}}]}), ToolMessage(content="Tu as appelé correctement cet outil.", tool_call_id='c75e57cc-8212-4959-81e9-9477b0b79126'), HumanMessage(content="Fiona a voyagé loin de France en Espagne."), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': '69da50b5-e427-44be-b396-1e56d821c6b0', 'type': 'function', 'function': {'name': 'Personne', 'arguments': '{"nom": "Fiona", "couleur_de_cheveux": null, "taille_en_metres": null}'}}]}), ToolMessage(content="Tu as appelé correctement cet outil.", tool_call_id='69da50b5-e427-44be-b396-1e56d821c6b0'), HumanMessage(content="c'est un peu de texte")])
Créer un extracteur
Ici, nous allons créer un extracteur en utilisant gpt-4.
llm = ChatOpenAI(
model="gpt-4-0125-preview",
temperature=0,
)
executable = 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 fonction `with_structured_output` est en version bêta. Elle est actuellement en cours de développement, donc l'API peut changer.
warn_beta(
Sans exemples
Remarquez que même si nous utilisons gpt-4, il échoue avec un cas de test très simple!
for _ in range(5):
text = "Le système solaire est grand, mais la Terre n'a qu'une seule lune."
print(executable.invoke({"text": text, "examples": []}))
personnes=[]
personnes=[Personne(nom='Terre', couleur_de_cheveux=None, taille_en_metres=None)]
personnes=[Personne(nom='Terre', couleur_de_cheveux=None, taille_en_metres=None)]
personnes=[]
personnes=[]
Avec exemples
Les exemples de référence aident à corriger l'échec!
for _ in range(5):
text = "Le système solaire est grand, mais la Terre n'a qu'une seule lune."
print(executable.invoke({"text": text, "examples": messages}))
personnes=[]
personnes=[]
personnes=[]
personnes=[]
personnes=[]
executable.invoke(
{
"text": "Je m'appelle Harrison. Mes cheveux sont noirs.",
"examples": messages,
}
)
Données(personnes=[Personne(nom='Harrison', couleur_de_cheveux='noirs', taille_en_metres=None)])