Przykłady referencyjne

Jakość wydobycia danych często można poprawić, dostarczając przykładowe referencyjne dla LLM.

wskazówka: Chociaż ten samouczek skupia się na użyciu przykładów w narzędziu wywołującym model, ta technika jest ogólnie zastosowalna i będzie działać również z technikami opartymi na JSON lub zapytaniach.

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Jesteś ekspertem w algorytmach ekstrakcji. "
            "Wydobywaj tylko istotne informacje z tekstu. "
            "Jeśli nie znasz wartości danego atrybutu, "
            "proszę zwrócić null jako wartość atrybutu.",
        ),
        MessagesPlaceholder("examples"),  # <-- PRZYKŁADY!
        ("human", "{text}"),
    ]
)

Wypróbuj szablon:

from langchain_core.messages import (
    HumanMessage,
)

prompt.invoke(
    {"text": "to jest jakiś tekst", "examples": [HumanMessage(content="testowanie 1 2 3")]}
)
ChatPromptValue(messages=[SystemMessage(content='Jesteś ekspertem w algorytmach ekstrakcji. Wydobywaj tylko istotne informacje z tekstu. Jeśli nie znasz wartości danego atrybutu, proszę zwrócić null jako wartość atrybutu.'), HumanMessage(content='testowanie 1 2 3'), HumanMessage(content='to jest jakiś tekst')])

Zdefiniuj schemat

Ponownie użyjemy schematu osoby z szybkiego startu.

from typing import List, Optional

from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI


class Person(BaseModel):
    """Informacje o osobie."""


    name: Optional[str] = Field(..., description="Imię osoby")
    hair_color: Optional[str] = Field(
        ..., description="Kolor oczu osoby, jeśli znany"
    )
    height_in_meters: Optional[str] = Field(..., description="Wzrost w metrach")


class Data(BaseModel):
    """Wydobyte dane o osobach."""

    people: List[Person]

Zdefiniuj przykłady odniesienia

Przykłady mogą być zdefiniowane jako lista par wejście-wyjście.

Każdy przykład zawiera tekst wejścia oraz oczekiwane wyjście, pokazujące co powinno zostać wyodrębnione z tekstu.

info

To trochę zagłębione, więc śmiało można zignorować, jeśli nie jest jasne!

Format przykładu musi pasować do używanego interfejsu API (np. wywołanie narzędzia lub tryb JSON itp.).

Tutaj sformatowane przykłady będą pasować do oczekiwanego formatu dla interfejsu wywołującego narzędzie, ponieważ to właśnie używamy.

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):
    """Reprezentacja przykładu składającego się z tekstu wejściowego i oczekiwanych wywołań narzędzi.

    Dla wyodrębnienia wywołania narzędzi są reprezentowane jako instancje modelu pydantic.
    """

    input: str  # To jest tekst przykładu
    tool_calls: List[BaseModel]  # Instancje modeli pydantic, które powinny zostać wyodrębnione


def tool_example_to_messages(example: Example) -> List[BaseMessage]:
    """Konwertuje przykład na listę wiadomości, które można podać do modelu językowego.

    Ten kod stanowi adapter, który konwertuje nasz przykład na listę wiadomości,
    które można podać do modelu rozmowy.

    Lista wiadomości na przykład odpowiada:

    1) HumanMessage: zawiera treść, z której powinna zostać wyodrębniona zawartość.
    2) AIMessage: zawiera wyodrębnioną informację z modelu
    3) ToolMessage: zawiera potwierdzenie dla modelu, że poprawnie wywołano narzędzie.

    Wiadomość ToolMessage jest wymagana, ponieważ niektóre modele rozmowy są hiperzoptymalizowane dla agentów
    niż dla zastosowania wyodrębniania.
    """
    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 [
        "Poprawnie wywołałeś to narzędzie."
    ] * 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

Teraz zdefiniujmy nasze przykłady i przekształćmy je na format wiadomości.

examples = [
    (
        "Ocean jest ogromny i niebieski. Ma ponad 20 000 stóp głębokości. Wiele ryb w nim pływa.",
        Person(name=None, height_in_meters=None, hair_color=None),
    ),
    (
        "Fiona podróżowała daleko od Francji do Hiszpanii.",
        Person(name="Fiona", height_in_meters=None, hair_color=None),
    ),
]

messages = []

for text, tool_call in examples:
    messages.extend(
        tool_example_to_messages({"input": text, "tool_calls": [tool_call]})
    )

Sprawdźmy teraz polecenie

prompt.invoke({"text": "to jest jakiś tekst", "examples": messages})
ChatPromptValue(messages=[SystemMessage(content="Jesteś ekspertem od ekstrakcji algorytmów. Wydobywaj tylko istotne informacje z tekstu. Jeśli nie znasz wartości pytanej cechy do wydobycia, zwróć null dla wartości tej cechy."), HumanMessage(content="Ocean jest ogromny i niebieski. Ma ponad 20 000 stóp głębokości. Wiele ryb znajduje się w nim."), 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='Poprawnie wywołałeś ten narzędzie.', tool_call_id='c75e57cc-8212-4959-81e9-9477b0b79126'), HumanMessage(content='Fiona podróżowała daleko od Francji do Hiszpanii.'), 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='Poprawnie wywołałeś to narzędzie.', tool_call_id='69da50b5-e427-44be-b396-1e56d821c6b0'), HumanMessage(content='to jest jakiś tekst')])

Stwórz ekstraktor

Tutaj stworzymy ekstraktor używając 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: Funkcja `with_structured_output` jest w fazie beta. Aktualnie jest aktywnie rozwijana, więc API może ulec zmianie.
  warn_beta(

Bez przykładów

Zauważ, że mimo iż używamy gpt-4, zawodzi on przy bardzo prostym teście przypadku!

for _ in range(5):
    text = "Układ słoneczny jest duży, ale Ziemia ma tylko 1 księżyc."
    print(runnable.invoke({"text": text, "examples": []}))
ludzie=[]
ludzie=[Osoba(imię='ziemia', kolor_włosów=None, wzrost_w_metrach=None)]
ludzie=[Osoba(imię='ziemia', kolor_włosów=None, wzrost_w_metrach=None)]
ludzie=[]
ludzie=[]

Z przykładami

Przykłady referencyjne pomagają naprawić niepowodzenie!

for _ in range(5):
    text = "Układ słoneczny jest duży, ale Ziemia ma tylko 1 księżyc."
    print(runnable.invoke({"text": text, "examples": messages}))
ludzie=[]
ludzie=[]
ludzie=[]
ludzie=[]
ludzie=[]
runnable.invoke(
    {
        "text": "Mam na imię Harrison. Moje włosy są czarne.",
        "examples": messages,
    }
)
Dane(people=[Osoba(imię='Harrison', kolor_włosów='czarne', wzrost_w_metrach=None)])