Home / ์—์ด์ „ํŠธ ๊ธฐ์ดˆ / ๐Ÿ“ ์—์ด์ „ํŠธ ๋„๊ตฌ ์„ค๊ณ„
Note

๐Ÿ“ ์—์ด์ „ํŠธ ๋„๊ตฌ ์„ค๊ณ„

๋„๊ตฌ ์ •์˜, ์„ค๊ณ„ ํŒจํ„ด, ๋„๊ตฌ ํ…Œ์ŠคํŠธ

โฑ 35๋ถ„ 70 / 189

์—์ด์ „ํŠธ ๋„๊ตฌ ์„ค๊ณ„

๋„๊ตฌ ์ •์˜, ์„ค๊ณ„ ํŒจํ„ด, ๋„๊ตฌ ํ…Œ์ŠคํŠธ

๋„๊ตฌ๋ฅผ ์“ฐ๋Š” AI๊ฐ€ ์—์ด์ „ํŠธ๋‹ค

LLM์ด ์ž์œจ์ ์œผ๋กœ ํŒ๋‹จํ•˜๊ณ  ํ–‰๋™ํ•˜๋Š” ์‹œ์Šคํ…œ์˜ ํ•ต์‹ฌ ์›๋ฆฌ

๋„๊ตฌ ์„ค๊ณ„

ํ•จ์ˆ˜ vs ๋„๊ตฌ ยท @tool ๋ณ€ํ™˜ ยท ์Šคํ‚ค๋งˆ ยท ์„ค๊ณ„ ์›์น™

PART 3 ยท ๋„๊ตฌ ์„ค๊ณ„

๋„๊ตฌ ์„ค๊ณ„

์ผ๋ฐ˜ ํ•จ์ˆ˜๊ฐ€ LLM์ด ์“ธ ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๊ฐ€ ๋˜๊ธฐ๊นŒ์ง€์˜ ์„ค๊ณ„ ์š”์†Œ ์กฐ๊ฐ

๋„๊ตฌ = ํ•จ์ˆ˜ + JSON Schema

LLM์€ ์ฝ”๋“œ๋ฅผ ์ฝ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค โ€” nameยทdescriptionยทinputSchema ์„ค๋ช…์„œ๊ฐ€ ๋„๊ตฌ ์„ ํƒ์˜ ์œ ์ผํ•œ ๊ทผ๊ฑฐ์ž…๋‹ˆ๋‹ค.

  • ํ•จ์ˆ˜ vs ๋„๊ตฌ โ€” ํ˜ธ์ถœ ์ฃผ์ฒด๊ฐ€ ๊ฐœ๋ฐœ์ž์—์„œ LLM์œผ๋กœ
  • @tool ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ โ€” Python ํ•จ์ˆ˜๋ฅผ ๋„๊ตฌ๋กœ ์ž๋™ ๋ณ€ํ™˜
  • ์Šคํ‚ค๋งˆ 3์š”์†Œ โ€” name ยท description ยท inputSchema
  • ์„ค๊ณ„ ์›์น™ โ€” ๋‹จ์ผ ์ฑ…์ž„ ยท ๊ตฌ์กฐํ™” ๋ฐ˜ํ™˜ ยท ๋ช…ํ™•ํ•œ ์—๋Ÿฌ
takeaway

์ข‹์€ description์€ "์–ธ์ œ + ๋ญ˜ ๋„ฃ๊ณ  + ๋ญ˜ ๋ฐ›๋‚˜ + ์ฃผ์˜์‚ฌํ•ญ"์„ ๋‹ด์Šต๋‹ˆ๋‹ค โ€” ์„ค๋ช…์„œ ํ’ˆ์งˆ์ด ๋„๊ตฌ ์„ ํƒ ์ •ํ™•๋„๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

PART 3 ยท ๋„๊ตฌ ์„ค๊ณ„

ํ•จ์ˆ˜ vs ๋„๊ตฌ

ํ•จ์ˆ˜๋ฅผ ๋„๊ตฌ๋กœ ๋งŒ๋“œ๋Š” ์กฐ๊ฑด โ€” JSON Schema(์„ค๋ช…์„œ)

์ผ๋ฐ˜ ํ•จ์ˆ˜

๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ˜ธ์ถœ

  • ํ˜ธ์ถœ ์ฃผ์ฒด: ๊ฐœ๋ฐœ์ž (์ฝ”๋“œ์—์„œ ์ง์ ‘)
  • ์„ค๋ช… ๋ถˆํ•„์š” โ€” ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋จ
  • ํŒŒ๋ผ๋ฏธํ„ฐ: ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜
  • ์„ ํƒ ๊ธฐ์ค€: ๊ฐœ๋ฐœ์ž ํŒ๋‹จ

๊ฐœ๋ฐœ์ž๊ฐ€ ํ•จ์ˆ˜๋ช…๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ถ”๊ฐ€ ์„ค๋ช… ์—†์ด ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์—์ด์ „ํŠธ ๋„๊ตฌ

LLM์ด ์ž์œจ ๊ฒฐ์ •

  • ํ˜ธ์ถœ ์ฃผ์ฒด: LLM (์ถ”๋ก  ํ›„ ์ž์œจ)
  • ์„ค๋ช… ํ•„์ˆ˜ โ€” LLM์€ ์ฝ”๋“œ๋ฅผ ๋ชป ์ฝ์Œ
  • ํŒŒ๋ผ๋ฏธํ„ฐ: JSON Schema
  • ์„ ํƒ ๊ธฐ์ค€: description ํ…์ŠคํŠธ

LLM์€ ์ฝ”๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, nameยทdescriptionยทinputSchema๋งŒ์œผ๋กœ "์ด ๋„๊ตฌ๋ฅผ ์ง€๊ธˆ ์จ์•ผ ํ•˜๋‚˜" ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค.

PART 3 ยท ๋„๊ตฌ ์„ค๊ณ„

@tool ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ

Python ํ•จ์ˆ˜๋ฅผ ์—์ด์ „ํŠธ ๋„๊ตฌ๋กœ ์ž๋™ ๋ณ€ํ™˜

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์„ ์ข…ํ•ฉํ•ด ์ตœ์ข… ๋‹ต๋ณ€
PART 3 ยท ๋„๊ตฌ ์„ค๊ณ„

๋„๊ตฌ ์Šคํ‚ค๋งˆ 3์š”์†Œ

LLM์ด ๋„๊ตฌ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•œ ํ•„์ˆ˜ ์ •๋ณด

name

๋™์‚ฌ+๋ช…์‚ฌ ํŒจํ„ด โ€” search_restaurants, get_weather, create_ticket

description

์–ธ์ œ ์“ฐ๋Š”์ง€ + ์ž…๋ ฅ ํ˜•์‹ + ๋ฐ˜ํ™˜๊ฐ’ โ€” ๋„๊ตฌ ์„ ํƒ์˜ ์œ ์ผํ•œ ๊ทผ๊ฑฐ

inputSchema

required/optional ๊ตฌ๋ถ„, ํƒ€์ž… ์ œ์•ฝ, enum์œผ๋กœ ์ž…๋ ฅ ๊ฒ€์ฆ

takeaway

name์œผ๋กœ 1์ฐจ ํ•„ํ„ฐ๋ง, description์œผ๋กœ ์ตœ์ข… ์„ ํƒ, inputSchema๋กœ ์ž…๋ ฅ ๊ฒ€์ฆ โ€” ์„ธ ์š”์†Œ๊ฐ€ ํ•จ๊ป˜ ๋„๊ตฌ ์„ ํƒ ์ •ํ™•๋„๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

PART 3 ยท ๋„๊ตฌ ์„ค๊ณ„

๋„๊ตฌ ์„ค๊ณ„ ์›์น™

์ข‹์€ ๋„๊ตฌ = LLM์ด ์ •ํ™•ํžˆ ์„ ํƒํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์‹คํ–‰

์›์น™์ข‹์€ ์˜ˆ๋‚˜์œ ์˜ˆ
๋‹จ์ผ ์ฑ…์ž„search_restaurants (๊ฒ€์ƒ‰๋งŒ)manage_restaurant (๊ฒ€์ƒ‰+์˜ˆ์•ฝ+์ทจ์†Œ)
๋ช…ํ™•ํ•œ ์ด๋ฆ„get_weather (๋™์‚ฌ+๋ช…์‚ฌ)do_stuff, helper, process
๊ตฌ์ฒด์  ์„ค๋ช…"๋น„์šฉ ์งˆ๋ฌธ ์‹œ ํ˜ธ์ถœ. service, period ํ•„์ˆ˜""๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค"
๊ตฌ์กฐํ™” ๋ฐ˜ํ™˜JSON: {name, rating, price}์ž์œ  ํ˜•์‹ ํ…์ŠคํŠธ
์—๋Ÿฌ ๋ฉ”์‹œ์ง€{"error": "์„œ๋น„์Šค๋ช…์ด ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค"}๋นˆ ๋ฌธ์ž์—ด ๋˜๋Š” ์˜ˆ์™ธ
takeaway

ํ•œ ๋„๊ตฌ๋Š” ํ•œ ๊ฐ€์ง€ ์ผ๋งŒ ํ•˜๊ณ , ๋ฐ˜ํ™˜์€ ๊ตฌ์กฐํ™”ํ•˜๋ฉฐ, ์—๋Ÿฌ์—๋Š” ์ด์œ ๋ฅผ ๋‹ด์Šต๋‹ˆ๋‹ค โ€” LLM์ด ๋‹ค์Œ ํŒ๋‹จ์„ ์ด์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ๋Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

Human-in-the-Loop

์—์ด์ „ํŠธ ์˜ค๋ฅ˜ ยท ๋„๊ตฌ ๋ถ„๋ฅ˜ ยท HITL 3ํŒจํ„ด ยท ๊ตฌํ˜„

PART 4 ยท Human-in-the-Loop

Human-in-the-Loop

์—์ด์ „ํŠธ์˜ ์‹คํŒจ ๋ฐฉ์‹์„ ์•Œ๊ณ  ์œ„ํ—˜ํ•œ ํ˜ธ์ถœ ์•ž์—๋งŒ ์‚ฌ๋žŒ์˜ ํ™•์ธ์„ ์‹ฌ๋Š” ์„ค๊ณ„

์ฝ๊ธฐ = ์ž๋™ ยท ์“ฐ๊ธฐ = ์Šน์ธ ยท ๊ณ ์œ„ํ—˜ = ์ด์ค‘ ํ™•์ธ

์ž์œจ์„ฑ์ด ๋†’์„์ˆ˜๋ก ์œ„ํ—˜๋„ ์ปค์ง‘๋‹ˆ๋‹ค โ€” ๋„๊ตฌ๋ฅผ ์œ„ํ—˜๋„๋กœ ๋ถ„๋ฅ˜ํ•˜๊ณ  ์œ„ํ—˜ํ•œ ํ˜ธ์ถœ ์•ž์—์„œ๋งŒ ๋ฉˆ์ถฅ๋‹ˆ๋‹ค.

  • ์‹คํŒจ ๋ฐฉ์‹ โ€” ํ™˜๊ฐ ยท ์ž˜๋ชป๋œ ๋„๊ตฌ ์„ ํƒ ยท ๋ฒ”์œ„ ์ดˆ๊ณผ
  • HITL 3ํŒจํ„ด โ€” ์Šน์ธ ๊ฒŒ์ดํŠธ ยท ์—์Šค์ปฌ๋ ˆ์ด์…˜ ยท ๊ฐ์‚ฌ ๋กœ๊ทธ
  • Hook ๊ตฌํ˜„ โ€” BeforeToolCallEvent + event.interrupt()
  • ์„ค๊ณ„ ์›์น™ โ€” ์ตœ์†Œ ๊ถŒํ•œ ยท ์ ์ง„์  ์ž์œจ ยท ์‹คํŒจ ์•ˆ์ „
takeaway

๋„๊ตฌ๋ฅผ ์ฝ๊ธฐยท์“ฐ๊ธฐยท๊ณ ์œ„ํ—˜์œผ๋กœ ๋ถ„๋ฅ˜ํ•˜๊ณ  ์œ„ํ—˜ํ•œ ํ˜ธ์ถœ๋งŒ ์‚ฌ๋žŒ์ด ํ™•์ธํ•ฉ๋‹ˆ๋‹ค โ€” ์•ˆ์ „๊ณผ ํšจ์œจ์˜ ๊ท ํ˜•์ด HITL ์„ค๊ณ„์˜ ๋ชฉํ‘œ์ž…๋‹ˆ๋‹ค.

PART 4 ยท Human-in-the-Loop

์—์ด์ „ํŠธ๊ฐ€ ์‹คํŒจํ•˜๋Š” ๋ฐฉ์‹

์ž์œจ์„ฑ์— ๋น„๋ก€ํ•ด ์ปค์ง€๋Š” ์œ„ํ—˜

ํ™˜๊ฐ (Hallucination)

์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ฑ

์ž˜๋ชป๋œ ๋„๊ตฌ ์„ ํƒ

delete๋ฅผ ์จ์•ผ ํ•˜๋Š”๋ฐ create๋ฅผ ํ˜ธ์ถœ โ€” description ๋ชจํ˜ธ ์‹œ ๋นˆ๋ฒˆ

๋ฒ”์œ„ ์ดˆ๊ณผ (Excessive Agency)

ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ์‹œ์Šคํ…œ์— ์ ‘๊ทผ ์‹œ๋„ โ€” OWASP LLM Top 10์˜ Excessive Agency ํ•ญ๋ชฉ

takeaway

์„ธ ๊ฐ€์ง€ ๋ชจ๋‘ ์ž์œจ์„ฑ์ด ๋งŒ๋“œ๋Š” ์‹คํŒจ์ž…๋‹ˆ๋‹ค โ€” ๋„๊ตฌ ํ˜ผ๋™์€ description ์ฐจ๋ณ„ํ™”๋กœ, ๋ฒ”์œ„ ์ดˆ๊ณผ๋Š” ์ตœ์†Œ ๊ถŒํ•œ ์›์น™์œผ๋กœ ์ค„์ž…๋‹ˆ๋‹ค.

PART 4 ยท Human-in-the-Loop

๋„๊ตฌ ์œ„ํ—˜ ๋ถ„๋ฅ˜

์ฝ๊ธฐ = ์ž๋™, ์“ฐ๊ธฐ = ์Šน์ธ, ๊ณ ์œ„ํ—˜ = ์ด์ค‘ ํ™•์ธ

์ฝ๊ธฐ ์ „์šฉ (์กฐํšŒ)

์ž๋™ ์‹คํ–‰ ํ—ˆ์šฉ

  • search_restaurants
  • get_weather
  • query_status

์–ธ์ œ โ€” ๋ถ€์ž‘์šฉ ์—†์Œ โ€” ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์—†์ด ์ •๋ณด๋งŒ ๋ฐ˜ํ™˜

์“ฐ๊ธฐ (๋ณ€๊ฒฝ)

์‚ฌ์šฉ์ž ์Šน์ธ ํ›„ ์‹คํ–‰

  • create_reservation
  • update_profile
  • send_email

์–ธ์ œ โ€” ๋˜๋Œ๋ฆฌ๊ธฐ ์–ด๋ ค์šด ๋ณ€๊ฒฝ โ€” ์ƒ์„ฑ/์ˆ˜์ •/์‚ญ์ œ

๊ณ ์œ„ํ—˜ (๋น„๊ฐ€์—ญ)

์ด์ค‘ ํ™•์ธ + ๊ฐ์‚ฌ ๋กœ๊ทธ

  • cancel_order
  • process_refund
  • delete_account

์–ธ์ œ โ€” ๊ธˆ์ „์  ์˜ํ–ฅ, ๋ฐ์ดํ„ฐ ์†์‹ค, ๋ฒ•์  ์ฑ…์ž„

takeaway

๋ถ€์ž‘์šฉ์ด ์—†์œผ๋ฉด ์ž๋™, ๋˜๋Œ๋ฆฌ๊ธฐ ์–ด๋ ค์šฐ๋ฉด ์Šน์ธ, ๊ธˆ์ „ยท๋ฒ•์  ์˜ํ–ฅ์ด๋ฉด ์ด์ค‘ ํ™•์ธ โ€” ๋ถ€์ž‘์šฉ์˜ ํฌ๊ธฐ๊ฐ€ ๊ฒŒ์ดํŠธ์˜ ๊ฐ•๋„๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

PART 4 ยท Human-in-the-Loop

HITL 3ํŒจํ„ด

์‚ฌ๋žŒ์ด ์—์ด์ „ํŠธ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ œ์–ดํ•˜๋Š” ์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•

  1. 1
    ์Šน์ธ ๊ฒŒ์ดํŠธ
    • ์—์ด์ „ํŠธ ์‹คํ–‰ ์ผ์‹œ ์ค‘์ง€
    • ์‚ฌ์šฉ์ž์—๊ฒŒ ๋™์ž‘ ์„ค๋ช… + ์Šน์ธ ์š”์ฒญ
    • ์Šน์ธ โ†’ ์‹คํ–‰ ์žฌ๊ฐœ, ๊ฑฐ๋ถ€ โ†’ ์ค‘๋‹จ
  2. 2
    ์—์Šค์ปฌ๋ ˆ์ด์…˜
    • ๋ถˆํ™•์‹คํ•œ ์š”์ฒญ ๊ฐ์ง€
    • ์‚ฌ๋žŒ(์ƒ๋‹ด์›)์—๊ฒŒ ์ „ํ™˜
    • ํ•ด๊ฒฐ ํ›„ ์—์ด์ „ํŠธ๋กœ ๋ณต๊ท€ ๊ฐ€๋Šฅ
  3. 3
    ๊ฐ์‚ฌ ๋กœ๊ทธ
    • ๋„๊ตฌ ํ˜ธ์ถœ ์ด๋ ฅ ์ „๋ถ€ ์ €์žฅ
    • ๋น„์ •์ƒ ํŒจํ„ด ํƒ์ง€
    • ์ •์ฑ… ๊ทœ์น™ ์—…๋ฐ์ดํŠธ ๊ทผ๊ฑฐ
takeaway

์Šน์ธ ๊ฒŒ์ดํŠธ๋Š” ์‹คํ–‰ ์ „์—, ์—์Šค์ปฌ๋ ˆ์ด์…˜์€ ํŒ๋‹จ์ด ๋ง‰ํž ๋•Œ, ๊ฐ์‚ฌ ๋กœ๊ทธ๋Š” ์‹คํ–‰ ํ›„์— ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค โ€” ์‹œ์ ์ด ๋‹ค๋ฅธ ์„ธ ๊ฒน์˜ ์•ˆ์ „์žฅ์น˜์ž…๋‹ˆ๋‹ค.

PART 4 ยท Human-in-the-Loop

Hook ๊ธฐ๋ฐ˜ ์Šน์ธ ๊ฒŒ์ดํŠธ

Strands SDK๋กœ HITL ๊ตฌํ˜„

python
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์— ๋ถ™์ด๋Š” ์ˆœ๊ฐ„ ๋ชจ๋“  ๋„๊ตฌ ํ˜ธ์ถœ์ด ์ด ๊ฒŒ์ดํŠธ๋ฅผ ๊ฑฐ์นจ. ๋„๊ตฌ ์ฝ”๋“œ๋Š” ๋ฌด๋ณ€๊ฒฝ
PART 4 ยท Human-in-the-Loop

HITL ์„ค๊ณ„ ์›์น™

์•ˆ์ „๊ณผ ํšจ์œจ์˜ ๊ท ํ˜•

์ตœ์†Œ ๊ถŒํ•œ ยท ์ ์ง„์  ์ž์œจ ยท ์‹คํŒจ ์•ˆ์ „

ํ•„์š”ํ•œ ๋„๊ตฌ๋งŒ ์ œ๊ณตํ•˜๊ณ , ์‹ ๋ขฐ๊ฐ€ ์Œ“์ด๋ฉด ์ž๋™ ์Šน์ธ์„ ํ™•๋Œ€ํ•˜๋ฉฐ, ์˜ค๋ฅ˜ ์‹œ ๋ฐ˜๋“œ์‹œ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค

  • Least Privilege
  • Graduated Autonomy
  • Fail-Safe
์—์ด์ „ํŠธ๋Š” ๋ชจ๋ธ์ด ์•„๋‹ˆ๋ผ ํ•˜๋„ค์Šค๊ฐ€ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋„๊ตฌ ยท ๋ฃจํ”„ ยท ์•ˆ์ „์žฅ์น˜๋ฅผ ๊ฐ–์ถ˜ ์‹œ์Šคํ…œ ์„ค๊ณ„