Analyse

Les LLM capables de bien suivre les instructions peuvent être chargés de produire des informations dans un format donné.

Cette approche repose sur la conception de bons exemples, puis sur l'analyse de la sortie des LLM pour les amener à extraire efficacement les informations.

Ici, nous utiliserons Claude qui est excellent pour suivre les instructions! Voir Anthropic models.

from langchain_anthropic.chat_models import ChatAnthropic

model = ChatAnthropic(model_name="claude-3-sonnet-20240229", temperature=0)

astuce: Toutes les mêmes considérations sur la qualité de l'extraction s'appliquent à l'approche d'analyse. Consultez les directives pour la qualité de l'extraction.

Ce tutoriel se veut simple, mais devrait généralement inclure des exemples de référence pour optimiser les performances!

Utilisation de PydanticOutputParser

L'exemple suivant utilise le PydanticOutputParser intégré pour analyser la sortie d'un modèle 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):
    """Informations sur une personne."""

    name: str = Field(..., description="Le nom de la personne")
    height_in_meters: float = Field(
        ..., description="La taille de la personne exprimée en mètres."
    )


class People(BaseModel):
    """Informations d'identification sur toutes les personnes dans un texte."""

    people: List[Person]


parser = PydanticOutputParser(pydantic_object=People)

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Répondez à la requête de l'utilisateur. Enveloppez la sortie dans des balises `json`.\n{format_instructions}",
        ),
        ("human", "{query}"),
    ]
).partial(format_instructions=parser.get_format_instructions())

Jetons un coup d'œil aux informations envoyées au modèle

query = "Anna a 23 ans et elle mesure 1,83 mètre"
print(prompt.format_prompt(query=query).to_string())
Système: Répondez à la requête de l'utilisateur. Enveloppez la sortie dans des balises `json`.
La sortie doit être formatée comme une instance JSON conforme au schéma JSON ci-dessous.

Par exemple, pour le schéma {"properties": {"foo": {"title": "Foo", "description": "une liste de chaînes", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
l'objet {"foo": ["bar", "baz"]} est une instance bien formatée du schéma. L'objet {"properties": {"foo": ["bar", "baz"]}} n'est pas bien formaté.

Voici le schéma de sortie:
{"description": "Informations d'identification sur toutes les personnes dans un texte.", "properties": {"people": {"title": "People", "type": "array", "items": {"$ref": "#/definitions/Person"}}}, "required": ["people"], "definitions": {"Person": {"title": "Person", "description": "Informations sur une personne.", "type": "object", "properties": {"name": {"title": "Name", "description": "Le nom de la personne", "type": "string"}, "height_in_meters": {"title": "Height In Meters", "description": "La taille de la personne exprimée en mètres.", "type": "number"}}, "required": ["name", "height_in_meters"]}}}

Humain: Anna a 23 ans et elle mesure 1,83 mètre
chain = prompt | model | parser
chain.invoke({"query": query})
People(people=[Person(name='Anna', height_in_meters=1.83)])

Analyse personnalisée

Il est facile de créer une invitation personnalisée et un analyseur avec LangChain et LCEL.

Vous pouvez utiliser une fonction simple pour analyser la sortie du modèle !

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):
    """Informations sur une personne."""

    name: str = Field(..., description="Le nom de la personne")
    height_in_meters: float = Field(
        ..., description="La taille de la personne exprimée en mètres."
    )


class People(BaseModel):
    """Informations d'identification sur toutes les personnes dans un texte."""

    people: List[Person]


prompt = ChatPromptTemplate.from_messages(
    [
        (
            "système",
            "Répondez à la requête de l'utilisateur. Sortez votre réponse en JSON qui correspond au schéma donné : ```json\n{schema}\n```. "
            "Assurez-vous d'encadrer la réponse dans les balises ```json et ```",
        ),
        ("humain", "{query}"),
    ]
).partial(schema=People.schema())


def extract_json(message: AIMessage) -> List[dict]:
    """Extrait le contenu JSON d'une chaîne où le JSON est inclus entre les balises ```json et ```.

    Paramètres :
        texte (str) : Le texte contenant le contenu JSON.

    Renvoie :
        list : Une liste de chaînes JSON extraites.
    """
    texte = message.content
    motif = r"```json(.*?)```"

    correspondances = re.findall(motif, texte, re.DOTALL)

    try:
        return [json.loads(correspondance.strip()) for correspondance in correspondances]
    except Exception:
        raise ValueError(f"Échec de l'analyse : {message}")
query = "Anna a 23 ans et elle mesure 1,83 mètre de haut"
print(prompt.format_prompt(query=query).to_string())
Système : Répondez à la requête de l'utilisateur. Sortez votre réponse en JSON qui correspond au schéma donné : \`\`\`json
{'title': 'People', 'description': 'Informations d'identification sur toutes les personnes dans un texte.', 'type': 'object', 'properties': {'people': {'title': 'People', 'type': 'array', 'items': {'$ref': '#/definitions/Person'}}}, 'required': ['people'], 'definitions': {'Person': {'title': 'Person', 'description': 'Informations sur une personne.', 'type': 'object', 'properties': {'name': {'title': 'Name', 'description': 'Le nom de la personne', 'type': 'string'}, 'height_in_meters': {'title': 'Height In Meters', 'description': 'La taille de la personne exprimée en mètres.', 'type': 'number'}}, 'required': ['name', 'height_in_meters']}}}
\`\`\`. Assurez-vous d'encadrer la réponse dans les balises \`\`\`json et \`\`\`
Humain : Anna a 23 ans et elle mesure 1,83 mètre de haut
chaîne = invitation | modèle | extract_json
chaîne.invoke({"query": query})
[{'people': [{'name': 'Anna', 'height_in_meters': 1.83}]}]

Autres bibliothèques

Si vous cherchez à extraire en utilisant une approche d'analyse, jetez un œil à la bibliothèque Kor. Elle est rédigée par l'un des mainteneurs de LangChain et elle aide à créer une invitation qui prend en compte des exemples, permet de contrôler les formats (par exemple, JSON ou CSV) et exprime le schéma en TypeScript. Elle semble être assez efficace !