Home / Strands ํ™•์žฅ๊ณผ ์•ˆ์ „ / ๐ŸŽฏ Strands ์ œ์–ด์™€ ํ™•์žฅ
Module

๐ŸŽฏ Strands ์ œ์–ด์™€ ํ™•์žฅ

Hooks, Plugins, Interventions, Sandbox

โฑ 60๋ถ„ 92 / 189

Strands ์ œ์–ด์™€ ํ™•์žฅ

Hooks ยท Plugins ยท Interventions ยท Sandbox

์—์ด์ „ํŠธ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ œ์–ดํ•œ๋‹ค

Hooks์—์„œ Sandbox๊นŒ์ง€ โ€” 4๊ณ„์ธต ์ œ์–ด ์ฒด๊ณ„

์ œ์–ด์™€ ํ™•์žฅ ์ฒด๊ณ„

4๊ณ„์ธต ๋ฐฉ์–ด ์‹ฌ๋„

PART 1 ยท ์ œ์–ด์™€ ํ™•์žฅ ์ฒด๊ณ„

์ž์œจ์— ํ•„์š”ํ•œ ๊ฒฝ๊ณ„

๋ชจ๋ธ์ด ์Šค์Šค๋กœ ๋„๊ตฌ์™€ ๋ฐ˜๋ณต์„ ๊ฒฐ์ •ํ•˜๋Š” ์—์ด์ „ํŠธ โ€” ํ†ต์ œ ์—†๋Š” ์ž์œจ์ด ๋งŒ๋“œ๋Š” ์‚ฌ๊ณ ๋“ค

์œ„ํ—˜ ๋„๊ตฌ ์‹คํ–‰

๋ชจ๋ธ์ด ๊ณ ๋ฅธ ๋„๊ตฌ๊ฐ€ ํ•ญ์ƒ ์•ˆ์ „ํ•˜์ง€๋Š” ์•Š์Œ

๋น„์šฉ ํญ์ฃผ

๋ฃจํ”„๊ฐ€ ๋Œ ๋•Œ๋งˆ๋‹ค ํ† ํฐ ๊ณผ๊ธˆ โ€” ์ƒํ•œ ์—†๋Š” ์žฌ์‹œ๋„

๋ฌดํ•œ ๋ฃจํ”„

๊ฐ™์€ ๋„๊ตฌ๋ฅผ ๊ณ„์† ๋ฐ˜๋ณต โ€” ์Šค์Šค๋กœ๋Š” ๋ฉˆ์ถ”์ง€ ๋ชปํ•จ

๋ฐ์ดํ„ฐ ์œ ์ถœ

๋„๊ตฌ ๊ฒฐ๊ณผ์™€ ์‘๋‹ต์— ๋ฏผ๊ฐ ์ •๋ณด๊ฐ€ ์„ž์—ฌ ๋‚˜๊ฐ

takeaway

์ž์œจ์„ฑ์„ ์ฃฝ์ด์ง€ ์•Š๊ณ  ๊ฒฝ๊ณ„๋ฅผ ์„ธ์šฐ๋Š” ๊ฒƒ โ€” ๊ทธ ํ•ด๋ฒ•์ด ์ง€๊ธˆ๋ถ€ํ„ฐ ๋ณผ ์ œ์–ด 4๊ณ„์ธต์ž…๋‹ˆ๋‹ค.

PART 1 ยท ์ œ์–ด์™€ ํ™•์žฅ ์ฒด๊ณ„

์ œ์–ด์˜ 4๊ณ„์ธต

์ž์œจ์€ ๋‚จ๊ธฐ๊ณ  ๊ฒฝ๊ณ„๋งŒ ์„ธ์šฐ๋Š” 4๊ณ„์ธต โ€” ๊ฐ€๋ณ๊ฒŒ๋Š” Hooks, ์ตœํ›„์—๋Š” Sandbox

Sandbox

์‹คํ–‰ ํ™˜๊ฒฝ ์ž์ฒด๋ฅผ ๊ฒฉ๋ฆฌ โ€” ์ตœํ›„์˜ ๋ฐฉ์–ด์„ 

Interventions

Cedar ์ •์ฑ…์œผ๋กœ ๋™์ž‘ ํ—ˆ์šฉ/๊ฑฐ๋ถ€ ํŒ์ •

Plugins

deny/steer ์ •์ฑ… ์ œ์–ด ๋“ฑ ํ™•์žฅ ๋ชจ๋“ˆ ๋ถ€์ฐฉ

Hooks

์ด๋ฒคํŠธ ์ฝœ๋ฐฑ์œผ๋กœ ๊ด€์ฐฐยท๊ฐœ์ž… โ€” ๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ์ œ์–ด

PART 1 ยท ์ œ์–ด์™€ ํ™•์žฅ ์ฒด๊ณ„

๊ณ„์ธต๋ณ„ ๋น„๊ต

์ ์šฉ ์‹œ์ ยท์ˆ˜์ค€ยท๊ตฌํ˜„ ๋ฐฉ์‹์ด ๋ชจ๋‘ ๋‹ค๋ฅธ 4๊ฐœ ๋ ˆ์ด์–ด

๊ณ„์ธต์ ์šฉ ์‹œ์ ์ œ์–ด ์ˆ˜์ค€๊ตฌํ˜„ ๋ฐฉ์‹
Hooks์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ๊ด€์ฐฐ + ์„ ํƒ์  ์ค‘๋‹จ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋“ฑ๋ก
Plugins์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™” ์‹œ์ •์ฑ… ์ œ์–ดยท๊ธฐ๋Šฅ ์ฃผ์ž…ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค ๋ถ€์ฐฉ
Interventions๋„๊ตฌ ํ˜ธ์ถœ ์ง์ „ํ—ˆ์šฉ/๊ฑฐ๋ถ€/์Šน์ธ ๋Œ€๊ธฐCedar ์ •์ฑ… ํŒŒ์ผ
Sandboxํ”„๋กœ์„ธ์Šค ์‹œ์ž‘ ์ „ํ™˜๊ฒฝ ๊ฒฉ๋ฆฌDocker/SSH ์„ค์ •
takeaway

๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด Hooks๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด ํ•„์š”ํ•œ ๋งŒํผ ์•„๋ž˜ ๊ณ„์ธต์„ ๋”ํ•ฉ๋‹ˆ๋‹ค โ€” ๋„ค ์ธต์„ ๋‹ค ์“ฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์›Œํฌ๋กœ๋“œ์˜ ์œ„ํ—˜๋„๋งŒํผ ์”๋‹ˆ๋‹ค.

PART 1 ยท ์ œ์–ด์™€ ํ™•์žฅ ์ฒด๊ณ„

์š”์ฒญ์ด ์ง€๋‚˜๋Š” ๊ด€๋ฌธ ์ˆœ์„œ

Hook ๊ฒ€์‚ฌ โ†’ Plugin ์ •์ฑ… โ†’ Intervention ํŒ์ • โ†’ Sandbox ๊ฒฉ๋ฆฌ โ€” ๋„ค ๊ณ„์ธต์ด ๋ฒˆ๊ฐˆ์•„ ๊ฐœ์ž…ํ•˜๋Š” ๊ฒฝ๋กœ

  1. 1
    Hook: BeforeModelCallEvent

    ๋ชจ๋ธ ํ˜ธ์ถœ ์ „ ๊ฒ€์‚ฌ โ€” ํ”„๋กฌํ”„ํŠธ ๊ฒ€์ฆ, ๋น„์šฉ ์ฒดํฌ

  2. 2
    Plugin: ์ •์ฑ… ํ™•์ธ

    deny/steer ๊ทœ์น™ ํ‰๊ฐ€ โ€” ์œ„๋ฐ˜ ์‹œ ์ฐจ๋‹จํ•˜๊ฑฐ๋‚˜ ๋ฐฉํ–ฅ ์ˆ˜์ •

  3. 3
    Hook: BeforeToolCallEvent

    ๋„๊ตฌ ํ˜ธ์ถœ ์ „ ์ธ์ž ๊ฒ€์ฆยท๋กœ๊น…

  4. 4
    Intervention: ํŒ์ •

    Cedar ์ •์ฑ…์ด permit/forbid ํŒ์ •, HumanInTheLoop์ด ๋ฏผ๊ฐ ๋„๊ตฌ ์Šน์ธ ์š”๊ตฌ โ€” ๋ณ„๊ฐœ ํด๋ž˜์Šค

  5. 5
    Sandbox: ๊ฒฉ๋ฆฌ ์‹คํ–‰

    ํ—ˆ์šฉ๋œ ๋„๊ตฌ๋ฅผ ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์—์„œ ์‹คํ–‰

takeaway

ํ•œ ๊ด€๋ฌธ์ด๋ผ๋„ ๋ง‰ํžˆ๋ฉด ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ๊ฒน๊ฒน์˜ ๊ด€๋ฌธ์ด ๊ณง ๋ฐฉ์–ด ์‹ฌ๋„์ž…๋‹ˆ๋‹ค.

Hooks

Event Callbacks ยท cancel_tool ยท ๋ฃจํ”„ ์ œ์–ด

PART 2 ยท Hooks

Hooks

๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ์ œ์–ด ๊ณ„์ธต โ€” ์ด๋ฒคํŠธ๋งˆ๋‹ค ์ฝœ๋ฐฑ์„ ๊ฑธ์–ด ๊ด€์ฐฐํ•˜๊ณ  ๊ฐœ์ž…

Hooks

์—์ด์ „ํ‹ฑ ๋ฃจํ”„์˜ ๋ชจ๋“  ์ง€์ ์—์„œ ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ์œผ๋กœ ๊ด€์ฐฐํ•˜๊ณ , ํ•„์š”ํ•˜๋ฉด ๊ฐœ์ž…ํ•ฉ๋‹ˆ๋‹ค.

  • ์ด๋ฒคํŠธ 8์ข… โ€” ๋ฃจํ”„ ์ „ ๊ตฌ๊ฐ„ ์ปค๋ฒ„
  • cancel_tool โ€” ๋„๊ตฌ ์‹คํ–‰ ์ทจ์†Œ
  • ๊ธฐ์กด ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ๋ถ€์ฐฉ
  • ๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ์ œ์–ด
takeaway

๊ด€์ฐฐ์ด ๋จผ์ €์ž…๋‹ˆ๋‹ค โ€” ๋ณด์ด์ง€ ์•Š์œผ๋ฉด ์ œ์–ดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค

PART 2 ยท Hooks

8๊ฐ€์ง€ Hook Event

์—์ด์ „ํ‹ฑ ๋ฃจํ”„ ์ „ ๊ตฌ๊ฐ„์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•ํƒ€์ž… ์ด๋ฒคํŠธ ํฌ์ธํŠธ

Hook Event๋ฐœ์ƒ ์‹œ์ ์ฃผ์š” ์šฉ๋„
AgentInitializedEvent์—์ด์ „ํŠธ ์ƒ์„ฑ์ž ์™„๋ฃŒ ํ›„์ดˆ๊ธฐ ์„ค์ • ๊ฒ€์ฆ, ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ฐ”์ธ๋”ฉ
BeforeInvocationEvent์—์ด์ „ํŠธ ํ˜ธ์ถœ ์‹œ์ž‘ ์ „์š”์ฒญ ๋กœ๊น…, ์นด์šดํ„ฐ ๋ฆฌ์…‹
BeforeModelCallEvent๋ชจ๋ธ ์ถ”๋ก  ํ˜ธ์ถœ ์ง์ „ํ”„๋กฌํ”„ํŠธ ๊ฒ€์ฆ, ๋น„์šฉ ์‚ฌ์ „ ์ฒดํฌ
AfterModelCallEvent๋ชจ๋ธ ์‘๋‹ต ์ˆ˜์‹  ํ›„์‘๋‹ต ํ•„ํ„ฐ๋ง, ์žฌ์‹œ๋„ ํŒ์ •
BeforeToolCallEvent๋„๊ตฌ ์‹คํ–‰ ์ง์ „์ธ์ž ๊ฒ€์ฆ, ์œ„ํ—˜ ๋„๊ตฌ ์ฐจ๋‹จ/๊ต์ฒด
AfterToolCallEvent๋„๊ตฌ ์‹คํ–‰ ์™„๋ฃŒ ํ›„๊ฒฐ๊ณผ ์ˆ˜์ •, ์žฌ์‹œ๋„ ํŒ์ •
MessageAddedEvent๋Œ€ํ™” ์ด๋ ฅ์— ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€ ์‹œ๋กœ๊น…, ๋ฉ”์‹œ์ง€ ๊ฐ์‚ฌ
AfterInvocationEvent์—์ด์ „ํŠธ ํ˜ธ์ถœ ์ข…๋ฃŒ ํ›„์ตœ์ข… ์‘๋‹ต ๊ฒ€์‚ฌ, ๊ฐ์‚ฌ ๋กœ๊น…
takeaway

Before ์ด๋ฒคํŠธ๋Š” ๋ง‰์„ ์ˆ˜ ์žˆ๋Š” ์ง€์ , After ์ด๋ฒคํŠธ๋Š” ๋ฐ”๋กœ์žก์„ ์ˆ˜ ์žˆ๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค โ€” ๊ฐœ์ž… ์œ„์น˜ ์„ ํƒ์ด ๊ณง ์ œ์–ด ์ „๋žต์ž…๋‹ˆ๋‹ค.

PART 2 ยท Hooks

Hook ๋“ฑ๋ก

HookProvider ํ”„๋กœํ† ์ฝœ๋กœ ๊ธฐ์กด ์—์ด์ „ํŠธ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ์ฝœ๋ฐฑ ๋ถ€์ฐฉ

python
from strands import Agent
from strands.hooks import BeforeToolCallEvent, HookProvider, HookRegistry

class BlockDangerousTools(HookProvider):
    """์œ„ํ—˜ ๋„๊ตฌ ํ˜ธ์ถœ์„ ์‚ฌ์ „ ์ฐจ๋‹จ"""
    BLOCKED = {"delete_file", "drop_table", "rm_rf"}

    def register_hooks(self, registry: HookRegistry, **kwargs) -> None:
        registry.add_callback(BeforeToolCallEvent, self.check_tool)

    def check_tool(self, event: BeforeToolCallEvent) -> None:
        tool_name = event.tool_use["name"]
        if tool_name in self.BLOCKED:
            event.cancel_tool = f"Blocked: {tool_name} is not allowed"

agent = Agent(
    model="us.anthropic.claude-sonnet-4-6",
    hooks=[BlockDangerousTools()],
)
PART 2 ยท Hooks

Hooks ๊ฐœ์ž… ํŒจํ„ด

๊ด€์ฐฐ์—์„œ ๊ฐœ์ž…์œผ๋กœ โ€” ์ทจ์†Œยท์˜ˆ์™ธยท๋งˆ์Šคํ‚น์„ ์กฐํ•ฉํ•œ 4๊ฐ€์ง€ ๋Œ€ํ‘œ ์‹œ๋‚˜๋ฆฌ์˜ค

๋น„์šฉ ํญ์ฃผ ์ฐจ๋‹จ

ํ† ํฐ ์‚ฌ์šฉ๋Ÿ‰์ด ์ž„๊ณ„๊ฐ’ ์ดˆ๊ณผ ์‹œ ์ฆ‰์‹œ ์ค‘๋‹จ

์œ„ํ—˜ ๋„๊ตฌ ์ฐจ๋‹จ

ํ—ˆ์šฉ ๋ชฉ๋ก์— ์—†๋Š” ๋„๊ตฌ ํ˜ธ์ถœ ์‹œ ๊ฑฐ๋ถ€

๋ฌดํ•œ ๋ฃจํ”„ ํƒ์ง€

๋™์ผ ๋„๊ตฌ ๋ฐ˜๋ณต ํ˜ธ์ถœ ํŒจํ„ด ๊ฐ์ง€ ์‹œ ํƒˆ์ถœ

PII ์œ ์ถœ ๋ฐฉ์ง€

์‘๋‹ต์— ๊ฐœ์ธ์ •๋ณด ํŒจํ„ด ๊ฐ์ง€ ์‹œ ์ฐจ๋‹จ

takeaway

๋„ค ํŒจํ„ด์˜ ๋ผˆ๋Œ€๋Š” ๊ฐ™์Šต๋‹ˆ๋‹ค โ€” ์ด๋ฒคํŠธ์—์„œ ์กฐ๊ฑด์„ ๊ฒ€์‚ฌํ•˜๊ณ , cancel_toolยท์˜ˆ์™ธยท๋งˆ์Šคํ‚น์œผ๋กœ ๊ฐœ์ž…ํ•ฉ๋‹ˆ๋‹ค.

Plugins

AgentControlPlugin ยท Skills ยท ContextOffloader

PART 3 ยท Plugins

Plugins

ํ™•์žฅ ๊ณ„์ธต โ€” ์ œ์–ด ๋กœ์ง๊ณผ ๋„๊ตฌ๋ฅผ ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ๋กœ ๋ฌถ์–ด ์žฅ์ฐฉ

Plugins

ํ›…๊ณผ ๋„๊ตฌ๋ฅผ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋กœ ๋ฌถ์–ด ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™” ์‹œ ์žฅ์ฐฉํ•ฉ๋‹ˆ๋‹ค.

  • @hook + @tool ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ
  • AgentControlPlugin โ€” deny/steer ์ •์ฑ…
  • ContextOffloader โ€” ์ปจํ…์ŠคํŠธ ์ ˆ์•ฝ
  • ์ดˆ๊ธฐํ™” ์‹œ 1ํšŒ ์žฅ์ฐฉ
takeaway

์ •์ฑ…๊ณผ ๊ธฐ๋Šฅ์„ ๋ชจ๋“ˆ๋กœ โ€” ์—์ด์ „ํŠธ ์ฝ”๋“œ๋Š” ๊ทธ๋Œ€๋กœ ๋‘ก๋‹ˆ๋‹ค.

PART 3 ยท Plugins

ํ•ต์‹ฌ ํ”Œ๋Ÿฌ๊ทธ์ธ 5์ข…

์ •์ฑ… ์ œ์–ดยท์ง€์‹œ์–ด ๋กœ๋“œยท์ปจํ…์ŠคํŠธ ์˜คํ”„๋กœ๋”ฉยท๊ฐ€์ด๋˜์Šคยท์‹ค์‹œ๊ฐ„ ํ…์ŠคํŠธ ์ฃผ์ž…์„ ๋ถ„๋‹ดํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ

AgentControlPlugin

์„œ๋ฒ„ ๊ด€๋ฆฌ ๊ทœ์น™์œผ๋กœ ๋„๊ตฌ ํ˜ธ์ถœ์„ deny/steer ์ œ์–ด โ€” ๋ณ„๋„ ํŒจํ‚ค์ง€

Skills

๋ชจ๋“ˆ์‹ ์ง€์‹œ์–ด ํŒจํ‚ค์ง€(SKILL.md)๋ฅผ ํ•„์š”ํ•  ๋•Œ๋งŒ ๋กœ๋“œ

Context Offloader

๊ณผ๋Œ€ ๋„๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ์Šคํ† ๋ฆฌ์ง€๋กœ ์˜คํ”„๋กœ๋“œํ•˜์—ฌ ์ปจํ…์ŠคํŠธ ์ ˆ์•ฝ

Steering

์ง„ํ–‰ ์ค‘์ธ ์—์ด์ „ํŠธ์— ์ปจํ…์ŠคํŠธ ์ธ์ง€ ๊ฐ€์ด๋˜์Šค๋ฅผ ์ฃผ์ž…

Context Injector

๋ชจ๋ธ ํ˜ธ์ถœ ์ง์ „์— ์‹ค์‹œ๊ฐ„ ํ…์ŠคํŠธ๋ฅผ ์ฃผ์ž…

takeaway

SkillsยทContextOffloaderยทSteeringยทContext Injector๋Š” SDK๊ฐ€ ์ œ๊ณตํ•˜๊ณ , AgentControlPlugin๋งŒ ๋ณ„๋„ ํŒจํ‚ค์ง€์ž…๋‹ˆ๋‹ค โ€” ์ •์ฑ… ์ œ์–ด๋Š” ์„œ๋ฒ„ยทcontrols.yaml ์—ฐ๋™์ด ์ „์ œ์ž…๋‹ˆ๋‹ค.

PART 3 ยท Plugins

์ปค์Šคํ…€ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ž‘์„ฑ

Plugin์„ ์ƒ์†ํ•˜์—ฌ ์ž์ฒด ์ œ์–ด ๋กœ์ง ๊ตฌํ˜„

python
from strands import Agent
from strands.plugins import Plugin, hook
from strands.hooks import AfterModelCallEvent, BeforeInvocationEvent

class CostGuardPlugin(Plugin):  # ํ† ํฐ ๋น„์šฉ ๋ˆ„์  ์ถ”์ , ์˜ˆ์‚ฐ ์ดˆ๊ณผ ์‹œ ์ค‘๋‹จ
    name = "cost-guard"

    def __init__(self, budget_usd: float = 1.0):
        super().__init__()
        self.budget_usd = budget_usd
        self.baseline_tokens, self.spent_usd = 0, 0.0

    @hook
    def reset_on_invocation(self, event: BeforeInvocationEvent) -> None:
        # ํ˜ธ์ถœ ์‹œ์ž‘ ์‹œ์ ์˜ ๋ˆ„์  ํ† ํฐ์„ ๊ธฐ์ค€์ ์œผ๋กœ ๊ธฐ๋ก
        metrics = event.agent.event_loop_metrics
        self.baseline_tokens = metrics.accumulated_usage["totalTokens"]
        self.spent_usd = 0.0

    @hook
    def check_cost(self, event: AfterModelCallEvent) -> None:
        total = event.agent.event_loop_metrics.accumulated_usage["totalTokens"]
        # 0.000003์€ ํ† ํฐ๋‹น ์˜ˆ์‹œ ๋‹จ๊ฐ€ โ€” ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ธ์˜ ์‹ค์ œ ๋‹จ๊ฐ€๋กœ ๊ต์ฒด
        self.spent_usd = (total - self.baseline_tokens) * 0.000003
        if self.spent_usd >= self.budget_usd:
            raise RuntimeError(f"Budget exceeded: ${self.spent_usd:.4f}")
agent = Agent(model="us.anthropic.claude-sonnet-4-6", plugins=[CostGuardPlugin(budget_usd=0.50)])
PART 3 ยท Plugins

ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ผ์ดํ”„์‚ฌ์ดํด

ํ”Œ๋Ÿฌ๊ทธ์ธ ์ดˆ๊ธฐํ™”๋ถ€ํ„ฐ ์ด๋ฒคํŠธ ๊ตฌ๋…๊นŒ์ง€์˜ ๋™์ž‘ ์ˆœ์„œ

  1. 1
    Discovery

    Plugin ํด๋ž˜์Šค์—์„œ @hook, @tool ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ถ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์Šค์บ”ํ•˜์—ฌ ์ˆ˜์ง‘

  2. 2
    Hook Registration

    ๊ฐ @hook ๋ฉ”์„œ๋“œ์˜ ํƒ€์ž… ํžŒํŠธ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ•ด๋‹น ์ด๋ฒคํŠธ ํƒ€์ž…์— ์ฝœ๋ฐฑ ๋“ฑ๋ก

  3. 3
    Tool Registration

    @tool ๋ฉ”์„œ๋“œ๋ฅผ ์—์ด์ „ํŠธ์˜ ๋„๊ตฌ ๋ชฉ๋ก์— ์ถ”๊ฐ€ โ€” ๋ชจ๋ธ์ด ํ˜ธ์ถœ ๊ฐ€๋Šฅ

  4. 4
    init_agent ํ˜ธ์ถœ

    ์ปค์Šคํ…€ ์ดˆ๊ธฐํ™” ๋กœ์ง ์‹คํ–‰ โ€” ์ƒํƒœ ์„ค์ •, ์กฐ๊ฑด๋ถ€ ํ›… ์ถ”๊ฐ€, ์—์ด์ „ํŠธ ์†์„ฑ ์ ‘๊ทผ

  5. 5
    Plugin Ready

    ๋“ฑ๋ก ์™„๋ฃŒ ํ›„ ์—์ด์ „ํŠธ ์‹คํ–‰ ์‹œ ์ด๋ฒคํŠธ ๋ฐœ์ƒ๋งˆ๋‹ค ์ฝœ๋ฐฑ ์ž๋™ ํ˜ธ์ถœ

takeaway

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋งŒ ๋ถ™์ด๋ฉด ๋ฐœ๊ฒฌ๊ณผ ๋“ฑ๋ก์€ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค โ€” ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฝ”๋“œ๋Š” ๋กœ์ง์—๋งŒ ์ง‘์ค‘

Interventions์™€ Cedar

์ •์ฑ… ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด ยท HITL

PART 4 ยท Interventions์™€ Cedar

Interventions

์ •์ฑ… ๊ณ„์ธต โ€” ๋„๊ตฌ ํ˜ธ์ถœ์„ ํ—ˆ์šฉยท๊ฑฐ๋ถ€ยท์Šน์ธ ๋Œ€๊ธฐ๋กœ ํŒ์ •

Interventions

Cedar ์„ ์–ธํ˜• ์ •์ฑ…์œผ๋กœ ๋„๊ตฌ ํ˜ธ์ถœ์„ ์ผ๊ด€๋˜๊ฒŒ ํŒ์ •ํ•ฉ๋‹ˆ๋‹ค.

  • permit / forbid ์„ ์–ธํ˜• ๊ทœ์น™
  • ๋ณด์•ˆํŒ€์ด ์ •์ฑ… ๋…๋ฆฝ ๊ด€๋ฆฌ
  • HITL ์Šน์ธ ์›Œํฌํ”Œ๋กœ์šฐ ๋‚ด์žฅ
  • principal ํ•ด์„ ์‹คํŒจ ์‹œ fail-closed
takeaway

์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ์ •์ฑ…์ด ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค โ€” ์ผ๊ด€์„ฑ์€ ์„ ์–ธ์—์„œ ๋‚˜์˜ต๋‹ˆ๋‹ค.

PART 4 ยท Interventions์™€ Cedar

Hooks vs Interventions

๊ด€์ฐฐํ˜• ์ œ์–ด์™€ ์ •์ฑ…ํ˜• ์ œ์–ด์˜ ๊ทผ๋ณธ์  ์ฐจ์ด

Hooks

์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ๊ด€์ฐฐ

  • ์ฝ”๋“œ๋กœ ์กฐ๊ฑด ๋ถ„๊ธฐ ์ž‘์„ฑ
  • ๊ฐœ๋ฐœ์ž๊ฐ€ ๋กœ์ง ์ง์ ‘ ๊ตฌํ˜„
  • ์œ ์—ฐํ•˜์ง€๋งŒ ์ผ๊ด€์„ฑ ๋ณด์žฅ ์–ด๋ ค์›€
  • cancel_tool๋กœ ๋„๊ตฌ ์‹คํ–‰ ์ทจ์†Œ ๊ฐ€๋Šฅํ•˜๋‚˜ ์„ ํƒ์ 

๊ด€์ฐฐ๊ณผ ๊ฐ€๋ฒผ์šด ๊ฐœ์ž…์— ์ ํ•ฉ. ๋กœ์ง์ด ์ฝ”๋“œ์— ํฉ์–ด์ง€๋ฏ€๋กœ ํŒ€ ์ฐจ์›์˜ ์ผ๊ด€๋œ ํ†ต์ œ์—๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Interventions

์ •์ฑ… ๊ธฐ๋ฐ˜ ํŒ์ •

  • Cedar ์„ ์–ธํ˜• ์ •์ฑ…์œผ๋กœ ๊ทœ์น™ ์ •์˜
  • ๋ณด์•ˆํŒ€์ด ์ •์ฑ… ๋…๋ฆฝ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
  • ์ผ๊ด€๋œ permit/forbid ํŒ์ • ๋ณด์žฅ
  • HITL ์Šน์ธ ์›Œํฌํ”Œ๋กœ์šฐ ๋‚ด์žฅ

ํ†ต์ œ๋ฅผ ์ฝ”๋“œ ๋ฐ–์œผ๋กœ ๋ถ„๋ฆฌ. ์ •์ฑ… ํŒŒ์ผ๋งŒ ๋ฐ”๊พธ๋ฉด ์ „์ฒด ์—์ด์ „ํŠธ์— ์ผ๊ด€ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

takeaway

๊ฒน์น˜๋Š” ๊ด€๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ์—ญํ•  ๋ถ„๋‹ด์ž…๋‹ˆ๋‹ค โ€” ๊ฐœ๋ฐœ์ž์˜ ์œ ์—ฐํ•œ ๊ฐœ์ž…์€ Hooks, ์กฐ์ง์˜ ์ผ๊ด€๋œ ํ†ต์ œ๋Š” Interventions๋กœ ๋‚˜๋ˆ  ๋งก๊น๋‹ˆ๋‹ค.

PART 4 ยท Interventions์™€ Cedar

Cedar ์ •์ฑ…

permit/forbid ๊ทœ์น™์œผ๋กœ ๋„๊ตฌ ์ ‘๊ทผ์„ ์„ ์–ธ์  ์ œ์–ด

cedar
// policy.cedar โ€” ์—์ด์ „ํŠธ ๋„๊ตฌ ์ ‘๊ทผ ์ •์ฑ… (action์ด ๊ณง ๋„๊ตฌ ์ด๋ฆ„)

// ์ฝ๊ธฐ ๋„๊ตฌ๋Š” ๋ชจ๋“  principal์— ํ—ˆ์šฉ
permit(
  principal,
  action == Action::"read_file",
  resource
);

// ํ”„๋กœ๋•์…˜ DB ์“ฐ๊ธฐ๋Š” admin ์—ญํ• ๋งŒ โ€” context_enricher๊ฐ€ ์ฃผ์ž…ํ•œ role ๊ฒ€์‚ฌ
permit(
  principal,
  action == Action::"write_database",
  resource
) when {
  context.session.role == "admin"
};

// ํŒŒ์ผ ์‚ญ์ œ๋Š” ์ „๋ฉด ๊ธˆ์ง€
forbid(
  principal,
  action == Action::"delete_file",
  resource
);
// ํ˜ธ์ถœ ์ธก โ€” agent(prompt, invocation_state={"role": "admin"})
// principal์€ principal_resolver๊ฐ€ invocation_state์—์„œ ํ•ด์„ (์‹คํŒจ ์‹œ fail-closed)
PART 4 ยท Interventions์™€ Cedar

HITL ์Šน์ธ ์›Œํฌํ”Œ๋กœ์šฐ

๋ฏผ๊ฐ ์ž‘์—… ์‹คํ–‰ ์ „ ์ธ๊ฐ„ ์Šน์ธ์„ ์š”๊ตฌํ•˜๋Š” Intervention ํ๋ฆ„

  1. 1
    ๋„๊ตฌ ํ˜ธ์ถœ ์š”์ฒญ

    ์—์ด์ „ํŠธ๊ฐ€ ๋ฏผ๊ฐ ๋„๊ตฌ(์˜ˆ: deploy_production) ํ˜ธ์ถœ ์‹œ๋„

  2. 2
    HumanInTheLoop ํŒ์ •

    allowed_tools์— ์—†๋Š” ๋ฏผ๊ฐ ๋„๊ตฌ๋ฉด ์Šน์ธ ์š”๊ตฌ

  3. 3
    ์Šน์ธ ๋Œ€๊ธฐ

    ์‹คํ–‰ ์ผ์‹œ ์ค‘์ง€, ask ์ฝœ๋ฐฑ์œผ๋กœ ์šด์˜์ž ์งˆ์˜ โ€” ๊ธฐ๋ณธ stdio, ์ฝœ๋ฐฑ์œผ๋กœ Slack ๋“ฑ ์—ฐ๋™

  4. 4
    ์ธ๊ฐ„ ํŒ๋‹จ

    ์šด์˜์ž๊ฐ€ ์ปจํ…์ŠคํŠธ ํ™•์ธ ํ›„ approve ๋˜๋Š” deny ์‘๋‹ต

  5. 5
    ์‹คํ–‰ ๋˜๋Š” ์ค‘๋‹จ

    approve ์‹œ ๋„๊ตฌ ์‹คํ–‰ ์†ํ–‰, deny ์‹œ ์—์ด์ „ํŠธ์— ๊ฑฐ๋ถ€ ์‚ฌ์œ  ์ „๋‹ฌ

takeaway

์Šน์ธ ์—†์ด๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ์‚ฌ๋žŒ์ด ๋งˆ์ง€๋ง‰ ๊ด€๋ฌธ์ž…๋‹ˆ๋‹ค.

Sandbox

Docker ยท SSH ยท Strands Shell

PART 5 ยท Sandbox

Sandbox

๊ฒฉ๋ฆฌ ๊ณ„์ธต โ€” ์‹คํ–‰ ํ™˜๊ฒฝ ์ž์ฒด๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ์ตœํ›„์˜ ๋ฐฉ์–ด์„ 

Sandbox

์—์ด์ „ํŠธ์˜ ํŒŒ์ผยท์…ธ ์ž‘์—…์„ ํ˜ธ์ŠคํŠธ์—์„œ ๋ถ„๋ฆฌ๋œ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • Docker โ€” ์ปจํ…Œ์ด๋„ˆ ๊ฒฉ๋ฆฌ
  • SSH โ€” ๋ณ„๋„ ์„œ๋ฒ„ ๋ฌผ๋ฆฌ ๋ถ„๋ฆฌ
  • Strands Shell โ€” ๊ฒฉ๋ฆฌ ๋ฐฑ์—”๋“œ ์…ธ
  • ์œ„ ๊ณ„์ธต์ด ๋šซ๋ ค๋„ ์—ฌ๊ธฐ์„œ ๋ฉˆ์ถค
takeaway

๋ชจ๋“  ์ œ์–ด๊ฐ€ ์‹คํŒจํ•ด๋„ ํ”ผํ•ด ๋ฐ˜๊ฒฝ์€ ์ƒŒ๋“œ๋ฐ•์Šค ์•ˆ์ž…๋‹ˆ๋‹ค.

PART 5 ยท Sandbox

๊ฒฉ๋ฆฌ ์‹คํ–‰ 3๊ฐ€์ง€ ๋ฐฉ์‹

์ปจํ…Œ์ด๋„ˆ ๊ฒฝ๊ณ„(Docker) ยท ๋ฌผ๋ฆฌ ๋ถ„๋ฆฌ(SSH) ยท ๋„๊ตฌํ˜• ์…ธ(Strands Shell) โ€” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€๊ณผ ์šด์˜ ๋ถ€๋‹ด์˜ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„

Docker ์ปจํ…Œ์ด๋„ˆ

ํŒŒ์ผ์‹œ์Šคํ…œยท๋„คํŠธ์›Œํฌยทํ”„๋กœ์„ธ์Šค๋ฅผ ์ปจํ…Œ์ด๋„ˆ ๊ฒฝ๊ณ„๋กœ ๊ฒฉ๋ฆฌ

  • โœ“ ํ™˜๊ฒฝ ์žฌํ˜„์„ฑ ๋†’์Œ
  • โœ“ ๋„คํŠธ์›Œํฌ ์ •์ฑ… ์„ธ๋ฐ€ ์ œ์–ด
  • โœ“ ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ ๋น ๋ฅธ ํ”„๋กœ๋น„์ €๋‹
  • โœ— Docker ๋ฐ๋ชฌ ํ•„์š”
  • โœ— GPU ํŒจ์Šค์Šค๋ฃจ ์„ค์ • ๋ณต์žก

SSH ์›๊ฒฉ ์‹คํ–‰

๋ณ„๋„ ์„œ๋ฒ„์—์„œ ๋ช…๋ น ์‹คํ–‰ โ€” ํ˜ธ์ŠคํŠธ์™€ ๋ฌผ๋ฆฌ์  ๋ถ„๋ฆฌ

  • โœ“ ์™„์ „ํ•œ ํ™˜๊ฒฝ ๋ถ„๋ฆฌ
  • โœ“ ๊ธฐ์กด ์ธํ”„๋ผ ํ™œ์šฉ ๊ฐ€๋Šฅ
  • โœ“ ๋ฉ€ํ‹ฐ ํ…Œ๋„ŒํŠธ ์ง€์›
  • โœ— ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ๋ฐœ์ƒ
  • โœ— ์„œ๋ฒ„ ๊ด€๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ

Strands Shell

DockerยทSSH ๊ฒฉ๋ฆฌ ๋ฐฑ์—”๋“œ ์•ˆ์—์„œ ์‹คํ–‰๋˜๋Š” ์…ธ ํ™˜๊ฒฝ

  • โœ“ ์…ธ ์‹คํ–‰์„ ๋„๊ตฌ๋กœ ๋ฐ”๋กœ ์ œ๊ณต
  • โœ“ ๋ฐฑ์—”๋“œ ์„ ํƒ์œผ๋กœ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€ ์กฐ์ ˆ
  • โœ“ ๋น ๋ฅธ ์‹œ์ž‘
  • โœ— ๊ฒฉ๋ฆฌ ๋ฐฑ์—”๋“œ ๋ณ„๋„ ๊ตฌ์„ฑ ํ•„์š”
  • โœ— ๋ณต์žกํ•œ ์›Œํฌํ”Œ๋กœ์šฐ์— ํ•œ๊ณ„
takeaway

์„ธ ๋ฐฉ์‹์€ ๋ฐฐํƒ€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” Strands Shell์ด DockerยทSSH ๋ฐฑ์—”๋“œ ์œ„์—์„œ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์กฐํ•ฉ์ด ๊ธฐ๋ณธํ˜•์ž…๋‹ˆ๋‹ค.

PART 5 ยท Sandbox

Docker Sandbox ์—ฐ๊ฒฐ

Agent ์ƒ์„ฑ ์‹œ sandbox=๋กœ ์‹คํ–‰ ์ค‘ ์ปจํ…Œ์ด๋„ˆ์— ์—ฐ๊ฒฐ โ€” ํŒŒ์ผยท์…ธ ์ž‘์—… ๊ฒฉ๋ฆฌ

python
from strands import Agent
from strands.sandbox.docker import DockerSandbox

# ์‚ฌ์ „์— ์‹คํ–‰ ์ค‘์ธ ์ปจํ…Œ์ด๋„ˆ์— ์—ฐ๊ฒฐ
sandbox = DockerSandbox(container="agent-workspace")

agent = Agent(
    model="us.anthropic.claude-sonnet-4-6",
    sandbox=sandbox,
    # sandbox_bash, sandbox_file_editor ๋„๊ตฌ๊ฐ€ ์ž๋™ ๋“ฑ๋ก๋จ
)

# ์—์ด์ „ํŠธ์˜ ๋ชจ๋“  ํŒŒ์ผ/์…ธ ์ž‘์—…์ด ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์—์„œ ์‹คํ–‰
result = agent("ํ”„๋กœ์ ํŠธ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์š”์•ฝํ•ด์ค˜")
PART 5 ยท Sandbox

๊ฒฉ๋ฆฌ ์ˆ˜์ค€ ์„ ํƒ

๋ณด์•ˆ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์„ ํƒํ•˜๋Š” 3๋‹จ๊ณ„ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€

Level 1: Strands Shell

๊ฒฉ๋ฆฌ ๋ฐฑ์—”๋“œ(DockerยทSSH) ์•ˆ์—์„œ ์‹คํ–‰๋˜๋Š” ์…ธ ๋„๊ตฌ

Level 2: Docker

์ปจํ…Œ์ด๋„ˆ ๊ฒฉ๋ฆฌ โ€” ํŒŒ์ผยท๋„คํŠธ์›Œํฌยท์ž์› ๊ฒฝ๊ณ„ ์„ค์ •

Level 3: SSH + ์ „์šฉ ์„œ๋ฒ„

๋ฌผ๋ฆฌ ๋ถ„๋ฆฌ โ€” ํ˜ธ์ŠคํŠธ์™€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋จธ์‹ ์—์„œ ์‹คํ–‰

takeaway

๊ฒฉ๋ฆฌ ์ˆ˜์ค€์€ ๋„๊ตฌ์˜ ํŒŒ๊ดด๋ ฅ์— ๋น„๋ก€ํ•ด ์˜ฌ๋ฆฝ๋‹ˆ๋‹ค โ€” ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ๋•์…˜์€ Level 2(Docker)๊ฐ€ ์ถœ๋ฐœ์ ์ž…๋‹ˆ๋‹ค.

์ œ์–ด ์—†๋Š” ์ž์œจ์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค.

Hooks ยท Plugins ยท Interventions ยท Sandbox โ€” 4๊ณ„์ธต์œผ๋กœ ์—์ด์ „ํŠธ๋ฅผ ํ†ต์ œ