参照例の使用

LLMに参照例を提供することで、抽出の品質を高めることができます。

ヒント: このチュートリアルでは、モデルを呼び出すツールで例を使用する方法に焦点を当てていますが、このテクニックは一般的に適用可能であり、JSONやプロンプトベースの技術とも使用できます。

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "あなたは抽出アルゴリズムのエキスパートです。"
            "テキストから関連する情報のみを抽出してください。"
            "抽出する属性の値がわからない場合は、その属性の値にはnullを返してください。",
        ),
        MessagesPlaceholder("examples"),  # <-- 例!
        ("human", "{text}"),
    ]
)

テンプレートを試してみる:

from langchain_core.messages import (
    HumanMessage,
)

prompt.invoke(
    {"text": "これはテストテキストです", "examples": [HumanMessage(content="テスト1 2 3")]}
)
ChatPromptValue(messages=[SystemMessage(content="あなたは抽出アルゴリズムのエキスパートです。テキストから関連する情報のみを抽出してください。抽出する属性の値がわからない場合は、その属性の値にはnullを返してください。"), HumanMessage(content='テスト1 2 3'), HumanMessage(content='これはテストテキストです')])

スキーマの定義

クイックスタートから人のスキーマを再利用しましょう。

from typing import List, Optional

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


class Person(BaseModel):
    """人物に関する情報。"""


    name: Optional[str] = Field(..., description="人物の名前")
    hair_color: Optional[str] = Field(
        ..., description="わかっている場合は人物の髪の色"
    )
    height_in_meters: Optional[str] = Field(..., description="メートル単位の身長")


class Data(BaseModel):
    """人物に関する抽出データ。"""

    people: List[Person]

参照例の定義

例は、入出力のペアのリストとして定義することができます。

それぞれの例には、例の input テキストと、テキストから抽出されるべき内容を示す output が含まれます。

情報

これは少し専門的な内容なので、理解できない場合は無視しても構いません!

例のフォーマットは使用されるAPI(例:ツールの呼び出しやJSONモードなど)に一致する必要があります。

ここでは、ツールの呼び出しAPIに期待されるフォーマットに一致するようにフォーマットされた例が示されます。

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):
    """テキスト入力と予想されるツール呼び出しで構成される例の表現。

    抽出のために、ツールの呼び出しはpydanticモデルのインスタンスとして表されます。
    """

    input: str  # これは例のテキストです
    tool_calls: List[BaseModel]  # 抽出されるべきpydanticモデルのインスタンス


def tool_example_to_messages(example: Example) -> List[BaseMessage]:
    """例をLLMに供給できるメッセージのリストに変換します。

    このコードは、例をチャットモデルに供給できるメッセージのリストに変換するアダプターです。

    例ごとのメッセージリストは以下のものに対応しています:

    1) HumanMessage: 抽出すべき内容を含む
    2) AIMessage: モデルから抽出された情報を含む
    3) ToolMessage: モデルに対して正しくツールが要求されたことを確認する

    一部のチャットモデルは抽出ユースケースではなくエージェント向けに過剰最適化されているため、ToolMessageが必要です。
    """
    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 [
        "You have correctly called this tool."
    ] * 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

次に、例を定義し、それらをメッセージ形式に変換します。

examples = [
    (
        "大洋は広大で青いです。深さは2万フィート以上あります。多くの魚がいます。",
        Person(name=None, height_in_meters=None, hair_color=None),
    ),
    (
        "フィオナはフランスからスペインまで遠く旅行しました。",
        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]})
    )

プロンプトをテストしてみましょう。

prompt.invoke({"text": "これはテキストです", "examples": messages})
ChatPromptValue(messages=[SystemMessage(content="抽出アルゴリズムの専門家です。テキストから関連情報のみを抽出します。抽出される属性の値がわからない場合は、その属性の値にはnullを返してください。"), HumanMessage(content="海は広大で青いです。深さは2万フィート以上です。たくさんの魚がいます。"), 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='このツールを正しく呼び出しました。', tool_call_id='c75e57cc-8212-4959-81e9-9477b0b79126'), HumanMessage(content='フィオナはフランスからスペインまで遠く旅行しました。'), 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='このツールを正しく呼び出しました。', tool_call_id='69da50b5-e427-44be-b396-1e56d821c6b0'), HumanMessage(content='これはテキストです')])

エクストラクターの作成

ここでは、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: 関数 `with_structured_output` はベータ版です。積極的に取り組んでいるため、API が変更される可能性があります。
  warn_beta(

例なし

gpt-4 を使用しているにもかかわらず、非常に簡単な テストケースでも失敗していることに注意してください!

for _ in range(5):
    text = "太陽系は広大ですが、地球は月がたった1つしかありません。"
    print(runnable.invoke({"text": text, "examples": []}))
people=[]
people=[Person(name='earth', hair_color=None, height_in_meters=None)]
people=[Person(name='earth', hair_color=None, height_in_meters=None)]
people=[]
people=[]

例を含む

参考例は失敗を修正するのに役立ちます!

for _ in range(5):
    text = "太陽系は広大ですが、地球は月がたった1つしかありません。"
    print(runnable.invoke({"text": text, "examples": messages}))
people=[]
people=[]
people=[]
people=[]
people=[]
runnable.invoke(
    {
        "text": "私の名前はHarrisonです。私の髪は黒です。",
        "examples": messages,
    }
)
Data(people=[Person(name='Harrison', hair_color='black', height_in_meters=None)])