StructuredOutputParserについてまとめておく
2025.4時点でStructuredOutputParserについての記述があまりないので、その一助のために記載しておく
pydamic function callの内藤とかとまじってしまっていて、AIさまも正しい内容をだしてくれてない感じしたので
コード
from duckduckgo_search import DDGS
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain_community.document_loaders import UnstructuredURLLoader
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
# OutputParserの準備
response_schemas = [
ResponseSchema(name="address", description="会場の住所"),
ResponseSchema(name="access", description="アクセス方法"),
ResponseSchema(name="features", description="会場の特徴"),
ResponseSchema(name="manager", description="会場の担当者"),
ResponseSchema(name="tel", description="会場の電話番号"),
ResponseSchema(name="email", description="メールアドレス"),
ResponseSchema(name="url", description="URL"),
ResponseSchema(name="open", type="boolean", description="営業しているかどうか"),
ResponseSchema(name="venues", type="list", description="会場内の施設のリスト"),
]
# parserを生成
parser = StructuredOutputParser.from_response_schemas(response_schemas)
def register_chroma(word:str):
# Chromaの初期化
results = DDGS().text(word, max_results=20, region="jp-jp")
urls = list(map(lambda x: x['href'], results))
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
loader = UnstructuredURLLoader(urls=urls)
documents = loader.load()
docs = splitter.split_documents(documents)
embeddings = OpenAIEmbeddings()
chroma = Chroma.from_documents(docs, embeddings, persist_directory="./chromadb")
# chroma.persist()
return chroma
word = 'Bunkamura'
chroma = register_chroma(word)
retriever = chroma.as_retriever()
llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0)
parser = StructuredOutputParser.from_response_schemas(response_schemas)
template = """\
指定された会場の情報を教えてください。
文脈:{context}
{format_instructions}
会場:{input}
"""
# Promptを生成し、内容を部分適用する
prompt = ChatPromptTemplate.from_template(template=template)
prompt_with_parser = prompt.partial(format_instructions=parser.get_format_instructions())
# クエリを投げる
chain = {"context": retriever, "input": RunnablePassthrough()} | prompt_with_parser | llm | parser
result = chain.invoke(word)
print(result)
流れとしては
- chromadbからのretrieverの読みだし
- lChatPromptTemlateからpartialを設定して部分適用されたpromptを生成
- それをLCELで流す
- ResponseSchemaの型はデフォルトだが、型情報をわたすと、それにしたがって生成する
- 最終的にはjsonがかえってくる
langchain関連のインポートなりduckduckgoなりのインタフェイスについてはいくらでも情報があるので調べてください
注意
ResponseSchemaのnameのところは問いあわせに使われたりもするので、ミススペルなどするとinvalid jsonで落ちる罠とかある
LLMならではという感じがしますね
(capasityとかいれてたら落ちたよ)
まとめ
ResponseSchemaの使いかたとPromptの流れがわかれば大丈夫だと思います
ではenjoy