๐ฏ Strands ์ํ ๊ด๋ฆฌ
Session, Conversation, Memory, Context, Snapshot
Strands ์ํ ๊ด๋ฆฌ
Session ยท Conversation ยท Memory ยท Context
์์ด์ ํธ์ ๊ธฐ์ต์ ์ค๊ณํ๋ค
์ธ์ ์์ํ๋ถํฐ ์ปจํ ์คํธ ์๋ ๊ด๋ฆฌ๊น์ง โ ์ํ์ 4๊ณ์ธต
์ํ์ ๊ธฐ์ด
ํด๊ณผ ์ธ์ ยท messages[] ยท ์ ์ํ ๊ด๋ฆฌ์ธ๊ฐ
์์ด์ ํธ ๋ํ์ ๊ตฌ์กฐ โ ํด ยท ์ธ์ ยท ๊ธฐ์ต
๋ฉ์์ง๊ฐ ๋ชจ์ฌ ํด, ํด์ด ๋ชจ์ฌ ์ธ์ โ ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ ๋ถ๋ฅผ ๊ธฐ์ตํ๋ ๊ณณ
๊ธฐ์ต์ ์ค์ฒด โ messages[]
๋ชจ๋ธ์ ์๋ฌด๊ฒ๋ ๊ธฐ์ตํ์ง ์์ โ ๋งค ํด, ์ง๊ธ๊น์ง์ ๋ํ ์ ์ฒด๋ฅผ ์ฌ์ ์ก
์ํ๊ฐ ์์ผ๋ฉด ์๊ธฐ๋ ์ธ ๊ฐ์ง ๋ฌธ์
์ธ๋ฉ๋ชจ๋ฆฌ messages[]๋ฅผ ๊ทธ๋๋ก ํ๋ก๋์ ์ ๋๋ฉด ์๊ธฐ๋ ๋ฌธ์
๋งฅ๋ฝ ์ ์ค
์ฌ์์ยท์ฝ๋ ์คํํธยท๋ฐฐํฌ = ๊ธฐ์ต ์์ค
- ์๋ฒ ์ฌ์์ ํ "์๊น ๊ทธ๊ฑฐ"๋ฅผ ๋ชจ๋ฆ
- ์ฌ์ฉ์๊ฐ ์ฒ์๋ถํฐ ๋ค์ ์ค๋ช ํด์ผ ํจ
ํ ํฐ ํญ๋ฐ
๋งค ํธ์ถ์ ์ ์ฒด ํ์คํ ๋ฆฌ ์ ์ก
- 50ํด์ด๋ฉด ๋งค๋ฒ ์๋ง ํ ํฐ ๊ณผ๊ธ
- ๋น์ฉ๊ณผ ์ง์ฐ์ด ๋ํ ๊ธธ์ด์ ๋น๋ก ์ฆ๊ฐ
์๋์ฐ ์ด๊ณผ
์ปจํ ์คํธ ํ๋๋ฅผ ๋์ผ๋ฉด ํธ์ถ ์คํจ
- ๊ธด ๋ํยทํฐ ๋๊ตฌ ๊ฒฐ๊ณผ๊ฐ ํ๋๋ฅผ ๋๊น
- ์ ๋ฆฌ ์ ๋ต ์์ด๋ ๋ํ๊ฐ ์ค๋จ
์ด ์ธ ๋ฌธ์ ์ ํด๋ฒ์ด ๊ณง ์ํ ๊ด๋ฆฌ์
๋๋ค.
Strands๋ ์ด๋ฅผ ๋ค ๊ณ์ธต์ผ๋ก ํ์ด๋
๋๋ค โ ์ ์ฅ์ Session, ๊ธธ์ด๋ Conversation, ๊ธฐ์ต์ Memory, ์กฐ๋ฆฝ์ Context
๋ค ๊ฐ์ง ์ด๋ฆ์ ์ค์ฒด
์ ์ฅยท๊ธธ์ดยท๊ธฐ์ตยท์กฐ๋ฆฝ โ ๊ฐ ์ด๋ฆ์ด Strands์์ ์ค์ ๋ก ๊ฐ๋ฆฌํค๋ ๊ฒ
Session
์ ์ฅ โ ๋ํ ์ ์ฒด๋ฅผ ์์ํยท๋ณต์
Conversation
๊ธธ์ด โ ์์ด๋ ๋ํ ์ด๋ ฅ๊ณผ ๊ทธ ๊ด๋ฆฌ
Memory
๊ธฐ์ต โ ์ธ์ ์ ๋์ด ๋จ๋ ์ฌ์ค๊ณผ ์ ํธ
Context
์กฐ๋ฆฝ โ ์ด๋ฒ ํธ์ถ์ ์ค์ ๋ก ๋ค์ด๊ฐ๋ ์ ๋ ฅ
Strands์ "์ํ ๊ด๋ฆฌ"๋ผ๋ ๋จ์ผ API๋ ์์ต๋๋ค โ ์ ๋ค ๊ณ์ธต์ ์กฐํฉ์ด๋ฉฐ, ๋ณ๋๋ก agent.state(๋ชจ๋ธ์ ์ ์ก๋์ง ์๋ key-value ์ ์ฅ์)๊ฐ ์ธ์ ๊ณผ ํจ๊ป ์ ์ฅ๋ฉ๋๋ค.
์ํ ๊ด๋ฆฌ ๊ณ์ธต
Session โ Conversation โ Memory โ Context
4๊ณ์ธต ์ง๋ โ ์์๊ฐ๋ ์ ํ
์ํฌ๋ก๋๊ฐ ๋ณต์กํด์ง์๋ก ์๋๋ถํฐ ํ๋์ฉ ์์ด๋ ๊ณ์ธต
๋ชจ๋ธ ์ ๋ ฅ์ด ๋๊ธฐ๊น์ง โ Context ์กฐ๋ฆฝ ๋ผ์ธ
๋ค ๊ณ์ธต์ด ๊ฐ์์ ๊ธฐ์ฌ๋ฌผ์ ๊ฝ์ ๋ฃ๋, ๋งค ํธ์ถ ์๋ก ์กฐ๋ฆฝ๋๋ Context
SessionManager
๋ผ์ดํ์ฌ์ดํด ยท File ยท S3 ยท Repository
SessionManager
์ธ์ ์์ํ ๊ณ์ธต โ Agent์ ์ฅ์ฐฉํ๋ฉด ์ ์ฅ๊ณผ ๋ณต์์ด ์๋
SessionManager
๋ํ ์ํ๋ฅผ ์ ์ฅ์์ ์๋์ผ๋ก ์์ํํ๊ณ , session_id ํ๋๋ก ๋์ด๋ฆฝ๋๋ค
- ์ ์ฅ ๋์: messages[] + agent.state
- ์ ์ฅ ์์ : ๋งค ํด ์๋
- ๋ณต์ ํค: session_id
- ๋ฐฑ์๋: File ยท S3 ยท ์ปค์คํ Repository
๊ฐ๋ฐ์๊ฐ save()๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค โ ์ฅ์ฐฉ๋ง ํ๋ฉด ์ธ์ ์ด Agent๋ฅผ ๋ฐ๋ผ๋ค๋๋๋ค.
์ธ์ ๋ผ์ดํ์ฌ์ดํด
๋ช ์์ ์ผ๋ก ์ด๊ณ ๋ซ์ง ์๋ ์ธ์ โ ์ํ ์ฌ์ด๋ฅผ ์ค๊ฐ๋ ์ ์ฅยท๋ณต์ยท์๋ฉธ์ ํ๋ฆ
SessionManager ๋ฐฑ์๋
์ธ์ ๋ฐ์ดํฐ๋ฅผ ์ด๋์ ์ ์ฅํ ์ง ์ ํ โ ํ๊ฒฝ์ ๋ง๋ ๋ฐฑ์๋
FileSessionManager
- ๋ก์ปฌ ํ์ผ ์์คํ ์ JSON ์ ์ฅ
- ๊ฐ๋ฐ/ํ ์คํธ ํ๊ฒฝ์ ์ ํฉ
- ๋ฉํฐ ํ๋ก์ธ์ค ์ ๊ทผ ์ ์ถฉ๋ ๊ฐ๋ฅ
์ธ์ โ ๋ก์ปฌ ๊ฐ๋ฐ, ๋จ์ผ ํ๋ก์ธ์ค, ๋น ๋ฅธ ํ๋กํ ํ์
S3SessionManager
- S3 ๋ฒํท์ ์ธ์ ์ ์ฅ
- ์๋ฒ๋ฆฌ์ค ํ๊ฒฝ(Lambda)์ ์ ํฉ
- ๋ฒ์ ๊ด๋ฆฌ์ ์๋ช ์ฃผ๊ธฐ ์ ์ฑ ํ์ฉ ๊ฐ๋ฅ
์ธ์ โ Lambda ๋ฐฐํฌ, ๋์ฉ๋ ์ธ์ , ์ฅ๊ธฐ ๋ณด๊ด ํ์
AgentCore Memory
- AgentCore Memory ๊ธฐ๋ฐ ์ธ์ ์ ์ฅ
- TTL ์๋ ๋ง๋ฃ, ์ ์ง์ฐ ์กฐํ
- ์ฅ๊ธฐ ๊ธฐ์ต(LTM)๊ณผ ๋จ๊ธฐ ๊ธฐ์ต(STM) ํตํฉ
์ธ์ โ ํ๋ก๋์ , ๊ณ ๊ฐ์ฉ์ฑ, ์ฅ๊ธฐ ๊ธฐ์ต ํตํฉ, ์๋ ๋ง๋ฃ
๊ฐ๋ฐ์ File, ์๋ฒ๋ฆฌ์ค๋ S3, ํ๋ก๋์ ํตํฉ์ AgentCore Memory โ ์ด๋ ์ชฝ์ด๋ ์ฝ๋๋ ํ ์ค๋ง ๋ฐ๋๋๋ค.
์ธ์ ์ ์ฅ๊ณผ ๋ณต์
session_id ํ๋๋ก ์ ์ฒด ๋ํ ์ํ๋ฅผ ์์ํยท๋ณต์
ํต์ฌ ํฌ์ธํธ
- session_manager=
- ์ฅ์ฐฉ ํ ์ค๋ก ์ ์ฅยท๋ณต์ ์๋ โ save()๋ฅผ ํธ์ถํ์ง ์์
- session_id
- ๋ณต์ ํค โ ๊ฐ์ ID๋ก Agent๋ฅผ ๋ค์ ๋ง๋ค๋ฉด ์ด์ ๋ํ๊ฐ ๊ทธ๋๋ก
- ์ ์ฅ ์์
- ๋งค ํด ์๋ โ messages[]์ agent.state๊ฐ ํจ๊ป ์์ํ
- S3 ๋ฐฑ์๋
- ํ์ผ์์คํ ์๋ LambdaยทFargate์์๋ ์ธ์ ์ ์ง
์ฝ๋
from strands import Agent
from strands.session import S3SessionManager
# ์ธ์
๋งค๋์ โ session_id + S3 ๋ฒํท์ผ๋ก ์ ์ฅ ์์น ์ง์
session_mgr = S3SessionManager(
session_id="user-123-chat-1",
bucket="agent-sessions-bucket",
)
agent = Agent(session_manager=session_mgr)
agent("๋ด AWS ๋น์ฉ์ ๋ถ์ํด์ค")
# ๋์ค์ โ ๊ฐ์ session_id๋ก ์ฌ์์ฑํ๋ฉด ์ด์ ๋ํ ์๋ ๋ก๋
agent2 = Agent(session_manager=S3SessionManager(
session_id="user-123-chat-1",
bucket="agent-sessions-bucket",
))
agent2("์๊น ๋ถ์ํ ๊ฒฐ๊ณผ์์ ๊ฐ์ฅ ๋น์ผ ์๋น์ค๋?")
messages[] ๋ฐ์ ์ํ โ agent.state
๋ชจ๋ธ์๊ฒ๋ ๋ณด์ด์ง ์์ง๋ง, ์ธ์ ๊ณผ ํจ๊ป ์ ์ฅ๋๋ key-value ์ํ
ํต์ฌ ํฌ์ธํธ
- agent.state
- ๋ํ ๋ฐ key-value ์ ์ฅ์ โ ๋ชจ๋ธ ์ปจํ ์คํธ์ ์ ์ก๋์ง ์์
- set / get
- ์นด์ดํฐยทํ๋๊ทธยท์ฌ์ฉ์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ฝ๋์์ ์ง์ ์ฝ๊ณ ์
- ์์ํ
- SessionManager๊ฐ messages[]์ ํจ๊ป ์ ์ฅยท๋ณต์
- ์ฉ๋
- ์๊ธ์ ยทํธ์ถ ํ์ยท์ค๊ฐ ๊ฒฐ๊ณผ์ฒ๋ผ ๋ชจ๋ธ์ด ๋ชฐ๋ผ๋ ๋๋ ๊ฐ
์ฝ๋
from strands import Agent
from strands.session import FileSessionManager
agent = Agent(
session_manager=FileSessionManager(session_id="user-123"),
)
# ๋ชจ๋ธ ์ปจํ
์คํธ์ ๋ค์ด๊ฐ์ง ์๋ key-value ์ํ
agent.state.set("user_tier", "premium")
agent.state.set("api_calls", 3)
print(agent.state.get("user_tier")) # "premium"
# ์ธ์
์ ์ฅ์์ messages[]์ ํจ๊ป ์์ํ โ ์ฌ์์ฑํด๋ ์ ์ง
agent2 = Agent(
session_manager=FileSessionManager(session_id="user-123"),
)
print(agent2.state.get("api_calls")) # 3
์ธ์ ๊ฒฉ๋ฆฌ์ ๋ณด์
๋ฉํฐํ ๋ํธ ํ๊ฒฝ์์ ์ธ์ ๊ฐ ๋ฐ์ดํฐ ์ ์ถ ๋ฐฉ์ง
session_id ๋ค์ด๋ฐ
user-{userId}-{chatId} ํจํด์ผ๋ก ์ฌ์ฉ์๋ณ ๊ฒฉ๋ฆฌ
TTL ์๋ ๋ง๋ฃ
์คํ ๋ฆฌ์ง ์๋ช ์ฃผ๊ธฐ ์ ์ฑ ์ผ๋ก ๋นํ์ฑ ์ธ์ ์๋ ์ญ์ โ ๋ฐ์ดํฐ ๋ณด์กด ์ ์ฑ ์ค์
์ํธํ
SSE-KMS๋ก ์ ์ฅ ์ ์ํธํ, TLS๋ก ์ ์ก ์ ์ํธํ
์ธ์ ์๋ ์ฌ์ฉ์์ ๋ํ๊ฐ ํต์งธ๋ก ๋ค์ด ์์ต๋๋ค โ ์ ์ฅ์ ๋ณด์์ด ๊ณง ๋ํ ๋ณด์์ ๋๋ค.
ConversationManager
SlidingWindow ยท Summarizing ยท NullConversationManager
ConversationManager
๋ํ ๊ธธ์ด ๊ด๋ฆฌ ๊ณ์ธต โ ๋ชจ๋ธ์ ๋ณด๋ผ messages[] ๋ถ๋์ ์ ์ฑ ์ผ๋ก ๊ฒฐ์
ConversationManager
ํด์ด ๋๋ ๋๋ง๋ค ๋ํ ์ด๋ ฅ์ ์ ๋ฆฌ ์ ์ฑ ์ ์๋ ์ ์ฉํฉ๋๋ค
- SlidingWindow โ ์ต๊ทผ N๊ฐ ๋ฉ์์ง (๊ธฐ๋ณธ๊ฐ)
- Summarizing โ ์ค๋๋ ๊ตฌ๊ฐ์ ์์ฝ์ผ๋ก ์์ถ
- Null โ ์ด๋ ฅ์ ๊ฑด๋๋ฆฌ์ง ์์
- ์ ์ฉ ์์ : ๋งค ์ฌ์ดํด ์๋
์ค์ ํ์ง ์์๋ ์ด๋ฏธ ๋์ ์ค์ ๋๋ค โ ๊ธฐ๋ณธ๊ฐ SlidingWindow(window_size=40)
SlidingWindow vs Summarizing
๋ํ ์ด๋ ฅ์ ์ผ๋ง๋, ์ด๋ป๊ฒ ๋ณด์กดํ ์ง โ ์์ฑ ๋๋น์ ์ค์ ์ฝ๋
window_size=20 # ๊ธฐ๋ณธ๊ฐ 40
)
summary_ratio=0.3,
preserve_recent_messages=10
)
์ธ ์ ๋ต์ ์ ํ ๊ธฐ์ค
Null๊น์ง ํฌํจํ ์ธ ์ ๋ต โ ์ํฌ๋ก๋ ํน์ฑ์ด ๊ฐ๋ฅด๋ ๊ฐ๋ฆผ๊ธธ
| ์ ๋ต | ํ ํฐ ์ฌ์ฉ | ๋งฅ๋ฝ ๋ณด์กด | ๋น์ฉ | ์ ํฉ ์๋๋ฆฌ์ค |
|---|---|---|---|---|
| SlidingWindow | ๊ณ ์ (N๊ฐ ๋ฉ์์ง) | ์ต๊ทผ๋ง | ์์ธก ๊ฐ๋ฅ | ์ฑ๋ด, FAQ, ๋จ์ ์์ |
| Summarizing | ๊ฐ์ (์์ฝ) | ์ฅ๊ธฐ ๋ณด์กด | ์์ฝ ํธ์ถ ์ถ๊ฐ | ๊ฐ์ธ ๋น์, ํ๋ก์ ํธ ๊ด๋ฆฌ |
| NullConversationManager | ๊ด๋ฆฌ ์ ํจ (๊ณ์ ๋์ ) | ์ ์ฒด ์ ์ง | ์ถ๊ฐ ํธ์ถ ์์ | stateful ๋ชจ๋ธ, ์๋ ๊ด๋ฆฌ |
๋ง์ค์ฌ์ง๋ฉด ๊ธฐ๋ณธ๊ฐ ๊ทธ๋๋ก โ SlidingWindow๋ก ์์ํ๊ณ , ์ด๊ธฐ ๋งฅ๋ฝ ์ ์ค์ด ๋ณด์ด๋ฉด Summarizing์ผ๋ก ๋ฐ๊ฟ๋๋ค.
Memory
MemoryManager ยท Recall ยท Injection ยท Extraction
MemoryManager
์ฅ๊ธฐ ๊ธฐ์ต ๊ณ์ธต โ ์ธ์ ์ด ๋๋๋ ๋จ๋ ์ฌ์ค๊ณผ ์ ํธ๋ฅผ ์ถ์
MemoryManager
๋ํ์์ ๊ธฐ์ตํ ์ฌ์ค์ ์ถ์ถํด ์ ์ฅํ๊ณ , ๊ด๋ จ ๊ธฐ์ต์ ์ฐพ์ ์ปจํ ์คํธ์ ์ฃผ์ ํฉ๋๋ค
- Extraction โ ๋ํ์์ ์ฌ์ค ์ถ์ถ
- Storage โ ์คํ ์ด์ ์ ์ฅ
- Recall โ ๊ด๋ จ ๊ธฐ์ต ๊ฒ์
- Injection โ ์ปจํ ์คํธ ์ฃผ์
Session์ด ์ด ๋ํ๋ฅผ ๊ธฐ์ตํ๋ค๋ฉด, Memory๋ ์ด ์ฌ์ฉ์๋ฅผ ๊ธฐ์ตํฉ๋๋ค.
MemoryManager ๊ธฐ์ต ์ฌ์ดํด
์ถ์ถยท์ ์ฅ์ ์ฐ๊ธฐ, ๊ฒ์ยท์ฃผ์ ์ ์ฝ๊ธฐ โ ๋ค ๋จ๊ณ ๋ชจ๋ ์๋, ๊ฐ๋ฐ์๋ ์คํ ์ด๋ง ์ฐ๊ฒฐ
Memory ๊ตฌํ
MemoryManager ์ค์ ์ผ๋ก ์ฅ๊ธฐ ๊ธฐ์ต ํ์ฑํ
ํต์ฌ ํฌ์ธํธ
- BedrockKnowledgeBaseStore
- ์ฅ๊ธฐ ๊ธฐ์ต ์ ์ฅ์ โ knowledge_base_id๋ก ์ฐ๊ฒฐ
- MemoryManager(stores=)
- ์คํ ์ด ๋ฆฌ์คํธ ์ฅ์ฐฉ โ ๊ฒ์ยท์ถ์ถยท์ฃผ์ ์ด ์๋
- ์ฐ๊ธฐ
- ๋ํ์์ ๊ธฐ์ตํ ์ฌ์ค์ ์ถ์ถํด ์คํ ์ด์ ๊ธฐ๋ก
- ์ฝ๊ธฐ
- ์ง๋ฌธ๊ณผ ๊ด๋ จ๋ ๊ธฐ์ต๋ง recallํด ์ปจํ ์คํธ์ ์ฃผ์
์ฝ๋
from strands import Agent
from strands.memory import MemoryManager
from strands.vended_memory_stores import BedrockKnowledgeBaseStore
# ์คํ ์ด โ Bedrock Knowledge Base๋ฅผ ์ฅ๊ธฐ ๊ธฐ์ต ์ ์ฅ์๋ก
store = BedrockKnowledgeBaseStore(
config={"knowledge_base_id": "KB12345678"},
name="user-memory",
)
# ๋งค๋์ ์ฅ์ฐฉ โ ๊ฒ์ยท์ถ์ถยท์ฃผ์
์๋
agent = Agent(memory_manager=MemoryManager(stores=[store]))
# ์ฒซ ๋ํ โ ๊ธฐ์ต ์ถ์ถ + ์ ์ฅ
agent("๋๋ Python๊ณผ us-east-1 ๋ฆฌ์ ์ ์ ํธํด")
# ๋์ค ๋ํ โ ์๋ recall + injection
agent("์ Lambda ํจ์๋ฅผ ๋ง๋ค์ด์ค") # Python + us-east-1 ์๋ ์ ์ฉ
Memory ํ์ฉ ํจํด
์ฅ๊ธฐ ๊ธฐ์ต์ผ๋ก ์์ด์ ํธ์ ๊ฐ์ธํ ์์ค์ ๋์ด๋ 3๊ฐ์ง ํจํด
์ฌ์ฉ์ ์ ํธ๋
์ธ์ด, ๋ฆฌ์ , ์ฝ๋ฉ ์คํ์ผ, ์ถ๋ ฅ ํ์ ๋ฑ ๋ฐ๋ณต๋๋ ์ ํธ ์ถ์
๊ณผ๊ฑฐ ๊ฒฐ์ ์ด๋ ฅ
์ด์ ์์ ์ ๊ฒฐ๊ณผ์ ๊ฒฐ์ ์ ๊ธฐ์ตํ์ฌ ์ผ๊ด์ฑ ์ ์ง
๋๋ฉ์ธ ์ง์
ํ๋ก์ ํธ ๊ตฌ์กฐ, ํ ์ปจ๋ฒค์ , ๋น์ฆ๋์ค ๊ท์น์ ์ถ์
์ธ ํจํด์ ๊ณตํต์ โ ๋งํ์ง ์์๋ ์๋ ์์ด์ ํธ๋ฅผ ๋ง๋๋ ์ฌ๋ฃ์ ๋๋ค.
Context Management
์งํค๊ธฐ โ ์์ถยท์คํ๋ก๋ ยท ๋ฉ์ถ๊ธฐ โ CheckpointยทHITL
Context Management
๋งค ํธ์ถ์ ๋ชจ๋ธ ์ ๋ ฅ์ ํ๋ ์์ ์งํค๋ ์๋ ๋ฐฉ์ด, ๊ทธ๋ฆฌ๊ณ ์คํ์ ๋ฉ์ท๋ค ์ด์ด๊ฐ๋ ์ ์ด
Context Management
์ปจํ ์คํธ ํ๋ ๋ฐฉ์ด 2๊ฐ์ง ยท ์คํ ์ ์งยท์ฌ๊ฐ ์ ์ด 2๊ฐ์ง
- context_manager
- ContextOffloader
- Checkpoint
- Interrupts
์งํค๊ธฐ(๋ฐฉ์ด โ ์คํ๋ก๋), ๊ทธ๋ค์ ๋ฉ์ถ๊ธฐ(์ฒดํฌํฌ์ธํธ โ ์น์ธ) ์์๋ก ์ดํด๋ด ๋๋ค.
์งํค๊ธฐ vs ๋ฉ์ถ๊ธฐ
์งํค๊ธฐ = ์ปจํ ์คํธ๊ฐ ํ๋๋ฅผ ๋์ง ์๊ฒ ์ ์ง ยท ๋ฉ์ถ๊ธฐ = ์คํ์ ๋ฉ์ท๋ค ๋ค์ ์๋ ์ฌ๊ฐ
์งํค๊ธฐ
ํ๋ ์์์ ์ปจํ ์คํธ๋ฅผ ๋ณดํธ
- context_manager โ ์๊ณ์น ๊ฐ์ง ํ ์ ์ ์์ฝ (์ด๊ณผ ์ง์ ์ ์ฌ์์ฝ)
- ContextOffloader โ ํฐ ๋๊ตฌ ๊ฒฐ๊ณผ๋ ์ ์ฅ์๋ก
- ๋ค๋ฃจ๋ ๊ฒ: ๋งค ํธ์ถ์ ๋ชจ๋ธ ์ ๋ ฅ (ํ ํฐ)
- ์ป๋ ๊ฒ: ๋น์ฉ ์ ๊ฐ ยท ์๋์ฐ ์ด๊ณผ ๋ฐฉ์ง
๋ํ๊ฐ ์๋ฌด๋ฆฌ ๊ธธ์ด์ ธ๋ ํธ์ถ์ด ์คํจํ์ง ์๊ฒ โ ์ค์ ๋ง ํ๋ฉด ์๋์ผ๋ก ๋์ํฉ๋๋ค.
๋ฉ์ถ๊ธฐ
์คํ์ ์ ์งํ๋ค๊ฐ ์ด์ด๊ฐ๊ธฐ
- Checkpoint โ ์์คํ ์ด ๊ณํ์ ์ผ๋ก ์ ์ง
- Interrupts โ ์ฌ๋์ ์น์ธ ๋๋ฌธ์ ์ ์ง
- ๋ค๋ฃจ๋ ๊ฒ: ์์ด์ ํธ์ ์คํ ํ๋ฆ
- ์ป๋ ๊ฒ: ์ฅ๊ธฐ ์์ ๋ถํ ยท HITL ์์ ์ฅ์น
๋ฉ์ท๋ค๊ฐ ์ด์ด์ ์ฌ๊ฐ โ ๋์ ์ฐจ์ด๋ ๋ค์์ ์์ธํ ๋น๊ตํฉ๋๋ค.
์งํค๊ธฐ๋ ์ค์ ๋ง ํ๋ฉด ์๋์ผ๋ก ๊ฐ์ , ๋ฉ์ถ๊ธฐ๋ ๋ฉ์ถ ์ง์ ์ ์ฝ๋๋ก ์ฌ๊ฐ โ ์ฑ๊ฒฉ์ด ๋ฌ๋ผ ๋ท์ ํจ๊ป ์ธ ์ ์์ต๋๋ค.
context_manager ์๋ ๋ฐฉ์ด
์งํค๊ธฐ โ โ ํ๋ ์ ๊ทผ ๊ฐ์ง ์ ์ ์ ์์ฝ + ๋์ฉ๋ ๋๊ตฌ ๊ฒฐ๊ณผ ์คํ๋ก๋ฉ ๊ฐ์
-
1
์๊ณ์น ๊ฐ์ง
ํ์ฌ ์ปจํ ์คํธ ํ ํฐ ์๊ฐ ๋ชจ๋ธ ํ๋์ 85%๋ฅผ ์ด๊ณผํ๋ฉด ์๋ ํธ๋ฆฌ๊ฑฐ.
-
2
์ ์ ์์ฝ
์ค๋๋ ๋ํ๋ฅผ LLM์ด ์์ฝ์ผ๋ก ์์ถ. ํต์ฌ ์ ๋ณด(๊ฒฐ์ , ์ฌ์ค, ์์ ์ํ)๋ฅผ ๋ณด์กด.
-
3
์คํ๋ก๋ฉยท์ฌ์์ฝ
๋์ฉ๋ ๋๊ตฌ ๊ฒฐ๊ณผ๋ ContextOffloader๊ฐ ์คํ ๋ฆฌ์ง๋ก ์คํ๋ก๋. ์์ฝ ํ์๋ ์ด๊ณผ๊ฐ ์ง์๋๋ฉด ๋ฐ์์ ์ผ๋ก ์ฌ์์ฝ.
-
4
๋ชจ๋ธ ํธ์ถ
์์ถ๋ ์ปจํ ์คํธ๋ก ์ ์ ์ถ๋ก ์งํ. ์ฌ์ฉ์์๊ฒ ํฌ๋ช ํ๊ฒ ๋์.
- None
- ๊ธฐ๋ณธ๊ฐ โ ์๋ ๊ฐ์ ์์, ConversationManager ์ ์ฑ ๋ง ๋์
- 'auto'
- ์์ฝ + ์คํ๋ก๋ฉ์ ์๋ ์ ์ฉ โ ๋๋ถ๋ถ์ ํ๋ก๋์ ๊ถ์ฅ
- 'agentic'
- ๋ชจ๋ธ์ด ์ค์ค๋ก ์์ถยท์คํ๋ก๋ฉ ์์ ์ ํ๋จ (ํ ํฐโ์ ํ๋ ํธ๋ ์ด๋์คํ)
๊ฐ์งยท์์ฝยท์คํ๋ก๋ฉ ์ ๋ถ ์๋ โ ๊ฐ๋ฐ์ ์ฝ๋๋ context_manager='auto' ํ ์ค์ ๋๋ค.
ํฐ ๋๊ตฌ ๊ฒฐ๊ณผ๋ ๋ฐ์ผ๋ก โ ContextOffloader
์งํค๊ธฐ โก โ "ํฐ ๋๊ตฌ ๊ฒฐ๊ณผ๋ ๋งค๋ฒ ๋ค์ ์ ์ก"๋๋ ๋น์ฉ์ ์คํ๋ก๋ฉ์ผ๋ก ์ฐจ๋จ
ํต์ฌ ํฌ์ธํธ
- max_result_tokens
- ์ด ํฌ๊ธฐ๋ฅผ ๋๋ ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ์ธ๋ถ ์ ์ฅ์๋ก ์ด๋ (๊ธฐ๋ณธ 2500)
- preview_tokens
- ์ปจํ ์คํธ์๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ง ๋จ๊น (๊ธฐ๋ณธ 1000)
- storage
- InMemory ยท File ยท S3 ์ ์ฅ์ ์ ํ
- Unified Storage
- ์คํ ๋ฆฌ์ง ๋ฐฑ์๋ ํตํฉ ์ธํฐํ์ด์ค โ ์คํ๋ก๋ ์ ์ฅ์์ ์๋ ๋ค์์คํ์ด์ค(auto-namespace) ์ ์ฉ
- retrieve_offloaded_content
- ์๋ณธ์ด ํ์ํ๋ฉด ์๋ ๋ฑ๋ก๋ ๋๊ตฌ๋ก ์์ด์ ํธ๊ฐ ์ง์ ์กฐํ
์ฝ๋
from strands import Agent
from strands.vended_plugins.context_offloader.plugin import ContextOffloader
from strands.vended_plugins.context_offloader.storage import S3Storage
# 2500ํ ํฐ ์ด๊ณผ ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ S3๋ก โ ์ปจํ
์คํธ์๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ง
agent = Agent(
model="us.anthropic.claude-sonnet-4-6",
plugins=[ContextOffloader(
max_result_tokens=2500,
preview_tokens=1000,
storage=S3Storage(bucket="ctx-offload"),
)],
)
# ์๋ณธ์ด ํ์ํ๋ฉด retrieve_offloaded_content ๋๊ตฌ๋ก ์๋ ์กฐํ
์งํค๊ธฐ ๋ ๋๊ตฌ์ ๋ถ๋ด โ context_manager + ContextOffloader
๊ณ ๋ฅด๋ ๊ฒ์ด ์๋๋ผ ํจ๊ป ์ผ๋ ์กฐํฉ โ ์งํค๋ ๋์์ด ๋ค๋ฆ
context_manager
์์ฌ๊ฐ๋ ๋ํ ์ด๋ ฅ์ ์งํจ๋ค
- ๋์: ๋ํ ์ด๋ ฅ ์ ์ฒด (ํ ํฐ ํฉ๊ณ)
- ๋ฐฉ์: ์๊ณ์น ๊ฐ์ง โ ์ ์ ์์ฝ (์ด๊ณผ ์ ์ฌ์์ฝ)
- ์์ : ํ๋์ ์ ๊ทผํ ๋๋ง ๊ฐ์
- ๊ฒฐ๊ณผ: ์ด๋ ฅ์ด ์์ถ๋์ด ํ๋ ์์ผ๋ก
์ค์ ์ context_manager='auto' ํ ์ค โ ํ์์๋ ๊ฐ์ ํ์ง ์๋ค๊ฐ ํ๋ ์ ๊ทผ ์์๋ง ๋์ํฉ๋๋ค.
ContextOffloader
ํฐ ๋๊ตฌ ๊ฒฐ๊ณผ ํ๋๋ฅผ ๊ฒฉ๋ฆฌํ๋ค
- ๋์: ์๊ณ์น๋ฅผ ๋๋ ๊ฐ๋ณ ๋๊ตฌ ๊ฒฐ๊ณผ
- ๋ฐฉ์: ์ ์ฅ์๋ก ์คํ๋ก๋ + ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ง ์ ์ง
- ์์ : ํฐ ๊ฒฐ๊ณผ๊ฐ ์๊ธฐ๋ ์ฆ์
- ๊ฒฐ๊ณผ: ์๋ณธ์ ๋ฐ์, ํ์ํ๋ฉด ๋๊ตฌ๋ก ์กฐํ
ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ฅ์ฐฉ โ ๋ํ๊ฐ ์งง์๋ ๋๊ตฌ ๊ฒฐ๊ณผ ํ๋๊ฐ ํฌ๋ฉด ์ด์ชฝ์ด ๋ง์ต๋๋ค.
๋ฐํ์ ๋ ธํธ
๋ ๋๊ตฌ๋ ๊ฒฝ์ ๊ด๊ณ๊ฐ ์๋๋ผ ๋ถ๋ด ๊ด๊ณ์ ๋๋ค. context_manager๋ ๋ํ๊ฐ ๊ธธ์ด์ ธ์ ์๊ธฐ๋ ๋ฌธ์ ๋ฅผ, ContextOffloader๋ ๋๊ตฌ ๊ฒฐ๊ณผ ํ๋๊ฐ ์ปค์ ์๊ธฐ๋ ๋ฌธ์ ๋ฅผ ๊ฐ๊ฐ ๋ง์์. ๊ทธ๋์ ์ค๋ฌด์์๋ ๋ณดํต ๋ ๋ค ์ผญ๋๋ค. ๊ฐ์ด๋ฐ๊ฐ VS๊ฐ ์๋๋ผ ํ๋ฌ์ค์ธ ์ด์ ์ ๋๋ค.
๋ฉ์ถ๊ธฐ ๋ ๋ฐฉ์ โ Checkpoint vs Interrupts
๋ ๋ค "๋ฉ์ท๋ค ์ด์ด๊ฐ๊ธฐ" โ ์ฐจ์ด๋ ๋ฉ์ถ๋ ์ฃผ์ฒด์ ์ด์
Checkpoint
์์คํ ์ด ๋ฉ์ถ๋ค
- ๋๊ตฌ ์ฌ์ดํด ๊ฒฝ๊ณ์์ ๊ณํ์ ์ผ์ ์ ์ง
- ์ฅ๊ธฐ ์์ ๋ถํ , ์ฌ๋ฐฐํฌยท์ค๋จ ๋๋น
- stop_reason="checkpoint"๋ก ๋ฐํ
- ์ฌ๊ฐ: checkpointResume๋ฅผ ๋ด์ ์ฌํธ์ถ
์คํ์ ์ชผ๊ฐ ๋์๋ค๊ฐ ์ด์ด ๋ถ์ด๋ ์ฉ๋ โ ์ฌ๋์ ๊ฐ์ ์์ด๋ ๋์๊ฐ๋๋ค.
Interrupts
์ฌ๋ ๋๋ฌธ์ ๋ฉ์ถ๋ค
- ๊ณ ์ํ ๋๊ตฌ ์ง์ ์น์ธ ๋๊ธฐ (HITL)
- BeforeToolCallEvent์์ event.interrupt()
- stop_reason="interrupt"๋ก ๋ฐํ
- ์ฌ๊ฐ: interruptResponse๋ฅผ ๋ด์ ์ฌํธ์ถ
์ฌ๋์ ์น์ธ/๊ฑฐ๋ถ๊ฐ ๊ณง ์ฌ๊ฐ ์กฐ๊ฑด โ ํ๋ก๋์ ์์ ๋ฒจํธ์ ๋๋ค.
Checkpoint โ ์ผ์ ์ ์ง์ ์ฌ๊ฐ
๋ฉ์ถ๊ธฐ โ โ ๋๊ตฌ ์ฌ์ดํด ๊ฒฝ๊ณ์์ ๋ฉ์ท๋ค๊ฐ ์ด์ด์ ์ฌ๊ฐ (experimental, ์ํ ์บก์ฒ๋ take_snapshot()์ด ๋ณ๋)
ํต์ฌ ํฌ์ธํธ
- checkpointing=True
- ์ฒดํฌํฌ์ธํธ ํ์ฑํ โ experimental ๊ธฐ๋ฅ
- stop_reason="checkpoint"
- ๋๊ตฌ ์ฌ์ดํด ๊ฒฝ๊ณ์์ ์ผ์ ์ ์งํ๋ฉฐ ๋ฐํ
- to_dict / from_dict
- ์ง๋ ฌํํด ์ธ๋ถ ์ ์ฅ์์ ๋ณด๊ด, checkpointResume๋ก ์ฌ๊ฐ
- ์ฃผ์
- ๋ํ ์ด๋ ฅ์ ์บก์ฒํ์ง ์์ โ ์์ํ๋ SessionManager ๋ณํ
์ฝ๋
from strands import Agent
# ์ฒดํฌํฌ์ธํธ ํ์ฑํ โ tool_use ์ฌ์ดํด ๊ฒฝ๊ณ์์ ์ผ์ ์ ์ง (experimental)
agent = Agent(model="us.anthropic.claude-sonnet-4-6", checkpointing=True)
# ์คํ โ ์ฌ์ดํด ๊ฒฝ๊ณ์ ๋๋ฌํ๋ฉด stop_reason="checkpoint"๋ก ๋ฐํ
result = agent("ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ๋ถ์ํด์ค")
# ์ง๋ ฌํ โ ์ฒดํฌํฌ์ธํธ๋ฅผ dict๋ก ๋ณํํด ์ธ๋ถ ์ ์ฅ์์ ๋ณด๊ด
saved = result.checkpoint.to_dict()
# ์ฌ๊ฐ โ ์ ์ฅํ dict๋ฅผ checkpointResume๋ก ๊ทธ๋๋ก ๋๋๋ ค ์ ๋ฌ
agent({"checkpointResume": {"checkpoint": saved}})
Interrupts โ ๋ฉ์ถ๊ณ , ๋ฌป๊ณ , ์ฌ๊ฐํ๋ ์ ์ฐจ
๋ฉ์ถ๊ธฐ โก โ ๊ณ ์ํ ๋์ ์์์ ์ฌ๋์ ์น์ธ์ ๊ธฐ๋ค๋ฆฌ๋ HITL 4๋จ๊ณ
-
1
ํธ๋ฆฌ๊ฑฐ
BeforeToolCallEvent์์ event.interrupt(name, reason) ํธ์ถ โ ๊ณ ์ํ ๋์(ํ์ผ ์ญ์ , ๊ฒฐ์ ) ์ ์ ๋ฐ๋.
-
2
์ผ์ ์ ์ง
stop_reason="interrupt"๋ก ๋ฐํ โ ์ฌ๊ฐ์ ํ์ํ ์ ๋ณด๋ result.interrupts์ ๋ด๊น.
-
3
์ฌ์ฉ์ ํ์ธ
์ธ๋ถ ์์คํ (UI, Slack, API)์ด ์ฌ์ฉ์์๊ฒ ์น์ธ/๊ฑฐ๋ถ๋ฅผ ์์ฒญ.
-
4
์ฌ๊ฐ ๋๋ ์ค๋จ
์๋ต์ interruptResponse๋ก ๋ด์ ์ฌํธ์ถํ๋ฉด ์ด์ด์ ์คํ โ ๊ฑฐ๋ถ ์๋ต์ด๋ฉด ์์ด์ ํธ๊ฐ ๋์ ํ์.
- HumanInTheLoop
- ๋ด์ฅ HITL โ from strands.vended_interventions.hitl, Agent(interventions=[...])๋ก ์ฅ์ฐฉ
- allowed_tools
- ์น์ธ ์์ด ํต๊ณผ์ํฌ ๋๊ตฌ ๋ชฉ๋ก โ ๋๋จธ์ง๋ ์ฌ๋์๊ฒ ๋ฌป์ต๋๋ค.
- ask='stdio'
- ๊ธฐ๋ณธ์ ์ฝ์ ์น์ธ โ ์ฝ๋ฐฑ์ ๋๊ธฐ๋ฉด Slackยท์น UI๋ก ์ฐ๋
๊ณ ์ํ ๋๊ตฌ ์์์ ๋ฉ์ถ๊ณ , ์ฌ๋์ ์น์ธ์ผ๋ก๋ง ์ง๋๊ฐ๋๋ค โ ํ๋ก๋์ ์์ด์ ํธ์ ์์ ๋ฒจํธ
Session ยท Conversation ยท Memory ยท Context โ 4๊ณ์ธต์ผ๋ก ๊ธฐ์ต์ ์ค๊ณ