LangChain 챗봇4장 · 대화형 챗봇과 메모리 전략5 / 22← 이전목차다음 →MetaContents

4장. 대화형 챗봇과 메모리 전략

Pydantic 으로 틀 정하기

은행 창구의 서식에는 "생년월일(숫자 8자리)", "금액(숫자만)"처럼 칸마다 조건이 적혀 있습니다. 직원은 서식을 받으면 칸을 하나씩 훑어보고, 금액 칸에 "많이"라고 적혀 있으면 다시 써 달라고 돌려줍니다. Pydantic 이 하는 일이 이 직원입니다. 파이썬 클래스로 칸과 조건을 정해 두면, 값이 들어올 때마다 조건에 맞는지 검사합니다.

BaseModel 로 틀 정하기, 값 넣기, 칸마다 검사하기, 통과하면 객체 또는 어기면 ValidationError 의 네 걸음을 이은 흐름도

네 상자는 틀을 정하고 값을 넣어 검사하는 차례입니다. 마지막 상자에서 길이 둘로 갈립니다. 조건을 모두 지키면 값이 담긴 객체가 만들어지고, 하나라도 어기면 어느 칸이 왜 틀렸는지 적힌 ValidationError 가 납니다. 여기서 은행 서식이 BaseModel 을 물려받은 클래스, 칸마다 적힌 조건이 Field(...), 다시 써 달라고 돌려주는 일이 ValidationError 입니다. 비유와 다른 점은, Pydantic 은 "2"처럼 숫자로 바꿀 수 있는 글자는 돌려보내지 않고 알아서 숫자 2 로 바꿔 받는다는 것입니다.

칸에 붙이는 조건

쓰는 것원래 말뜻예
int, str, list[str]자료형칸에 들어갈 값의 종류nights: int
description=설명칸의 뜻. 모델에게도 그대로 전해진다"몇 박인지. 2박 3일이면 2"
ge=greater than or equal이 값 이상ge=1 (1박 이상)
le=less than or equal이 값 이하le=30
default=기본값값이 없을 때 쓸 값default=0

짧은 예시

여행 조건의 틀을 정하고, 맞는 값과 틀린 값을 넣어 봅니다. 칸 이름은 모델이 읽기 쉽게 영어로 쓰고, 뜻은 description 에 한국어로 적었습니다.

Python
from pydantic import BaseModel, Field, ValidationError


class TripRequest(BaseModel):
    """손님의 여행 조건"""
    destination: str = Field(description="여행 목적지")
    nights: int = Field(description="몇 박인지. 2박 3일이면 2", ge=1, le=30)
    adults: int = Field(description="어른 수", ge=1)
    children: int = Field(default=0, description="아이 수. 없으면 0", ge=0)


# "2" 는 글자지만 숫자로 바꿀 수 있어서 2 로 받는다. children 은 비워서 기본값 0
ok = TripRequest(destination="제주도", nights="2", adults=2)
print(ok)
print("박수의 자료형:", type(ok.nights).__name__)

try:
    # 박수가 -1, 어른이 0 이라 두 칸이 조건을 어긴다
    TripRequest(destination="제주도", nights=-1, adults=0)
except ValidationError as e:
    print("틀린 칸 수:", e.error_count())
    for err in e.errors():
        # loc = location(위치, 어느 칸), type = 어긴 조건의 이름
        print(err["loc"], err["type"])
출력
destination='제주도' nights=2 adults=2 children=0
박수의 자료형: int
틀린 칸 수: 2
('nights',) greater_than_equal
('adults',) greater_than_equal

첫 줄은 검사를 통과한 객체입니다. 글자 "2"가 정수 2 로 바뀌었고, 비워 둔 children 에는 기본값 0 이 들어갔습니다. 둘째 시도는 두 칸이 조건을 어겨 ValidationError 가 났고, 어느 칸이(nights, adults) 어떤 조건(greater_than_equal, 이상이어야 함)을 어겼는지 알려 줍니다.

코드가 의미하는 것

이 코드는 은행 서식과 서식을 훑는 직원을 파이썬으로 옮긴 것입니다. 서식(틀)을 정하고, 맞게 쓴 서식과 틀리게 쓴 서식을 한 장씩 넣어 봅니다.

코드하는 일챗봇에서 뜻하는 것
class TripRequest(BaseModel)칸 넷의 틀을 정한다모델의 답이 가져야 할 상담 카드의 양식입니다. 틀의 칸 이름이 곧 답의 열쇠 이름이 됩니다
Field(description=…, ge=1, le=30)칸에 뜻과 범위를 붙인다1박부터 30박까지만 받겠다는 규칙입니다. description 은 다음 절에서 모델에게도 그대로 전해집니다
TripRequest(destination="제주도", nights="2", adults=2)값을 넣어 객체를 만든다모델이 채운 답이 틀을 지나가는 순간입니다. 숫자로 바꿀 수 있는 글자 "2"는 숫자로 바꿔 받습니다
except ValidationError as e조건을 어긴 값을 잡는다모델이 칸은 채웠지만 값이 말이 안 될 때, 그 값이 프로그램 안으로 들어가기 전에 막는 자리입니다
e.errors() 의 loc, type어느 칸이 어떤 조건을 어겼는지 꺼낸다오류를 기록하거나 손님에게 다시 물을 때 쓸 단서입니다

결과에서 읽을 것은 세 가지입니다.

  • 기본값이 빈칸을 메웠다. children 을 넘기지 않았는데 children=0 이 들어갔습니다. 아이 이야기가 없는 요청에서도 칸이 비지 않습니다.
  • 글자 "2"가 정수가 됐다. 박수의 자료형이 int 입니다. 모델이 숫자를 글자로 적어 보내도 틀이 바로잡습니다.
  • 틀린 칸을 한꺼번에 알려 준다. 틀린 칸 수: 2 이고 두 칸 모두 greater_than_equal 입니다. 첫 오류에서 멈추지 않고 어긴 칸을 모두 모아 줍니다.

주의할 점

  • description 은 사람을 위한 메모이면서 모델에게 보내는 설명이기도 합니다. "몇 박인지. 2박 3일이면 2"처럼 헷갈릴 만한 곳을 예로 적어 두면 모델이 덜 틀립니다.
  • Pydantic 은 틀에 맞는지만 봅니다. "제주"와 "제주도"처럼 뜻은 같고 글자가 다른 값은 둘 다 통과합니다. 목적지 이름을 맞추려면 고를 수 있는 값을 정해 두는 방법(Literal["제주도", "부산"])을 씁니다.
← 이전 절4장 · JSON 과 JsonOutputParser다음 절 →4장 · with_structured_output 으로 틀째 받기