1. LangChain의 첫걸음

🎯 이 μ±•ν„°μ—μ„œ 배울 것

  • LangChain을 μ‚¬μš©ν•˜μ—¬ μ–Έμ–΄ λͺ¨λΈ(LLM)κ³Ό μ±— λͺ¨λΈμ„ μ΄ˆκΈ°ν™”ν•˜λŠ” 방법
  • predict와 predict_messages의 차이점 μ΄ν•΄ν•˜κΈ°
  • PromptTemplate을 μ‚¬μš©ν•˜μ—¬ λ™μ μœΌλ‘œ ν”„λ‘¬ν”„νŠΈλ₯Ό μƒμ„±ν•˜λŠ” 방법
  • OutputParserλ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ¨λΈμ˜ 좜λ ₯을 μ›ν•˜λŠ” ν˜•μ‹μœΌλ‘œ λ³€ν™˜ν•˜λŠ” 방법
  • LangChain Expression Language (LCEL)을 μ‚¬μš©ν•˜μ—¬ μ—¬λŸ¬ ꡬ성 μš”μ†Œλ₯Ό μ—°κ²°(chain)ν•˜λŠ” 방법

LLMκ³Ό Chat Model

🎯 이번 λ‹¨κ³„μ—μ„œ 배울 것

  • LangChain의 ChatOpenAI λͺ¨λΈμ„ μ΄ˆκΈ°ν™”ν•˜λŠ” 방법
  • predict λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ κ°„λ‹¨ν•œ μ§ˆλ¬Έμ— λŒ€ν•œ 닡변을 μ–»λŠ” 방법

πŸ“ 1단계: ChatOpenAI λͺ¨λΈ μ΄ˆκΈ°ν™” 및 μ‚¬μš©

전체 μ½”λ“œ (notebook.ipynb):

1
2
3
4
5
6
7
from langchain.chat_models import ChatOpenAI

chat = ChatOpenAI()

b = chat.predict("How many planets are there?")

b

πŸ” μ½”λ“œ 상세 μ„€λͺ…

1. ChatOpenAIλž€?
ChatOpenAIλŠ” LangChain λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ μ œκ³΅ν•˜λŠ” ꡬ성 μš”μ†Œλ‘œ, OpenAI의 GPT λͺ¨λΈ(예: GPT-3.5, GPT-4)κ³Ό μƒν˜Έμž‘μš©ν•  수 있게 ν•΄μ£ΌλŠ” 닀리 역할을 ν•©λ‹ˆλ‹€. 이 클래슀λ₯Ό μ‚¬μš©ν•˜λ©΄ λ³΅μž‘ν•œ API 호좜 없이 Python μ½”λ“œ λ‚΄μ—μ„œ 직접 λŒ€ν™”ν˜• AI λͺ¨λΈμ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • μ™œ μ‚¬μš©ν•˜λŠ”κ°€?: OpenAI의 κ°•λ ₯ν•œ μ–Έμ–΄ λͺ¨λΈμ„ 우리 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— μ‰½κ²Œ 톡합할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ–΄λ–»κ²Œ μž‘λ™ν•˜λŠ”κ°€?: ChatOpenAI()λ₯Ό ν˜ΈμΆœν•˜λ©΄, λ‚΄λΆ€μ μœΌλ‘œ OpenAI API에 μ—°κ²°ν•  μ€€λΉ„λ₯Ό ν•©λ‹ˆλ‹€. 이 λ•Œ, μ‹œμŠ€ν…œμ— OPENAI_API_KEY ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ–΄ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

2. .predict() λ©”μ†Œλ“œ
.predict()λŠ” κ°€μž₯ κ°„λ‹¨ν•˜κ²Œ λͺ¨λΈμ—κ²Œ μ§ˆλ¬Έμ„ λ˜μ§€κ³  λ‹΅λ³€(λ¬Έμžμ—΄)을 λ°›λŠ” λ°©λ²•μž…λ‹ˆλ‹€.

  • μ‚¬μš©λ²•: chat.predict("질문 λ‚΄μš©") ν˜•νƒœλ‘œ μ‚¬μš©ν•˜λ©°, λ¬Έμžμ—΄μ„ μž…λ ₯λ°›μ•„ λ¬Έμžμ—΄μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

비ꡐ μ˜ˆμ‹œ:

1
2
3
4
5
6
7
8
9
# Before (LangChain μ‚¬μš© μ „)
# import openai
# openai.Completion.create(model="text-davinci-003", prompt="...")
# μœ„μ™€ 같이 λ³΅μž‘ν•œ API 호좜이 ν•„μš”ν–ˆμŠ΅λ‹ˆλ‹€.

# After (LangChain μ‚¬μš© ν›„)
chat = ChatOpenAI()
chat.predict("How many planets are there?")
# 단 두 μ€„λ‘œ λͺ¨λΈμ˜ 응닡을 받을 수 μžˆμŠ΅λ‹ˆλ‹€.

βœ… 체크리슀트

  • langchain λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ„€μΉ˜λ˜μ—ˆλ‚˜μš”?
  • OPENAI_API_KEY ν™˜κ²½ λ³€μˆ˜λ₯Ό μ„€μ •ν–ˆλ‚˜μš”?
  • ChatOpenAIλ₯Ό importν•˜κ³  μ΄ˆκΈ°ν™”ν–ˆλ‚˜μš”?
  • predict λ©”μ†Œλ“œλ‘œ μ§ˆλ¬Έμ„ 보내고 κ²°κ³Όλ₯Ό ν™•μΈν–ˆλ‚˜μš”?

Predict Messages

🎯 이번 λ‹¨κ³„μ—μ„œ 배울 것

  • SystemMessage, AIMessage, HumanMessage의 μ—­ν•  μ΄ν•΄ν•˜κΈ°
  • predict_messagesλ₯Ό μ‚¬μš©ν•˜μ—¬ 더 λ³΅μž‘ν•œ λŒ€ν™” λ§₯락을 μ „λ‹¬ν•˜λŠ” 방법

πŸ“ 1단계: λ‹€μ–‘ν•œ μ—­ν• μ˜ λ©”μ‹œμ§€ μ‚¬μš©ν•˜κΈ°

전체 μ½”λ“œ (notebook.ipynb):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, AIMessage, SystemMessage

chat = ChatOpenAI(temperature=0.1)

messages = [
SystemMessage(
content="You are a geography expert. And you only reply in {language}.",
),
AIMessage(content="Ciao, mi chiamo {name}!"),
HumanMessage(
content="What is the distance between {country_a} and {country_b}. Also, what is your name?",
),
]

chat.predict_messages(messages)

πŸ” μ½”λ“œ 상세 μ„€λͺ…

1. λ©”μ‹œμ§€ νƒ€μž…: System, AI, Human

  • SystemMessage: λͺ¨λΈμ˜ μ—­ν• μ΄λ‚˜ 행동 방식을 μ§€μ‹œν•˜λŠ” λ©”μ‹œμ§€μž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, β€œλ„ˆλŠ” λ²ˆμ—­κ°€μ•Όβ€ λ˜λŠ” β€œμΉœμ ˆν•˜κ²Œ λŒ€λ‹΅ν•΄β€ 와 같은 지침을 λ‚΄λ¦½λ‹ˆλ‹€.
  • HumanMessage: μ‚¬μš©μžκ°€ μž…λ ₯ν•˜λŠ” λ©”μ‹œμ§€μž…λ‹ˆλ‹€.
  • AIMessage: AI λͺ¨λΈμ΄ 이전에 ν–ˆλ˜ 응닡을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€. λŒ€ν™”μ˜ 흐름을 μœ μ§€ν•  λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€.

2. .predict_messages() λ©”μ†Œλ“œ
.predict()κ°€ λ‹¨μˆœν•œ λ¬Έμžμ—΄ 질문만 λ°›λŠ” 것과 달리, .predict_messages()λŠ” μœ„μ—μ„œ μ„€λͺ…ν•œ λ©”μ‹œμ§€ κ°μ²΄λ“€μ˜ 리슀트λ₯Ό μž…λ ₯으둜 λ°›μŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 λͺ¨λΈμ—κ²Œ μ—­ν• , 이전 λŒ€ν™” λ‚΄μš© λ“± 더 ν’λΆ€ν•œ λ§₯락을 μ „λ‹¬ν•˜μ—¬ μ •κ΅ν•œ 닡변을 μœ λ„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

비ꡐ μ˜ˆμ‹œ:

1
2
3
4
5
6
7
8
9
10
11
# Before (predict)
# 단일 질문만 κ°€λŠ₯
chat.predict("What is the distance between Mexico and Thailand?")

# After (predict_messages)
# μ—­ν•  뢀여와 이전 λŒ€ν™” λ‚΄μš©μ„ ν¬ν•¨ν•œ 닀쀑 λ©”μ‹œμ§€ 전달 κ°€λŠ₯
messages = [
SystemMessage(content="You are a geography expert."),
HumanMessage(content="What is the distance between Mexico and Thailand?"),
]
chat.predict_messages(messages)

βœ… 체크리슀트

  • SystemMessage, AIMessage, HumanMessageλ₯Ό import ν–ˆλ‚˜μš”?
  • μ„Έ κ°€μ§€ λ©”μ‹œμ§€ νƒ€μž…μ˜ 역할을 μ΄ν•΄ν–ˆλ‚˜μš”?
  • λ©”μ‹œμ§€ 리슀트λ₯Ό λ§Œλ“€μ–΄ predict_messages에 전달해 λ³΄μ•˜λ‚˜μš”?

Prompt Templates

🎯 이번 λ‹¨κ³„μ—μ„œ 배울 것

  • PromptTemplateκ³Ό ChatPromptTemplate의 μ‚¬μš©λ²•
  • ν…œν”Œλ¦Ώμ„ μ‚¬μš©ν•˜μ—¬ λ™μ μœΌλ‘œ ν”„λ‘¬ν”„νŠΈλ₯Ό λ§Œλ“œλŠ” 방법

πŸ“ 1단계: ν…œν”Œλ¦ΏμœΌλ‘œ ν”„λ‘¬ν”„νŠΈ μƒμ„±ν•˜κΈ°

전체 μ½”λ“œ (notebook.ipynb):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate

chat = ChatOpenAI(temperature=0.1)

template = ChatPromptTemplate.from_messages(
[
("system", "You are a geography expert. And you only reply in {language}."),
("ai", "Ciao, mi chiamo {name}!"),
(
"human",
"What is the distance between {country_a} and {country_b}. Also, what is your name?",
),
]
)

prompt = template.format_messages(
language="Greek",
name="Socrates",
country_a="Mexico",
country_b="Thailand",
)

chat.predict_messages(prompt)

πŸ” μ½”λ“œ 상세 μ„€λͺ…

1. ChatPromptTemplateμ΄λž€?
ChatPromptTemplate은 λ©”μ‹œμ§€ λͺ©λ‘μ˜ ν…œν”Œλ¦Ώμ„ λ§Œλ“œλŠ” λ„κ΅¬μž…λ‹ˆλ‹€. {variable}κ³Ό 같은 ν”Œλ ˆμ΄μŠ€ν™€λ”λ₯Ό μ‚¬μš©ν•˜μ—¬ ν”„λ‘¬ν”„νŠΈμ˜ 일뢀λ₯Ό λ™μ μœΌλ‘œ λ³€κ²½ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • μ™œ μ‚¬μš©ν•˜λŠ”κ°€?: 맀번 SystemMessage, HumanMessage 객체λ₯Ό μˆ˜λ™μœΌλ‘œ λ§Œλ“€ ν•„μš” 없이, μ •ν•΄μ§„ 틀에 λ³€μˆ˜λ§Œ λ°”κΏ” λΌμ›Œλ„£μ–΄ 효율적으둜 ν”„λ‘¬ν”„νŠΈλ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

2. .from_messages()와 .format_messages()

  • .from_messages(): λ©”μ‹œμ§€ μ—­ν• κ³Ό ν…œν”Œλ¦Ώ λ¬Έμžμ—΄μ˜ νŠœν”Œ 리슀트λ₯Ό λ°›μ•„ ν…œν”Œλ¦Ώ 객체λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.
  • .format_messages(): μƒμ„±λœ ν…œν”Œλ¦Ώ 객체에 μ‹€μ œ λ³€μˆ˜ 값을 μ „λ‹¬ν•˜μ—¬ μ΅œμ’… λ©”μ‹œμ§€ 리슀트λ₯Ό λ§Œλ“­λ‹ˆλ‹€.

μ‹œκ°ν™”:

1
2
3
4
5
6
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ChatPromptTemplate β”‚ β”‚ .format_messages() β”‚ β”‚ Final Messages β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ ("system", "...{lang}...") β”‚ + β”‚ lang="Greek", ... β”‚ -> β”‚ [SystemMessage(..Greek..)] β”‚
β”‚ ("human", "...{country}...") β”‚ β”‚ country="Mexico" β”‚ β”‚ [HumanMessage(..Mexico..)] β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… 체크리슀트

  • ChatPromptTemplate을 import ν–ˆλ‚˜μš”?
  • from_messagesλ₯Ό μ‚¬μš©ν•΄ ν…œν”Œλ¦Ώμ„ λ§Œλ“€μ—ˆλ‚˜μš”?
  • format_messages에 λ³€μˆ˜λ₯Ό μ „λ‹¬ν•˜μ—¬ μ΅œμ’… ν”„λ‘¬ν”„νŠΈλ₯Ό μƒμ„±ν–ˆλ‚˜μš”?

Output Parser와 LCEL

🎯 이번 λ‹¨κ³„μ—μ„œ 배울 것

  • BaseOutputParserλ₯Ό 상속받아 μ»€μŠ€ν…€ νŒŒμ„œλ₯Ό λ§Œλ“œλŠ” 방법
  • LangChain Expression Language (LCEL)의 νŒŒμ΄ν”„(|) μ—°μ‚°μž μ‚¬μš©λ²•

πŸ“ 1단계: 좜λ ₯ νŒŒμ„œ μ •μ˜ 및 체인 μ—°κ²°

전체 μ½”λ“œ (notebook.ipynb):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser

class CommaOutputParser(BaseOutputParser):
def parse(self, text):
items = text.strip().split(",")
return list(map(str.strip, items))

chat = ChatOpenAI(temperature=0.1)

template = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a list generating machine. Everything you are asked will be answered with a comma separated list of max {max_items} in lowercase. Do NOT reply with anything else.",
),
("human", "{question}"),
]
)

# LCEL을 μ‚¬μš©ν•œ 체인 μ—°κ²°
chain = template | chat | CommaOutputParser()

chain.invoke({"max_items": 5, "question": "What are the pokemons?"})

πŸ” μ½”λ“œ 상세 μ„€λͺ…

1. BaseOutputParser
λͺ¨λΈμ˜ 좜λ ₯(주둜 λ¬Έμžμ—΄)을 μš°λ¦¬κ°€ μ›ν•˜λŠ” ν˜•νƒœ(예: 리슀트, JSON)둜 λ³€ν™˜ν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€. BaseOutputParserλ₯Ό μƒμ†ν•˜κ³  parse λ©”μ†Œλ“œλ₯Ό κ΅¬ν˜„ν•˜μ—¬ μ»€μŠ€ν…€ νŒŒμ„œλ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

  • CommaOutputParser: 이 μ˜ˆμ œμ—μ„œλŠ” μ‰Όν‘œλ‘œ κ΅¬λΆ„λœ λ¬Έμžμ—΄μ„ Python 리슀트둜 λ³€ν™˜ν•˜λŠ” νŒŒμ„œλ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

2. LangChain Expression Language (LCEL)
LCEL은 LangChain의 μ—¬λŸ¬ ꡬ성 μš”μ†Œλ₯Ό | (νŒŒμ΄ν”„) μ—°μ‚°μžλ‘œ μ‰½κ²Œ μ—°κ²°ν•  수 있게 ν•΄μ£ΌλŠ” κ°•λ ₯ν•œ κΈ°λŠ₯μž…λ‹ˆλ‹€. 데이터가 μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ 흐λ₯΄λ©° 각 단계λ₯Ό κ±°μΉ©λ‹ˆλ‹€.

λ™μž‘ 흐름:

1
2
3
4
5
6
7
8
9
10
11
12
13
1. `chain.invoke`에 λ”•μ…”λ„ˆλ¦¬ 전달
{"max_items": 5, "question": "..."}
|
V
2. `template`이 λ”•μ…”λ„ˆλ¦¬λ₯Ό λ°›μ•„ ν”„λ‘¬ν”„νŠΈ(λ©”μ‹œμ§€ 리슀트) 생성
|
V
3. `chat` λͺ¨λΈμ΄ ν”„λ‘¬ν”„νŠΈλ₯Ό λ°›μ•„ 응닡(λ¬Έμžμ—΄) 생성
"pikachu, charizard, bulbasaur, ..."
|
V
4. `CommaOutputParser`κ°€ λ¬Έμžμ—΄μ„ λ°›μ•„ μ΅œμ’… κ²°κ³Ό(Python 리슀트) λ°˜ν™˜
['pikachu', 'charizard', 'bulbasaur', ...]

βœ… 체크리슀트

  • BaseOutputParserλ₯Ό μƒμ†ν•˜μ—¬ λ‚˜λ§Œμ˜ νŒŒμ„œλ₯Ό λ§Œλ“€μ—ˆλ‚˜μš”?
  • | μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•˜μ—¬ template, chat, parserλ₯Ό μ—°κ²°ν–ˆλ‚˜μš”?
  • chain.invoke()λ₯Ό μ‚¬μš©ν•˜μ—¬ 전체 체인을 μ‹€ν–‰ν–ˆλ‚˜μš”?

Chaining Chains

🎯 이번 λ‹¨κ³„μ—μ„œ 배울 것

  • μ—¬λŸ¬ 개의 체인을 ν•˜λ‚˜λ‘œ μ—°κ²°ν•˜λŠ” 방법
  • 슀트리밍 좜λ ₯을 μ²˜λ¦¬ν•˜λŠ” 방법

πŸ“ 1단계: 두 개의 체인 μ—°κ²°ν•˜κΈ°

전체 μ½”λ“œ (notebook.ipynb):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.callbacks import StreamingStdOutCallbackHandler

chat = ChatOpenAI(
temperature=0.1,
streaming=True,
callbacks=[
StreamingStdOutCallbackHandler(),
],
)

# 첫 번째 체인: μš”λ¦¬ μ’…λ₯˜λ₯Ό λ°›μ•„ λ ˆμ‹œν”Όλ₯Ό 생성
chef_prompt = ChatPromptTemplate.from_messages(
[
("system", "You are a world-class international chef..."),
("human", "I want to cook {cuisine} food."),
]
)
chef_chain = chef_prompt | chat

# 두 번째 체인: λ ˆμ‹œν”Όλ₯Ό λ°›μ•„ μ±„μ‹μ£Όμ˜μžμš©μœΌλ‘œ λ³€κ²½
veg_chef_prompt = ChatPromptTemplate.from_messages(
[
("system", "You are a vegetarian chef..."),
("human", "{recipe}"),
]
)
veg_chain = veg_chef_prompt | chat

# 두 체인 μ—°κ²°
final_chain = {"recipe": chef_chain} | veg_chain

final_chain.invoke({"cuisine": "indian"})

πŸ” μ½”λ“œ 상세 μ„€λͺ…

1. StreamingStdOutCallbackHandler
λͺ¨λΈμ΄ 응닡을 생성할 λ•Œ, 전체 응닡이 μ™„λ£Œλ  λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬λŠ” λŒ€μ‹  단어(토큰)κ°€ 생성될 λ•Œλ§ˆλ‹€ μ‹€μ‹œκ°„μœΌλ‘œ 좜λ ₯ν•΄μ£ΌλŠ” 콜백 ν•Έλ“€λŸ¬μž…λ‹ˆλ‹€. μ‚¬μš©μž κ²½ν—˜μ„ ν–₯μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

2. 체인 μ—°κ²°ν•˜κΈ°
LCEL을 μ‚¬μš©ν•˜λ©΄ ν•œ 체인의 좜λ ₯을 λ‹€λ₯Έ 체인의 μž…λ ₯으둜 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.

λ™μž‘ 흐름:

1
2
3
4
5
6
7
8
9
10
1. `final_chain.invoke`에 {"cuisine": "indian"} 전달
|
V
2. `chef_chain`이 'indian'을 λ°›μ•„ λ ˆμ‹œν”Ό(AIMessage) 생성
|
V
3. {"recipe": AIMessage(...)} ν˜•νƒœμ˜ λ”•μ…”λ„ˆλ¦¬κ°€ `veg_chain`으둜 전달됨
|
V
4. `veg_chain`이 λ ˆμ‹œν”Όλ₯Ό μž…λ ₯λ°›μ•„ μ΅œμ’…μ μΈ 채식 λ ˆμ‹œν”Όλ₯Ό 슀트리밍으둜 좜λ ₯

βœ… 체크리슀트

  • StreamingStdOutCallbackHandlerλ₯Ό μ‚¬μš©ν•˜μ—¬ μ‹€μ‹œκ°„ 좜λ ₯을 ν™•μΈν–ˆλ‚˜μš”?
  • 두 개 μ΄μƒμ˜ ν”„λ‘¬ν”„νŠΈμ™€ λͺ¨λΈμ„ 각각의 체인으둜 λ§Œλ“€μ—ˆλ‚˜μš”?
  • 첫 번째 체인의 좜λ ₯을 두 번째 체인의 μž…λ ₯으둜 μ „λ‹¬ν•˜λ„λ‘ final_chain을 κ΅¬μ„±ν–ˆλ‚˜μš”?

Recap

🎯 이번 λ‹¨κ³„μ—μ„œ 배울 것

  • 챕터 1μ—μ„œ 배운 λͺ¨λ“  κ°œλ…μ„ μ’…ν•©ν•˜μ—¬ ν•˜λ‚˜μ˜ 체인을 μ™„μ„±ν•˜λŠ” 방법

πŸ“ 1단계: μ΅œμ’… 체인 μ™„μ„± 및 κ°œμ„ 

전체 μ½”λ“œ (notebook.ipynb):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.callbacks import StreamingStdOutCallbackHandler

# 1. 슀트리밍 μ½œλ°±μ„ ν¬ν•¨ν•œ μ±— λͺ¨λΈ μ΄ˆκΈ°ν™”
chat = ChatOpenAI(
temperature=0.1,
streaming=True,
callbacks=[
StreamingStdOutCallbackHandler(),
],
)

# 2. μš”λ¦¬μ‚¬ 역할을 μ •μ˜ν•˜λŠ” ν”„λ‘¬ν”„νŠΈ ν…œν”Œλ¦Ώ
chef_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a world-class international chef. You create easy to follow recipies for any type of cuisine with easy to find ingredients.",
),
("human", "I want to cook {cuisine} food."),
]
)

# 3. μš”λ¦¬μ‚¬ 체인
chef_chain = chef_prompt | chat

# 4. μ±„μ‹μ£Όμ˜μž μš”λ¦¬μ‚¬ 역할을 μ •μ˜ν•˜λŠ” ν”„λ‘¬ν”„νŠΈ ν…œν”Œλ¦Ώ
veg_chef_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a vegetarian chef specialized on making traditional recipies vegetarian. You find alternative ingredients and explain their preparation. You don't radically modify the recipe. If there is no alternative for a food just say you don't know how to replace it.",
),
("human", "{recipe}"),
]
)

# 5. μ±„μ‹μ£Όμ˜μž μš”λ¦¬μ‚¬ 체인
veg_chain = veg_chef_prompt | chat

# 6. 두 체인을 μ—°κ²°ν•œ μ΅œμ’… 체인
final_chain = {"recipe": chef_chain} | veg_chain

# 7. μ΅œμ’… 체인 μ‹€ν–‰
final_chain.invoke({"cuisine": "indian"})

πŸ” μ½”λ“œ 상세 μ„€λͺ…

이번 λ‹¨κ³„μ—μ„œλŠ” μ΄μ „κΉŒμ§€ 배운 λͺ¨λ“  것을 μ’…ν•©ν•©λ‹ˆλ‹€.

  • ChatOpenAIλ₯Ό StreamingStdOutCallbackHandler와 ν•¨κ»˜ μ„€μ •ν•˜μ—¬ μ‹€μ‹œκ°„ 응닡을 λ°›μŠ΅λ‹ˆλ‹€.
  • 각기 λ‹€λ₯Έ 역할을 κ°€μ§„ 두 개의 ChatPromptTemplate (chef_prompt, veg_chef_prompt)을 μ •μ˜ν•©λ‹ˆλ‹€.
  • 각 ν…œν”Œλ¦Ώμ„ chat λͺ¨λΈκ³Ό | μ—°μ‚°μžλ‘œ μ—°κ²°ν•˜μ—¬ 두 개의 κΈ°λ³Έ 체인(chef_chain, veg_chain)을 λ§Œλ“­λ‹ˆλ‹€.
  • chef_chain의 좜λ ₯을 veg_chain의 recipe μž…λ ₯으둜 λ§€ν•‘ν•˜μ—¬ final_chain을 κ΅¬μ„±ν•©λ‹ˆλ‹€.
  • invokeλ₯Ό μ‚¬μš©ν•˜μ—¬ 전체 ν”„λ‘œμ„ΈμŠ€λ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€.

이것이 λ°”λ‘œ LangChain의 핡심 μ•„μ΄λ””μ–΄μž…λ‹ˆλ‹€. μž‘κ³  μž¬μ‚¬μš© κ°€λŠ₯ν•œ ꡬ성 μš”μ†Œ(LLM, Prompt, Parser λ“±)λ₯Ό λ§Œλ“€μ–΄ LCEL을 톡해 레고 λΈ”λ‘μ²˜λŸΌ μ‘°λ¦½ν•˜μ—¬ λ³΅μž‘ν•œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ ꡬ좕할 수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ’‘ μ—°μŠ΅ 과제

  1. λ²ˆμ—­ 체인 μΆ”κ°€ν•˜κΈ°: final_chain의 λ§ˆμ§€λ§‰μ— λ²ˆμ—­κ°€ 역할을 ν•˜λŠ” μ„Έ 번째 체인을 μΆ”κ°€ν•˜μ—¬, μ΅œμ’… λ ˆμ‹œν”Όλ₯Ό μŠ€νŽ˜μΈμ–΄λ‘œ λ²ˆμ—­ν•˜λ„λ‘ λ§Œλ“€μ–΄λ³΄μ„Έμš”.
  2. 좜λ ₯ νŒŒμ„œ μ‚¬μš©ν•˜κΈ°: chef_chain λ‹€μŒμ— CommaOutputParser와 μœ μ‚¬ν•œ νŒŒμ„œλ₯Ό μΆ”κ°€ν•˜μ—¬, λ ˆμ‹œν”Όμ—μ„œ 재료 λͺ©λ‘λ§Œ μΆ”μΆœν•˜λ„λ‘ μˆ˜μ •ν•΄λ³΄μ„Έμš”.

좜처 : https://nomadcoders.co/fullstack-gpt