LLM 출력 데이터를 원하는 형식으로 변환하는 LangChain 출력 파서 활용 가이드

GoGoComputer·2024년 10월 20일
0

LangChain Basics

목록 보기
9/40

개요 1/3

이번 강의에서는 출력 파서(Output Parser)를 사용하여 대형 언어 모델(LLM)의 출력을 원하는 데이터 형식으로 변환하는 방법에 대해 알아보겠습니다. 특히 LangChain 라이브러리를 활용하여 LLM의 출력인 문자열을 파싱하고, 이를 Python의 데이터 타입으로 변환하는 과정을 살펴볼 것입니다.


왜 출력 파서가 필요한가요?

LLM은 강력한 자연어 처리 도구이지만, 그 출력은 기본적으로 문자열입니다. 그러나 실제 애플리케이션에서는 특정 데이터 형식이 필요할 때가 많습니다. 예를 들어:

  • Python의 datetime 객체
  • JSON 형식
  • 사용자 지정 클래스 인스턴스

출력 파서를 사용하면 LLM의 출력을 원하는 데이터 유형으로 쉽게 변환할 수 있습니다. 이는 다음과 같은 이점을 제공합니다:

  1. 일관성 있는 데이터 형식 유지: 모델의 출력이 항상 동일한 형식을 따르도록 보장합니다.
  2. 데이터 처리의 용이성: 문자열을 파싱하여 원하는 데이터 타입으로 변환함으로써 후속 데이터 처리를 쉽게 할 수 있습니다.
  3. 에러 감소: 예상치 못한 출력 형식으로 인한 에러를 줄일 수 있습니다.

출력 파서의 주요 구성 요소

출력 파서는 두 가지 주요 요소로 구성되어 있습니다:

1. 형식 설명서 (Format Instructions)

  • 정의: 모델에게 원하는 출력 형식을 설명하는 지침입니다.
  • 역할: 프롬프트의 끝에 추가되어 모델이 특정 형식으로 응답하도록 유도합니다.
  • 예시: "출력은 쉼표로 구분된 값의 목록이어야 합니다."

2. 파서 (Parser)

  • 정의: 모델의 출력을 파싱하여 원하는 데이터 타입으로 변환하는 메서드를 제공합니다.
  • 역할: 문자열로 반환된 모델의 출력을 실제 Python 객체로 변환합니다.
  • 예시: 쉼표로 구분된 문자열을 리스트로 변환하거나, 날짜 형식의 문자열을 datetime 객체로 변환합니다.

출력 파서의 실제 사용 예시

시나리오

  • 목표: 과학적 발견의 날짜를 알아내고, 그 날짜를 Python의 datetime 객체로 사용하고 싶습니다.
  • 문제점:
    1. LLM은 문자열로 응답합니다.
    2. 날짜 형식이 일관되지 않을 수 있습니다. (예: "2020년 1월 1일", "2020-01-01", "January 1, 2020" 등)

해결 방법

  • 출력 파서 사용: LLM의 출력이 올바른 형식을 따르도록 지시하고, 파서를 통해 문자열을 원하는 데이터 타입으로 변환합니다.
  • 형식 설명서 추가: 프롬프트에 형식 설명서를 추가하여 모델이 일관된 형식으로 응답하도록 합니다.
  • 파서의 parse 메서드 사용: 모델의 출력을 받아 파싱하고, Python의 datetime 객체로 변환합니다.

출력 파서의 작동 과정

  1. 파서 불러오기 및 인스턴스 생성: 필요한 파서를 임포트하고 인스턴스를 생성합니다.
    from langchain.output_parsers import DatetimeOutputParser
    output_parser = DatetimeOutputParser()
  2. 형식 설명서 얻기: 파서에서 제공하는 형식 설명서를 가져옵니다.
    format_instructions = output_parser.get_format_instructions()
  3. 프롬프트 생성: 사용자 요청에 형식 설명서를 추가하여 프롬프트를 만듭니다.
    prompt = f"{user_input}\n{format_instructions}"
  4. 모델 응답 받기: 프롬프트를 모델에 전달하고 응답을 받습니다.
    response = llm(prompt)
  5. 출력 파싱: 모델의 응답을 파싱하여 원하는 데이터 타입으로 변환합니다.
    parsed_output = output_parser.parse(response)

예제: 쉼표로 구분된 목록 출력 파서 사용하기

단계 1: 필요한 라이브러리 임포트 및 API 키 설정

import os
from dotenv import load_dotenv
from langchain import OpenAI
from langchain.output_parsers import CommaSeparatedListOutputParser

# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# LLM 모델 초기화
llm = OpenAI(temperature=0.7, openai_api_key=OPENAI_API_KEY)

단계 2: 출력 파서 인스턴스 생성 및 형식 설명서 얻기

# 출력 파서 인스턴스 생성
output_parser = CommaSeparatedListOutputParser()

# 형식 설명서 얻기
format_instructions = output_parser.get_format_instructions()

단계 3: 사용자 요청 및 프롬프트 생성

# 사용자 요청
user_input = "개의 특징을 다섯 가지 말해줘."

# 프롬프트 생성 (형식 설명서 추가)
prompt = f"{user_input}\n\n{format_instructions}"

단계 4: 모델 응답 받기

# 모델 응답 받기
response = llm(prompt)

단계 5: 출력 파싱

# 출력 파싱
parsed_output = output_parser.parse(response)

단계 6: 결과 출력

print("모델의 원본 응답:")
print(response)
print("\n파싱된 출력:")
print(parsed_output)

전체 실습 코드

아래는 위에서 설명한 모든 단계를 포함한 전체 코드입니다.

import os
from dotenv import load_dotenv
from langchain import OpenAI
from langchain.output_parsers import CommaSeparatedListOutputParser

# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# LLM 모델 초기화
llm = OpenAI(temperature=0.7, openai_api_key=OPENAI_API_KEY)

# 출력 파서 인스턴스 생성
output_parser = CommaSeparatedListOutputParser()

# 형식 설명서 얻기
format_instructions = output_parser.get_format_instructions()

# 사용자 요청
user_input = "개의 특징을 다섯 가지 말해줘."

# 프롬프트 생성 (형식 설명서 추가)
prompt = f"{user_input}\n\n{format_instructions}"

# 모델 응답 받기
response = llm(prompt)

# 출력 파싱
parsed_output = output_parser.parse(response)

# 결과 출력
print("모델의 원본 응답:")
print(response)
print("\n파싱된 출력:")
print(parsed_output)

코드 설명

  1. 환경 변수 로드:

    • dotenv 라이브러리를 사용하여 .env 파일에 저장된 OPENAI_API_KEY를 불러옵니다.
    • 이는 API 키를 코드에 직접 작성하지 않고도 안전하게 불러올 수 있게 합니다.
  2. LLM 모델 초기화:

    • OpenAI 클래스를 사용하여 LLM 모델을 초기화합니다.
    • temperature 파라미터는 출력의 창의성을 조절합니다.
  3. 출력 파서 및 형식 설명서:

    • CommaSeparatedListOutputParser를 사용하여 쉼표로 구분된 목록을 파싱합니다.
    • get_format_instructions() 메서드를 통해 형식 설명서를 얻습니다.
  4. 프롬프트 생성:

    • 사용자 요청에 형식 설명서를 추가하여 모델이 원하는 형식으로 응답하도록 유도합니다.
    • 형식 설명서는 모델에게 출력 형식에 대한 명확한 지침을 제공합니다.
  5. 모델 응답 및 파싱:

    • 생성된 프롬프트를 모델에 전달하고 응답을 받습니다.
    • 응답은 문자열 형태이며, 이를 파서의 parse() 메서드를 사용하여 파싱합니다.
  6. 결과 출력:

    • 원본 응답과 파싱된 출력을 각각 출력합니다.
    • 파싱된 출력은 Python의 리스트 형태로, 이후 데이터 처리에 용이합니다.

실행 결과 예시

모델의 원본 응답:
충성심이 강함, 후각이 예민함, 사회성이 높음, 다양한 품종이 있음, 사람과 친화적임

파싱된 출력:
['충성심이 강함', '후각이 예민함', '사회성이 높음', '다양한 품종이 있음', '사람과 친화적임']

추가 설명

형식 설명서의 중요성

  • 역할: 모델에게 출력 형식을 명확하게 지시하여 일관된 출력을 얻을 수 있습니다.
  • 활용 방법: 프롬프트의 끝에 형식 설명서를 추가하여 모델이 특정 형식을 따르도록 합니다.

파서의 활용

  • 데이터 타입 변환: 문자열 형태의 모델 출력을 Python의 원하는 데이터 타입으로 변환합니다.
  • 유연성: 다양한 파서가 있어 필요한 데이터 형식에 맞게 선택하여 사용할 수 있습니다.
    • 예: DatetimeOutputParser, BooleanOutputParser

에러 처리 및 수정

  • 출력 수정: 모델의 출력이 형식 설명서와 일치하지 않을 경우, 파서를 통해 수정하거나 재요청할 수 있습니다.
  • 자동 수정: 일부 파서는 잘못된 출력을 자동으로 수정하는 기능을 제공합니다.

시스템 프롬프트의 활용

  • 출력 개선: 시스템 프롬프트를 사용하여 모델의 출력을 더욱 개선할 수 있습니다.
  • 예시: 다음 강의에서는 시스템 프롬프트를 활용하여 에러를 수정하는 방법을 살펴볼 예정입니다.

마무리

출력 파서는 LLM의 출력을 원하는 데이터 형식으로 변환하는 데 매우 유용한 도구입니다. 이를 통해 데이터 처리의 효율성과 안정성을 높일 수 있습니다. 이번 설명에서는 쉼표로 구분된 목록 출력 파서를 예시로 사용했지만, 다양한 파서를 활용하여 여러 형태의 데이터를 처리할 수 있습니다.

OPENAI_API_KEY.env 파일에 저장하고 불러오는 방법도 함께 살펴보았습니다. 제공된 전체 실습 코드를 직접 실행해 보시면서 이해를 더욱 깊게 하실 수 있을 것입니다.


개요 2/3

이번 강의에서는 출력 파서(Output Parser)를 사용하는 방법에 대해 심화 학습을 진행합니다. 특히, 모델의 출력이 원하는 형식과 맞지 않을 때 이를 해결하는 방법에 대해 알아볼 것입니다.

  • 방법 1: 시스템 프롬프트를 추가하여 모델의 출력을 원하는 형식으로 조정합니다.
  • 방법 2: LangChain의 Output Fixing Parser를 사용하여 모델의 출력을 수정합니다.

이 두 가지 방법을 통해 모델의 출력이 형식 지침과 일치하지 않을 때 문제를 해결할 수 있습니다.


왜 출력 형식이 중요한가요?

대형 언어 모델(LLM)은 자연어 처리에 뛰어나지만, 출력 결과가 항상 우리가 원하는 형식과 일치하지 않을 수 있습니다. 예를 들어, 날짜 정보를 요청했을 때 다양한 형식으로 반환될 수 있습니다:

  • "2021년 12월 25일"
  • "December 25, 2021"
  • "2021-12-25"

이렇게 다양한 형식의 출력은 후속 데이터 처리에 어려움을 줄 수 있습니다. 따라서 일관된 형식의 출력을 얻는 것은 매우 중요합니다.


방법 1: 시스템 프롬프트 사용하여 출력 형식 조정하기

시스템 프롬프트란?

  • 정의: 모델에게 특정한 지시나 배경 정보를 제공하여 응답 방식에 영향을 주는 역할을 합니다.
  • 사용 목적: 모델의 출력이 원하는 형식과 일치하도록 가이드합니다.

단계별 설명

  1. 시스템 프롬프트 생성: 모델에게 정확한 출력 형식을 지시하는 시스템 프롬프트를 작성합니다.
    system_prompt = "당신은 항상 질문에 날짜와 시간 패턴에 맞게만 답변해야 합니다."
  2. 형식 지침 추가: 출력 파서에서 제공하는 형식 지침을 가져와 프롬프트에 포함시킵니다.
    format_instructions = output_parser.get_format_instructions()
  3. 프롬프트 구성: 시스템 프롬프트와 사용자 요청, 그리고 형식 지침을 결합하여 프롬프트를 만듭니다.
    prompt = f"{system_prompt}\n\n{user_input}\n\n{format_instructions}"
  4. 모델 응답 받기: 구성된 프롬프트를 모델에 전달하고 응답을 받습니다.
    response = llm(prompt)
  5. 출력 파싱: 모델의 응답을 파싱하여 원하는 데이터 타입으로 변환합니다.
    parsed_output = output_parser.parse(response)

예시

사용자가 "13차 수정헌법이 언제 비준되었나요?"라고 물었을 때, 모델이 추가적인 정보 없이 정확한 날짜만 반환하도록 시스템 프롬프트를 사용합니다.


방법 2: Output Fixing Parser를 사용하여 출력 수정하기

Output Fixing Parser란?

  • 정의: 모델의 출력이 형식 지침과 일치하지 않을 때, 이를 수정하기 위해 사용되는 LangChain의 도구입니다.
  • 사용 목적: 원본 출력을 모델에게 다시 전달하여 형식에 맞게 수정된 출력을 얻습니다.

단계별 설명

  1. 잘못된 출력 확인: 모델의 출력이 형식과 일치하지 않는 경우를 확인합니다.

  2. Output Fixing Parser 생성: 원본 파서와 모델을 사용하여 Output Fixing Parser의 인스턴스를 생성합니다.

    from langchain.output_parsers import OutputFixingParser
    
    fixing_parser = OutputFixingParser.from_llm(parser=output_parser, llm=llm)
  3. 출력 수정 요청: 잘못된 출력을 Output Fixing Parser에 전달하여 수정된 출력을 받습니다.

    fixed_output = fixing_parser.parse(bad_output)
  4. 결과 확인: 수정된 출력이 원하는 형식과 일치하는지 확인합니다.

예시

모델이 "수정헌법 제13조는 1865년 12월 6일에 비준되었습니다."와 같이 추가 정보를 포함한 출력을 반환했을 때, Output Fixing Parser를 사용하여 정확한 날짜만 추출합니다.


실습 코드

아래는 위에서 설명한 두 가지 방법을 모두 포함한 전체 실습 코드입니다.

import os
from dotenv import load_dotenv
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import DatetimeOutputParser, OutputFixingParser
from langchain.prompts import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# LLM 모델 초기화
llm = ChatOpenAI(temperature=0.0, openai_api_key=OPENAI_API_KEY)

# 출력 파서 인스턴스 생성 (DatetimeOutputParser)
output_parser = DatetimeOutputParser()

# 형식 지침 얻기
format_instructions = output_parser.get_format_instructions()

# 사용자 요청
user_input = "13차 수정헌법이 언제 비준되었나요?"

# 방법 1: 시스템 프롬프트 사용

# 시스템 프롬프트 생성
system_prompt = SystemMessagePromptTemplate.from_template(
    "당신은 항상 질문에 날짜와 시간 패턴에 맞게만 답변해야 합니다."
)

# 인간 프롬프트 생성
human_prompt = HumanMessagePromptTemplate.from_template(
    "{user_input}\n\n{format_instructions}"
)

# 전체 프롬프트 구성
chat_prompt = ChatPromptTemplate.from_messages([system_prompt, human_prompt])

# 프롬프트 포맷팅
messages = chat_prompt.format_messages(
    user_input=user_input, format_instructions=format_instructions
)

# 모델 응답 받기
response = llm(messages)

# 출력 파싱
try:
    parsed_output = output_parser.parse(response.content)
    print("방법 1 - 파싱된 출력:")
    print(parsed_output)
except Exception as e:
    print("방법 1 - 파싱 실패:")
    print(e)

# 방법 2: Output Fixing Parser 사용

# 잘못된 출력 (시스템 프롬프트 없이 얻은 응답)
bad_response = "수정헌법 제13조는 1865년 12월 6일에 미국에서 비준되었습니다."

# Output Fixing Parser 생성
fixing_parser = OutputFixingParser.from_llm(parser=output_parser, llm=llm)

# 출력 수정 요청
try:
    fixed_output = fixing_parser.parse(bad_response)
    print("\n방법 2 - 수정된 출력:")
    print(fixed_output)
except Exception as e:
    print("방법 2 - 출력 수정 실패:")
    print(e)

코드 설명

1. 환경 변수 로드 및 모델 초기화

  • dotenv 사용: .env 파일에서 OPENAI_API_KEY를 로드합니다.
  • ChatOpenAI 모델: 대화형 LLM 모델을 초기화합니다.

2. 출력 파서 생성

  • DatetimeOutputParser: 날짜와 시간을 파싱하기 위한 출력 파서를 생성합니다.
  • 형식 지침: get_format_instructions()를 사용하여 형식 지침을 얻습니다.

3. 사용자 요청 정의

  • user_input: 사용자가 모델에게 묻는 질문입니다.

4. 방법 1: 시스템 프롬프트 사용

  • 시스템 프롬프트 생성: 모델에게 출력 형식을 지시하는 시스템 프롬프트를 작성합니다.
  • 인간 프롬프트 생성: 사용자 요청과 형식 지침을 포함한 프롬프트를 만듭니다.
  • 프롬프트 구성: 시스템 프롬프트와 인간 프롬프트를 결합하여 전체 프롬프트를 만듭니다.
  • 모델 응답 받기: 구성된 프롬프트를 모델에 전달하고 응답을 받습니다.
  • 출력 파싱: 응답을 파싱하여 datetime 객체로 변환합니다.

5. 방법 2: Output Fixing Parser 사용

  • 잘못된 출력 설정: 시스템 프롬프트 없이 모델이 반환한 잘못된 출력을 설정합니다.
  • Output Fixing Parser 생성: 원본 파서와 모델을 사용하여 Output Fixing Parser를 생성합니다.
  • 출력 수정 요청: 잘못된 출력을 파서에 전달하여 수정된 출력을 받습니다.
  • 결과 확인: 수정된 출력이 원하는 형식과 일치하는지 확인합니다.

실행 결과 예시

방법 1 - 파싱된 출력:
1865-12-06 00:00:00

방법 2 - 수정된 출력:
1865-12-06 00:00:00

추가 설명

형식 지침의 역할

  • 형식 지침은 모델에게 원하는 출력 형식을 명확하게 지시합니다.
  • 모델은 이 지침을 따라 출력 형식을 맞추려고 노력합니다.

시스템 프롬프트의 중요성

  • 시스템 프롬프트는 모델의 전반적인 응답 스타일을 조정하는 데 도움이 됩니다.
  • 출력 형식을 일관되게 유지하는 데 큰 역할을 합니다.

Output Fixing Parser의 활용

  • 모델의 출력이 형식 지침과 일치하지 않을 때 자동으로 수정할 수 있습니다.
  • 원본 출력을 다시 모델에 전달하여 형식에 맞게 수정된 출력을 얻습니다.

에러 처리

  • 파싱 과정에서 에러가 발생할 수 있으므로 try-except 블록을 사용하여 에러를 처리합니다.
  • 에러가 발생하면 적절한 메시지를 출력하여 문제를 확인합니다.

마무리

이번 강의에서는 모델의 출력이 원하는 형식과 맞지 않을 때 이를 해결하는 두 가지 방법에 대해 알아보았습니다.

  1. 시스템 프롬프트 사용: 모델에게 출력 형식을 명확하게 지시하여 원하는 형식의 출력을 얻습니다.
  2. Output Fixing Parser 사용: 잘못된 출력을 모델에게 다시 전달하여 형식에 맞게 수정된 출력을 받습니다.

이러한 방법을 통해 모델의 출력 형식을 일관되게 유지하고, 후속 데이터 처리를 용이하게 할 수 있습니다.


주의: 제공된 코드를 실행하려면 .env 파일에 OPENAI_API_KEY를 설정해야 합니다. .env 파일은 다음과 같이 작성됩니다:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

YOUR_OPENAI_API_KEY를 실제 API 키로 교체해주세요.


이상으로 요청하신 내용을 쉽게, 자세하게, 그리고 길게 설명해 드렸습니다. 추가로 궁금하신 사항이나 도움이 필요하신 부분이 있다면 언제든지 말씀해 주세요!

안녕하세요! 요청하신 내용을 쉽게, 자세하게, 그리고 길게 설명해 드리겠습니다. 또한 마지막에 작동 가능한 전체 실습 코드를 제공해 드리겠습니다. OPENAI_API_KEY.env 파일에 저장하여 불러오는 방식으로 진행하겠습니다.


개요 3/3

이번 강의에서는 Pydantic 라이브러리를 활용하여 LangChain출력 파서(Output Parser)를 사용하고, 이를 통해 대형 언어 모델(LLM)의 출력을 사용자 정의 Python 객체로 변환하는 방법에 대해 알아보겠습니다.

  • 목표: LLM의 응답을 직접 사용자 정의 Python 객체로 변환하기.
  • 사용 도구:
    • LangChainPydanticOutputParser
    • Pydantic 라이브러리
  • 전제 조건: Pydantic 라이브러리가 설치되어 있어야 합니다.

왜 PydanticOutputParser를 사용하나요?

LLM은 기본적으로 문자열 형태로 응답합니다. 하지만 실제 애플리케이션에서는 이 문자열을 특정 데이터 타입이나 객체로 변환해야 할 때가 많습니다. PydanticOutputParser를 사용하면 LLM의 출력을 자동으로 사용자 정의 Pydantic 모델로 변환할 수 있습니다.

  • 장점:
    • 타입 검증: 예상치 못한 데이터 타입이나 값으로 인한 오류를 방지합니다.
    • 간편한 변환: LLM의 출력을 직접 Python 객체로 변환하여 추가 처리가 용이합니다.
    • 유연성: 복잡한 데이터 구조도 처리할 수 있습니다.

사전 준비

1. Pydantic 설치

Pydantic 라이브러리가 설치되어 있지 않다면 다음 명령어를 사용하여 설치합니다:

pip install pydantic

2. 환경 변수 설정

  • .env 파일 생성: 프로젝트 디렉토리에 .env 파일을 생성합니다.
  • OPENAI_API_KEY 저장: .env 파일에 다음과 같이 API 키를 저장합니다.
OPENAI_API_KEY=YOUR_OPENAI_API_KEY

YOUR_OPENAI_API_KEY를 실제 OpenAI API 키로 대체하세요.


단계별 가이드

단계 1: 필요한 라이브러리 임포트 및 API 키 설정

import os
from dotenv import load_dotenv
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from langchain.prompts import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
)
  • dotenv 사용: .env 파일에서 환경 변수를 로드하기 위해 load_dotenv()를 사용합니다.
  • 환경 변수 로드:
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

단계 2: Pydantic 모델 정의

class Scientist(BaseModel):
    name: str = Field(description="과학자의 이름")
    discoveries: list = Field(description="과학자의 발견 목록")
  • BaseModel 상속: Pydantic의 BaseModel을 상속받아 Scientist 클래스를 정의합니다.
  • 필드 정의:
    • name: 과학자의 이름을 나타내는 문자열 필드입니다.
    • discoveries: 과학자의 발견을 담은 리스트 필드입니다.
  • Field 설명 추가: 각 필드에 description을 추가하여 모델에 대한 설명을 제공합니다.

단계 3: PydanticOutputParser 인스턴스 생성

# PydanticOutputParser 인스턴스 생성
output_parser = PydanticOutputParser(pydantic_object=Scientist)
  • pydantic_object 매개변수에 우리가 정의한 Scientist 클래스를 전달합니다.
  • 이 파서는 LLM의 출력을 Scientist 객체로 파싱합니다.

단계 4: 형식 지침 얻기

# 형식 지침 얻기
format_instructions = output_parser.get_format_instructions()
  • 이 지침은 LLM에게 출력 형식을 어떻게 맞춰야 하는지 알려주는 역할을 합니다.
  • 지침은 JSON 형식의 예시와 스키마를 포함하고 있습니다.

단계 5: 프롬프트 생성

# 사용자 요청
user_input = "유명한 과학자에 대해 알려주세요."

# 인간 프롬프트 생성
human_prompt = HumanMessagePromptTemplate.from_template(
    "{user_input}\n\n{format_instructions}"
)
  • 사용자 요청: "유명한 과학자에 대해 알려주세요."라는 질문을 합니다.
  • 프롬프트 템플릿 생성: 사용자 요청과 형식 지침을 포함한 프롬프트를 만듭니다.

단계 6: 전체 프롬프트 구성

# 전체 프롬프트 구성
chat_prompt = ChatPromptTemplate.from_messages([human_prompt])

# 프롬프트 포맷팅
messages = chat_prompt.format_messages(
    user_input=user_input, format_instructions=format_instructions
)
  • ChatPromptTemplate 사용: 메시지 리스트를 기반으로 전체 프롬프트를 생성합니다.
  • 프롬프트 포맷팅: 앞서 만든 프롬프트에 실제 변수들을 대입합니다.

단계 7: 모델 응답 받기

# LLM 모델 초기화
llm = ChatOpenAI(temperature=0.0, openai_api_key=OPENAI_API_KEY)

# 모델 응답 받기
response = llm(messages)
  • LLM 초기화: temperature를 0으로 설정하여 출력의 일관성을 높입니다.
  • 응답 받기: 구성된 메시지를 모델에 전달하고 응답을 받습니다.

단계 8: 출력 파싱

# 출력 파싱
parsed_output = output_parser.parse(response.content)
  • 모델의 응답을 파싱하여 Scientist 객체로 변환합니다.

단계 9: 결과 확인

# 결과 출력
print("모델의 원본 응답:")
print(response.content)
print("\n파싱된 출력:")
print(parsed_output)
  • 원본 응답: 모델이 반환한 원본 응답을 출력합니다.
  • 파싱된 출력: 파싱된 결과를 출력합니다. 이때 parsed_outputScientist 객체입니다.

전체 실습 코드

아래는 위에서 설명한 모든 단계를 포함한 전체 코드입니다.

import os
from dotenv import load_dotenv
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from langchain.prompts import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
)

# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# LLM 모델 초기화
llm = ChatOpenAI(temperature=0.0, openai_api_key=OPENAI_API_KEY)

# Pydantic 모델 정의
class Scientist(BaseModel):
    name: str = Field(description="과학자의 이름")
    discoveries: list = Field(description="과학자의 발견 목록")

# PydanticOutputParser 인스턴스 생성
output_parser = PydanticOutputParser(pydantic_object=Scientist)

# 형식 지침 얻기
format_instructions = output_parser.get_format_instructions()

# 사용자 요청
user_input = "유명한 과학자에 대해 알려주세요."

# 인간 프롬프트 생성
human_prompt = HumanMessagePromptTemplate.from_template(
    "{user_input}\n\n{format_instructions}"
)

# 전체 프롬프트 구성
chat_prompt = ChatPromptTemplate.from_messages([human_prompt])

# 프롬프트 포맷팅
messages = chat_prompt.format_messages(
    user_input=user_input, format_instructions=format_instructions
)

# 모델 응답 받기
response = llm(messages)

# 출력 파싱
parsed_output = output_parser.parse(response.content)

# 결과 출력
print("모델의 원본 응답:")
print(response.content)
print("\n파싱된 출력:")
print(parsed_output)

# 파싱된 출력의 세부 정보 출력
print("\n과학자 이름:", parsed_output.name)
print("발견 목록:", parsed_output.discoveries)

코드 설명

1. 환경 변수 로드 및 모델 초기화

  • dotenv 사용: .env 파일에서 OPENAI_API_KEY를 로드합니다.
  • LLM 모델 초기화: ChatOpenAI를 사용하여 LLM 모델을 초기화하고, temperature를 0으로 설정하여 모델의 출력이 일관되게 만듭니다.

2. Pydantic 모델 정의

  • Scientist 클래스: 과학자의 이름과 발견 목록을 속성으로 갖는 Pydantic 모델입니다.
  • Field 설명: 각 필드에 설명을 추가하여 모델의 스키마를 명확히 합니다.

3. PydanticOutputParser 인스턴스 생성

  • output_parser: Scientist Pydantic 모델을 사용하여 출력 파서를 생성합니다.
  • 역할: LLM의 출력을 Scientist 객체로 파싱합니다.

4. 형식 지침 얻기

  • 형식 지침: 모델에게 출력 형식을 알려주는 문자열입니다.
  • 내용: JSON 형식의 예시와 출력 스키마를 포함하고 있습니다.

5. 프롬프트 생성 및 포맷팅

  • 사용자 요청: 모델에게 전달할 질문입니다.
  • HumanMessagePromptTemplate: 사용자 요청과 형식 지침을 결합한 프롬프트를 생성합니다.
  • ChatPromptTemplate: 여러 메시지를 하나의 프롬프트로 구성합니다.
  • 프롬프트 포맷팅: 실제 값들을 프롬프트에 대입합니다.

6. 모델 응답 및 출력 파싱

  • 모델 응답: 구성된 프롬프트를 모델에 전달하고 응답을 받습니다.
  • 출력 파싱: output_parser.parse()를 사용하여 응답을 Scientist 객체로 변환합니다.

7. 결과 출력

  • 원본 응답 출력: 모델이 반환한 원본 텍스트를 출력합니다.
  • 파싱된 출력 출력: 파싱된 Scientist 객체를 출력합니다.
  • 세부 정보 출력: 과학자의 이름과 발견 목록을 개별적으로 출력합니다.

실행 결과 예시

모델의 원본 응답:
{
  "name": "알베르트 아인슈타인",
  "discoveries": [
    "특수 상대성 이론",
    "일반 상대성 이론",
    "광전 효과",
    "브라운 운동 설명",
    "에너지 질량 등가성 (E=mc²)"
  ]
}

파싱된 출력:
name='알베르트 아인슈타인' discoveries=['특수 상대성 이론', '일반 상대성 이론', '광전 효과', '브라운 운동 설명', '에너지 질량 등가성 (E=mc²)']

과학자 이름: 알베르트 아인슈타인
발견 목록: ['특수 상대성 이론', '일반 상대성 이론', '광전 효과', '브라운 운동 설명', '에너지 질량 등가성 (E=mc²)']

추가 설명

Pydantic의 역할

  • 데이터 검증: 입력된 데이터가 지정된 타입과 일치하는지 확인합니다.
  • 자동 파싱: 문자열 데이터를 자동으로 지정된 데이터 타입으로 변환합니다.
  • 에러 처리: 데이터 타입이 일치하지 않을 경우 명확한 에러 메시지를 제공합니다.

형식 지침의 중요성

  • 모델이 출력해야 하는 형식과 스키마를 명확히 정의하여 일관된 출력을 얻을 수 있습니다.
  • 복잡한 데이터 구조도 정확하게 모델링할 수 있습니다.

LLM의 응답 제어

  • temperature 조절: temperature를 낮게 설정하면 모델의 출력이 더 일관적이고 예측 가능해집니다.
  • 명확한 지시: 프롬프트에 형식 지침과 예시를 포함하면 모델이 원하는 형식으로 응답할 가능성이 높아집니다.

잠재적 이슈 및 해결 방법

  • 환각 문제: LLM이 잘못된 정보를 생성할 수 있습니다. 이를 최소화하기 위해 temperature를 낮게 설정하고, 명확한 지시를 제공합니다.
  • 파싱 에러: 모델의 출력이 형식 지침과 일치하지 않을 경우 파싱 에러가 발생할 수 있습니다. 이때는 시스템 프롬프트를 추가하여 모델의 출력을 조정하거나, Output Fixing Parser를 사용할 수 있습니다.

마무리

이번 강의에서는 Pydantic을 활용하여 LLM의 출력을 사용자 정의 Python 객체로 변환하는 방법에 대해 알아보았습니다. 이를 통해 데이터 타입 검증과 자동 파싱이 가능하며, 후속 데이터 처리를 더욱 효율적으로 할 수 있습니다.

OPENAI_API_KEY.env 파일에 저장하고 불러오는 방법도 함께 살펴보았습니다. 제공된 전체 실습 코드를 직접 실행해 보시면서 이해를 더욱 깊게 하실 수 있을 것입니다.


주의: 코드를 실행하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요.

pip install openai langchain pydantic python-dotenv

profile
IT를 좋아합니다.

0개의 댓글