3장. LangChain 기본 구조와 LCEL
OutputParser 와 StrOutputParser
택배 상자를 받으면 상자를 뜯어 안의 물건만 꺼내 씁니다. 상자에는 송장, 완충재, 영수증이 함께 들어 있지만 필요한 것은 물건 하나입니다. 모델의 답도 택배 상자처럼 글 말고도 여러 정보(토큰 수, 모델 이름, 끝난 까닭)를 함께 담아 옵니다. 출력 파서는 그 상자에서 필요한 것만 꺼내는 손입니다.
왼쪽 상자가 모델이 돌려준 AIMessage, 가운데가 출력 파서, 오른쪽이 바로 쓸 수 있는 값입니다. 여기서 택배 상자가 AIMessage, 물건이 답의 글, 상자를 뜯는 손이 파서입니다. 비유와 다른 점은, 택배는 물건이 이미 정해진 모양으로 오지만 모델의 답은 글이라서, 목록이나 사전을 원하면 파서가 글을 읽고 잘라 모양을 만들어야 한다는 것입니다.
자주 쓰는 출력 파서
| 파서 | 받는 것 | 돌려주는 것 | 쓰는 장 |
|---|---|---|---|
StrOutputParser | AIMessage | 글(str) | 3장부터 늘 |
CommaSeparatedListOutputParser | 쉼표로 이은 글 | 목록(list) | 3장 실습 5 |
JsonOutputParser | JSON 꼴의 글 | 사전(dict) | 4장 |
PydanticOutputParser | JSON 꼴의 글 | 정해 둔 꼴의 객체 | 4장 |
CommaSeparatedListOutputParser 는 Comma(쉼표), Separated(나뉜), List(목록)를 붙인 이름으로, "성산일출봉, 우도, 비자림" 같은 글을 쉼표에서 잘라 목록으로 바꿉니다.
짧은 예시
모델 대신 AIMessage 를 손으로 만들어 파서에 넣어 봅니다.
from langchain_core.messages import AIMessage
from langchain_core.output_parsers import CommaSeparatedListOutputParser, StrOutputParser
# 모델의 답이라고 치고 AIMessage 를 직접 만든다
reply = AIMessage("성산일출봉, 우도, 비자림")
# StrOutputParser: AIMessage 에서 글만 꺼낸다
text = StrOutputParser().invoke(reply)
print(isinstance(text, str), "|", text)
# CommaSeparatedListOutputParser: 쉼표로 잘라 목록으로 바꾼다
list_parser = CommaSeparatedListOutputParser()
print(list_parser.invoke(reply))
# get_format_instructions(): 모델에게 "이런 꼴로 답하라"고 알려 줄 지시문
print(list_parser.get_format_instructions())True | 성산일출봉, 우도, 비자림
['성산일출봉', '우도', '비자림']
Your response should be a list of comma separated values, eg: `foo, bar, baz` or `foo,bar,baz`isinstance(text, str) 이 True 이므로 꺼낸 것은 글자열입니다. 목록 파서는 쉼표 뒤의 빈칸까지 지워 깔끔한 목록을 만들었습니다. 셋째 줄의 영어 지시문은 "쉼표로 나눈 값의 목록으로 답하라"는 뜻입니다. 이 글을 프롬프트에 붙여 두면 모델이 파서가 읽을 수 있는 꼴로 답합니다.
코드가 의미하는 것
이 코드는 택배 상자 하나를 두 가지 방법으로 뜯어 보는 일을 흉내 낸 것입니다. 모델의 답이라고 친 상자(AIMessage)를 만들고, 글만 꺼내 보고, 쉼표에서 잘라 목록으로 꺼내 보고, 상자를 어떻게 싸 달라는 안내문을 읽습니다.
| 코드 | 하는 일 | 챗봇에서 뜻하는 것 |
|---|---|---|
AIMessage("성산일출봉, 우도, 비자림") | 모델의 답을 손으로 만든다 | 모델을 부르지 않고 파서만 따로 시험하는 방법입니다 |
StrOutputParser().invoke(reply) | AIMessage 에서 글만 꺼낸다 | 챗봇 화면에 보여 줄 답의 글만 남깁니다. 체인 끝에 늘 붙는 부품입니다 |
CommaSeparatedListOutputParser().invoke(reply) | 쉼표로 잘라 목록으로 바꾼다 | 답을 글이 아니라 파이썬 목록으로 받아, 코드가 하나씩 꺼내 쓸 수 있게 합니다 |
list_parser.get_format_instructions() | 파서가 읽을 수 있는 꼴을 적은 지시문을 돌려준다 | 이 글을 프롬프트에 붙이면 모델이 파서가 읽을 꼴로 답하게 됩니다 |
결과에서 읽을 것은 세 가지입니다.
- 글 파서는 글자열을 돌려줍니다. 첫 줄의
True는 꺼낸 값이 글자열이라는 뜻입니다. - 목록 파서는 빈칸까지 정리합니다. 둘째 줄은 쉼표 뒤의 빈칸이 지워진 항목 세 개입니다.
- 파서에는 짝이 되는 지시문이 있습니다. 셋째 줄의 영어 지시문을 프롬프트에 넣는 것은 실습 5에서
partial로 합니다.
주의할 점
- 파서는 모델이 꼴을 지켰을 때만 제대로 일합니다. 모델이 "추천 장소는 성산일출봉과 우도입니다"처럼 답하면 목록 파서는 그 문장을 통째로 한 항목으로 만듭니다. 그래서 프롬프트에 형식 지시를 함께 넣습니다.
- 설치된 langchain-core 1.7 에서
StrOutputParser가 돌려주는 값의 꼴 이름은TextAccessor로 찍힙니다. 글자열(str)을 조금 넓힌 꼴이라 str 과 똑같이 씁니다.