출력 파서
LLM 언어 모델은 텍스트 형식으로 콘텐츠를 출력하지만, AI 애플리케이션을 개발할 때는 결과를 객체, 배열 등으로 변환하여 프로그램 처리를 용이하게 하고 싶습니다. 이를 위해서는 LangChain에서 제공하는 출력 파서를 사용하여 모델이 반환한 내용을 형식화해야 합니다.
출력 파서의 기능은 언어 모델이 반환한 결과를 형식화하는 것입니다. 출력 파서는 두 가지 필수 메서드를 구현해야 합니다.
- "get_format_instructions": 언어 모델이 어떤 형식으로 반환해야 하는지에 대한 지시사항을 포함한 문자열을 반환합니다.
- "parse": 모델이 반환한 내용을 대상 형식으로 파싱합니다.
이제 LangChain의 내장 출력 파서를 살펴보겠습니다.
Pydantic 파서
아래는 LangChain에 의해 캡슐화된 핵심 출력 파서인 PydanticOutputParser
입니다. 이 파서는 Python의 pydantic 라이브러리를 기반으로 하며 모델의 출력 결과를 Python 객체로 변환하는 데 사용됩니다.
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field, validator
from langchain_openai import OpenAI
model = OpenAI(model_name="gpt-3.5-turbo-instruct", temperature=0.0)
class Joke(BaseModel):
setup: str = Field(description="농담의 설정을 나타냅니다.")
punchline: str = Field(description="농담의 해답을 나타냅니다.")
@validator("setup")
def question_ends_with_question_mark(cls, field):
if field[-1] != "?":
raise ValueError("잘못된 형식의 질문입니다!")
return field
parser = PydanticOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
template="사용자 쿼리에 답하세요.\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
prompt_and_model = prompt | model
output = prompt_and_model.invoke({"query": "농담 좀 해줘."})
parser.invoke(output)
샘플 반환 결과:
Joke(setup='닭이 길을 건너는 이유는 뭔가요?', punchline='반대편으로 가기 위해서에요!')
LCEL 인터페이스
Runnable 인터페이스
출력 파서는 LangChain 표현 언어(LCEL)의 기본 블록 중 하나인 Runnable 인터페이스를 구현합니다. 이는 invoke
, ainvoke
, stream
, astream
, batch
, abatch
, astream_log
등과 같은 호출 메서드를 지원합니다.
LCEL에서의 출력 파서의 적용
출력 파서는 문자열 또는 BaseMessage
를 입력으로 받아 어떤 유형의 구조화된 데이터를 반환할 수 있습니다. 파서를 Runnable 시퀀스에 추가하여 파서 체인을 구축하고 호출할 수 있습니다.
chain = prompt | model | parser
chain.invoke({"query": "농담 좀 해줘."})
반환
Joke(setup='닭이 길을 건너는 이유는 뭔가요?', punchline='반대편으로 가기 위해서에요!')
일부 파서는 SimpleJsonOutputParser
처럼 부분 파싱 객체를 스트리밍할 수 있고, 다른 파서는 스트리밍을 지원하지 않을 수도 있습니다. 최종 출력은 파서가 부분 파싱 객체를 구축할 수 있는지에 따라 다릅니다.
from langchain.output_parsers.json import SimpleJsonOutputParser
json_prompt = PromptTemplate.from_template(
"질문에 답변하는 `answer` 키를 포함한 JSON 객체를 반환합니다: {question}"
)
json_parser = SimpleJsonOutputParser()
json_chain = json_prompt | model | json_parser
list(json_chain.stream({"question": "현미경을 발명한 사람은 누구인가요?"}))
[{},
{'answer': ''},
{'answer': '배미벙'},
{'answer': '배미적'},
{'answer': '배미적남자'},
{'answer': '배미적남자문'},
{'answer': '배미적남자문남자'},
{'answer': '배미적남자문남자선'},
{'answer': '배미적남자문남자선향'},
{'answer': '배미적남자문남자선향행'},
{'answer': '배미적남자문남자선향행썽'}]
LCEL에서는 다양한 요구 사항을 충족시키기 위해 서로 다른 파서를 결합하여 복잡한 데이터 처리 흐름을 구축할 수 있습니다.