Coding/Study

[AI]LangChain 기본 이론&실습(3)

후__아 2024. 7. 31. 18:25

LangChain이 제공하는 언어 모델 두 가지

 

※ LLM

단일 요청에 대한 복잡한 출력 생성 ex) 문서 요약, 질문 답변 생성, etc

텍스트 문자열 in → 텍스트 문자열 out

+표준화된 인터페이스 → 다양한 LLM 제공 업체 간 호환성 → 유연한 모델 전환/다중 LLM 통합 가

 

※ ChatModel

사용자와의 상호작용을 통한 연속적 대화 관리 ex) 챗봇

메시지 리스트 in → 하나의 메시지 out

대화의 맥락을 유지하며 적절한 응답 생성

+다양한 모델 제공 업체/작동 모드


※ LLM 모델 파라미터

-Temperature: 생성된 텍스트의 다양성 조정

- Max Tokens: 생성할 최대 토큰 수(텍스트 길이 제한)

- Top P(Probability): 생성 과정에서 특정 확률 분포 내 상위 P% 토큰만 고려

- Frequency Penalty: 값이 클수록 재등장할 확률 감소시키기, 반복↓ 다양성↑

- Presence Penalty: 텍스트 내 단어의 존재 유무에 따른 해당 단어의 선택 확률 조정

- Stop Sequences: 특정 단어/구절이 등장하면 생성을 멈추도록 설정

 

LLM 모델 만들기
1. 파라미터 직접 전달
from langchain_openai import ChatOpenAI

params = {# 기본 파라미터
    "temperature": 0.7,
    "max_tokens": 100,
    "frequency_penalty": 0.5,
    "presence_penalty": 0.5,
    "stop": ['\n']
}

model = ChatOpenAI(model = "gpt-3.5-turbo-0125", **params)
quest = "태양계에서 가장 큰 행성은 무엇인가요?"
resp = model.invoke(input = quest)

resp.content

 

2. 모델 파라미터 추가-bind 메소드

특정 모델 설정을 기본값으로 사용할 때 or 일부 파라미터만 다르게 적용할 때 bind 활용

코드의 가독성&재사용성 ↑

# bind
from langchain_core.prompts import ChatPromptTemplate

prom = ChatPromptTemplate.from_messages([
    ('system', "이 시스템은 역사학 질문에 답변할 수 있습니다."),
    ('user', '{user_input}'),
])

model = ChatOpenAI(model='gpt-3.5-turbo-0125', max_tokens=100)
messages = prom.format_messages(user_input = "한국의 독립기념일은 언제인가요?")
answer1 = model.invoke(messages)
print(answer1)    # binding 이전

chain = prom | model.bind(max_tokens = 10)
answer2 = chain.invoke({'user_input': "한국의 독립기념일은 언제인가요?"})
print(answer2)
content='한국의 독립기념일은 3월 1일입니다. 이 날은 1919년 3월 1일 대한민국의 광복을 위한 독립운동이 시작된 날로 기념됩니다. 현재 대한민국에서는 3월 1일을 독립운동 기념일로 지' response_metadata={'token_usage': {'completion_tokens': 100, 'prompt_tokens': 56, 'total_tokens': 156}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'length', 'logprobs': None} id='run-861a8964-0965-4bdf-a1ad-79fab9a4c1e0-0' usage_metadata={'input_tokens': 56, 'output_tokens': 100, 'total_tokens': 156}
content='대한민국의 독' response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 56, 'total_tokens': 65}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'length', 'logprobs': None} id='run-bc0f9ec8-d128-46ca-8e74-522bc6b1f6a2-0' usage_metadata={'input_tokens': 56, 'output_tokens': 9, 'total_tokens': 65}

※ 출력 파서 Output Parser

-출력 포맷 변경: 원하는 형식으로 출력

-정보 추출: 필요한 정보만 추출

-결과 정제: 후처리 작업 수행

-조건부 로직 적용: 출력 데이터 기반 다른 처리 수

1. CSV Parser

랭체인의 CommaSeparatedListOutputParser

모델이 생성한 텍스트에서 ','로 구분된 항목 추출 & 리스트로 파싱

get_format_instructions(): 모델에 전달할 포맷 지시사항

from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import CommaSeparatedListOutputParser

output_parser = CommaSeparatedListOutputParser()
format_instructions = output_parser.get_format_instructions()

prom = PromptTemplate(
    template = "다섯 명의 {인물}을 나열해주세요. \n{format_instructions}",
    input_variables = ["subject"],
    partial_variables = {'format_instructions': format_instructions},
)

llm = ChatOpenAI(model='gpt-3.5-turbo-0125', temperature = 0)  # temperature=0: 일관된 출력 생성
chain = prom | llm | output_parser
chain.invoke({"인물": "세계 최고의 부자"})
['Jeff Bezos', 'Elon Musk', 'Bernard Arnault', 'Bill Gates', 'Mark Zuckerberg']

 

2. JSON Parser

다음 예제에선 JsonOutputPaser와 Pydantic 사용 → 모델 출력(JSON 파싱) 후 Pydantic 모델로 구조화

#JSON
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field

# 자료구조 정의 (pydantic)
class CusineRecipe(BaseModel):
    name: str = Field(description="name of a cusine")
    recipe: str = Field(description="recipe to cook the cusine")

# 출력 파서 정의
output_parser = JsonOutputParser(pydantic_object=CusineRecipe)
format_instructions = output_parser.get_format_instructions()

print(format_instructions)

prompt = PromptTemplate(
    template="Answer the user query.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": format_instructions},
)
chain = prompt | model | output_parser

chain.invoke({"query": "Let me know how to cook Bibimbap"})
The output should be formatted as a JSON instance that conforms to the JSON schema below.

As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.

Here is the output schema:
```
{"properties": {"name": {"title": "Name", "description": "name of a cusine", "type": "string"}, "recipe": {"title": "Recipe", "description": "recipe to cook the cusine", "type": "string"}}, "required": ["name", "recipe"]}
```

{'name': 'Bibimbap',
 'recipe': 'Bibimbap is a Korean mixed rice dish made with warm white rice topped with sautéed and seasoned vegetables, chili pepper paste, soy sauce, or doenjang, and a raw or fried egg. The ingredients are stirred together just before eating. It can be served either cold or hot.'}

 

cf)

https://wikidocs.net/231346

https://aws.amazon.com/ko/what-is/langchain/

https://www.samsungsds.com/kr/insights/what-is-langchain.html