[๊ฐ์๋ ธํธ] LangChain Academy : Introduction to LangGraph (Module 1)

๋ญ์ฒด์ธ(LangChain)๊ณผ ๋ญ๊ทธ๋ํ(LangGraph)๋ ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ(LLM)์ ํ์ฉํ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ๋๊ตฌ๋ค์ ๋๋ค. ์ ๊ฐ์๋ LangChain์์ ์ด์ํ๋ LangChain Academy์์ ์ ์ํ โIntroduction to LangGraphโ ๊ฐ์์ ๋ด์ฉ์ ์ ๋ฆฌ ๋ฐ ์ถ๊ฐ ์ค๋ช ํ ๋ด์ฉ์ ๋๋ค.
- ๊ฐ์ ๋งํฌ : https://youtu.be/29XE10U6ooc
- ๋ญ์ฒด์ธ : https://www.langchain.com/
์ด๋ฒ ํฌ์คํธ๋ โIntroductionโ๊ณผ โModule1โ๋ด์ฉ์ ๋ค๋ฃน๋๋ค:
๋ชฉ์ฐจ
- Introduction: ๋ญ์ฒด์ธ(LangChain), ๊ทธ๋ฆฌ๊ณ ๋ญ๊ทธ๋ํ(LangGraph)
- Lesson 1: Motivation, Introduction to Langraph
- Lesson 2: Simple Graph
- Lesson 3: LangGraph Studio
- Lesson 4: Chain
- Lesson 5: Router
- Lesson 6: Agent
- Lesson 7: Agent with Memory
- Lesson 8: Deployment
-
Introduction
๋ญ์ฒด์ธ(LangChain)
๋ญ์ฒด์ธ์ ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ(LLM)์ ํ์ฉํ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์ ์ํ ํฌ๊ด์ ์ธ ํ๋ ์์ํฌ์
๋๋ค. ์ด ํ๋ ์์ํฌ๋ LLM๊ณผ ์ ํ๋ฆฌ์ผ์ด์
์ ํตํฉ์ ๊ฐ์ํํ๊ธฐ ์ํด ์ค๊ณ๋์์ผ๋ฉฐ, ๊ฐ๋ฐ์๋ค์ด LLM ๊ธฐ๋ฐ ์์คํ
์ ๋ ์ฝ๊ณ ํจ์จ์ ์ผ๋ก ๊ตฌ์ถํ ์ ์๋๋ก ๋์ต๋๋ค.

์ฃผ์ ๊ตฌ์ฑ ์์
- ๋ฐ์ดํฐ ์์ค ์ฐ๊ฒฐ: ๋ญ์ฒด์ธ์ PDF, ์น ํ์ด์ง, CSV, ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฑ ๋ค์ํ ์ธ๋ถ ๋ฐ์ดํฐ ์์ค์์ ์ฐ๋์ ์ง์ํฉ๋๋ค. ์ด๋ฅผ ํตํด LLM์ ํ๋ถํ ์ปจํ ์คํธ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
- ๋จ์ด ์๋ฒ ๋ฉ: ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ๋ฒกํฐ๋ก ๋ณํํ๋ ๊ณผ์ ์ ์ง์ํฉ๋๋ค. ๋ญ์ฒด์ธ์ ์ ํํ LLM์ ์ ํฉํ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ์๋์ผ๋ก ์ ํํฉ๋๋ค.
- ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค: ์์ฑ๋ ์๋ฒ ๋ฉ์ ์ ์ฅํ๊ณ ๊ฒ์ํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๋ด ๋ฐฐ์ด๋ถํฐ Pinecone๊ณผ ๊ฐ์ ํธ์คํ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊น์ง ๋ค์ํ ์ต์ ์ ์ง์ํฉ๋๋ค.
- ์ธ์ด ๋ชจ๋ธ ํตํฉ: OpenAI, Cohere, AI21 ๋ฑ์ ์ฃผ์ LLM ์ ๊ณต์ ์ฒด์ Hugging Face์ ์คํ์์ค ๋ชจ๋ธ์ ์ง์ํฉ๋๋ค.
- ์์ด์ ํธ: LLM์ ์ฌ์ฉํ์ฌ ๋์ ์ผ๋ก ์์ ๊ณํ์ ์๋ฆฝํ๊ณ ์คํํ ์ ์๋ ๊ฐ๋ ฅํ ๋ชจ๋์ ๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ: LLM์ ๋จ๊ธฐ ๋ฐ ์ฅ๊ธฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ถ๊ฐํ์ฌ ๋ํ์ ์ปจํ ์คํธ๋ฅผ ์ ์งํ ์ ์์ต๋๋ค.
- ์ฝ๋ฐฑ ์์คํ : ๊ฐ๋ฐ์๊ฐ LLM ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ํ ๋จ๊ณ์ ์ฐ๊ฒฐํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ์ฒด์ธ: ์ฌ๋ฌ ๊ตฌ์ฑ ์์๋ฅผ ์ฐ๊ฒฐํ์ฌ ๋ณต์กํ ์์ ํ๋ฆ์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
๋ญ์ฒด์ธ์ ์ด๋ฌํ ๊ตฌ์ฑ ์์๋ค์ ํตํฉํ์ฌ ๊ฐ๋ฐ์๊ฐ LLM ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ์ฝ๊ฒ ๊ตฌ์ถํ ์ ์๋๋ก ๋์ต๋๋ค. ํนํ, ํ๋กฌํํธ ์์ง๋์ด๋ง, API ํธ์ถ, ๊ฒฐ๊ณผ ํด์ ๋ฑ LLM๊ณผ์ ์ํธ์์ฉ์ ํ์ํ ๋ค์ํ ์์ ์ ์ถ์ํํ์ฌ ์ ๊ณตํฉ๋๋ค.
๋ญ๊ทธ๋ํ(LangGraph)
๋ญ๊ทธ๋ํ๋ ๋ณต์กํ ์์ด์ ํธ ์์คํ
์ ์ํ ์ค์ผ์คํธ๋ ์ด์
ํ๋ ์์ํฌ์
๋๋ค. ๋ญ์ฒด์ธ๋ณด๋ค ๋ ๋ฎ์ ์์ค์ ์ ์ด๋ฅผ ์ ๊ณตํ๋ฉฐ, ๊ธฐ์
์ ๊ณ ์ ํ ์๊ตฌ์ฌํญ์ ๋ง๋ ๋ณต์กํ ์์
์ ์ฒ๋ฆฌํ ์ ์๋ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.

์ฃผ์ ํน์ง
- ์ธ๋ฐํ ์ ์ด: ๋ญ๊ทธ๋ํ๋ ๋ญ์ฒด์ธ์ ์์ด์ ํธ๋ณด๋ค ๋ ์ธ๋ฐํ ์์ค์ ์ ์ด๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ๋ณต์กํ ์ํฌํ๋ก์ฐ๋ฅผ ๋ ์ ๋ฐํ๊ฒ ์ค๊ณํ๊ณ ๊ตฌํํ ์ ์์ต๋๋ค.
- ์ ์ฐํ ํ๋ ์์ํฌ: ๊ธฐ์ ์ ๊ณ ์ ํ ์๊ตฌ์ฌํญ์ ๋ง๋ ๋ณต์กํ ์์ ์ ์ฒ๋ฆฌํ ์ ์๋ ํํ๋ ฅ ์๋ ํ๋ ์์ํฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๋จ์ผํ ๋ธ๋๋ฐ์ค ์ธ์ง ์ํคํ ์ฒ์ ์ ํ๋์ง ์๊ณ ๋ค์ํ ์ ๊ทผ ๋ฐฉ์์ ๊ตฌํํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
- ์คํธ๋ฆฌ๋ฐ ์ต์ ํ: ๋ญ๊ทธ๋ํ๋ ์คํธ๋ฆฌ๋ฐ ์ํฌํ๋ก์ฐ๋ฅผ ์ผ๋์ ๋๊ณ ์ค๊ณ๋์์ต๋๋ค. ์ด๋ ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์๋ต์ด ํ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ํนํ ์ ์ฉํฉ๋๋ค.
- ์คํ์์ค: MIT ๋ผ์ด์ ์ค๋ก ์ ๊ณต๋๋ ๋ฌด๋ฃ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ด๋ ๊ฐ๋ฐ์๋ค์ด ์์ ๋กญ๊ฒ ์ฌ์ฉํ๊ณ ์์ ํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
- ๋ญ๊ทธ๋ํ ํด๋ผ์ฐ๋: ๋ญ๊ทธ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐฐํฌ์ ํ์ฅ์ ์ํ ์๋น์ค๋ก, ํ๋กํ ํ์ดํ, ๋๋ฒ๊น , ๊ณต์ ๋ฅผ ์ํ ์คํ๋์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๋ญ๊ทธ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐ๊ณผ ์ด์์ ๋์ฑ ํจ์จ์ ์ผ๋ก ๋ง๋ญ๋๋ค.
๋ญ๊ทธ๋ํ๋ ํนํ ๋ณต์กํ ์์ด์ ํธ ์์คํ ์ ๊ตฌ์ถํ๋ ๋ฐ ์ ํฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ๋ฌ ๋จ๊ณ์ ์์ฌ ๊ฒฐ์ ์ด ํ์ํ ์์ , ๋ค์ํ ์ธ๋ถ ๋๊ตฌ์์ ์ํธ์์ฉ์ด ํ์ํ ์์คํ , ๋๋ ๋์ ์ผ๋ก ๋ณํํ๋ ํ๊ฒฝ์ ์ ์ํด์ผ ํ๋ ์์ด์ ํธ ๋ฑ์ ๊ตฌํํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
-
Course Overview

Lesson 1: Motivation, Introduction to Langraph

Langraph๋ฅผ ๋์ ํ ์ด์ ๋ ๋จ์ํ LLM(Language Model) ์์ฒด๋ง์ผ๋ก๋ ํ๊ณ๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. LLM์ ์ธ๋ถ ๋๊ตฌ๋ ๋ฌธ์ ๊ฐ์ ์ธ๋ถ ์ปจํ ์คํธ์ ์ ๊ทผํ ์ ์๊ณ , ๋ณต์กํ ๋ฉํฐ์คํ ์์ ์ ์์ฒด์ ์ผ๋ก ์ํํ๊ธฐ ์ด๋ ต์ต๋๋ค.

๊ทธ๋์ ๋ง์ LLM ์ ํ๋ฆฌ์ผ์ด์ ์ LLM ํธ์ถ ์ ํ์ ์ฌ๋ฌ ๋จ๊ณ๋ก ๊ตฌ์ฑ๋ ์ผ๋ จ์ ์์ ํ๋ฆ์ ์ฌ์ฉํ๋ฉฐ, ์ด๋ฅผ ์ฒด์ธ(Chain)์ด๋ผ๊ณ ํฉ๋๋ค.

์ฒด์ธ์ ์ผ์ ํ ํ๋ฆ์ ๋ฐ๋ฅด๊ธฐ ๋๋ฌธ์ ์์ ์ ์ด์ง๋ง, ๋๋ก๋ LLM ์์ฒด๊ฐ ๋ฌธ์ ์ ๋ฐ๋ผ ์์ ์์๋ฅผ ๊ฒฐ์ ํ ์ ์๋ค๋ ๋จ์ ์ด ์กด์ฌํ๊ฒ ๋ฉ๋๋ค.

๋ฐ๋ผ์, ์์ ์์๋ฅผ ๊ฒฐ์ ํ ์ ์๋ ์์ด์ ํธ(Agent)๊ฐ ํ์๋ก ํ๊ฒ ๋ฉ๋๋ค. ์์ด์ ํธ๋ LLM์ด ์ฃผ๋ํ๋ ์์ ํ๋ฆ์ด๋ฉฐ, ์ด๋ LLM์ ์์ ๋จ๊ณ๋ฅผ ์ค์ค๋ก ์ ํํฉ๋๋ค.

์ ์ด ์์ค์ด ๋์์ง์๋ก ์์ด์ ํธ๋ ๋ ๋ง์ ์์จ์ฑ์ ๊ฐ์ง๊ฒ ๋์ด ๋ค์ํ ์ํฉ์ ๋ํด ๋ ์ ์ฐํ๊ฒ ๋์ฒํ ์ ์์ต๋๋ค.
- ์๋ฅผ ๋ค์ด, LLM(๋ํ ์ธ์ด ๋ชจ๋ธ)์ด ์์ ์ ์ํฌํ๋ก์ฐ๋ฅผ ์ค์ค๋ก ๊ฒฐ์ ํ ์ ์๊ฒ ํ๋ฉด, ๋ณต์กํ ๋ฌธ์ ์ ๋ํด ๋ ์ ์ ํ ๊ฒฐ์ ์ ๋ด๋ฆด ์ ์๋ ๊ฐ๋ฅ์ฑ์ด ๋์์ง๋๋ค.

ํ์ง๋ง, ์ ์ด ์์ค์ด ๋์์ง๋ฉด ์์ธก ๊ฐ๋ฅ์ฑ์ด ์ค์ด๋ค๊ณ , ๊ฐ ๋จ๊ณ์์ ๋ฐ์ํ ์ ์๋ ๋ณ๋์ฑ์ด๋ ์ค๋ฅ๊ฐ ์ฆ๊ฐํ ์ ์์ต๋๋ค. ์ด๋ ์์คํ ์ ์์ ์ฑ์ ์ํฅ์ ๋ฏธ์น๋ฉฐ, ํนํ ์๋ํ๋ ์์ฌ๊ฒฐ์ ์์ ๋ฐ์ํ ์ ์๋ ์ค๋ฅ ๊ฐ๋ฅ์ฑ์ด ๋์์ง ์ ์์ต๋๋ค.

๐ โ์ ์ด ์์ค์ด ๋์์ง๋คโ๋ ์๋ฏธ๋ ์์คํ , ํนํ LLM(๋ํ ์ธ์ด ๋ชจ๋ธ)์ด ์ํํ๋ ์์ ์์ ๋ ๋ง์ ์์จ์ฑ์ ๋ถ์ฌ๋ฐ๋ ๊ฒ์ ๋ปํฉ๋๋ค. ์ฌ๊ธฐ์ โ์ ์ดโ๋ ์ํฌํ๋ก์ฐ์ ํ๋ฆ์ ๊ฒฐ์ ํ๋ ๊ถํ์ ๋งํ๋ฉฐ, ์ ์ด ์์ค์ด ๋์์ง์๋ก LLM์ด๋ ์์ด์ ํธ๊ฐ ๋ ๋ง์ ๊ฒฐ์ ๊ณผ ์์ ์์๋ฅผ ์ค์ค๋ก ์ ํํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ ์ด ์์ค ๋ฎ์: LLM์ด ์ฃผ์ด์ง ์ ๋ ฅ์ ๋ฐ์์ ๊ณ ์ ๋ ์ ์ฐจ์ ๋ฐ๋ผ ์์ฐจ์ ์ผ๋ก ๋๊ตฌ๋ฅผ ํธ์ถํ๊ฑฐ๋ ์๋ต์ ์์ฑ. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ์ง๋ฌธ์ ํ๋ฉด LLM์ด ํญ์ โ ๊ฒ์ โก ๋ฌธ์ ์์ฝ โข ์๋ต ์์ฑ์ด๋ผ๋ ๊ณ ์ ๋ ์์๋ก ์์ ์ ์ํ.์ ์ด ์์ค ๋์: LLM์ด ๋ฌธ์ ์ ๋ณต์ก์ฑ์ด๋ ์ํฉ์ ๋ฐ๋ผ ์ด๋ค ๋๊ตฌ๋ฅผ ํธ์ถํ ์ง, ๋ช ๋จ๊ณ์ ์์ ์ ์ํํ ์ง, ๋๋ ์๋ก์ด ๋จ๊ณ๋ฅผ ์์ฑํ ์ง๋ฅผ ์ค์ค๋ก ํ๋จ. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์์ ์ง๋ฌธ์ ๋ฐ๋ผ โ ๊ฒ์์ด ํ์ ์๋ค๊ณ ํ๋จํ๊ฑฐ๋ โก ์๋ก์ด ๋๊ตฌ ํธ์ถ ๋จ๊ณ๋ฅผ ์ถ๊ฐํ๋ ๋ฑ ๋ณ๋์ ์ธ ์ํฌํ๋ก์ฐ๋ฅผ ์ ์ฉ.
Langraph๋ LLM์ ์ ์ด ์์ค์ ๋์ด๋ฉด์๋ ์์ ์ฑ์ ์ ์งํ ์ ์๋๋ก ๋๋ ๋๊ตฌ์ ๋๋ค. Langraph๋ ๊ทธ๋ํ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ฑ๋๋ฉฐ, ๊ฐ ๋ ธ๋(Node)๋ ํน์ ์์ ์ ์๋ฏธํ๊ณ ์ฃ์ง(Edge)๋ ๋ ธ๋ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ํ๋ ๋๋ค.

Langraph์ ์ฃผ์ Intuition๊ณผ ๊ด๋ จํ์ฌ ์๋ ๋ด์ฉ์ ์๊ฐํฉ๋๋ค:

์ ์ฌ๋ผ์ด๋๋ ๊ฐ๋ฐ์๊ฐ ์ ์ด ํ๋ก์ฐ์ ์ผ๋ถ๋ฅผ ๊ณ ์ ํ๋ ๊ฐ๋ ์ ์ค๋ช ํฉ๋๋ค. ๊ฐ๋ฐ์๊ฐ ์์ ํ๋ฆ์ ์ผ๋ถ ๋จ๊ณ๋ฅผ ๋ช ํํ๊ฒ ์ค์ ํ๋ฉด, ํด๋น ์ํฌํ๋ก์ฐ๋ ํญ์ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ํ๋๋ฏ๋ก ์ ๋ขฐ์ฑ(reliable)์ด ๋ณด์ฅ๋ฉ๋๋ค.
- ์๋ฅผ ๋ค์ด, ์์(Start)์์ ์ฒซ ๋ฒ์งธ ๋จ๊ณ(Step 1), ๋ ๋ฒ์งธ ๋จ๊ณ(Step 2)๋ก ์ด์ด์ง๋ ๊ณ ์ ๋ ํ๋ฆ์ด ์์ต๋๋ค. ์ด๋ ํญ์ ๊ฐ์ ์์๋ก ์์ ์ด ์งํ๋์ด ์์ธก ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค.

์ ์ฌ๋ผ์ด๋๋ LLM(๋ํ ์ธ์ด ๋ชจ๋ธ)์ ์ฃผ์ ํ์ฌ ์์ด์ ํธ๋ก ์ ํํ๋ ๊ฐ๋ ์ ์ค๋ช ํฉ๋๋ค. ์ฌ๊ธฐ์ LLM์ ๊ณ ์ ๋ ํ๋ฆ ๋์ , ํน์ ์์ ์์ ์ค์ค๋ก ํ๋จํ์ฌ ํ๋ฆ์ ๋ณ๊ฒฝ(control)ํ ์ ์์ต๋๋ค.
- LLM์ด ์ปจํธ๋กค์ ๊ฐ์ ธ๊ฐ๋ ์์ ์์ ๋ณด๋ค ์ ์ฐํ๊ฒ ๋์ํ์ง๋ง, ์ ๋ขฐ์ฑ์ด ๋จ์ด์ง ๊ฐ๋ฅ์ฑ๋ ์์ต๋๋ค. ์ด ์ฌ๋ผ์ด๋๋ ์์๋ถํฐ LLM์ด ๊ฐ์ ํ์ฌ ์ํฌํ๋ก์ฐ์ ์ผ๋ถ๋ฅผ ๋์ ์ผ๋ก ์กฐ์ ํ ์ ์๋ ๊ตฌ์กฐ๋ฅผ ๋ณด์ฌ์ค๋๋ค.

์ ์ฌ๋ผ์ด๋๋ ์ปค์คํ ์ ์ด ํ๋ฆ์ ๊ทธ๋ํ ํํ๋ก ํํํ๋ LangGraph์ ๊ตฌ์กฐ๋ฅผ ๋ํ๋ ๋๋ค. ๊ฐ ๋จ๊ณ(Node)๋ ์์ ์ ๋ํ๋ด๊ณ , ์ฃ์ง(Edge)๋ ๋ ธ๋ ๊ฐ์ ์ฐ๊ฒฐ์ ์๋ฏธํฉ๋๋ค.
- ์ฌ๊ธฐ์ LLM์ ์ฃ์ง์ ์์นํ์ฌ ๊ฐ ๋จ๊ณ๋ฅผ ๊ฒฐ์ ํ๋ฉฐ, ์ด๋ฅผ ํตํด ์ ์ฐํ ํ๋ฆ ์ ์ด๊ฐ ๊ฐ๋ฅํด์ง๋๋ค. LangGraph๋ ์ด๋ฌํ ๊ตฌ์กฐ๋ฅผ ์๊ฐํํ๊ณ ๊ด๋ฆฌํ ์ ์๋ ๋๊ตฌ์ ๋๋ค.

์ ์ฌ๋ผ์ด๋๋ LangGraph์ ์ธ ๊ฐ์ง ์ค์ํ ๊ฐ๋ ์ ์ค๋ช ํฉ๋๋ค:
- Memory (๋ฉ๋ชจ๋ฆฌ): ๊ทธ๋ํ ์ ๋ฐ์ ๊ฑธ์ณ
๊ณต์ ๋๋ ์ํ๋ฅผ ์๋ฏธํฉ๋๋ค.- ์ฆ, ์ํ๊ฐ ๊ณ์ ์ ์ง๋์ด ๊ทธ๋ํ๊ฐ ์งํ๋ ๋ ์ด๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
- Tools (๋๊ตฌ): ๊ฐ ๋ ธ๋๊ฐ ์ธ๋ถ ๋๊ตฌ๋ฅผ ํธ์ถํ๊ณ ์ํ๋ฅผ ์์ ํ ์ ์๋ ๊ธฐ๋ฅ์ ์๋ฏธํฉ๋๋ค.
- Planning (๊ณํ): ์ฃ์ง๋ LLM์ ๊ฒฐ์ ์ ๋ฐ๋ผ ์ ์ด ํ๋ก์ฐ๋ฅผ ์กฐ์ ํ ์ ์์ต๋๋ค.
- ์ด๋ฅผ ํตํด ์ํฌํ๋ก์ฐ๋ฅผ ๋์ฑ ์ ๊ตํ๊ฒ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.

์ ์ฌ๋ผ์ด๋๋ ์ดํ LangGraph์ ๊ฐ ๋ชจ๋์์ ๋ฐฐ์ธ ๋ด์ฉ์ ๊ฐ์๋ก ์ค๋ช ํฉ๋๋ค:
- Foundations: LangGraph์ ๊ธฐ์ด, ์ฒด์ธ, ๋ผ์ฐํฐ, ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ธ ์์จ ์์ด์ ํธ ๊ตฌ์ถ.
- Memory: ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ์ํ๋ฅผ ๊ธฐ์ตํ๋ ์์ด์ ํธ.
- Human-In-The-Loop: ์ฌ๋์ด ๊ฐ์ ํ์ฌ ์์ด์ ํธ๋ฅผ ๊ฐ๋ ํ๋ ๊ธฐ๋ฅ.
- Customization: ๋ง์ถคํ ์์ด์ ํธ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ.
Lesson 2: Simple Graph
Langraph์ ๊ธฐ๋ณธ ๊ตฌ์ฑ ์์์ธ ๊ทธ๋ํ(Graph)๋ฅผ ์ดํดํ๋ ๊ฐ๋จํ ์์ ๋ฅผ ์๊ฐํฉ๋๋ค.
๊ทธ๋ํ์๋ ๋ ธ๋(Node)์ ์ฃ์ง(Edge)๊ฐ ์กด์ฌํฉ๋๋ค.
- ๊ฐ ๋ ธ๋๋ ํน์ ์์ (์: ๋๊ตฌ ํธ์ถ, ๋ฐ์ดํฐ ๊ฒ์ ๋ฑ)์ ์ํํฉ๋๋ค.
- ๊ฐ ์ฃ์ง๋ ๋ ธ๋ ๊ฐ์ ์์ ํ๋ฆ์ ์ฐ๊ฒฐํ๋ ์ญํ ์ ํฉ๋๋ค.
๊ฐ๋จํ ๊ทธ๋ํ ์์์์๋ ์์(Start)์์ ๋ ธ๋ 1๋ก ๊ฐ๊ณ , ๋ ธ๋ 1์์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ ธ๋ 2 ๋๋ ๋ ธ๋ 3์ผ๋ก ์ด๋ํ ํ ์ข ๋ฃํฉ๋๋ค. ์ด๋ ์กฐ๊ฑด๋ถ ์ฃ์ง(Conditional Edge)๋ฅผ ์ฌ์ฉํด LLM์ ๊ฒฐ์ ์ ๋ฐ๋ผ ๋ ธ๋ 2๋ ๋ ธ๋ 3 ์ค ํ๋๋ก ๋ถ๊ธฐํ ์ ์์ต๋๋ค.
์ฃผ์ ๊ฐ๋ :
- ์ํ(State): ๊ฐ ๋ ธ๋๋ ๊ทธ๋ํ ์ํ๋ฅผ ๋ฐ์ ์์ ์ ์ํํ๊ณ , ์ํ๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
- ์กฐ๊ฑด๋ถ ์ฃ์ง(Conditional Edge): ํน์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ค์ ๋ ธ๋๋ฅผ ์ ํํฉ๋๋ค.
์ฝ๋ ์ค์ต
TypedDict๋ก State์ ์ ์ํฉ๋๋ค.TypedDict๋ Python 3.8๋ถํฐ ๋์ ๋ ๊ธฐ๋ฅ์ผ๋ก, ๋์ ๋๋ฆฌ์ ๊ตฌ์กฐ๋ฅผ ํ์ ํํธ๋ก ๋ช ์ํ ์ ์๊ฒ ํด์ค๋๋ค.- ์ด๋ ์ฃผ๋ก Type Hinting์ ์ผํ์ผ๋ก ์ฌ์ฉ๋๋ฉฐ, ๋์ ๋๋ฆฌ ๋ด์์ ์ฌ์ฉ๋๋ ํค์ ๊ฐ์ ํ์ ์ ์ ์ํ ์ ์์ต๋๋ค.
- ์ด๋ฅผ ํตํด ์ฝ๋์ ๊ฐ๋ ์ฑ์ ๋์ด๊ณ , IDE ๋๋ ํ์ ์ฒด์ปค(myPy ๋ฑ)๋ฅผ ์ด์ฉํ์ฌ ์ฝ๋์ ํ์ ์ค๋ฅ๋ฅผ ๋ฏธ๋ฆฌ ์ก์๋ผ ์ ์์ต๋๋ค.
1
2
3
4
5
# STATE ์ ์
from typing_extensions import TypedDict
class State(TypedDict):
graph_state: str
- ์ ์ฝ๋์์ State๋ผ๋ ์ด๋ฆ์ TypedDict๊ฐ ์ ์๋์ด ์์ต๋๋ค.
- ์ด ๊ตฌ์กฐ์ฒด๋ graph_state๋ผ๋ ํค๋ฅผ ๊ฐ์ง๊ณ , ํด๋น ํค์ ๊ฐ์ str ํ์ ์ด์ด์ผ ํ๋ค๋ ๊ฒ์ ๋ช ์ํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
# NODE ์ ์
def node_1(state):
print("---Node 1---")
return {"graph_state": state['graph_state'] +" I am"}
def node_2(state):
print("---Node 2---")
return {"graph_state": state['graph_state'] +" happy!"}
def node_3(state):
print("---Node 3---")
return {"graph_state": state['graph_state'] +" sad!"}
- ์ด ํจ์๋ state๋ผ๋ ๋ณ์๋ฅผ ๋ฐ์, ๊ทธ ์์ graph_state ํค์ ์ ๊ทผํ ํ, ํด๋น ๊ฐ์ ๋ณ๊ฒฝํ์ฌ ๋ฐํํฉ๋๋ค.
- ์ฌ๊ธฐ์
state['graph_state']๊ฐ ๋ฌธ์์ด์์ด ๋ณด์ฅ๋๋ฏ๋ก, ๋ฌธ์์ด ๊ฒฐํฉ(+) ์ฐ์ฐ์ด ๊ฐ๋ฅํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# EDGE ์ ์
import random
from typing import Literal
def decide_mood(state) -> Literal["node_2", "node_3"]:
# Often, we will use state to decide on the next node to visit
user_input = state['graph_state']
# Here, let's just do a 50 / 50 split between nodes 2, 3
if random.random() < 0.5:
# 50% of the time, we return Node 2
return "node_2"
# 50% of the time, we return Node 3
return "node_3"
- ์ด ํจ์๋ ์ํ(state)๋ฅผ ์
๋ ฅ๋ฐ์, ์ํ์ ๋ฐ๋ผ ๋ค์์ ์ด๋ ๋
ธ๋๋ก ์ด๋ํ ์ง๋ฅผ ์ฃ์ง๋ฅผ ๊ฒฐ์ ํ๋ ๋ก์ง์
๋๋ค.
- ์ ๋ ฅ: state๋ TypedDict๋ก ์ ์๋ ๋์ ๋๋ฆฌ์ด๋ฉฐ, graph_state๋ผ๋ ํค์ ๋ฌธ์์ด์ ์ ์ฅํฉ๋๋ค.
- ๊ธฐ๋ฅ: random.random()์ ์ฌ์ฉํ์ฌ 50% ํ๋ฅ ๋ก โnode_2โ ํน์ โnode_3โ์ ๋ฐํํฉ๋๋ค.
- ๋ฆฌํด๊ฐ: โnode_2โ ๋๋ โnode_3โ์ด๋ผ๋ ๋ฌธ์์ด์ ๋ฐํํ์ฌ, ์ด๋ค ๋ ธ๋๋ก ์ด๋ํ ์ง ๊ฒฐ์ ํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# GRAPH ์ ์
from IPython.display import Image, display
from langgraph.graph import StateGraph, START, END
# Build graph
builder = StateGraph(State)
builder.add_node("node_1", node_1)
builder.add_node("node_2", node_2)
builder.add_node("node_3", node_3)
# Logic
builder.add_edge(START, "node_1")
builder.add_conditional_edges("node_1", decide_mood)
builder.add_edge("node_2", END)
builder.add_edge("node_3", END)
# Add
graph = builder.compile()
# View
display(Image(graph.get_graph().draw_mermaid_png()))
- ์๋ ๊ณผ์ ์ ํตํด ์ํ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ํ๋ฆ์ ๊ฒฐ์ ํ๋ ์ํ ์ ์ด ๊ทธ๋ํ๊ฐ ์์ฑ๋ฉ๋๋ค.
- ๊ทธ๋ํ๊ฐ
START์์ ์์ํ์ฌnode_1๋ก ์ด๋ํฉ๋๋ค. node_1์์decide_mood ํจ์๊ฐ ํธ์ถ๋์ด,๋ฌด์์๋ก node_2 ๋๋ node_3๋ก ์ด๋ํฉ๋๋ค.node_2๋๋node_3์ ๋๋ฌํ๋ฉด ๊ทธ๋ํ๊ฐ์ข ๋ฃ(END)๋ฉ๋๋ค.
- ๊ทธ๋ํ๊ฐ

- ๋๋ค ๊ฐ์ด๋ฏ๋ก ๋๋ฆด ๋๋ง๋ค ๋ค๋ฅด๊ฒ ๊ฐ์ด ๋์ค๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค:

Lesson 3: LangGraph Studio
Langraph Studio๋ ์๊ฐ์ ์ผ๋ก ๊ทธ๋ํ๋ฅผ ๊ตฌ์ถํ๊ณ ๋๋ฒ๊น ํ ์ ์๋ ํตํฉ ๊ฐ๋ฐ ํ๊ฒฝ(IDE)์ ๋๋ค. Studio๋ฅผ ์ฌ์ฉํ๋ฉด ์์ด์ ํธ๋ฅผ ์๊ฐ์ ์ผ๋ก ๋๋ฒ๊น ํ๊ณ , ๊ฐ ๋ ธ๋์์ ์ํ๊ฐ ์ด๋ป๊ฒ ๋ณํํ๋์ง ์ฝ๊ฒ ์ถ์ ํ ์ ์์ต๋๋ค.

- ์ด๋ฏธ์ง ์ถ์ฒ : https://blog.langchain.dev/langgraph-studio-the-first-agent-ide/
- ๋ญ์คํ๋์ค ๊นํ๋ธ : https://github.com/langchain-ai/langgraph-studio
Studio์์๋ ์ํ๋ฅผ ์ง์ ์ ๋ ฅํ๊ณ ๊ฐ ๋ ธ๋์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ผ๋ฉฐ, ์ด์ ์คํ ๊ธฐ๋ก์ ์ค๋ ๋(Thread)๋ก ๊ด๋ฆฌํ ์ ์์ด ๋๋ฒ๊น ์ด ์์ํฉ๋๋ค.
Studio๋ Docker๋ฅผ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํํ์ฌ ์ฝ๊ฒ ๋ก์ปฌ ํ๊ฒฝ์์ ์คํํ ์ ์์ผ๋ฉฐ, Studio์์ ์์ฑํ ๊ทธ๋ํ๋ Langraph API์ ์ฐ๊ฒฐ๋์ด ํด๋ผ์ฐ๋์์๋ ์คํํ ์ ์์ต๋๋ค.
์ ๋ ๋งฅ๋ถ ์ ์ ๊ฐ ์๋๋ผ ์์ง ์ฌ์ฉ์ด ๋ถ๊ฐํ๊ธฐ ๋๋ฌธ์ LangGraph Studio ๋ถ๋ถ๋ค์ ์ ์ธํ๊ณ ์งํํ๊ฒ ์ต๋๋ค.
Lesson 4: Chain
๐ท chat models & messages
chat models๋ ๋ํ ๋ด์์ ๋ค์ํ ์ญํ ์ ๋ํ๋ด๋ โmessagesโ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- LangChain์ ์ฌ๋ฌ ๋ฉ์์ง ์ ํ(message types)์ ์ง์ํฉ๋๋ค:
- HumanMessage: ์ฌ์ฉ์์ ๋ฉ์์ง
- AIMessage: ์ฑํ ๋ชจ๋ธ์ ์๋ต ๋ฉ์์ง
- SystemMessage: ์ฑํ ๋ชจ๋ธ์ ํ๋์ ์ง์ํ๋ ๋ฉ์์ง
- ToolMessage: ๋๊ตฌ ํธ์ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ด๋ ๋ฉ์์ง
๊ฐ ๋ฉ์์ง๋ ๋ค์ ์์๋ก ๊ตฌ์ฑ๋ ์ ์์ต๋๋ค:
- content: ๋ฉ์์ง ๋ด์ฉ
- name: ๋ฉ์์ง ์์ฑ์ (์ ํ์ฌํญ)
- response_metadata: ๋ฉํ๋ฐ์ดํฐ ๋์ ๋๋ฆฌ (์ ํ์ฌํญ, ์ฃผ๋ก AIMessage์์ ๋ชจ๋ธ ์ ๊ณต์๊ฐ ์ฑ์)
์๋ ์์ ์ฝ๋๋ฅผ ํตํด ๋ค์ํ ๋ฉ์์ง ์ ํ์ผ๋ก ๋ํ ๋ชฉ๋ก์ ๋ง๋ค ์ ์์ต๋๋ค.
1
2
3
4
5
6
7
8
9
10
from pprint import pprint
from langchain_core.messages import AIMessage, HumanMessage
messages = [AIMessage(content=f"So you said you were researching ocean mammals?", name="GPT")]
messages.append(HumanMessage(content=f"Yes, that's right.",name="HUMAN"))
messages.append(AIMessage(content=f"Great, what would you like to learn about.", name="GPT"))
messages.append(HumanMessage(content=f"I want to learn about the best place to see Orcas in the US.", name="HUMAN"))
for m in messages:
m.pretty_print()

์ด๋ฌํ ๋ฉ์์ง์ ์ฑํ ๋ชจ๋ธ์ ํ์ฉํ๋ฉด ๋ํํ AI ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ํจ๊ณผ์ ์ผ๋ก ๊ตฌ์ถํ ์ ์์ต๋๋ค.
- LangChain์์๋ ๋ค์ํ ์ฑํ ๋ชจ๋ธ์ ์ ํํ ์ ์์ผ๋ฉฐ, ์๋ ์์๋ค์ OpenAI ๋ชจ๋ธ์ ์ฌ์ฉํ ์์์ ๋๋ค.
1
2
3
4
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
result = llm.invoke(messages)
type(result)
์๊น ์ ๊ฐ ๋ง์ง๋ง์ผ๋ก ๋งํ๊ฑฐ์ ์ด์ด์ AIMessage๊ฐ ๋ต๋ณํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.

๊ทธ๋ผ โI want to learn about the best place to see Orcas in the USโ, ํด์ํ๋ฉด โ๋ฏธ๊ตญ์์ ๋ฒ๊ณ ๋๋ฅผ ๊ฐ์ฅ ์ ๋ณผ ์ ์๋ ๊ณณ์ ๋ํด ๋ฐฐ์ฐ๊ณ ์ถ์ต๋๋ค.โ๋ผ๊ณ ๋ฌผ์ด๋ดค์๋ AI๋ ๋ญ๋ผ๊ณ ๋ต๋ณํ๋์ง ๋ณผ๊น์?
1
result.content
๋ต๋ณ์ ๊ฐ์ ธ์์ ๋ณด๋ฉด,
1
"Orcas, also known as killer whales, are fascinating creatures, and there are several great places in the United States where you can observe them in their natural habitat. Here are some of the best locations:\n\n1. **San Juan Islands, Washington**: This is one of the most famous spots for orca watching. The waters around the San Juan Islands are home to several pods of resident orcas, particularly during the summer months. You can take boat tours from Friday Harbor or other nearby locations...
์ค! ์ ๋๋ก ๋ต๋ณ์ ์ ์ํํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ result.response_metadata๋ฅผ ์ํํด๋ณด๋ฉด ํด๋น ๋ต๋ณ์ ์์ธ ์ ๋ณด๋ฅผ ์ดํด๋ณผ ์ ์์ต๋๋ค.

๐ท tools
๋๊ตฌ(tools)๋ ๋ชจ๋ธ์ด ์ธ๋ถ ์์คํ ๊ณผ ์ํธ์์ฉํ ๋ ์ ์ฉํฉ๋๋ค. (Tools are useful whenever you want a model to interact with external systems.)

Tool์ ์ฃผ์ ์ญํ
-
ํ์ด๋ก๋ ์์ฑ: LLM์ ์ฌ์ฉ์์ ์์ฐ์ด ์ ๋ ฅ์ ํด์ํ์ฌ ํน์ ๋๊ตฌ(ํจ์)๋ฅผ ์คํํ๋ ๋ฐ ํ์ํ ์ ํํ ์ธ์(ํ์ด๋ก๋)๋ฅผ ์์ฑํฉ๋๋ค.โ ํ์ด๋ก๋๋?
์ปดํจํฐ ๋คํธ์ํฌ์์, ๋ฐ์ดํฐ ํจํท์์ ์ค์ ์ ์กํ๊ณ ์ ํ๋ ๋ฐ์ดํฐ ๋ถ๋ถ์ ์๋ฏธํฉ๋๋ค. ํจ์ ์คํ ์ค๋น: ์์ฑ๋ ํ์ด๋ก๋๋ ๋ฐ์ธ๋ฉ๋ ํจ์์ ๋งค๊ฐ๋ณ์์ ๋ง๋ ํ์์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.์ธํฐํ์ด์ค ์ ๊ณต: Tool์ LLM๊ณผ ์ค์ ์คํ๋ ํจ์ ์ฌ์ด์ ์ธํฐํ์ด์ค ์ญํ ์ ํฉ๋๋ค. LLM์ด ์ดํดํ ์ฌ์ฉ์์ ์๋๋ฅผ ์ค์ ์คํ ๊ฐ๋ฅํ ํํ๋ก ๋ณํํฉ๋๋ค.์ ์ฐ์ฑ ํ๋ณด: ๋ค์ํ ์ธ๋ถ ์์คํ , API, ๋๋ ํจ์๋ค์ LLM์ ์ฝ๊ฒ ์ฐ๊ฒฐํ ์ ์๊ฒ ํด์ค๋๋ค.์ ํ์ฑ ํฅ์: ์ฌ์ฉ์์ ์๋๋ฅผ ์ ํํ๊ฒ ํด์ํ์ฌ ์ ์ ํ ํจ์๋ฅผ ํธ์ถํ๊ณ , ํ์ํ ์ธ์๋ฅผ ์ ํํ ์ ๊ณตํจ์ผ๋ก์จ ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๊ฒ ํฉ๋๋ค.
Tool์ ์๋ ๋ฐฉ์
- ๋ชจ๋ธ์ ์ฌ์ฉ์์ ์์ฐ์ด ์ ๋ ฅ์ ๊ธฐ๋ฐ์ผ๋ก ๋๊ตฌ๋ฅผ ํธ์ถํ ์ง ๊ฒฐ์ ํฉ๋๋ค.
- ๋ชจ๋ธ์ ๋๊ตฌ์ ์คํค๋ง์ ๋ง๋ ์ถ๋ ฅ์ ๋ฐํํฉ๋๋ค.
- ๋๊ตฌ๋ฅผ ์ ์ํ๋ ๊ฒ ์์ฒด๋ ๋ฌด๋ฃ์ง๋ง, ๋๊ตฌ๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ ๋ ์ฐ๊ด๋ ์๋น์ค๋ API ํธ์ถ์ ๋ฐ๋ฅธ ๋น์ฉ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
- ๊ฐ๋ฐ์๋ ์ด๋ฌํ ์ ์ฌ์ ๋น์ฉ์ ๊ณ ๋ คํ์ฌ ๋๊ตฌ๋ฅผ ์ค๊ณํ๊ณ ์ฌ์ฉํด์ผ ํฉ๋๋ค
LangChain์ Tool ํธ์ถ ์ธํฐํ์ด์ค
- ๋ง์ LLM ์ ๊ณต์ ์ฒด๊ฐ ๋๊ตฌ ํธ์ถ์ ์ง์ํ๋ฉฐ, LangChain์์๋ ๊ฐ๋จํ ๋๊ตฌ ํธ์ถ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Python ํจ์๋ฅผ
ChatModel.bind_tools(function)์ ์ ๋ฌํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ชจ๋ธ์ ํด๋น ํจ์๋ฅผ ๋๊ตฌ๋ก ์ธ์ํ๊ณ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
์์ 1
-
LLM(Large Language Model)์ด ๋๊ตฌ(tool)๋ฅผ ์ฌ์ฉํ ๋์ ๊ณผ์ ์ ์ข ๋ ์์ธํ ์ค๋ช ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ฌ์ฉ์๊ฐ ์์ฐ์ด๋ก ์์ฒญ์ ํฉ๋๋ค.
- LLM์ ์ด ์์ฐ์ด ์์ฒญ์ ์ดํดํ๊ณ , ์ด๋ค ๋๊ตฌ๋ฅผ ์ฌ์ฉํด์ผ ํ ์ง ๊ฒฐ์ ํฉ๋๋ค.
- LLM์ ์ ํํ ๋๊ตฌ๋ฅผ ์คํํ๊ธฐ ์ํด ํ์ํ ์ ํํ ์ธ์(arguments)๋ฅผ ์์ฑํฉ๋๋ค. ์ด ์ธ์๋ค์ด ๋ฐ๋ก โํ์ด๋ก๋โ์ ๋๋ค.
- ์ด ํ์ด๋ก๋(์ธ์๋ค)๋ ๋๊ตฌ ํจ์์ ๋งค๊ฐ๋ณ์์ ๋ง๋ ํ์์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
- ์์ฑ๋ ํ์ด๋ก๋๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ตฌ ํจ์๊ฐ ์คํ๋ฉ๋๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
def get_weather(city: str, date: str): # ๋ ์จ ์ ๋ณด๋ฅผ ๋ฐํํ๋ ํจ์ pass # ์ฌ์ฉ์ ์ ๋ ฅ: "๋ด์ผ ์์ธ์ ๋ ์จ๋ ์ด๋?" # LLM์ด ์์ฑํ ํ์ด๋ก๋ payload = { "city": "์์ธ", "date": "2024-10-16" # ๋ด์ผ ๋ ์ง } # ์ด ํ์ด๋ก๋๋ฅผ ์ฌ์ฉํ์ฌ get_weather ํจ์ ํธ์ถ result = get_weather(**payload)์์ ๊ฐ์ ๊ณผ์ ์ ํตํด LLM์ ์์ฐ์ด ๋ช ๋ น์ ๊ตฌ์กฐํ๋ ํจ์ ํธ์ถ๋ก ๋ณํํ ์ ์๊ฒ ๋ฉ๋๋ค. ์ด๋ LLM์ด ๋ค์ํ ์ธ๋ถ ์์คํ ์ด๋ API์ ํจ๊ณผ์ ์ผ๋ก ์ํธ์์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค.
์์ 2
-
ํ์ด์ฌ multiplyํจ์ args๋ฅผ ๋ง์ถฐ์ฃผ๋ llm์ binding์ง์ ์์ผ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
1 2 3 4 5 6 7 8 9 10 11 12
def multiply(a: int, b: int) -> int: """Multiply a and b. Args: a: first int b: second int """ return a * b llm_with_tools = gpt4o_chat.bind_tools([multiply]) llm_with_tools.bind_tools([multiply]) llm_with_tools.kwargs - ์ผ๋จ ์ ํจ์๋ก binding์ ์์ผฐ๊ณ ์.

- ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด โWhat is 2 multiplied by 3โ, โ2 ๊ณฑํ๊ธฐ 3์ ๋ฌด์์ธ๊ฐ์?โ๋ผ๊ณ ๋ฌป๋ ์์ฐ์ด๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ์์์ argument๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.

- GPT-4o๋ผ์ ๊ทธ๋ฐ์ง ํ๊ธ๋ก ํด๋ ์ ์๋ํ๋ ๊ตฐ์!

- ์ฐธ๊ณ ๋ก ์ฌ๊ธฐ์ ๋์จ ๋ต๋ณ์ ์ข ๋ ์์ธํ๊ฒ ์ดํด๋ณด๋ฉด, AiMessage์์ Contents๊ฐ ๊ณต๋์ธ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
-
LangChain์์ Tool์ ๋ต๋ณ(invoke ๊ฒฐ๊ณผ)์ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์ฒ๋ฆฌ๋ฉ๋๋ค:
- Tool์ ์คํ ๊ฒฐ๊ณผ๋ ๊ธฐ๋ณธ์ ์ผ๋ก AIMessage์ content ํ๋์ ๋ค์ด๊ฐ๋๋ค.
- ๊ทธ๋ฌ๋ Tool์ ์คํ ๊ฒฐ๊ณผ์ ์ถ๊ฐ์ ์ธ ๋ฉํ๋ฐ์ดํฐ๋ ๊ตฌ์กฐํ๋ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์๋ค๋ฉด, ์ด๋ additional_kwargs ๋์ ๋๋ฆฌ์ ์ ์ฅ๋ฉ๋๋ค.
- ํนํ OpenAI์ ํจ์ ํธ์ถ(function calling) ๊ธฐ๋ฅ์ ์ฌ์ฉํ ๋, Tool์ ๊ฒฐ๊ณผ๋ ์ฃผ๋ก additional_kwargs ๋ด์ function_call ํค์ ์ ์ฅ๋ฉ๋๋ค.
- ๋ง์ฝ์ ๋ด๊ฐ tool์ด๋ ์ ํ ์๊ด์๋ ์๋ฆฌ๋ฅผ ํ๋ฉด LLM์ด tool์ ํธ์ถํ์ง ์๊ณ ์ ์์ ์ผ๋ก content๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.

๊ทธ๋ผ ์ด์ ๊ธฐ์ต์ผ๋ก ๋ค์ ์ด์ ์ฑํฐ โLesson 2: Simple Graphโ๋ก ๊ธฐ์ต์ ๋์ง์ด์ ๊ฐ๋ด ์๋ค!
- ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ๊ทธ๋ํ์
State๋ฅผ PythonTypeDict์ฌ์ฉํ ํ์ ํํ ๊ฐ์ฒด๋ก ์ ์ํ์๋๋ฐ์.
- ์ด๋ ์ฝ๋ ์์ฑ ์
IDE๋ ํ์ ์ฒด์ปค์๊ฒ ํํธ๋ฅผ ์ ๊ณตํ์ง๋ง,์ค์ ํ์ด์ฌ ๋ฐํ์์๋ ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค.
- ์ด๋ ์ฝ๋ ์์ฑ ์
- ๊ทธ๋ฆฌ๊ณ ์ค์ ๋ก
builder = StateGraph(State)์์State๋ ํ์ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๊ทธ๋ํ๊ฐ ์ด๋ค ํํ์ ์ํ๋ฅผ ๋ค๋ฃฐ์ง ๋ช ์ํ๋ ์ญํ ์ ํฉ๋๋ค.
- ์คํ ์, ๊ฐ๊ฐ์ ๋ ธ๋ ํจ์(์๋ก, node_1 ํจ์)๋ ๋์ ๋๋ฆฌ ํํ์ ๊ฐ์ฒด๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํฉ๋๋ค. ์ด ๊ฐ์ฒด๊ฐ State ํ์ ๊ณผ ์ผ์นํ๋์ง๋ ๋ฐํ์์ ํ์ธ๋์ง ์์ต๋๋ค.
์! ๊ทธ๋ฌ๋ฉด ๋ง์ฐฌ๊ฐ์ง๋ก LLM์์์ ๋ฉ์ธ์ง๋ฅผ State๋ก ํ์ฉํ ์ ์์ต๋๋ค.
1
2
3
4
5
from typing_extensions import TypedDict
from langchain_core.messages import AnyMessage
class MessagesState(TypedDict):
messages: list[AnyMessage]
-
MessagesState: ๋ฉ์ธ์ง๋ค ์ญ์ ๋ํ ์ํ๋ฅผ ๋ํ๋ด๋ MessagesState(TypedDict ํํ)๋ก ๋ํ๋ด๋ณผ ์ ์๊ฒ ์ฃ ? messages ํค ํ๋๋ง ๊ฐ์ง๋ฉฐ, ์ด๋๋ฉ์์ง ๊ฐ์ฒด(HumanMessage, AIMessage ๋ฑ)์ ๋ฆฌ์คํธ์ ๋๋ค.- ์ผ๋ฐ์ ์ธ
TypedDict์ ๊ด๋ จ๋ ๋ฌธ์ ๋ถํฐ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์๋ฅผ ๋ค์ด,TypedDict๋ก ์ํ๋ฅผ ์ ์ํ๋ฉด ๊ฐ ๋ ธ๋๊ฐ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ๋ ๋ฎ์ด์ฐ๊ธฐ(override)๊ฐ ๊ธฐ๋ณธ ๋์์ผ๋ก ์ํ๋ฉ๋๋ค.- ์ด๋ ์ํ์ ์ด์ ๊ฐ์ด ์์ ํ ๋์ฒด๋๊ธฐ ๋๋ฌธ์, ์ ๊ฐ์ผ๋ก ๋ฎ์ด์์์ ธ ์ด์ ๋ฉ์์ง๋ค์ด ์ฌ๋ผ์ง๊ฒ ๋๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํต๋๋ค.
- ์ผ๋ฐ์ ์ธ
-
์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ผ๋ฐ์ ์ผ๋ก ์ด์ ๋ฉ์์ง๋ค์ ์ ์งํ๋ฉด์ ์ ๋ฉ์์ง๋ฅผ ์ถ๊ฐํ๊ณ ์ ํฉ๋๋ค.
- ํ์ง๋ง ์ด ์ฝ๋์์๋ ๊ฐ ๋ ธ๋๊ฐ ์คํ๋ ๋๋ง๋ค ์ ์ฒด ๋ฉ์์ง ๋ฆฌ์คํธ๊ฐ ๋ฎ์ด์์์ง๋๋ค.
-
์ด๋ฌํ ๋ฌธ์ ๋๋ฌธ์, ๋จ์ํ TypedDict ์ ์๋ง์ผ๋ก๋ ํจ๊ณผ์ ์ธ ๋ฉ์์ง ์ํ ๊ด๋ฆฌ๊ฐ ์ด๋ ต์ต๋๋ค. TypedDict๋ฅผ ๋จ์ํ ์ฌ์ฉํ๋ฉด, ๊ฐ ๋ ธ๋์์ ๋ฐํ๋ ์๋ก์ด ๊ฐ์ด ์ด์ ์ํ๋ฅผ ๋ฎ์ด์์ฐ๊ฒ ๋ฉ๋๋ค.
- ๋ฌผ๋ก ์ด์ ์ฒ๋ผ
+๋appendํจ์๋ฅผ ์ฌ์ฉํด์ ๋ฌธ์์ด์ ์ ๋ณด๋ฅผ ๋์ ํด์ค ์ ์์ง๋ง, LangGraph์์๋ ๋ณ๋๋ก ๋ฆฌ๋์ ํจ์๋ผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. - LangGraph์์๋ ๋ฆฌ๋์ ํจ์(์:
add_messages)๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ๋ฎ์ด์ฐ๋ ๋์ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ธฐ์กด ์ํ์ ์ถ๊ฐํ ์ ์๋๋ก ๋ง๋ญ๋๋ค. MessagesState๋ ๋ฏธ๋ฆฌ ์ ์๋ ์ํ ๊ตฌ์กฐ์add_messages๋ฆฌ๋์๋ฅผ ํฌํจํ๊ณ ์๊ธฐ ๋๋ฌธ์, ๋ฉ์์ง ์ํ ๊ด๋ฆฌ์ ์ต์ ํ๋์ด ์์ต๋๋ค.
- ๋ฌผ๋ก ์ด์ ์ฒ๋ผ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from langgraph.graph import MessagesState
class MessagesState(MessagesState):
# Add any keys needed beyond messages, which is pre-built
pass
# Initial state
initial_messages = [AIMessage(content="Hello! How can I assist you?", name="Model"),
HumanMessage(content="I'm looking for information on marine biology.", name="HUMAN")
]
# New message to add
new_message = AIMessage(content="Sure, I can help with that. What specifically are you interested in?", name="Model")
# Test
add_messages(initial_messages , new_message)

๊ทธ๋ผ ์ด์ ๊ทธ๋ํ๋ก ํ๋ฒ ์๊ฐํํด๋ณด๊ฒ ์ต๋๋ค. ํด๋น ๊ทธ๋ํ๋ ๋จ์ํ๊ฒ ์์์ ์ ์ํด๋ tool_calling_llm์ ํธ์ถํ๊ณ ์ด๋ฅผ ์๊ฐํํ ์ฝ๋์
๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from IPython.display import Image, display
from langgraph.graph import StateGraph, START, END
# Node
def tool_calling_llm(state: MessagesState):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
# Build graph
builder = StateGraph(MessagesState)
builder.add_node("tool_calling_llm", tool_calling_llm)
builder.add_edge(START, "tool_calling_llm")
builder.add_edge("tool_calling_llm", END)
graph = builder.compile()
# View
display(Image(graph.get_graph().draw_mermaid_png()))

๋ง๋ ๊ทธ๋ํ๊ฐ ์ ๋๋ก ์๋ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.

์๋์ฒ๋ผ ์ฝ๋๋ฅผ ์กฐ๊ธ ๋ณ๊ฒฝํ๋ฉด ์ด์ด์ ๋ํ๋ฅผ ์ํํด๋ณผ ์ ์์ต๋๋ค.
1
2
3
4
5
6
7
8
9
# Node
def tool_calling_llm(state: MessagesState):
# LLM ํธ์ถ์ ํตํด ์๋ก์ด ๋ฉ์์ง๋ฅผ ์ป์
new_message = llm_with_tools.invoke(state["messages"])
# ๊ธฐ์กด messages์ ์ ๋ฉ์์ง๋ฅผ ์ถ๊ฐ
updated_messages = add_messages(state["messages"], new_message)
return {"messages": updated_messages}

Lesson 5: Router
Router๋ LLM์ด ์์ฐ์ด ์๋ต ๋๋ ๋๊ตฌ ํธ์ถ ์ค ํ๋๋ฅผ ์ ํํ๋ ๊ตฌ์กฐ์
๋๋ค.
- ์ฌ์ฉ์์ ์ ๋ ฅ์ ๋ฐ์, LLM์ด ์ง์ ์๋ตํ ์ง ๋๊ตฌ๋ฅผ ํธ์ถํ ์ง ๊ฒฐ์ ํ๋ ๊ธฐ๋ณธ์ ์ธ ์์ด์ ํธ ๊ตฌ์กฐ๋ฅผ ๋ง๋ญ๋๋ค.

Router์ ํต์ฌ:
- LLM์ ์ ๋ ฅ์ ๋ฐ๋ผ ๋ ๊ฐ์ง ๊ฒฝ๋ก ์ค ํ๋๋ฅผ ์ ํํฉ๋๋ค.
- ๋๊ตฌ ํธ์ถ์ด ํ์ํ๋ฉด ๋๊ตฌ ๋ ธ๋๋ก ์ด๋ํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ต์ ๋ฐ๋ก ๋ฐํํฉ๋๋ค.
- Conditional Edge๋ฅผ ์ฌ์ฉํด LLM์ ์ถ๋ ฅ์ ๋ฐ๋ผ ๋๊ตฌ ํธ์ถ ๊ฒฝ๋ก๋ฅผ ์ ํํ๊ฑฐ๋ ์ข ๋ฃํฉ๋๋ค.
-
langgraph.prebuilt์ToolNode์tools_condition์ LangGraph์์ ์ ๊ณตํ๋ ์ ์ฉํ ๊ธฐ๋ฅ์ ๋๋ค. ๊ฐ๊ฐ์ ์ญํ ๊ณผ ๊ธฐ๋ฅ์ ์ค๋ช ํด๋๋ฆฌ๊ฒ ์ต๋๋ค:-
ToolNode:
- ๋ชฉ์ : ์ฌ๋ฌ ๋๊ตฌ(tools)๋ฅผ ํ๋์ ๋ ธ๋๋ก ๋ฌถ์ด ์คํํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ์ฌ์ฉ ๋ฐฉ๋ฒ:
ToolNode([tool1, tool2, ...])ํํ๋ก ์ด๊ธฐํํฉ๋๋ค. - ๊ธฐ๋ฅ:
- ์ฃผ์ด์ง ๋๊ตฌ ๋ชฉ๋ก์ ๋ฐ์ ์คํํ ์ ์๋ ๋ ธ๋๋ฅผ ์์ฑํฉ๋๋ค.
- ์ํ์์ ๋๊ตฌ ํธ์ถ ์ ๋ณด๋ฅผ ์ฝ๊ณ , ํด๋น ๋๊ตฌ๋ฅผ ์คํํฉ๋๋ค.
- ๋๊ตฌ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์ํ์ ์ถ๊ฐํฉ๋๋ค.
- ์ฅ์ :
- ์ฌ๋ฌ ๋๊ตฌ๋ฅผ ์ฝ๊ฒ ํตํฉํ ์ ์์ต๋๋ค.
- ๋๊ตฌ ์คํ ๋ก์ง์ ์๋์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
-
tools_condition:
- ๋ชฉ์ : LLM์ ์ถ๋ ฅ์ด ๋๊ตฌ ํธ์ถ์ธ์ง ์๋์ง๋ฅผ ํ๋จํ๋ ์กฐ๊ฑด๋ถ ๋ผ์ฐํ ํจ์์ ๋๋ค.
- ์ฌ์ฉ ๋ฐฉ๋ฒ:
add_conditional_edges()๋ฉ์๋์ ์กฐ๊ฑด ํจ์๋ก ์ฌ์ฉ๋ฉ๋๋ค. - ๊ธฐ๋ฅ:
- LLM์ ์ต์ ๋ฉ์์ง๋ฅผ ๊ฒ์ฌํ์ฌ ๋๊ตฌ ํธ์ถ ์ฌ๋ถ๋ฅผ ํ๋จํฉ๋๋ค.
- ๋๊ตฌ ํธ์ถ์ด๋ฉด โtoolsโ ๋ ธ๋๋ก ๋ผ์ฐํ ํฉ๋๋ค.
- ๋๊ตฌ ํธ์ถ์ด ์๋๋ฉด END ๋ ธ๋๋ก ๋ผ์ฐํ ํฉ๋๋ค.
- ์ฅ์ :
- ๋๊ตฌ ํธ์ถ ์ฌ๋ถ์ ๋ฐ๋ฅธ ์๋ ๋ผ์ฐํ ์ ์ ๊ณตํฉ๋๋ค.
- ๋ณต์กํ ์กฐ๊ฑด ๋ก์ง์ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
-
(์ฐธ๊ณ ) tools_conditionํจ์ snippet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17from typing import (Any,Literal,Union) from langchain_core.messages import AnyMessage # Route the graph def tools_condition( state: Union[list[AnyMessage], dict[str, Any], BaseModel], ) -> Literal["tools", "__end__"]: if isinstance(state, list): ai_message = state[-1] elif isinstance(state, dict) and (messages := state.get("messages", [])): ai_message = messages[-1] elif messages := getattr(state, "messages", []): ai_message = messages[-1] else: raise ValueError(f"No messages found in input state to tool_edge: {state}") if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0: return "tools" return "__end__"
์์ ์ฝ๋
- ์์ ์ฝ๋๋ฅผ ํ๋ฒ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
- ์ฌ์ฉ์ ์
๋ ฅ์ด ๋ค์ด์ค๋ฉด
tool_calling_llm๋ ธ๋๊ฐ ์คํ๋ฉ๋๋ค.- ์ฒซ ๋ฒ์งธ ์ธ์ โtool_calling_llmโ์ ์ถ๋ฐ ๋ ธ๋๋ฅผ ์ง์ ํฉ๋๋ค.
- LLM์ด ์๋ต์ ์์ฑํฉ๋๋ค.
tools_conditionํจ์๊ฐ LLM์ ์๋ต์ ๋ถ์ํฉ๋๋ค.- ๋ ๋ฒ์งธ ์ธ์
tools_condition์ ๋ผ์ฐํ ํจ์์ ๋๋ค. - ๋๊ตฌ ํธ์ถ์ด๋ฉด tools ๋ ธ๋๋ก ์ด๋(tools ๋ ธ๋๋ก ๋ผ์ฐํ )ํ์ฌ ๋๊ตฌ๋ฅผ ์คํํ ํ ์ข ๋ฃํฉ๋๋ค.
- ์ผ๋ฐ ์๋ต์ด๋ฉด ๋ฐ๋ก ์ข ๋ฃ๋ฉ๋๋ค. (END ๋ ธ๋๋ก ๋ผ์ฐํ )
- ๋ ๋ฒ์งธ ์ธ์
- ์ฌ์ฉ์ ์
๋ ฅ์ด ๋ค์ด์ค๋ฉด
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
from IPython.display import Image, display
from langgraph.graph import StateGraph, START, END
from langgraph.graph import MessagesState
from langgraph.prebuilt import ToolNode
from langgraph.prebuilt import tools_condition
# Node
def tool_calling_llm(state: MessagesState):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
# Build graph
builder = StateGraph(MessagesState)
# Define Nodes
builder.add_node("tool_calling_llm", tool_calling_llm)
builder.add_node("tools", ToolNode([multiply]))
# Define Edges
builder.add_edge(START, "tool_calling_llm")
builder.add_conditional_edges(
"tool_calling_llm",
# If the latest message (result) from assistant is a tool call -> tools_condition routes to tools
# If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END
tools_condition,
)
builder.add_edge("tools", END)
graph = builder.compile()
# View
display(Image(graph.get_graph().draw_mermaid_png()))

๐ค
tools_condition์ด tools ๋ ธ๋๋ก ์ฐ๊ฒฐ๋๋ ๋ก์ง์ tools_condition ํจ์ ๋ด๋ถ์ ๊ตฌํ๋์ด ์์ผ๋ฉฐ, add_conditional_edges ๋ฉ์๋๋ฅผ ํตํด ๊ทธ๋ํ์ ์ ์ฉ๋ฉ๋๋ค.

Lesson 6: Agent
์ด์ ์ ๊ตฌํํ ๋ผ์ฐํฐ๋ ์ฌ์ฉ์ ์
๋ ฅ์ ๋ฐ๋ผ ๋๊ตฌ ํธ์ถ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ์ต๋๋ค. ์กฐ๊ฑด๋ถ ์ฃ์ง(add_conditional_edges)๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ตฌ ํธ์ถ ๋
ธ๋๋ ์ข
๋ฃ๋ก ๋ผ์ฐํ
ํ์ต๋๋ค.
์ด๋ฒ ์ฑํฐ์์๋ Router๋ฅผ ํ์ฅํ์ฌ ์์ด์ ํธ(Agent)๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์์ด์ ํธ๋ Router์ ๋น์ทํ์ง๋ง, ๋๊ตฌ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ LLM์๊ฒ ์ ๋ฌํ๊ณ , LLM์ด ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ์ผ๋ก ์ถ๊ฐ์ ์ธ ๊ฒฐ์ ์ ๋ด๋ฆฌ๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค.

-
์ด๋ฅผ React ์์ด์ ํธ(๋ฐ์ํ ์์ด์ ํธ)๋ผ๊ณ ํ๋ฉฐ,
์ธ ๊ฐ์ง ๋จ๊ณ๋ก ๋๋ฉ๋๋ค.- Act: LLM์ด ๋๊ตฌ๋ฅผ ํธ์ถํ๋ ๋จ๊ณ.
- Observe: ๋๊ตฌ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ LLM์๊ฒ ์ ๋ฌํ๋ ๋จ๊ณ.
- Reason: LLM์ด ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ์ผ๋ก ์ถ๊ฐ์ ์ธ ๊ฒฐ์ ์ ๋ด๋ฆฌ๋ ๋จ๊ณ.
-
์ด ๋ฐฉ์์ ์ฌ๋ฌ ๋ฒ์ ๋๊ตฌ ํธ์ถ์ ํ์๋ก ํ๋ ๋ณต์กํ ์์ ์ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ, LLM์ด ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ถ๊ฐ ์์ ์ ์ํํ ์ ์๋ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.
์ฝ๋ ์์
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 langgraph.graph import START, StateGraph
from langgraph.prebuilt import tools_condition
from langgraph.prebuilt import ToolNode
from IPython.display import Image, display
# Graph
builder = StateGraph(MessagesState)
# Define nodes: these do the work
builder.add_node("assistant", assistant)
builder.add_node("tools", ToolNode(tools))
# Define edges: these determine how the control flow moves
builder.add_edge(START, "assistant")
builder.add_conditional_edges(
"assistant",
# If the latest message (result) from assistant is a tool call -> tools_condition routes to tools
# If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END
tools_condition,
)
builder.add_edge("tools", "assistant")
react_graph = builder.compile()
# Show
display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))

- Assistant ๋ ธ๋๊ฐ ์คํ๋ ํ, tools_condition์ด ๋๊ตฌ ํธ์ถ ์ฌ๋ถ๋ฅผ ํ์ธํฉ๋๋ค.
- ๋๊ตฌ ํธ์ถ์ด๋ฉด Tools ๋ ธ๋๋ก ์ด๋ํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ Assistant์ ์ ๋ฌํฉ๋๋ค.
- ์ด ๋ฃจํ๋ ๋ชจ๋ธ์ด ๋๊ตฌ ํธ์ถ์ ์ค๋จํ ๋๊น์ง ๊ณ์๋ฉ๋๋ค.
- ๋ชจ๋ธ์ด ์ง์ ์๋ตํ๋ฉด ๊ทธ๋ํ๊ฐ ์ข ๋ฃ๋ฉ๋๋ค.
์๋๋ ํด๋น ์ฝ๋๋ฅผ ์คํํ ๊ฒฐ๊ณผ์ ๋๋ค:
1
2
3
4
5
messages = [HumanMessage(content="3๊ณผ 4๋ฅผ ๋ํฉ๋๋ค. ์ถ๋ ฅ์ 2๋ฅผ ๊ณฑํฉ๋๋ค. ์ถ๋ ฅ์ 5๋ก ๋๋๋๋ค")]
messages = react_graph.invoke({"messages": messages})
for m in messages['messages']:
m.pretty_print()
- ๊ทธ๋ํ๋ START ๋ ธ๋์์ ์์ํ์ฌ ์ ์๋ ๋ ธ๋๋ค์ ์์ฐจ์ ์ผ๋ก ๋๋ ์กฐ๊ฑด์ ๋ฐ๋ผ ์คํํฉ๋๋ค.
- ์๋ ๊ทธ๋ฆผ์ ๋ณด๋ฉด Assistant ๋ ธ๋๊ฐ ์คํ๋ ํ, tools_condition๊ฐ ๋๊ตฌ๋ฅผ ์ฌ๋ฌ๋ฒ ํธ์ถํ๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.

์๋๋ LangSmith ๊ฒฐ๊ณผ์ธ๋ฐ ์ด๋ฅผ ๋ณด๋ฉด ์ค์ ๋ก๋ Assitant๊ฐ Tool์ ํธ์ถํด์ ์คํํ๊ณ ์๋ ๊ฒ์ ์ง์ ํ์ธํด๋ณผ ์๋ ์์ต๋๋ค.

Lesson 7: Agent with Memory
์์ Lesson6์ ์ด์ด์ ์ดํด๋ณด๋ฉด ์ด๋ ๊ฒ ๊ฐ๊ฐ ์๋ก ๋ค๋ฅธ ์ฃผํผํฐ Cell์์ ์คํ์ ํ๊ฒ๋๋ฉด ๋ค๋ฅธ Cell์์ ์๊ธฐํ๋ ๋ด์ฉ์ ๊ธฐ์ตํ์ง ๋ชปํ๊ณ ์๋กญ๊ฒ ๋ํ๋ฅผ ์ด์ด๋๊ฐ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.

์ด๋ ๋ฐ๋ก ๊ธฐ์ต(๋ฉ๋ชจ๋ฆฌ)๋ฅผ ํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ธ๋ฐ์.
- ์์ด์ ํธ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ฉด ์ํ๋ฅผ ์ ์งํ๊ณ , ์ด์ ์ ์ฒ๋ฆฌํ ์ ๋ณด๋ฅผ ๊ธฐ์ตํ์ฌ ๋ ๋ณต์กํ ์ํธ์์ฉ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- Langraph๋ ์ฒดํฌํฌ์ธํฐ(Checkpointer)๋ฅผ ์ฌ์ฉํด ๊ทธ๋ํ์ ์ํ๋ฅผ ๊ฐ ๋จ๊ณ๋ง๋ค ์ ์ฅํ๊ณ , ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ดํ์ ์ํ๋ฅผ ๋ณต์ํ์ฌ ์์ ์ ์ด์ด๋๊ฐ ์ ์์ต๋๋ค.

์ฃผ์ ์ฉ์ด ์ ๋ฆฌ:
MemorySaver:- LangGraph์์ ์ ๊ณตํ๋ ์ธ๋ฉ๋ชจ๋ฆฌ ์ฒดํฌํฌ์ธํฐ ๊ตฌํ์ ๋๋ค.
- ๊ทธ๋ํ์ ์ํ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๊ณ ๊ด๋ฆฌํฉ๋๋ค.
- ๊ฐ๋จํ๊ณ ๋น ๋ฅธ ์ํ ๊ด๋ฆฌ๋ฅผ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
Checkpointer (์ฒดํฌํฌ์ธํฐ):- ๊ทธ๋ํ ์คํ ์ค ๊ฐ ๋จ๊ณ์์ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฉ์ปค๋์ฆ์ ๋๋ค.
- ์ฌ๋ฌ ์ค๋ ๋์ ์ํ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
Thread (์ค๋ ๋):- ๊ทธ๋ํ ์คํ์ ๋ ๋ฆฝ์ ์ธ ์ธ์คํด์ค๋ฅผ ๋ํ๋ ๋๋ค.
- ๊ฐ ์ค๋ ๋๋ ๋ณ๋์ ๋ํ ์ธ์ ์ด๋ ์์ ํ๋ฆ์ ์๋ฏธํฉ๋๋ค.
Thread ID (์ค๋ ๋ ID):- ๊ฐ ์ค๋ ๋๋ฅผ ๊ณ ์ ํ๊ฒ ์๋ณํ๋ ์๋ณ์์ ๋๋ค.
- ์ฌ์ฉ์๊ฐ ์ ์ํ๋ฉฐ, ๋ณดํต ์ฌ์ฉ์ ID๋ ์ธ์ ID ๋ฑ์ ์ฌ์ฉํฉ๋๋ค.
์ด ๋ฐฉ์์ LLM์ด ํ ๋ฒ์ ์ฌ๋ฌ ์์ ์ ์ฒ๋ฆฌํ๋ ์ํฉ์์ ๋งค์ฐ ์ ์ฉํ๋ฉฐ, ์ํ ๊ฐ์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
์ค๋ ๋ ID์ ์ฒดํฌํฌ์ธํธ์ ์ฐ๊ด์ฑ:
- ๊ฐ ์ค๋ ๋๋ ๊ณ ์ ํ ID๋ฅผ ๊ฐ์ง๋๋ค.
- ์ฒดํฌํฌ์ธํฐ๋ ์ด ์ค๋ ๋ ID๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ค๋ ๋์ ์ํ๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ์ ์ฅํ๊ณ ๊ด๋ฆฌํฉ๋๋ค.
- ์ค๋ ๋ ID๋ฅผ ํตํด ํน์ ๋ํ๋ ์์ ์ ์ํ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph
memory = MemorySaver()
graph = StateGraph(...).compile(checkpointer=memory)
# ์ค๋ ๋ 1์ ์ํ ์ ์ฅ
result1 = graph.invoke(input_data, config={"configurable": {"thread_id": "user1"}})
# ์ค๋ ๋ 2์ ์ํ ์ ์ฅ
result2 = graph.invoke(input_data, config={"configurable": {"thread_id": "user2"}})
# ์ค๋ ๋ 1์ ์ํ ๋ถ๋ฌ์ค๊ธฐ
state1 = graph.get_state({"configurable": {"thread_id": "user1"}})
- ์ด๋ ๊ฒ
thread_id๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ๋ํ๋ ์์ ์ ์ํ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค. checkpointer๋ ์ดthread_id๋ฅผ ํค๋ก ์ฌ์ฉํ์ฌ ๊ฐ ์ค๋ ๋์ ์ํ๋ฅผ ์ ์ฅํ๊ณ ๊ฒ์ํ ์ ์์ต๋๋ค.
์ฝ๋ ์์
- config์ thread_id ์ ์ ํ message invoke
- ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋๋ thread_id๋ฅผ ์ง์ ํด์ผ ํฉ๋๋ค.
-
์ด thread_id๋ ๊ทธ๋ํ ์ํ์ ์ปฌ๋ ์ ์ ์ ์ฅํฉ๋๋ค.
1 2 3 4 5 6 7 8 9 10
# Specify a thread config = {"configurable": {"thread_id": "1"}} # Specify an input messages = [HumanMessage(content="Add 3 and 4.")] # Run messages = react_graph_memory.invoke({"messages": messages}, config) for m in messages['messages']: m.pretty_print()
- checkpointer๋ ๊ทธ๋ํ์ ๋ชจ๋ ๋จ๊ณ์์ ์ํ๋ฅผ ๊ธฐ๋กํฉ๋๋ค.
- ์ด ์ฒดํฌํฌ์ธํธ๋ค์ ์ค๋ ๋์ ์ ์ฅ๋ฉ๋๋ค.
- ๋์ค์ thread_id๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ์ค๋ ๋์ ์ ๊ทผํ ์ ์์ต๋๋ค.
-
ํด๋น
config๋ฅผ ๋ฌผ๊ณ ๋ค์ invoke๋ฅผ ์ํํ๋ฉด memory๊ฐ ์ ์ง๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.1 2 3 4
messages = [HumanMessage(content="Multiply that by 2.")] messages = react_graph_memory.invoke({"messages": messages}, config) for m in messages['messages']: m.pretty_print()
Lesson 8: Deployment
Langraph๋ก ๋ง๋ ์์ด์ ํธ๋ Langraph Cloud๋ฅผ ํตํด ์ฝ๊ฒ ๋ฐฐํฌํ ์ ์์ต๋๋ค. GitHub ์ ์ฅ์์ ์ฐ๊ฒฐํ๋ฉด ์๋์ผ๋ก ๋ฐฐํฌํ ์ ์์ผ๋ฉฐ, ๋ฐฐํฌ๋ ์์ด์ ํธ๋ API๋ฅผ ํตํด ์ ๊ทผํ ์ ์์ต๋๋ค. ์ ๋ ์ ๋ฃ ์ฌ์ฉ์๊ฐ ์๋๋ผ์ ๋ณ๋์ ์ค์ต์ ์ํํ์ง ์์์ต๋๋ค.
-
LangGraph:- Python๊ณผ JavaScript ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ์์ด์ ํธ ์ํฌํ๋ก์ฐ ์์ฑ ๊ฐ๋ฅ
-
LangGraph API:- ๊ทธ๋ํ ์ฝ๋๋ฅผ ๋ฒ๋ค๋ก ์ ๊ณต
- ๋น๋๊ธฐ ์์ ๊ด๋ฆฌ๋ฅผ ์ํ ํ์คํฌ ํ ์ ๊ณต
- ์ํธ์์ฉ ๊ฐ ์ํ ์ ์ง๋ฅผ ์ํ ์ง์์ฑ ์ ๊ณต
-
LangGraph Cloud:- LangGraph API์ ํธ์คํ ์๋น์ค
- GitHub ์ ์ฅ์์์ ๊ทธ๋ํ ๋ฐฐํฌ ๊ฐ๋ฅ
- ๋ฐฐํฌ๋ ๊ทธ๋ํ์ ๋ํ ๋ชจ๋ํฐ๋ง ๋ฐ ์ถ์ ์ ๊ณต
- ๊ฐ ๋ฐฐํฌ์ ๋ํด ๊ณ ์ URL ์ ๊ณต
-
LangGraph Studio:- LangGraph ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ํตํฉ ๊ฐ๋ฐ ํ๊ฒฝ(IDE)
- API๋ฅผ ๋ฐฑ์๋๋ก ์ฌ์ฉํ์ฌ ์ค์๊ฐ ํ ์คํธ ๋ฐ ๊ทธ๋ํ ํ์ ๊ฐ๋ฅ
- ๋ก์ปฌ ๋๋ ํด๋ผ์ฐ๋ ๋ฐฐํฌ๋ก ์คํ ๊ฐ๋ฅ
-
LangGraph SDK:- LangGraph ๊ทธ๋ํ์ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ์ํธ์์ฉํ๊ธฐ ์ํ Python ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ๋ก์ปฌ ๋๋ ํด๋ผ์ฐ๋์์ ์ ๊ณต๋๋ ๊ทธ๋ํ ์์ ์ ์ํ ์ผ๊ด๋ ์ธํฐํ์ด์ค ์ ๊ณต
- ํด๋ผ์ด์ธํธ ์์ฑ, ์ด์์คํดํธ ์ ๊ทผ, ์ค๋ ๋ ๊ด๋ฆฌ, ์คํ ๋ฑ ๊ฐ๋ฅ
-
๋ก์ปฌ ํ ์คํ:- LangGraph Studio์์ ๋ก์ปฌ๋ก ์ ๊ณต๋๋ ๊ทธ๋ํ์ ์ฝ๊ฒ ์ฐ๊ฒฐ ๊ฐ๋ฅ
- Studio UI์ ์ผ์ชฝ ํ๋จ์ ์ ๊ณต๋๋ URL์ ํตํด ์ฐ๊ฒฐ
์ด ๊ตฌ์กฐ๋ฅผ ํตํด LangGraph๋ ์์ด์ ํธ ์ํฌํ๋ก์ฐ์ ๊ฐ๋ฐ, ํ ์คํธ, ๋ฐฐํฌ, ๊ด๋ฆฌ๋ฅผ ์ํ ์ข ํฉ์ ์ธ ํ๊ฒฝ์ ์ ๊ณตํฉ๋๋ค. ๊ฐ๋ฐ์๋ ๋ก์ปฌ์์ ๊ทธ๋ํ๋ฅผ ๋ง๋ค๊ณ ํ ์คํธํ ํ, ํด๋ผ์ฐ๋์ ์ฝ๊ฒ ๋ฐฐํฌํ๊ณ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
๋ค์ Module์ 2๋ฒ์งธ ๋ชจ๋ State and Memory ๊ด๋ จ ๋ด์ฉ์ ๋๋ค.
๋ค์ ๊ธ์์ ๋ต๊ฒ ์ต๋๋ค ๐ค