๐ฏ AI ์์ด์ ํธ ๊ธฐ์ด
์์ด์ ํธ ์ ์, ReAct, Tool Use, ๋๊ตฌ ์ค๊ณ, Human-in-the-Loop
AI ์์ด์ ํธ ๊ธฐ์ด
์ ์ ยท ReAct ยท Tool Use ยท ๋๊ตฌ ์ค๊ณ ยท Human-in-the-Loop
๋๊ตฌ๋ฅผ ์ฐ๋ AI๊ฐ ์์ด์ ํธ๋ค
LLM์ด ์์จ์ ์ผ๋ก ํ๋จํ๊ณ ํ๋ํ๋ ์์คํ ์ ํต์ฌ ์๋ฆฌ
์์ด์ ํธ์ ์ ์์ ๊ตฌ์กฐ
์ ์ ยท ์ฑ๋ด๊ณผ์ ์ฐจ์ด ยท ์์ด์ ํฑ ๋ฃจํ ยท ์์จ์ฑ ๋ ๋ฒจ
์ ์์ ๊ตฌ์กฐ
์ฑ๋ด๊ณผ์ ์ฐจ์ด์์ ์์จ์ฑ ์์ค๊น์ง โ ์์ด์ ํธ๋ฅผ ๋ชจ๋ธ์ด ์๋๋ผ ์์คํ ์ผ๋ก ๋ณด๋ ๊ด์
๋ต๋ณ์ ๋์ด ํ๋ํ๋ AI
LLM์ด ๋๊ตฌ๋ฅผ ํธ์ถํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ๋จํ์ฌ ๋ชฉํ๋ฅผ ๋ฌ์ฑํ ๋๊น์ง ๋ฐ๋ณตํ๋ ์์คํ ์ ๋๋ค.
- ์ฑ๋ด vs ์์ด์ ํธ โ ๋ต๋ณ๋ง vs ํ๋จํ๊ณ ํ๋
- ์์ด์ ํฑ ๋ฃจํ โ Perception โ Reasoning โ Action โ Memory
- ๊ตฌ์ฑ์์ 5๊ฐ์ง โ Tools ยท Memory ยท Guardrails ยท Context ยท Orchestration
- ์์จ์ฑ 4๋จ๊ณ โ Manual โ Assisted โ Supervised โ Autonomous
์ฑ๋ด๊ณผ์ ์ฐจ์ด์์ ์ถ๋ฐํด ๋ฃจํ ยท ๊ตฌ์ฑ์์ ยท ์์จ์ฑ ๋จ๊ณ๊น์ง โ ์์ด์ ํธ๋ฅผ ๋ชจ๋ธ์ด ์๋๋ผ ์์คํ ์ผ๋ก ๋ณด๋ ๊ด์ ์ ์ธ์๋๋ค.
์ฑ๋ด vs ์์ด์ ํธ
๋ต๋ณํ๋ AI์์ ํ๋ํ๋ AI๋ก
์ฑ๋ด
๋ต๋ณ๋ง ์์ฑ
- LLM๋ง ์ฌ์ฉ โ ํ ์คํธ ์ ๋ ฅ โ ํ ์คํธ ์ถ๋ ฅ
- ์คํ ํ๋ฆ ๊ณ ์ (์ง๋ฌธโ๋ต๋ณ)
- "๊ฐ๋จ์ญ ์ดํ๋ฆฌ์ ์ถ์ฒํด์ค" โ ์ผ๋ฐ์ ์ ๋ณด ๋์ด
- ์ธ๋ถ ์์คํ ์ ๊ทผ ๋ถ๊ฐ
์ฑ๋ด์ ํ์ต๋ ๋ฐ์ดํฐ ๋ฒ์ ์์์๋ง ๋ต๋ณํฉ๋๋ค. ์ค์๊ฐ ์ ๋ณด, ์์ฝ ์คํ, ๋ฐ์ดํฐ ์กฐํ ๊ฐ์ "ํ๋"์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
์์ด์ ํธ
ํ๋จํ๊ณ ํ๋
- LLM + ๋๊ตฌ + ์ค์ผ์คํธ๋ ์ด์
- ๋ชจ๋ธ์ด ๋ค์ ํ๋์ ๋์ ๊ฒฐ์
- "๊ฐ๋จ์ญ ์ดํ๋ฆฌ์ ์ถ์ฒํด์ค" โ ๊ฒ์ ๋๊ตฌ ํธ์ถ โ ์ค์๊ฐ ๊ฒฐ๊ณผ
- API, DB, ํ์ผ, ์ฝ๋ ์คํ ๊ฐ๋ฅ
์์ด์ ํธ๋ ๋ชฉํ๋ฅผ ๋ฌ์ฑํ ๋๊น์ง ์ถ๋ก ๊ณผ ํ๋์ ๋ฐ๋ณตํฉ๋๋ค. ๋๊ตฌ๋ฅผ ํธ์ถํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ๋จํ์ฌ ๋ค์ ๋จ๊ณ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
์์ด์ ํฑ ๋ฃจํ
์ปจํ ์คํธ โ LLM โ ๋๊ตฌ๋ฅผ ๋ชฉํ ๋ฌ์ฑ๊น์ง ๋ฐ๋ณต
์์ด์ ํธ ๊ตฌ์ฑ์์
ํ๋ก๋์ ์์ด์ ํธ๋ฅผ ์ด๋ฃจ๋ 5๊ฐ์ง ํต์ฌ ์์
์์จ์ฑ 4๋จ๊ณ
์์ด์ ํธ์๊ฒ ๋ถ์ฌํ๋ ๊ถํ์ ํญ โ ์๋ ๋ณด์กฐ๋ถํฐ ์์ ์์จ๊น์ง
๋จ๊ณ๋ ์์ ์ํ๋์ ์ ๋ขฐ๊ฐ ์ ํฉ๋๋ค โ ํ๋ก๋์ ์ Supervised(์น์ธ ๊ฒ์ดํธ)์์ ์์ํด ์ ๋ขฐ๊ฐ ์์ธ ์์ ๋ถํฐ ์์จ๋ก ๋ํ๋๋ค.
ํต์ฌ ๋ฉ์ปค๋์ฆ
ReAct ยท ReWoo ยท Tool Use ํ๋กํ ์ฝ
ํต์ฌ ๋ฉ์ปค๋์ฆ
์์ด์ ํธ๊ฐ ์ถ๋ก ํ๊ณ ํ๋ํ๋ ๋ ๊ฐ์ง ํจํด๊ณผ ๋๊ตฌ ํธ์ถ ํ๋กํ ์ฝ์ ์กฐ๊ฐ
ReAct ยท ReWoo ยท Tool Use
ReAct๋ ๋งค ์คํ ํ๋จํ๊ณ ReWoo๋ ๊ณํ ํ ๋ณ๋ ฌ ์คํํฉ๋๋ค โ ๋๊ตฌ ํธ์ถ์ 6๋จ๊ณ ๋ฉ์์ง ํ๋กํ ์ฝ๋ก ์ค๊ฐ๋๋ค.
- ReAct โ ๋งค ์คํ ์ถ๋ก ํ ํ๋, ๋์ ์ ์๋ ฅ
- ReWoo โ ๊ณํ ๋จผ์ + ๋ณ๋ ฌ ์คํ, LLM 2ํ ํธ์ถ
- Tool Use 6๋จ๊ณ โ toolSpec โ tool_use โ toolResult
- ํจํด ์ ํ โ ๋ํํ์ ReAct, ๋ณ๋ ฌยท๋น์ฉ ๋ฏผ๊ฐ์ ReWoo
ReAct๋ ์ ์๋ ฅ์, ReWoo๋ ํ ํฐ ํจ์จ์ ์ป์ต๋๋ค โ ์์ ์ฑ๊ฒฉ์ด ํจํด์ ๊ฒฐ์ ํฉ๋๋ค.
ReAct ํจํด
Reasoning + Acting์ ๋งค ์คํ ๋ฐ๋ณต โ ์์ด์ ํธ์ ๊ธฐ๋ณธ ํจํด
ํ ์คํ ์ ๊ตฌ์กฐ
-
1
Thought
์ง๊ธ๊น์ง์ ๋ํยท๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ๋ค์ ํ๋์ ์ถ๋ก โ "๋ฌด์์ด ๋ ํ์ํ๊ฐ"
-
2
Action
์ถ๋ก ์ด ๊ณ ๋ฅธ ๋๊ตฌ๋ฅผ ํธ์ถ โ ๋๊ตฌ ์ด๋ฆ๊ณผ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ชจ๋ธ์ด ๊ฒฐ์
-
3
Observation
๋๊ตฌ ๊ฒฐ๊ณผ๊ฐ messages[]์ ์์ฌ ๋ค์ Thought์ ์ ๋ ฅ์ด ๋จ
-
4
๋ฐ๋ณต ๋๋ ์ข ๋ฃ
์ ๋ณด๊ฐ ์ถฉ๋ถํด์ง๋ฉด ๋๊ตฌ ํธ์ถ ๋์ ์ต์ข ๋ต๋ณ ์์ฑ
์ค์ ํธ๋ ์ด์ค โ ํ ์์ฒญ์ด ๋ ์คํ ์ ๋๋ ๊ณผ์
๋งค ์คํ ์ค๊ฐ ๊ฒฐ๊ณผ์ ๋ฐ์ํด ๋ค์ ํ๋์ ๋ฐ๊พธ๋ ๊ฒ์ด ReAct์ ๊ฐ์ ์ ๋๋ค.
ReWoo ํจํด
๊ณํ์ ๋จผ์ ์ธ์ฐ๊ณ ๋๊ตฌ๋ฅผ ๋ณ๋ ฌ ์คํ โ HotpotQA ๋ฒค์น๋งํฌ ๊ธฐ์ค ํ ํฐ ์ต๋ 5๋ฐฐ ํจ์จ
3์ญํ ๋ถ์ โ Reasoning WithOut Observation
-
1
Planner โ ์ค๊ณ๋ ์์ฑ (LLM 1ํ)
์ ์ฒด ๋๊ตฌ ํธ์ถ ๊ณํ์ ํ ๋ฒ์ ์๋ฆฝ โ ์์ง ์๋ ๊ฒฐ๊ณผ๋ #E1ยท#E2 ํ๋ ์ด์คํ๋๋ก ์ฐธ์กฐ
-
2
Worker โ ์ผ๊ด ์คํ (LLM 0ํ)
๊ณํ์ ๋๊ตฌ๋ฅผ ๋ชจ๋ธ ๊ฐ์ ์์ด ์คํ โ ์์กด์ฑ ์๋ ํธ์ถ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ
-
3
Solver โ ์ฆ๊ฑฐ ์ข ํฉ (LLM 1ํ)
ํ๋ ์ด์คํ๋ ์๋ฆฌ์ ์ค์ ๊ฒฐ๊ณผ๋ฅผ ์ฑ์ ์ต์ข ๋ต๋ณ ์์ฑ
๊ฐ์ ์์ฒญ์ ์คํ ๊ณํ์ โ Planner ์ถ๋ ฅ
Plan: ๊ฐ๋จ์ญ ์ดํ๋ฆฌ์ ๋ง์ง์ ์ฐพ๋๋ค
#E1 = search_restaurants(location="๊ฐ๋จ์ญ",
cuisine="์ดํ๋ฆฌ์")
Plan: ํ์ 1์ ์๋น์ ์ ๋
์ผ๋ก ์์ฝํ๋ค
#E2 = book_table(restaurant=#E1[0],
time="19:00")
๊ด์ฐฐ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๊ณํ์ ๋จผ์ ์์ฑํฉ๋๋ค โ LLM ํธ์ถ์ด ๊ณํยท์ข ํฉ 2ํ๋ก ๊ณ ์ ๋๋ ๊ฒ์ด ์คํ ๋ง๋ค ๋ชจ๋ธ์ ๋ถ๋ฅด๋ ReAct์์ ๊ฒฐ์ ์ ์ฐจ์ด์ ๋๋ค.
ReAct vs ReWoo
์์ ์ฑ๊ฒฉ์ ๋ฐ๋ผ ํจํด์ ์ ํ
| ๊ตฌ๋ถ | ReAct | ReWoo |
|---|---|---|
| ์ ๋ต | ๋งค ์คํ ํ๋จ | ๊ณํ ๋จผ์ , ์ผ๊ด ์คํ |
| LLM ํธ์ถ | Nํ (์คํ ๋ง๋ค) | 2ํ (๊ณํ + ์ข ํฉ) |
| ํ ํฐ ํจ์จ | ๋ฎ์ | ๋์ (HotpotQA ๊ธฐ์ค ์ต๋ 5๋ฐฐ) |
| ์คํ ์๊ฐ | ์ง๋ ฌ โ ๋๋ฆผ | ๋ณ๋ ฌ โ ๋น ๋ฆ |
| ์ ์๋ ฅ | โ ๋์ (์ค๊ฐ ๊ฒฐ๊ณผ์ ๋ฐ์) | ๋ฎ์ (๊ณํ ์คํจ ์ ์ฌ๊ณํ) |
| ์ ํฉํ ๊ฒฝ์ฐ | ๋ํํ, HITL, ๊ฒฐ๊ณผ ์์กด์ฑ ๋์ ๋ | ๋ฉํฐ๋๊ตฌ, ๋ณ๋ ฌ ๊ฐ๋ฅ, ๋น์ฉ ๋ฏผ๊ฐ |
๋ํํ์ด๊ฑฐ๋ ๊ฒฐ๊ณผ ์์กด์ฑ์ด ๋์ผ๋ฉด ReAct, ๋ณ๋ ฌ ๊ฐ๋ฅํ๊ณ ๋น์ฉ์ ๋ฏผ๊ฐํ๋ฉด ReWoo โ ์ ์๋ ฅ๊ณผ ํจ์จ์ ๋ง๊ตํ์ ๋๋ค.
Tool Use 6๋จ๊ณ
LLM๊ณผ ๋๊ตฌ ์ฌ์ด์ ๋ฉ์์ง ํ๋กํ ์ฝ
๋๊ตฌ ์ค๊ณ
ํจ์ vs ๋๊ตฌ ยท @tool ๋ณํ ยท ์คํค๋ง ยท ์ค๊ณ ์์น
๋๊ตฌ ์ค๊ณ
์ผ๋ฐ ํจ์๊ฐ LLM์ด ์ธ ์ ์๋ ๋๊ตฌ๊ฐ ๋๊ธฐ๊น์ง์ ์ค๊ณ ์์ ์กฐ๊ฐ
๋๊ตฌ = ํจ์ + JSON Schema
LLM์ ์ฝ๋๋ฅผ ์ฝ์ง ๋ชปํฉ๋๋ค โ nameยทdescriptionยทinputSchema ์ค๋ช ์๊ฐ ๋๊ตฌ ์ ํ์ ์ ์ผํ ๊ทผ๊ฑฐ์ ๋๋ค.
- ํจ์ vs ๋๊ตฌ โ ํธ์ถ ์ฃผ์ฒด๊ฐ ๊ฐ๋ฐ์์์ LLM์ผ๋ก
- @tool ๋ฐ์ฝ๋ ์ดํฐ โ Python ํจ์๋ฅผ ๋๊ตฌ๋ก ์๋ ๋ณํ
- ์คํค๋ง 3์์ โ name ยท description ยท inputSchema
- ์ค๊ณ ์์น โ ๋จ์ผ ์ฑ ์ ยท ๊ตฌ์กฐํ ๋ฐํ ยท ๋ช ํํ ์๋ฌ
์ข์ description์ "์ธ์ + ๋ญ ๋ฃ๊ณ + ๋ญ ๋ฐ๋ + ์ฃผ์์ฌํญ"์ ๋ด์ต๋๋ค โ ์ค๋ช ์ ํ์ง์ด ๋๊ตฌ ์ ํ ์ ํ๋๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
ํจ์ vs ๋๊ตฌ
ํจ์๋ฅผ ๋๊ตฌ๋ก ๋ง๋๋ ์กฐ๊ฑด โ JSON Schema(์ค๋ช ์)
์ผ๋ฐ ํจ์
๊ฐ๋ฐ์๊ฐ ์ง์ ํธ์ถ
- ํธ์ถ ์ฃผ์ฒด: ๊ฐ๋ฐ์ (์ฝ๋์์ ์ง์ )
- ์ค๋ช ๋ถํ์ โ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋จ
- ํ๋ผ๋ฏธํฐ: ํจ์ ์๊ทธ๋์ฒ
- ์ ํ ๊ธฐ์ค: ๊ฐ๋ฐ์ ํ๋จ
๊ฐ๋ฐ์๊ฐ ํจ์๋ช ๊ณผ ํ๋ผ๋ฏธํฐ๋ฅผ ์๊ณ ์์ผ๋ฏ๋ก ์ถ๊ฐ ์ค๋ช ์์ด ํธ์ถ ๊ฐ๋ฅํฉ๋๋ค.
์์ด์ ํธ ๋๊ตฌ
LLM์ด ์์จ ๊ฒฐ์
- ํธ์ถ ์ฃผ์ฒด: LLM (์ถ๋ก ํ ์์จ)
- ์ค๋ช ํ์ โ LLM์ ์ฝ๋๋ฅผ ๋ชป ์ฝ์
- ํ๋ผ๋ฏธํฐ: JSON Schema
- ์ ํ ๊ธฐ์ค: description ํ ์คํธ
LLM์ ์ฝ๋๋ฅผ ๋ณผ ์ ์์ผ๋ฏ๋ก, nameยทdescriptionยทinputSchema๋ง์ผ๋ก "์ด ๋๊ตฌ๋ฅผ ์ง๊ธ ์จ์ผ ํ๋" ํ๋จํฉ๋๋ค.
@tool ๋ฐ์ฝ๋ ์ดํฐ
Python ํจ์๋ฅผ ์์ด์ ํธ ๋๊ตฌ๋ก ์๋ ๋ณํ
from strands import Agent, tool
# โ ๋๊ตฌ ์ ์ โ docstring์ด LLM์๊ฒ ์ ๋ฌ๋๋ ๋๊ตฌ ์ค๋ช
@tool
def search_restaurants(location: str, cuisine: str = None) -> str:
"""์ง์ญ๊ณผ ์๋ฆฌ ์ข
๋ฅ๋ก ์๋น์ ๊ฒ์ํฉ๋๋ค.
์ฌ์ฉ์๊ฐ ์๋น ์ถ์ฒ์ ์์ฒญํ ๋ ํธ์ถํ์ธ์.
location: ๊ฒ์ํ ์ง์ญ๋ช
(์: "๊ฐ๋จ์ญ")
cuisine: ์๋ฆฌ ์ข
๋ฅ (์: "์ดํ๋ฆฌ์"). ์๋ตํ๋ฉด ์ ์ฒด ๊ฒ์
"""
return f"{location} ๊ทผ์ฒ ์๋น 3๊ณณ ๋ฐ๊ฒฌ"
# โก Agent์ ๋๊ตฌ ์ ๋ฌ โ ReAct ๋ฃจํ์์ ์์จ ํธ์ถ
agent = Agent(
model="us.anthropic.claude-sonnet-4-6",
tools=[search_restaurants],
)
# โข ์คํ โ ๋ชจ๋ธ์ด ์ค์ค๋ก ๋๊ตฌ ํธ์ถ์ ๊ฒฐ์ ํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ข
ํฉ
result = agent("๊ฐ๋จ์ญ ์ดํ๋ฆฌ์ ์ถ์ฒํด์ค")
- @tool ๋ฐ์ฝ๋ ์ดํฐ โ ํ๋ฒํ Python ํจ์๊ฐ ๊ทธ๋๋ก ๋๊ตฌ๊ฐ ๋จ. docstringยทํ์ ํํธ๊ฐ nameยทdescriptionยทinputSchema๋ก ์๋ ๋ณํ
- tools=[...] ๋ฑ๋ก โ ๋ชจ๋ธ์ด ์ ํํ ์ ์๋ ํ๋ ๋ชฉ๋ก. ๋ฆฌ์คํธ์ ๋ด๋ ์๊ฐ ReAct ๋ฃจํ์ ์ ํ์ง
- ์คํ โ ํธ์ถ ์ฌ๋ถยท์ธ์๋ฅผ ๋ชจ๋ธ์ด ์ค์ค๋ก ๊ฒฐ์ ํ๊ณ , Observation์ ์ข ํฉํด ์ต์ข ๋ต๋ณ
๋๊ตฌ ์คํค๋ง 3์์
LLM์ด ๋๊ตฌ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ ํํ๊ธฐ ์ํ ํ์ ์ ๋ณด
name
๋์ฌ+๋ช ์ฌ ํจํด โ search_restaurants, get_weather, create_ticket
description
์ธ์ ์ฐ๋์ง + ์ ๋ ฅ ํ์ + ๋ฐํ๊ฐ โ ๋๊ตฌ ์ ํ์ ์ ์ผํ ๊ทผ๊ฑฐ
inputSchema
required/optional ๊ตฌ๋ถ, ํ์ ์ ์ฝ, enum์ผ๋ก ์ ๋ ฅ ๊ฒ์ฆ
name์ผ๋ก 1์ฐจ ํํฐ๋ง, description์ผ๋ก ์ต์ข ์ ํ, inputSchema๋ก ์ ๋ ฅ ๊ฒ์ฆ โ ์ธ ์์๊ฐ ํจ๊ป ๋๊ตฌ ์ ํ ์ ํ๋๋ฅผ ๋ง๋ญ๋๋ค.
๋๊ตฌ ์ค๊ณ ์์น
์ข์ ๋๊ตฌ = LLM์ด ์ ํํ ์ ํํ๊ณ ์์ ํ๊ฒ ์คํ
| ์์น | ์ข์ ์ | ๋์ ์ |
|---|---|---|
| ๋จ์ผ ์ฑ ์ | search_restaurants (๊ฒ์๋ง) | manage_restaurant (๊ฒ์+์์ฝ+์ทจ์) |
| ๋ช ํํ ์ด๋ฆ | get_weather (๋์ฌ+๋ช ์ฌ) | do_stuff, helper, process |
| ๊ตฌ์ฒด์ ์ค๋ช | "๋น์ฉ ์ง๋ฌธ ์ ํธ์ถ. service, period ํ์" | "๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค" |
| ๊ตฌ์กฐํ ๋ฐํ | JSON: {name, rating, price} | ์์ ํ์ ํ ์คํธ |
| ์๋ฌ ๋ฉ์์ง | {"error": "์๋น์ค๋ช ์ด ์ ํจํ์ง ์์ต๋๋ค"} | ๋น ๋ฌธ์์ด ๋๋ ์์ธ |
ํ ๋๊ตฌ๋ ํ ๊ฐ์ง ์ผ๋ง ํ๊ณ , ๋ฐํ์ ๊ตฌ์กฐํํ๋ฉฐ, ์๋ฌ์๋ ์ด์ ๋ฅผ ๋ด์ต๋๋ค โ LLM์ด ๋ค์ ํ๋จ์ ์ด์ด๊ฐ ์ ์๋ ํํ๋ก ๋๋ ค์ฃผ๋ ๊ฒ์ด ํต์ฌ์ ๋๋ค.
Human-in-the-Loop
์์ด์ ํธ ์ค๋ฅ ยท ๋๊ตฌ ๋ถ๋ฅ ยท HITL 3ํจํด ยท ๊ตฌํ
Human-in-the-Loop
์์ด์ ํธ์ ์คํจ ๋ฐฉ์์ ์๊ณ ์ํํ ํธ์ถ ์์๋ง ์ฌ๋์ ํ์ธ์ ์ฌ๋ ์ค๊ณ
์ฝ๊ธฐ = ์๋ ยท ์ฐ๊ธฐ = ์น์ธ ยท ๊ณ ์ํ = ์ด์ค ํ์ธ
์์จ์ฑ์ด ๋์์๋ก ์ํ๋ ์ปค์ง๋๋ค โ ๋๊ตฌ๋ฅผ ์ํ๋๋ก ๋ถ๋ฅํ๊ณ ์ํํ ํธ์ถ ์์์๋ง ๋ฉ์ถฅ๋๋ค.
- ์คํจ ๋ฐฉ์ โ ํ๊ฐ ยท ์๋ชป๋ ๋๊ตฌ ์ ํ ยท ๋ฒ์ ์ด๊ณผ
- HITL 3ํจํด โ ์น์ธ ๊ฒ์ดํธ ยท ์์ค์ปฌ๋ ์ด์ ยท ๊ฐ์ฌ ๋ก๊ทธ
- Hook ๊ตฌํ โ BeforeToolCallEvent + event.interrupt()
- ์ค๊ณ ์์น โ ์ต์ ๊ถํ ยท ์ ์ง์ ์์จ ยท ์คํจ ์์
๋๊ตฌ๋ฅผ ์ฝ๊ธฐยท์ฐ๊ธฐยท๊ณ ์ํ์ผ๋ก ๋ถ๋ฅํ๊ณ ์ํํ ํธ์ถ๋ง ์ฌ๋์ด ํ์ธํฉ๋๋ค โ ์์ ๊ณผ ํจ์จ์ ๊ท ํ์ด HITL ์ค๊ณ์ ๋ชฉํ์ ๋๋ค.
์์ด์ ํธ๊ฐ ์คํจํ๋ ๋ฐฉ์
์์จ์ฑ์ ๋น๋กํด ์ปค์ง๋ ์ํ
ํ๊ฐ (Hallucination)
์กด์ฌํ์ง ์๋ ๋๊ตฌ๋ฅผ ํธ์ถํ๊ฑฐ๋ ์๋ชป๋ ํ๋ผ๋ฏธํฐ ์์ฑ
์๋ชป๋ ๋๊ตฌ ์ ํ
delete๋ฅผ ์จ์ผ ํ๋๋ฐ create๋ฅผ ํธ์ถ โ description ๋ชจํธ ์ ๋น๋ฒ
๋ฒ์ ์ด๊ณผ (Excessive Agency)
ํ์ฉ๋์ง ์์ ์์คํ ์ ์ ๊ทผ ์๋ โ OWASP LLM Top 10์ Excessive Agency ํญ๋ชฉ
์ธ ๊ฐ์ง ๋ชจ๋ ์์จ์ฑ์ด ๋ง๋๋ ์คํจ์ ๋๋ค โ ๋๊ตฌ ํผ๋์ description ์ฐจ๋ณํ๋ก, ๋ฒ์ ์ด๊ณผ๋ ์ต์ ๊ถํ ์์น์ผ๋ก ์ค์ ๋๋ค.
๋๊ตฌ ์ํ ๋ถ๋ฅ
์ฝ๊ธฐ = ์๋, ์ฐ๊ธฐ = ์น์ธ, ๊ณ ์ํ = ์ด์ค ํ์ธ
์ฝ๊ธฐ ์ ์ฉ (์กฐํ)
์๋ ์คํ ํ์ฉ
- search_restaurants
- get_weather
- query_status
์ธ์ โ ๋ถ์์ฉ ์์ โ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์์ด ์ ๋ณด๋ง ๋ฐํ
์ฐ๊ธฐ (๋ณ๊ฒฝ)
์ฌ์ฉ์ ์น์ธ ํ ์คํ
- create_reservation
- update_profile
- send_email
์ธ์ โ ๋๋๋ฆฌ๊ธฐ ์ด๋ ค์ด ๋ณ๊ฒฝ โ ์์ฑ/์์ /์ญ์
๊ณ ์ํ (๋น๊ฐ์ญ)
์ด์ค ํ์ธ + ๊ฐ์ฌ ๋ก๊ทธ
- cancel_order
- process_refund
- delete_account
์ธ์ โ ๊ธ์ ์ ์ํฅ, ๋ฐ์ดํฐ ์์ค, ๋ฒ์ ์ฑ ์
๋ถ์์ฉ์ด ์์ผ๋ฉด ์๋, ๋๋๋ฆฌ๊ธฐ ์ด๋ ค์ฐ๋ฉด ์น์ธ, ๊ธ์ ยท๋ฒ์ ์ํฅ์ด๋ฉด ์ด์ค ํ์ธ โ ๋ถ์์ฉ์ ํฌ๊ธฐ๊ฐ ๊ฒ์ดํธ์ ๊ฐ๋๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
HITL 3ํจํด
์ฌ๋์ด ์์ด์ ํธ๋ฅผ ์์ ํ๊ฒ ์ ์ดํ๋ ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ
-
1
์น์ธ ๊ฒ์ดํธ
- ์์ด์ ํธ ์คํ ์ผ์ ์ค์ง
- ์ฌ์ฉ์์๊ฒ ๋์ ์ค๋ช + ์น์ธ ์์ฒญ
- ์น์ธ โ ์คํ ์ฌ๊ฐ, ๊ฑฐ๋ถ โ ์ค๋จ
-
2
์์ค์ปฌ๋ ์ด์
- ๋ถํ์คํ ์์ฒญ ๊ฐ์ง
- ์ฌ๋(์๋ด์)์๊ฒ ์ ํ
- ํด๊ฒฐ ํ ์์ด์ ํธ๋ก ๋ณต๊ท ๊ฐ๋ฅ
-
3
๊ฐ์ฌ ๋ก๊ทธ
- ๋๊ตฌ ํธ์ถ ์ด๋ ฅ ์ ๋ถ ์ ์ฅ
- ๋น์ ์ ํจํด ํ์ง
- ์ ์ฑ ๊ท์น ์ ๋ฐ์ดํธ ๊ทผ๊ฑฐ
์น์ธ ๊ฒ์ดํธ๋ ์คํ ์ ์, ์์ค์ปฌ๋ ์ด์ ์ ํ๋จ์ด ๋งํ ๋, ๊ฐ์ฌ ๋ก๊ทธ๋ ์คํ ํ์ ์๋ํฉ๋๋ค โ ์์ ์ด ๋ค๋ฅธ ์ธ ๊ฒน์ ์์ ์ฅ์น์ ๋๋ค.
Hook ๊ธฐ๋ฐ ์น์ธ ๊ฒ์ดํธ
Strands SDK๋ก HITL ๊ตฌํ
from strands.hooks import BeforeToolCallEvent, HookProvider, HookRegistry
# โ Hook ์ ์ โ ๋๊ตฌ ์คํ ์ง์ (BeforeToolCallEvent)์ ๊ฐ์
class ApprovalGate(HookProvider):
"""๊ณ ์ํ ๋๊ตฌ ํธ์ถ ์ ์ฌ์ฉ์ ์น์ธ์ ์์ฒญํ๋ Hook"""
def register_hooks(self, registry: HookRegistry):
registry.add_callback(BeforeToolCallEvent, self.check)
def check(self, event: BeforeToolCallEvent):
# โก ์ฐ๊ธฐ/์ญ์ ๋๊ตฌ๋ง ์น์ธ ์์ฒญ โ ์ฝ๊ธฐ ๋๊ตฌ๋ ํต๊ณผ
dangerous = ["cancel_reservation", "delete_account"]
if event.tool_use["name"] in dangerous:
event.interrupt(
"approval_needed",
reason=f"'{event.tool_use['name']}' ์คํ์ ์น์ธํ์๊ฒ ์ต๋๊น?"
)
# โข ์์ด์ ํธ์ Hook ์ ์ฉ
agent = Agent(
model="us.anthropic.claude-sonnet-4-6",
tools=[cancel_reservation, search_restaurants],
hooks=[ApprovalGate()]
)
- BeforeToolCallEvent โ ๋๊ตฌ๊ฐ ์ค์ ๋ก ์คํ๋๊ธฐ ์ง์ ์ ๊ฐ์ ์ง์ . ์ฌ๊ธฐ์ ๋ฉ์ถ๋ฉด ๋๊ตฌ๋ ์คํ๋์ง ์์
- ์ ๋ณ ์น์ธ โ ๊ณ ์ํ ๋๊ตฌ๋ง event.interrupt()๋ก ์ผ์ ์ค์ง. ์น์ธ โ ์ฌ๊ฐ, ๊ฑฐ๋ถ โ ์ค๋จ
- hooks=[...] โ Agent์ ๋ถ์ด๋ ์๊ฐ ๋ชจ๋ ๋๊ตฌ ํธ์ถ์ด ์ด ๊ฒ์ดํธ๋ฅผ ๊ฑฐ์นจ. ๋๊ตฌ ์ฝ๋๋ ๋ฌด๋ณ๊ฒฝ
HITL ์ค๊ณ ์์น
์์ ๊ณผ ํจ์จ์ ๊ท ํ
์ต์ ๊ถํ ยท ์ ์ง์ ์์จ ยท ์คํจ ์์
ํ์ํ ๋๊ตฌ๋ง ์ ๊ณตํ๊ณ , ์ ๋ขฐ๊ฐ ์์ด๋ฉด ์๋ ์น์ธ์ ํ๋ํ๋ฉฐ, ์ค๋ฅ ์ ๋ฐ๋์ ์ค๋จํฉ๋๋ค
- Least Privilege
- Graduated Autonomy
- Fail-Safe
๋๊ตฌ ยท ๋ฃจํ ยท ์์ ์ฅ์น๋ฅผ ๊ฐ์ถ ์์คํ ์ค๊ณ