๐˜š๐˜ญ๐˜ฐ๐˜ธ ๐˜ฃ๐˜ถ๐˜ต ๐˜ด๐˜ต๐˜ฆ๐˜ข๐˜ฅ๐˜บ

[LLM] LangGraph๋ฅผ ์จ์„œ ๊ฐ„๋‹จํ•œ multi AI Agent ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค์–ด๋ณด์ž ๋ณธ๋ฌธ

machine learning/LLM

[LLM] LangGraph๋ฅผ ์จ์„œ ๊ฐ„๋‹จํ•œ multi AI Agent ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค์–ด๋ณด์ž

.23 2025. 7. 1. 11:07

๐Ÿฆœ๐Ÿ•ธ๏ธ LangGraph?

๋žญ๊ทธ๋ž˜ํ”„(LangGraph)๋Š” LangChain ์ƒํƒœ๊ณ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ๊ณผ AI ์›Œํฌํ”Œ๋กœ์šฐ ๊ฐœ๋ฐœ์— ํŠนํ™”๋˜์–ด ์žˆ๋‹ค. LangChain์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜์—ฌ LLM์„ ์‚ฌ์šฉํ•œ ์ƒํƒœ ์œ ์ง€์™€ ์—ฌ๋Ÿฌ ์—์ด์ „ํŠธ ๊ฐ„์˜ ํ˜‘์—…์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค. ์ฆ‰, LangGraph๋Š” ๋‹จ๋ฐฉํ–ฅ ์ฒด์ธ ํ˜•ํƒœ์˜ LangChain์„ ํ™•์žฅํ•˜์—ฌ ๋‹ค์ˆ˜์˜ ์—์ด์ „ํŠธ๋ฅผ ์ƒํƒœ ๊ธฐ๋ฐ˜(Stateful)์œผ๋กœ ์—ฐ๊ฒฐํ•˜๊ณ , ์กฐ๊ฑด ๋ถ„๊ธฐ, ๋ฃจํ”„, ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๋“ฑ์„ ํฌํ•จํ•˜๋Š” ๋ณต์žกํ•œ AI ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.

 

๐Ÿ”— ๋žญ์ฒด์ธ(LangChain)์ด ๋ญ์—์š”? : https://miiinnn23.tistory.com/117

 

LangChain์ด A → B → C ์ˆœ์œผ๋กœ ์ˆœ์ฐจ ์ˆ˜ํ–‰๋œ๋‹ค๋ฉด, 

LangGraph๋Š” '์กฐ๊ฑด ๋ถ„๊ธฐ'์™€ '๋ฐ˜๋ณต'์˜ ๊ฐœ๋…์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— A ↔ B ↔ C ์™€ ๊ฐ™์ด ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.

 

 

์ด๋Ÿฌํ•œ ๋žญ๊ทธ๋ž˜ํ”„๋Š” ๊ฐ ๋…ธ๋“œ๊ฐ€ LLM ์—์ด์ „ํŠธ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ , ์—ฃ์ง€๊ฐ€ ์—์ด์ „ํŠธ ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ทธ๋ž˜ํ”„ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ณต์žกํ•œ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํŠนํžˆ ์ˆœํ™˜(cycle) ๊ตฌ์กฐ๋ฅผ ์ง€์›ํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ง€์†์ ์œผ๋กœ ๋ฐ˜๋ณตํ•˜๋ฉฐ, ๋ณ€ํ™”ํ•˜๋Š” ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์ž‘์—…์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ ๋žญ๊ทธ๋ž˜ํ”„๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์—์ด์ „ํŠธ๊ฐ€ ์ •๋ณด๋ฅผ ๊ณต์œ ํ•˜๊ณ , ์ „์ฒด ์‹œ์Šคํ…œ์˜ ์ผ๊ด€์„ฑ๊ณผ ํšจ์œจ์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ ๋…ธ๋“œ๊ฐ€ ๊ธ€๋กœ๋ฒŒ ์ƒํƒœ(STATE)๋ฅผ ์ฐธ์กฐํ•˜๋ฉด์„œ ๋™์ž‘ํ•˜์—ฌ, LLM์„ ์‚ฌ์šฉํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์กด์žฌํ•œ๋‹ค.


์šฉ์–ด ์ •๋ฆฌ

โœ”๏ธ AI ์—์ด์ „ํŠธ: ์ฃผ์–ด์ง„ ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์ž…๋ ฅ์„ ๋ฐ›์•„ reasoning๊ณผ ํ–‰๋™์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋…๋ฆฝ์ ์ธ ์‹คํ–‰ ๋‹จ์œ„

โœ”๏ธ ์ƒํƒœ(STATE): ์—์ด์ „ํŠธ ์‹คํ–‰ ๊ณผ์ •์—์„œ ๊ณต์œ ๋˜๋ฉฐ, ํ๋ฆ„ ์ œ์–ด๋‚˜ ์˜์‚ฌ๊ฒฐ์ •์— ํ™œ์šฉ๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์ง‘ํ•ฉ

 

AI ์—์ด์ „ํŠธ๋Š” ๊ฐ๊ฐ์˜ ๋กœ์ง/์„œ๋น„์Šค ๋‹จ์œ„์ด๊ณ , ์ƒํƒœ๋Š” ๋กœ์ง๋“ค์ด ๊ณต์œ ํ•˜๋Š” ๋ฐ์ดํ„ฐ์ด๋‹ค.

'ํ”„๋กฌํ”„ํŠธ build' โžก๏ธ '์ƒ์„ฑ' โžก๏ธ 'ํŒŒ์ผ ์ƒ์„ฑ' ์˜ ๋กœ์ง์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋ ˆํฌํŠธ ์ƒ์„ฑ application์„ ์˜ˆ๋กœ ๋“ค์—ˆ์„ ๋•Œ, ๊ฐ ๋‹จ๊ณ„ ๋ณ„ ๋กœ์ง๋“ค์ด AI ์—์ด์ „ํŠธ์ด์ž ๋…ธ๋“œ๊ฐ€ ๋˜๊ณ ,

ํ”„๋กฌํ”„ํŠธ build์—์„œ ์ƒ์„ฑ ๋กœ์ง์œผ๋กœ ์ด์–ด์งˆ ๋•Œ '์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ'์™€ ๊ฐ™์ด AI ์—์ด์ „ํŠธ๋“ค์ด ์ƒ์„ฑํ•˜์—ฌ ๋‹ค์Œ ์—์ด์ „ํŠธ๋กœ ์ „ํ•ด์ค˜์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๊ณง ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

 


์‚ฌ์šฉ ํ™˜๊ฒฝ

โœ”๏ธ ํŒŒ์ด์ฌ: 3.11.9

โœ”๏ธ LangChain: 0.3.25

โœ”๏ธ LangGraph: 0.4.8

 


AI agent๋ฅผ ์„ค๊ณ„ํ•ด๋ณด์ž

์›น e2e ์ž๋™ํ™” ํ…Œ์ŠคํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ, ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค์™€ API ์ •๋ณด๋ฅผ ์ข…ํ•ฉํ•˜์—ฌ ๊ฐ API๋ณ„๋กœ ์ ํ•ฉํ•œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” 'TC Generator System'์„ ์„ค๊ณ„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๋‹จ์ˆœํžˆ ๋žญ์ฒด์ธ์„ ํ†ตํ•ด ํ”„๋กฌํ”„ํŠธ๋กœ TC๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ, ๋ช‡ ๊ฐ€์ง€ ๊ณ ๋ ค์‚ฌํ•ญ์ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ต์œก์—์„œ ๋“ค์—ˆ๋˜ LangGraph๋ฅผ ์‚ฌ์šฉํ•œ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค. ํ•ด๋‹น ์ƒ์„ฑ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ๋•Œ ๊ฐ€์žฅ ํฌ๊ฒŒ ๊ณ ๋ คํ•ด์•ผ ํ•  ์ ์€

 

- ์ƒ์„ฑ๋œ TC๊ฐ€ ์‹œ๋‚˜๋ฆฌ์˜ค ๋‚ด์—์„œ ์‚ฌ์šฉํ•˜๋Š” API์˜ ์ผ์ • ๋น„์œจ ์ด์ƒ์„ ์ปค๋ฒ„ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ

- LLM์˜ hallucination์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ˜๋“œ์‹œ ์ž๊ฐ€ ๊ฒ€์ฆ ๋กœ์ง์ด ์žˆ์–ด์•ผ ํ•จ

 

์ด๋ ‡๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํฌ๊ฒŒ API coverage ๊ณผ ์ž๊ฐ€ ๊ฒ€์ฆ ๋กœ์ง์„ ๋ถ„๊ธฐ์ ์œผ๋กœ ์žก๊ณ  agent 5๊ฐœ๋ฅผ ๊ฐ€์ง„ ์ž‘์€ ์ƒ์„ฑ ์‹œ์Šคํ…œ์„ ์„ค๊ณ„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

 

๊ทธ๋ž˜ํ”„ ์ •์˜

์‹ค์ œ ๋žญ๊ทธ๋ž˜ํ”„

โœ”๏ธ GENERATE_TC: ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋“ค๋กœ๋ถ€ํ„ฐ ํ”„๋กฌํ”„ํŠธ๋ฅผ buildํ•˜๊ณ , ์ด๋กœ๋ถ€ํ„ฐ LLM ๊ธฐ๋ฐ˜ TC ์ƒ์„ฑ.

โœ”๏ธ CHECK_COVERAGE: API๊ฐ€ ์ž„๊ณ„๊ฐ’ ์ด์ƒ ์ปค๋ฒ„ ๋˜์—ˆ๋Š”์ง€ ๋ฃฐ ๊ธฐ๋ฐ˜ ๊ฒ€์ฆ.

โœ”๏ธ CLEAR_TC: ์ƒ์„ฑ ์˜ค๋ฅ˜๋‚˜ ์ค‘๋‹จ๋˜์–ด ์ž„๊ณ„๊ฐ’ ์ดํ•˜์˜ API๋ฅผ ์ปค๋ฒ„ํ–ˆ์„ ์‹œ ์žฌ์ƒ์„ฑ ๋กœ์ง ๋Œ์ž…ํ•˜๊ธฐ ์œ„ํ•ด ์ง€๊ธˆ๊นŒ์ง€ ์ƒ์„ฑ๋œ TC ์ •๋ณด ์‚ญ์ œ.

โœ”๏ธ VALIDATE_TC: ์ƒ์„ฑ๋œ TC๊ฐ€ ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ๊ฒ€์ฆ ํฌ์ธํŠธ์— ๋งž๊ฒŒ ์„ค๊ณ„๋˜์—ˆ๋Š”์ง€, ๊ฐ’์˜ ์˜ค๋ฅ˜๋Š” ์—†๋Š”์ง€ LLM์„ ํ†ตํ•œ ์ž๊ฐ€ ๊ฒ€์ฆ.

โœ”๏ธ REGENERATE_TC: ๊ฒ€์ฆ ๋กœ์ง์—์„œ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ํŒ๋‹จ๋œ TC์— ํ•œ์ •ํ•˜์—ฌ TC ์žฌ์ƒ์„ฑ. ๊ณผ๋‹ค ์ƒ์„ฑ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด 3๋ฒˆ ์ด์ƒ ๊ฒ€์ฆ ๋กœ์ง์ด ๋ฐ˜๋ณต๋  ์‹œ ์ƒ์„ฑ ์ข…๋ฃŒ.

 

STATE ์ •์˜

TC ์ƒ์„ฑ์„ ์œ„ํ•œ ์ •๋ณด์™€ ๊ฒ€์ฆ ๋กœ์ง์— ํ•„์š”ํ•œ ์ „์—ญ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ STATE๋ฅผ ์ •์˜ํ•˜์˜€๋‹ค. STATE๋Š” ์ผ์ข…์˜ payload ๊ฐœ๋…์œผ๋กœ, ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ ๊ฐ ์—์ด์ „ํŠธ๊ฐ€ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ณตํ†ต์˜ ์ปจํ…์ŠคํŠธ๋กœ์„œ, ํ•„์š”ํ•œ ๊ฐ’์„ ์ ์ ˆํžˆ ์ •์˜ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

class FlowState(BaseModel):
    """
    TC ์ƒ์„ฑ STATE ์ •์˜
    - ์‹œ๋‚˜๋ฆฌ์˜ค ID
    - ์ƒ์„ฑ์— ํ•„์š”ํ•œ request ๊ฐ์ฒด
    - ์ƒ์„ฑ๋œ TC ๋ชฉ๋ก
    - TC์— ๋Œ€ํ•œ coverage ๊ฐ’(๊ฒ€์ฆ๋ฅ )
    - regenerated ํ•„์š”ํ•œ tc id ๋ฐ ์‚ฌ์œ 
    - ์žฌ์‹œ๋„ ํšŸ์ˆ˜
    """
    scenario_id: str
    request: TestcaseGenerationRequest
    tc_list: List[TestcaseData] = []
    coverage: Optional[float] = None
    revalidation_targets: List[Tuple[str, str]] = []  # (tc_list index, reason)
    retry_count: int = 0

 

๊ทธ๋ž˜ํ”„ ์„ค๊ณ„

๋…ธ๋“œ์™€ STATE ์ •์˜๊ฐ€ ๋๋‚ฌ๋‹ค๋ฉด, ์ด์ œ๋ถ€ํ„ฐ๋Š” ์‹ค์ œ ๋กœ์ง์„ ์„ค๊ณ„ํ•ด์ค€๋‹ค. LangGraph์˜ ์‹คํ–‰ ํ๋ฆ„์€ ๊ทธ๋ž˜ํ”„ ๋นŒ๋“œ → ์ปดํŒŒ์ผ → ์‹คํ–‰(invoke) ์ˆœ์„œ๋กœ ์ง„ํ–‰๋˜๋ฉฐ, ์ด ๊ณผ์ •์€ ๋งˆ์น˜ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋“ฏ ๋…ธ๋“œ๋ฅผ ๋ฐฐ์น˜ํ•˜๊ณ  ํ๋ฆ„์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ณผ์ •์— ๊ฐ€๊น๋‹ค. ๋ณ„๋„์˜ ๊ทธ๋ž˜ํ”„ ์„ค๊ณ„ ํ•จ์ˆ˜์—์„œ compile๊นŒ์ง€ ์™„๋ฃŒ๋œ ์ƒํƒœ์˜ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ •์˜ํ•ด์ฃผ์—ˆ๋‹ค.

 

๋จผ์ € ์–ด๋–ค STATE๋ฅผ ๊ฐ€์ง„ ๊ทธ๋ž˜ํ”„๋ฅผ ์„ค๊ณ„ํ•  ๊ฒƒ์ธ์ง€ StateGraph์˜ builder๋ฅผ ์ •์˜ํ•ด์ค€๋‹ค.

builder = StateGraph(state_schema=FlowState)

 

์ดํ›„ ์ฐจ๋ก€๋Œ€๋กœ ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

# 1. ๊ฐ API ๋งคํ•‘์— ๋Œ€ํ•ด TC ์ƒ์„ฑ → ์ƒ์„ฑ๋œ TC๋Š” ์ƒํƒœ์— ์ถ”๊ฐ€
builder.add_node("generate_tc", generate_tc_node)

# 2. coverage ํŒ๋‹จ ํ›„ ๋ถ„๊ธฐ
builder.add_node("check_coverage", coverage_check_node)

# 2-1. coverage ๋ฏธ๋‹ฌ ์‹œ ์žฌ์ƒ์„ฑ ๋กœ์ง ์ˆ˜ํ–‰ ์ „ TC ๋ฆฌ์ŠคํŠธ ์ดˆ๊ธฐํ™”
builder.add_node("clear_tc", clear_tc_node)

# 3. ๊ฒ€์ฆ ์ง„ํ–‰
builder.add_node("validate_tc", validate_tc_node)

# 4. ๊ฒ€์ฆ ํ›„ ์‹คํŒจ TC์— ๋Œ€ํ•œ ์žฌ์ƒ์„ฑ ์ˆ˜ํ–‰
builder.add_node("regenerate_tc", regenerate_tc_node)

 

๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ ํ›„ ์–ด๋””์„œ ์‹œ์ž‘ํ•˜๋Š”์ง€ entry point๋ฅผ ์„ค์ •ํ•˜๊ณ , ๊ฐ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•ด์ค€๋‹ค.

 

# ํ๋ฆ„ ์ •์˜
builder.set_entry_point("generate_tc")
builder.add_edge("generate_tc", "check_coverage")

# coverage ํŒ๋‹จ์— ๋”ฐ๋ผ ๋ถ„๊ธฐ
builder.add_conditional_edges(
    source="check_coverage",
    path=coverage_decision_fn,
    path_map={
        "pass": "validate_tc",     # coverage ์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ
        "fail": "clear_tc"         # ์•„๋‹์‹œ ์ƒ์„ฑ tc ์ดˆ๊ธฐํ™”
    }
)

builder.add_edge("clear_tc", "generate_tc")

# ๊ฒ€์ฆ ์‹คํŒจ TC ์กด์žฌ ์—ฌ๋ถ€์— ๋Œ€ํ•ด ๋ถ„๊ธฐ
builder.add_conditional_edges(
    source="validate_tc",
    path=regenerate_decision_fn,
    path_map={
        "pass": END,
        "fail": "regenerate_tc",    # validation ์‹คํŒจ ์‹œ ์žฌ์ƒ์„ฑ ๋กœ์ง ๋Œ์ž…
        "giveup": END               # validation - regenerate 3๋ฒˆ ๋ฐ˜๋ณต ์‹œ ๋ฃจํ”„ ํƒˆ์ถœ
    }
)

builder.add_edge("regenerate_tc", "validate_tc")  # ๋ฃจํ”„ ์ถ”๊ฐ€

 

์ด ๋•Œ ๋ถ„๊ธฐ์ ์€ add_conditional_edges๋ฅผ ํ†ตํ•ด ์–ด๋–ค ์ด๋ฆ„์˜ ๋…ธ๋“œ(source)๋กœ๋ถ€ํ„ฐ ์–ด๋–ค ํ•จ์ˆ˜๋ฅผ ๊ธฐ์ค€(path)์œผ๋กœ ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ค ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋А๋ƒ์— ๋”ฐ๋ผ ์–ด๋А ๋…ธ๋“œ๋กœ ๊ฐˆ์ง€(path_map)๋ฅผ ๊ฒฐ์ •ํ•ด์ค€๋‹ค.

 

def regenerate_decision_fn(state: FlowState) -> str:
    """
    revalidation_targets์— ์žฌ์ƒ์„ฑ ๋Œ€์ƒ์ด ์žˆ๋Š”์ง€ ํŒ๋‹จํ•˜์—ฌ ๋ถ„๊ธฐ
    - ์—†์œผ๋ฉด: "pass"
    - ์žˆ์œผ๋ฉด: "fail"
    - ์žฌ๊ฒ€์ฆ 3๋ฒˆ ์ด์ƒ: "giveup"
    """
    if not state.revalidation_targets:
        return "pass"
    if state.retry_count >= 3:
        return "giveup"  # 3ํšŒ ์‹คํŒจ ์‹œ
    return "fail"

 

์ด ๋•Œ์˜ path์— ๋“ค์–ด๊ฐˆ ํ•จ์ˆ˜๋Š” ์œ„์™€ ๊ฐ™์ด ์–ด๋–ค ์กฐ๊ฑด์— ๋”ฐ๋ผ ํŠน์ • ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ์„ ์–ธํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ํ•ด๋‹น ๋‹จ๊ณ„์—์„œ ์œ„์™€ ๊ฐ™์ด loop ์กฐ๊ฑด์„ ์„ค์ •ํ•ด์ค„ ์ˆ˜๋„ ์žˆ๊ณ , ๋‹จ์ˆœํžˆ ์–ด๋А ๋…ธ๋“œ๋กœ ๊ฐˆ์ง€ ๋ถ„๊ธฐ์ ๋งŒ ์—ฐ๊ฒฐํ•ด์ฃผ์–ด๋„ ๋œ๋‹ค.

 

์ดํ›„ builder๋ฅผ compile๊นŒ์ง€ ํ•˜์—ฌ returnํ•ด์ฃผ๋ฉด ๋ฐ”๋กœ invokeํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„ ๋นŒ๋“œ ํ•จ์ˆ˜ ๋!!

return builder.compile()

 

๊ทธ๋ž˜ํ”„ ์‹คํ–‰

๊ทธ๋ž˜ํ”„๋Š” controller๋‚˜ ๋‹ค๋ฅธ ๋‹จ์—์„œ ์ž…๋ ฅ๋ฐ›์€ request ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ state๋ฅผ ์ •์˜ํ•ด์ฃผ๊ณ , ๋นŒ๋“œ๋œ ๊ทธ๋ž˜ํ”„์— state๋ฅผ ๋„ฃ์–ด invoke๋งŒ ํ•ด์ฃผ๋ฉด ๋๋‚œ๋‹ค. ์ •๋ง ๊ฐ„๋‹จํ•˜์ฃ ?

์ดํ›„ ์ •์˜๋œ state๋ฅผ ์‘๋‹ต ๊ฐ์ฒด์— ๋งž๊ฒŒ ๋‹ค์‹œ ์ง๋ ฌํ™”ํ•˜์—ฌ ๋ฐ˜ํ™˜๋งŒ ํ•ด์ฃผ๋ฉด TC ์ƒ์„ฑ์€ ๋์ด๋‹ค. ์–ํ˜ธ๐Ÿ™Œ

state = FlowState(scenario_id=scenario_id, request=request)

# ๊ทธ๋ž˜ํ”„ ๋นŒ๋“œ
graph = build_testcase_flow()

# ๊ทธ๋ž˜ํ”„ ์‹คํ–‰
result: dict = await graph.ainvoke(state)

# ์‘๋‹ต ์กฐํ•ฉ
response = build_tc_response_from_state(result)

 


์‹คํ–‰ ๊ฒฐ๊ณผ

LangChain API KEY๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์•„ ์‹คํ–‰ํ•  ๋•Œ env์— ๋„ฃ์–ด์ฃผ๋ฉด ํŠธ๋ž˜ํ‚นํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ ๊ทธ๋ž˜ํ”„์˜ ์–ด๋–ค ๋กœ์ง์„ ํƒ”๋Š”์ง€, ๊ทธ ๋•Œ์˜ ๊ฒฐ๊ณผ๊ฐ’์ด ์–ด๋–ป๊ฒŒ ๋˜์—ˆ๋Š”์ง€, ์‹œ๊ฐ„์ด ์–ผ๋งˆ๋‚˜ ์†Œ์š”๋˜์—ˆ๋Š”์ง€, ์–ผ๋งˆ์˜ ํ† ํฐ์ด ์†Œ๋ชจ๋˜๋Š”์ง€, ์‹ฌ์ง€์–ด๋Š” ์–ด๋–ค ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ๊นŒ์ง€๋„ ๊ฐ„ํŽธํ•˜๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋ž˜ํ‚น ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.(๊ฐœ์ธ ์‚ฌ์šฉ ์‹œ Tracing์€ ๋ฌด๋ฃŒ!)

 

one-shot learning์œผ๋กœ ๊ฐ•๋ ฅํ•˜๊ฒŒ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ๋”๋‹ˆ JsonOutputParser๋ฅผ ํƒœ์›Œ๋„ ๋ฌธ์ œ์—†๋Š” ์‘๋‹ต์ด ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

coverage ๋ฒ”์œ„๋Š” 60%์œผ๋กœ ์žก์•˜๊ธฐ ๋•Œ๋ฌธ์—, TC ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๋„์ค‘ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋Š”๋‹ค๋ฉด ์›ฌ๋งŒํ•ด์„œ ๊ฒ€์ฆ๋กœ์ง์œผ๋กœ ์ž˜ ๋„˜์–ด๊ฐ„๋‹ค.

 

 

๊ทผ๋ฐ ๊ฐ€๋” LLM์˜ ๋ฐ˜๋ž€์ด ์ผ์–ด๋‚˜๋ฉด ์ €๋ ‡๊ฒŒ๋œ๋‹ค๐Ÿ˜‘

 

๊ทธ์น˜๋งŒ ์„ค๊ณ„ ์˜๋„๋Œ€๋กœ ๊ทธ๋ž˜ํ”„๋ฅผ ์ž˜ ํƒ€๋Š” ๊ฒƒ์— ์กฐ๊ธˆ์ด๋‚˜๋งˆ ์œ„์•ˆ์„..

ใ…œใ…œ

 

์ฒ˜์Œ์— ์„ค๊ณ„ํ•ด์ค˜์•ผ ํ•˜๋Š” ๋กœ์ง์ด๋‚˜ STATE ๊ฐœ๋…์ด ์–ด๋ ค์›Œ์„œ LangGraph์™€ ๋‚ฏ๊ฐ€๋ ธ๋Š”๋ฐ, (๋ฒ„์ „๋งˆ๋‹ค ์ฝ”๋“œ๋„ ์ฒœ์ฐจ๋งŒ๋ณ„์ด๋ผ GPT ํƒœ์›Œ์„œ ์ฝ”๋“œ ๋งŒ๋“ค์–ด๋‹ฌ๋ผํ•˜๊ธฐ๋„ ์–ด๋ ค์› ์Œ ใ…œใ…œ) ๋™์ž‘ ์›๋ฆฌ๋ฅผ ์–ด๋А์ •๋„ ์ดํ•ดํ•˜๊ณ  ๋‚˜๋‹ˆ ์ด๊ฑฐ๋งŒํผ ๊ฐ•๋ ฅํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋„ ์—†๋Š”๊ฑฐ๊ฐ™๋‹ค. ์‹ ๊ธฐ์ˆ ์„ ์—ด๋ฆฐ ๋งˆ์ธ๋“œ๋กœ ๋ฐฐ์šฐ์ž.

Comments