[๊ฐ•์˜๋…ธํŠธ] LangChain Academy : Introduction to LangGraph (Module 1)

Posted by Euisuk's Dev Log on October 10, 2024

[๊ฐ•์˜๋…ธํŠธ] LangChain Academy : Introduction to LangGraph (Module 1)

๋žญ์ฒด์ธ(LangChain)๊ณผ ๋žญ๊ทธ๋ž˜ํ”„(LangGraph)๋Š” ๋Œ€๊ทœ๋ชจ ์–ธ์–ด ๋ชจ๋ธ(LLM)์„ ํ™œ์šฉํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ๋„๊ตฌ๋“ค์ž…๋‹ˆ๋‹ค. ์œ„ ๊ฐ•์˜๋Š” LangChain์—์„œ ์šด์˜ํ•˜๋Š” LangChain Academy์—์„œ ์ œ์ž‘ํ•œ โ€œIntroduction to LangGraphโ€ ๊ฐ•์˜์˜ ๋‚ด์šฉ์„ ์ •๋ฆฌ ๋ฐ ์ถ”๊ฐ€ ์„ค๋ช…ํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŠธ๋Š” โ€œ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
  1. Introduction

๋žญ์ฒด์ธ(LangChain)

๋žญ์ฒด์ธ์€ ๋Œ€๊ทœ๋ชจ ์–ธ์–ด ๋ชจ๋ธ(LLM)์„ ํ™œ์šฉํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ํฌ๊ด„์ ์ธ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ์ด ํ”„๋ ˆ์ž„์›Œํฌ๋Š” LLM๊ณผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ†ตํ•ฉ์„ ๊ฐ„์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋˜์—ˆ์œผ๋ฉฐ, ๊ฐœ๋ฐœ์ž๋“ค์ด LLM ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์„ ๋” ์‰ฝ๊ณ  ํšจ์œจ์ ์œผ๋กœ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค.

์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ

  1. ๋ฐ์ดํ„ฐ ์†Œ์Šค ์—ฐ๊ฒฐ: ๋žญ์ฒด์ธ์€ PDF, ์›น ํŽ˜์ด์ง€, CSV, ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“ฑ ๋‹ค์–‘ํ•œ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค์™€์˜ ์—ฐ๋™์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด LLM์— ํ’๋ถ€ํ•œ ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๋‹จ์–ด ์ž„๋ฒ ๋”ฉ: ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒกํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋žญ์ฒด์ธ์€ ์„ ํƒํ•œ LLM์— ์ ํ•ฉํ•œ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ์ž๋™์œผ๋กœ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค: ์ƒ์„ฑ๋œ ์ž„๋ฒ ๋”ฉ์„ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ๋‚ด ๋ฐฐ์—ด๋ถ€ํ„ฐ Pinecone๊ณผ ๊ฐ™์€ ํ˜ธ์ŠคํŒ… ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊นŒ์ง€ ๋‹ค์–‘ํ•œ ์˜ต์…˜์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  4. ์–ธ์–ด ๋ชจ๋ธ ํ†ตํ•ฉ: OpenAI, Cohere, AI21 ๋“ฑ์˜ ์ฃผ์š” LLM ์ œ๊ณต์—…์ฒด์™€ Hugging Face์˜ ์˜คํ”ˆ์†Œ์Šค ๋ชจ๋ธ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  5. ์—์ด์ „ํŠธ: LLM์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ ์œผ๋กœ ์ž‘์—… ๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค.
  6. ๋ฉ”๋ชจ๋ฆฌ: LLM์— ๋‹จ๊ธฐ ๋ฐ ์žฅ๊ธฐ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋Œ€ํ™”์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  7. ์ฝœ๋ฐฑ ์‹œ์Šคํ…œ: ๊ฐœ๋ฐœ์ž๊ฐ€ LLM ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค์–‘ํ•œ ๋‹จ๊ณ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  8. ์ฒด์ธ: ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ ๋ณต์žกํ•œ ์ž‘์—… ํ๋ฆ„์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋žญ์ฒด์ธ์€ ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ ์š”์†Œ๋“ค์„ ํ†ตํ•ฉํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ LLM ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋” ์‰ฝ๊ฒŒ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค. ํŠนํžˆ, ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง, API ํ˜ธ์ถœ, ๊ฒฐ๊ณผ ํ•ด์„ ๋“ฑ LLM๊ณผ์˜ ์ƒํ˜ธ์ž‘์šฉ์— ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ถ”์ƒํ™”ํ•˜์—ฌ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋žญ๊ทธ๋ž˜ํ”„(LangGraph)

๋žญ๊ทธ๋ž˜ํ”„๋Š” ๋ณต์žกํ•œ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ์œ„ํ•œ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ๋žญ์ฒด์ธ๋ณด๋‹ค ๋” ๋‚ฎ์€ ์ˆ˜์ค€์˜ ์ œ์–ด๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ๊ธฐ์—…์˜ ๊ณ ์œ ํ•œ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๋Š” ๋ณต์žกํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ํŠน์ง•

  1. ์„ธ๋ฐ€ํ•œ ์ œ์–ด: ๋žญ๊ทธ๋ž˜ํ”„๋Š” ๋žญ์ฒด์ธ์˜ ์—์ด์ „ํŠธ๋ณด๋‹ค ๋” ์„ธ๋ฐ€ํ•œ ์ˆ˜์ค€์˜ ์ œ์–ด๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ๋ณต์žกํ•œ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ๋” ์ •๋ฐ€ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜๊ณ  ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์œ ์—ฐํ•œ ํ”„๋ ˆ์ž„์›Œํฌ: ๊ธฐ์—…์˜ ๊ณ ์œ ํ•œ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๋Š” ๋ณต์žกํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ‘œํ˜„๋ ฅ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ผํ•œ ๋ธ”๋ž™๋ฐ•์Šค ์ธ์ง€ ์•„ํ‚คํ…์ฒ˜์— ์ œํ•œ๋˜์ง€ ์•Š๊ณ  ๋‹ค์–‘ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  3. ์ŠคํŠธ๋ฆฌ๋ฐ ์ตœ์ ํ™”: ๋žญ๊ทธ๋ž˜ํ”„๋Š” ์ŠคํŠธ๋ฆฌ๋ฐ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ ์‘๋‹ต์ด ํ•„์š”ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  4. ์˜คํ”ˆ์†Œ์Šค: MIT ๋ผ์ด์„ ์Šค๋กœ ์ œ๊ณต๋˜๋Š” ๋ฌด๋ฃŒ ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  5. ๋žญ๊ทธ๋ž˜ํ”„ ํด๋ผ์šฐ๋“œ: ๋žญ๊ทธ๋ž˜ํ”„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฐฐํฌ์™€ ํ™•์žฅ์„ ์œ„ํ•œ ์„œ๋น„์Šค๋กœ, ํ”„๋กœํ† ํƒ€์ดํ•‘, ๋””๋ฒ„๊น…, ๊ณต์œ ๋ฅผ ์œ„ํ•œ ์ŠคํŠœ๋””์˜ค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋žญ๊ทธ๋ž˜ํ”„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฐœ๋ฐœ๊ณผ ์šด์˜์„ ๋”์šฑ ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋žญ๊ทธ๋ž˜ํ”„๋Š” ํŠนํžˆ ๋ณต์žกํ•œ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ ์˜์‚ฌ ๊ฒฐ์ •์ด ํ•„์š”ํ•œ ์ž‘์—…, ๋‹ค์–‘ํ•œ ์™ธ๋ถ€ ๋„๊ตฌ์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•œ ์‹œ์Šคํ…œ, ๋˜๋Š” ๋™์ ์œผ๋กœ ๋ณ€ํ™”ํ•˜๋Š” ํ™˜๊ฒฝ์— ์ ์‘ํ•ด์•ผ ํ•˜๋Š” ์—์ด์ „ํŠธ ๋“ฑ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

  1. 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๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—์ด์ „ํŠธ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ๋””๋ฒ„๊น…ํ•˜๊ณ , ๊ฐ ๋…ธ๋“œ์—์„œ ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™”ํ•˜๋Š”์ง€ ์‰ฝ๊ฒŒ ์ถ”์ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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์˜ ์ฃผ์š” ์—ญํ• 

  1. ํŽ˜์ด๋กœ๋“œ ์ƒ์„ฑ: LLM์€ ์‚ฌ์šฉ์ž์˜ ์ž์—ฐ์–ด ์ž…๋ ฅ์„ ํ•ด์„ํ•˜์—ฌ ํŠน์ • ๋„๊ตฌ(ํ•จ์ˆ˜)๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ •ํ™•ํ•œ ์ธ์ž(ํŽ˜์ด๋กœ๋“œ)๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

    โœ” ํŽ˜์ด๋กœ๋“œ๋ž€?
    ์ปดํ“จํ„ฐ ๋„คํŠธ์›Œํฌ์—์„œ, ๋ฐ์ดํ„ฐ ํŒจํ‚ท์—์„œ ์‹ค์ œ ์ „์†กํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๋ถ€๋ถ„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  2. ํ•จ์ˆ˜ ์‹คํ–‰ ์ค€๋น„: ์ƒ์„ฑ๋œ ํŽ˜์ด๋กœ๋“œ๋Š” ๋ฐ”์ธ๋”ฉ๋œ ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋งž๋Š” ํ˜•์‹์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  3. ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต: Tool์€ LLM๊ณผ ์‹ค์ œ ์‹คํ–‰๋  ํ•จ์ˆ˜ ์‚ฌ์ด์˜ ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. LLM์ด ์ดํ•ดํ•œ ์‚ฌ์šฉ์ž์˜ ์˜๋„๋ฅผ ์‹ค์ œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  4. ์œ ์—ฐ์„ฑ ํ™•๋ณด: ๋‹ค์–‘ํ•œ ์™ธ๋ถ€ ์‹œ์Šคํ…œ, API, ๋˜๋Š” ํ•จ์ˆ˜๋“ค์„ LLM์— ์‰ฝ๊ฒŒ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.
  5. ์ •ํ™•์„ฑ ํ–ฅ์ƒ: ์‚ฌ์šฉ์ž์˜ ์˜๋„๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ํ•ด์„ํ•˜์—ฌ ์ ์ ˆํ•œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ํ•„์š”ํ•œ ์ธ์ž๋ฅผ ์ •ํ™•ํžˆ ์ œ๊ณตํ•จ์œผ๋กœ์จ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

Tool์˜ ์ž‘๋™ ๋ฐฉ์‹

  • ๋ชจ๋ธ์€ ์‚ฌ์šฉ์ž์˜ ์ž์—ฐ์–ด ์ž…๋ ฅ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋ธ์€ ๋„๊ตฌ์˜ ์Šคํ‚ค๋งˆ์— ๋งž๋Š” ์ถœ๋ ฅ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๋„๊ตฌ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ ์ž์ฒด๋Š” ๋ฌด๋ฃŒ์ง€๋งŒ, ๋„๊ตฌ๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ์—ฐ๊ด€๋œ ์„œ๋น„์Šค๋‚˜ API ํ˜ธ์ถœ์— ๋”ฐ๋ฅธ ๋น„์šฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐœ๋ฐœ์ž๋Š” ์ด๋Ÿฌํ•œ ์ž ์žฌ์  ๋น„์šฉ์„ ๊ณ ๋ คํ•˜์—ฌ ๋„๊ตฌ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ  ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

LangChain์˜ Tool ํ˜ธ์ถœ ์ธํ„ฐํŽ˜์ด์Šค

  • ๋งŽ์€ LLM ์ œ๊ณต์—…์ฒด๊ฐ€ ๋„๊ตฌ ํ˜ธ์ถœ์„ ์ง€์›ํ•˜๋ฉฐ, LangChain์—์„œ๋Š” ๊ฐ„๋‹จํ•œ ๋„๊ตฌ ํ˜ธ์ถœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • Python ํ•จ์ˆ˜๋ฅผ ChatModel.bind_tools(function)์— ์ „๋‹ฌํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ชจ๋ธ์€ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ๋„๊ตฌ๋กœ ์ธ์‹ํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ 1

  • LLM(Large Language Model)์ด ๋„๊ตฌ(tool)๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์˜ ๊ณผ์ •์„ ์ข€ ๋” ์ƒ์„ธํžˆ ์„ค๋ช…ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

    1. ์‚ฌ์šฉ์ž๊ฐ€ ์ž์—ฐ์–ด๋กœ ์š”์ฒญ์„ ํ•ฉ๋‹ˆ๋‹ค.
    2. LLM์€ ์ด ์ž์—ฐ์–ด ์š”์ฒญ์„ ์ดํ•ดํ•˜๊ณ , ์–ด๋–ค ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
    3. LLM์€ ์„ ํƒํ•œ ๋„๊ตฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ์ •ํ™•ํ•œ ์ธ์ž(arguments)๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ์ธ์ž๋“ค์ด ๋ฐ”๋กœ โ€˜ํŽ˜์ด๋กœ๋“œโ€™์ž…๋‹ˆ๋‹ค.
    4. ์ด ํŽ˜์ด๋กœ๋“œ(์ธ์ž๋“ค)๋Š” ๋„๊ตฌ ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋งž๋Š” ํ˜•์‹์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.
    5. ์ƒ์„ฑ๋œ ํŽ˜์ด๋กœ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋„๊ตฌ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
    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 ๊ฒฐ๊ณผ)์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค:

    1. Tool์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ AIMessage์˜ content ํ•„๋“œ์— ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.
    2. ๊ทธ๋Ÿฌ๋‚˜ Tool์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ์— ์ถ”๊ฐ€์ ์ธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋‚˜ ๊ตฌ์กฐํ™”๋œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋ฉด, ์ด๋Š” additional_kwargs ๋”•์…”๋„ˆ๋ฆฌ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
    3. ํŠนํžˆ OpenAI์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ(function calling) ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ๋•Œ, Tool์˜ ๊ฒฐ๊ณผ๋Š” ์ฃผ๋กœ additional_kwargs ๋‚ด์˜ function_call ํ‚ค์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  • ๋งŒ์•ฝ์— ๋‚ด๊ฐ€ tool์ด๋ž‘ ์ „ํ˜€ ์ƒ๊ด€์—†๋Š” ์†Œ๋ฆฌ๋ฅผ ํ•˜๋ฉด LLM์ด tool์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ์ •์ƒ์ ์œผ๋กœ content๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ ๊ธฐ์–ต์œผ๋กœ ๋‹ค์‹œ ์ด์ „ ์ฑ•ํ„ฐ โ€œLesson 2: Simple Graphโ€๋กœ ๊ธฐ์–ต์„ ๋˜์งš์–ด์„œ ๊ฐ€๋ด…์‹œ๋‹ค!

  • ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” ๊ทธ๋ž˜ํ”„์˜ State๋ฅผ Python TypeDict ์‚ฌ์šฉํ•œ ํƒ€์ž… ํžŒํŒ… ๊ฐ์ฒด๋กœ ์ •์˜ํ–ˆ์—ˆ๋Š”๋ฐ์š”.
    • ์ด๋Š” ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ 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์—์„œ ์ œ๊ณตํ•˜๋Š” ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ์—ญํ• ๊ณผ ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•ด๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค:

    1. ToolNode:

      • ๋ชฉ์ : ์—ฌ๋Ÿฌ ๋„๊ตฌ(tools)๋ฅผ ํ•˜๋‚˜์˜ ๋…ธ๋“œ๋กœ ๋ฌถ์–ด ์‹คํ–‰ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
      • ์‚ฌ์šฉ ๋ฐฉ๋ฒ•: ToolNode([tool1, tool2, ...]) ํ˜•ํƒœ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
      • ๊ธฐ๋Šฅ:
        • ์ฃผ์–ด์ง„ ๋„๊ตฌ ๋ชฉ๋ก์„ ๋ฐ›์•„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
        • ์ƒํƒœ์—์„œ ๋„๊ตฌ ํ˜ธ์ถœ ์ •๋ณด๋ฅผ ์ฝ๊ณ , ํ•ด๋‹น ๋„๊ตฌ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
        • ๋„๊ตฌ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์ƒํƒœ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
      • ์žฅ์ :
        • ์—ฌ๋Ÿฌ ๋„๊ตฌ๋ฅผ ์‰ฝ๊ฒŒ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
        • ๋„๊ตฌ ์‹คํ–‰ ๋กœ์ง์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    2. 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
17
  from 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__"

์˜ˆ์‹œ ์ฝ”๋“œ

  • ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
    1. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ๋“ค์–ด์˜ค๋ฉด tool_calling_llm ๋…ธ๋“œ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
      • ์ฒซ ๋ฒˆ์งธ ์ธ์ž โ€œtool_calling_llmโ€์€ ์ถœ๋ฐœ ๋…ธ๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    2. LLM์ด ์‘๋‹ต์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    3. 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 ์—์ด์ „ํŠธ(๋ฐ˜์‘ํ˜• ์—์ด์ „ํŠธ)๋ผ๊ณ  ํ•˜๋ฉฐ, ์„ธ ๊ฐ€์ง€ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.

    1. Act: LLM์ด ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋‹จ๊ณ„.
    2. Observe: ๋„๊ตฌ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ LLM์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๋‹จ๊ณ„.
    3. 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()))

  1. Assistant ๋…ธ๋“œ๊ฐ€ ์‹คํ–‰๋œ ํ›„, tools_condition์ด ๋„๊ตฌ ํ˜ธ์ถœ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  2. ๋„๊ตฌ ํ˜ธ์ถœ์ด๋ฉด Tools ๋…ธ๋“œ๋กœ ์ด๋™ํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ Assistant์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  3. ์ด ๋ฃจํ”„๋Š” ๋ชจ๋ธ์ด ๋„๊ตฌ ํ˜ธ์ถœ์„ ์ค‘๋‹จํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์†๋ฉ๋‹ˆ๋‹ค.
  4. ๋ชจ๋ธ์ด ์ง์ ‘ ์‘๋‹ตํ•˜๋ฉด ๊ทธ๋ž˜ํ”„๊ฐ€ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค:

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๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์Šค๋ ˆ๋“œ์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ์˜ˆ์‹œ

  1. 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๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์Šค๋ ˆ๋“œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  1. ํ•ด๋‹น 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๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์œ ๋ฃŒ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹ˆ๋ผ์„œ ๋ณ„๋„์˜ ์‹ค์Šต์€ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

  1. LangGraph:

    • Python๊ณผ JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    • ์—์ด์ „ํŠธ ์›Œํฌํ”Œ๋กœ์šฐ ์ƒ์„ฑ ๊ฐ€๋Šฅ
  2. LangGraph API:

    • ๊ทธ๋ž˜ํ”„ ์ฝ”๋“œ๋ฅผ ๋ฒˆ๋“ค๋กœ ์ œ๊ณต
    • ๋น„๋™๊ธฐ ์ž‘์—… ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ํƒœ์Šคํฌ ํ ์ œ๊ณต
    • ์ƒํ˜ธ์ž‘์šฉ ๊ฐ„ ์ƒํƒœ ์œ ์ง€๋ฅผ ์œ„ํ•œ ์ง€์†์„ฑ ์ œ๊ณต
  3. LangGraph Cloud:

    • LangGraph API์˜ ํ˜ธ์ŠคํŒ… ์„œ๋น„์Šค
    • GitHub ์ €์žฅ์†Œ์—์„œ ๊ทธ๋ž˜ํ”„ ๋ฐฐํฌ ๊ฐ€๋Šฅ
    • ๋ฐฐํฌ๋œ ๊ทธ๋ž˜ํ”„์— ๋Œ€ํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ์ถ”์  ์ œ๊ณต
    • ๊ฐ ๋ฐฐํฌ์— ๋Œ€ํ•ด ๊ณ ์œ  URL ์ œ๊ณต
  4. LangGraph Studio:

    • LangGraph ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ํ†ตํ•ฉ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ(IDE)
    • API๋ฅผ ๋ฐฑ์—”๋“œ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์‹œ๊ฐ„ ํ…Œ์ŠคํŠธ ๋ฐ ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰ ๊ฐ€๋Šฅ
    • ๋กœ์ปฌ ๋˜๋Š” ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅ
  5. LangGraph SDK:

    • LangGraph ๊ทธ๋ž˜ํ”„์™€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•œ Python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    • ๋กœ์ปฌ ๋˜๋Š” ํด๋ผ์šฐ๋“œ์—์„œ ์ œ๊ณต๋˜๋Š” ๊ทธ๋ž˜ํ”„ ์ž‘์—…์„ ์œ„ํ•œ ์ผ๊ด€๋œ ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต
    • ํด๋ผ์ด์–ธํŠธ ์ƒ์„ฑ, ์–ด์‹œ์Šคํ„ดํŠธ ์ ‘๊ทผ, ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ, ์‹คํ–‰ ๋“ฑ ๊ฐ€๋Šฅ
  6. ๋กœ์ปฌ ํ…Œ์ŠคํŒ…:

    • LangGraph Studio์—์„œ ๋กœ์ปฌ๋กœ ์ œ๊ณต๋˜๋Š” ๊ทธ๋ž˜ํ”„์— ์‰ฝ๊ฒŒ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅ
    • Studio UI์˜ ์™ผ์ชฝ ํ•˜๋‹จ์— ์ œ๊ณต๋˜๋Š” URL์„ ํ†ตํ•ด ์—ฐ๊ฒฐ

์ด ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด LangGraph๋Š” ์—์ด์ „ํŠธ ์›Œํฌํ”Œ๋กœ์šฐ์˜ ๊ฐœ๋ฐœ, ํ…Œ์ŠคํŠธ, ๋ฐฐํฌ, ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์ข…ํ•ฉ์ ์ธ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๋กœ์ปฌ์—์„œ ๊ทธ๋ž˜ํ”„๋ฅผ ๋งŒ๋“ค๊ณ  ํ…Œ์ŠคํŠธํ•œ ํ›„, ํด๋ผ์šฐ๋“œ์— ์‰ฝ๊ฒŒ ๋ฐฐํฌํ•˜๊ณ  ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ Module์€ 2๋ฒˆ์งธ ๋ชจ๋“ˆ State and Memory ๊ด€๋ จ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ ๊ธ€์—์„œ ๋ต™๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿค—