見出し画像

LangChainでJSON配列を出力


作るもの

  • こんな感じに構造的な出力を得られるコードを作ります

% python character.py 鬼滅の刃の登場人物は? | tr "'" '"' | jq -r ".characters[]|[.name, .sex, .age, .personality]|@csv" | xsv table
竈門炭治郎  男  15    優しい、責任感が強い
禰豆子      女  14    おとなしい、強い意志を持つ
我妻善逸    男  16    臆病、しかし勇敢な一面も
嘴平伊之助  男  15    野生的、好戦的
煉獄杏寿郎  男  20    情熱的、正義感が強い
富岡義勇    男  23    冷静、責任感が強い
胡蝶しのぶ  女  18    知的、優雅
無惨        男  1000  冷酷、狡猾

事前準備

  • 今回は安いのでOpenAIのGPT-4o-miniを使います

  • 環境変数にOPENAI_API_KEYを設定しておいてください

  • とても参考になる記事はこちら

  • python環境の設定は済ませておいてください

  • langchainのインストールは済ませておいてください


構造化したデータを出力する流れ

  • LangChainでアウトプットパーサーを使うと構造化した出力を得られます。(JSON、XML、Pydanticなど)

  • さっそく以下の順番で作っていきましょう

  1. 構造体を定義する

  2. パーサーを設定する

  3. プロンプトを設定する

  4. LLMを設定する

  5. Chainを実行する

  6. 結果を出力する

  7. 結果を確認する


1. 構造体(配列)を定義する

  • langchain.output_parsers から ResponseSchemaを使います

from langchain.output_parsers import ResponseSchema
  • 構造体の定義

    • 映像作品の登場人物について以下を取得してみます

      • 名前 → name(string型)

      • 性別 → sex(string型)

      • 年齢 → age(int型)

      • 性格 → personality(string型)

# 構造体の設定
response_schemas = [
  ResponseSchema(
    name="characters", 
    description="配列形式の項目リスト。例: [{name: string,sex: string,age: int,personality: string}]",
    type="array(objects)"
  )
]
  • charactersは配列として複数人返ってくることを想定して、「名前」「性別」「年齢」「性格」は大括弧で括ります。


2. パーサーを設定する

  • langchain.output_parsers から StructuredOutputParser を使います

from langchain.output_parsers import ResponseSchema, StructuredOutputParser
  • パーサーの設定

    • 先ほど設定した response_schemas を出力する構造体(from_response_schemas)に指定します。


# パーサーの設定
parser = StructuredOutputParser.from_response_schemas(response_schemas)

3. プロンプトを設定する

  • langchain.prompts から ChatPromptTemplate を使います

from langchain.prompts import ChatPromptTemplate
  • プロンプトの設定

    • format_instructions には、先ほど設定した parser get_format_instructions() から取り出した内容を指定し、テンプレートに埋め込みます。

    • テンプレートの中の {question} は、chain の実行時に内容を指定するための変数です。

# プロンプトの設定
prompt_template=ChatPromptTemplate.from_template(
    template="次の質問に回答してください\n{format_instructions}\n{question}",
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

4. LLMを設定する

  • langchain_openai から ChatOpenAI を使います

from langchain_openai import ChatOpenAI
  • LLMの設定

    • ここでは temperature と model を指定しています

    • お好みに合わせて設定してください

# LLMの設定
llm = ChatOpenAI(
    temperature=0.7,
    model="gpt-4o-mini"
    )

5. Chainを実行する

  • chain の実行

    • 先ほど用意した以下をパイプで繋げます

      • prompt_template

      • llm

      • parser

# Chainの実行
chain = prompt_template | llm | parser

6. 結果を出力する

  • コード実行時に引数で質問を書けるようにします

    • sys を使います

import sys
  • 結果の出力

    • 引数を question に指定して実行します

    • 引数がない場合はドラえもんについて質問します

# 結果の出力
question = sys.argv[1] if len(sys.argv) > 1 else "ドラえもんの登場人物は?"
result = chain.invoke({"question": question})
print(result)

7. 結果を確認する

  • 結果の確認

    • 文字列がシングルクォートなので tr でダブルクォートに置換しています

    • 出力結果を jq で整形しています

% python character.py 美女と野獣の登場人物は? | tr "'" '"' | jq .
{
  "characters": [
    {
      "name": "ベル",
      "sex": "女性",
      "age": 17,
      "personality": "知的で勇敢"
    },
    {
      "name": "野獣",
      "sex": "男性",
      "age": 21,
      "personality": "孤独で優しい"
    },
    {
      "name": "ガストン",
      "sex": "男性",
      "age": 25,
      "personality": "自信過剰で傲慢"
    },
    {
      "name": "ルミエール",
      "sex": "男性",
      "age": 50,
      "personality": "陽気でおしゃべり"
    },
    {
      "name": "コグスワース",
      "sex": "男性",
      "age": 60,
      "personality": "几帳面で真面目"
    },
    {
      "name": "ポット夫人",
      "sex": "女性",
      "age": 55,
      "personality": "優しくて母性的"
    },
    {
      "name": "チップ",
      "sex": "男性",
      "age": 5,
      "personality": "無邪気で好奇心旺盛"
    }
  ]
}

コード全文

from langchain.output_parsers import ResponseSchema, StructuredOutputParser
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
import sys

# 構造体の定義
response_schemas = [
  ResponseSchema(
    name="characters", 
    description="配列形式の項目リスト。例: [{name: string,sex: string,age: int,personality: string}]",
    type="array(objects)"
  )
]

# パーサーの設定
parser = StructuredOutputParser.from_response_schemas(response_schemas)

# プロンプトの設定
prompt_template=ChatPromptTemplate.from_template(
    template="次の質問に回答してください\n{format_instructions}\n{question}",
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

# LLMの設定
llm = ChatOpenAI(
    temperature=0,
    model="gpt-4o-mini"
    )

# Chainの実行
chain = prompt_template | llm | parser

# 結果の出力
question = sys.argv[1] if len(sys.argv) > 1 else "ドラえもんの登場人物は?"
result = chain.invoke({"question": question})
print(result)


この記事が気に入ったらサポートをしてみませんか?