4장. 대화형 챗봇과 메모리 전략
구조화된 출력이 필요한 까닭
여행사 상담원이 손님의 말을 메모지에 줄글로 적어 두었다고 해 봅시다. "제주도로 2박 3일, 어른 둘 아이 둘, 150만 원쯤". 나중에 다른 직원이 "이번 달 손님들의 평균 예산"을 구하려면 메모를 한 장씩 읽어 숫자를 골라내야 합니다. 상담 카드에 목적지 칸, 박수 칸, 예산 칸이 따로 있으면 다릅니다. 예산 칸만 쭉 모으면 됩니다.
왼쪽은 모델이 쓴 줄글 답이고, 오른쪽은 열쇠와 값이 정해진 답입니다. 사람이 읽기에는 왼쪽도 괜찮지만, 프로그램이 값을 꺼내 계산하거나 화면의 칸에 넣으려면 오른쪽이어야 합니다. 여기서 메모지의 줄글이 3장까지 받은 글 답(StrOutputParser 의 결과)이고, 상담 카드가 구조화된 출력입니다. 비유와 다른 점은, 상담원은 카드의 칸을 알아서 채우지만 모델에게는 칸의 이름과 뜻을 우리가 알려 주어야 한다는 것입니다.
줄글과 칸으로 받기
| 견줄 것 | 줄글 답 | 구조화된 답 |
|---|---|---|
| 생김새 | "제주도로 2박 3일 가시는군요" | {"목적지": "제주도", "박수": 2} |
| 사람이 읽기 | 편하다 | 조금 딱딱하다 |
| 프로그램이 값 꺼내기 | 글을 찾아 잘라야 한다 | 열쇠 이름으로 바로 꺼낸다 |
| 계산하기 | 글자를 숫자로 바꿔야 한다 | 숫자 칸은 처음부터 숫자다 |
| 어울리는 곳 | 손님에게 보여 줄 답 | 예약 시스템, 표, 화면의 입력 칸 |
짧은 예시
같은 내용을 줄글과 사전으로 받았다고 보고, 박수와 1인당 예산을 꺼내 봅니다. 모델은 부르지 않습니다.
answer_text = "제주도로 2박 3일, 어른 둘과 아이 둘이 가시는군요. 예산은 150만 원입니다."
answer_dict = {"목적지": "제주도", "박수": 2, "어른": 2, "아이": 2, "예산": 150}
# 줄글에서는 "박" 글자를 찾아 그 앞 글자를 잘라 내야 한다
at = answer_text.index("박")
print("줄글에서 꺼낸 박수:", answer_text[at - 1: at], type(answer_text[at - 1: at]).__name__)
# 사전에서는 열쇠 이름으로 바로 꺼내고, 숫자라서 바로 계산한다
print("사전에서 꺼낸 박수:", answer_dict["박수"], type(answer_dict["박수"]).__name__)
print("1인당 예산(만 원):", answer_dict["예산"] / (answer_dict["어른"] + answer_dict["아이"]))줄글에서 꺼낸 박수: 2 str
사전에서 꺼낸 박수: 2 int
1인당 예산(만 원): 37.5줄글에서 꺼낸 "2"는 글자열(str)이라 계산하려면 다시 숫자로 바꿔야 합니다. "12박"처럼 두 자리가 되면 앞 글자 하나만 잘라 내는 이 코드는 틀린 값을 냅니다. 사전에서 꺼낸 2 는 처음부터 정수(int)라서 바로 나눗셈을 합니다.
코드가 의미하는 것
이 코드는 메모지의 줄글과 상담 카드에서 같은 값을 꺼내 보는 일을 흉내 냅니다. 같은 답을 두 모양으로 두고, 박수를 꺼내고, 계산까지 해 봅니다.
| 코드 | 하는 일 | 챗봇에서 뜻하는 것 |
|---|---|---|
answer_text = "제주도로 2박 3일, …" | 모델이 줄글로 답한 것을 둔다 | 3장까지 StrOutputParser 로 받던 답의 모양입니다. 사람에게는 읽기 좋지만 프로그램에는 글자 덩어리일 뿐입니다 |
answer_dict = {"목적지": …, "박수": 2, …} | 같은 답을 열쇠와 값으로 둔다 | 구조화된 출력으로 받은 답의 모양입니다. 실습 2에서 모델이 돌려줄 것이 이런 칸입니다 |
answer_text.index("박") 와 [at - 1: at] | "박" 자리를 찾아 그 앞 글자를 잘라 낸다 | 줄글 답에서 값을 꺼내려면 글의 생김새에 기대는 코드를 써야 합니다. 모델이 말투를 바꾸면 이 코드가 깨집니다 |
answer_dict["박수"] | 열쇠 이름으로 값을 꺼낸다 | 칸 이름만 알면 답의 말투와 상관없이 같은 코드로 꺼냅니다 |
answer_dict["예산"] / (…) | 꺼낸 숫자로 바로 나눈다 | 예약 시스템이나 표가 받아서 바로 쓸 수 있는 값이라는 뜻입니다 |
결과에서 읽을 것은 두 가지입니다.
- 같은 2, 다른 자료형. 줄글에서 꺼낸 2 는
str, 사전에서 꺼낸 2 는int입니다. 줄글 쪽은 계산하기 전에 한 번 더 바꿔야 합니다. - 칸으로 받으면 계산이 한 줄. 1인당 예산 37.5 는 사전의 값 셋만으로 구했습니다. 줄글이었다면 예산, 어른, 아이를 모두 글에서 찾아 잘라야 합니다.
주의할 점
- 손님에게 보여 줄 답까지 모두 구조화할 필요는 없습니다. 프로그램이 값을 써야 하는 곳에만 씁니다. 이 장의 여행 비서도 대화는 줄글로, 여행 조건은 칸으로 받습니다.
- 칸이 정해져 있어도 모델이 채운 값이 맞는지는 따로 확인해야 합니다. 칸이 맞는 것과 값이 맞는 것은 다른 일입니다. 실습 2에서 정답과 견줘 봅니다.