
Bedrock, Strands, AgentCore를 사용하여 AWS에서 AI 에이전트를 구축하고 배포하는 방법
요약
Amazon Bedrock, Strands, AgentCore를 활용하여 AWS 환경에서 AI 에이전트를 구축하고 배포하는 방법을 다룹니다. 모델 호출부터 도구를 갖춘 로컬 에이전트, 그리고 프로덕션 환경의 클라우드 배포까지의 단계별 계층 구조를 설명합니다.
핵심 포인트
- Amazon Bedrock은 에이전트의 두뇌 역할을 하는 모델을 제공합니다.
- Strands는 모델에 도구와 실행 루프를 제공하는 하네스 역할을 합니다.
- AgentCore는 구축된 에이전트를 프로덕션 환경에서 실행할 수 있게 합니다.
- 단순 모델 호출과 도구가 결합된 에이전트의 차이점을 이해할 수 있습니다.
단일 모델 호출부터 관리형 클라우드 엔드포인트에 이르기까지, Bedrock, Strands, AgentCore가 각각 무엇을 수행하고 어떻게 서로 결합되는지 이해할 수 있도록 AWS에서 AI 에이전트를 구축하고 배포하는 기초적인 관점을 살펴봅니다.
비디오 형식을 선호하신다면, 를 확인해 보세요.
요약 (TL;DR)
- 무엇을 구축하는가: "저녁으로 무엇을 만들어 먹을까?"라는 동일한 질문에 대해 세 가지 방식으로 답합니다. 원시 모델 호출 (raw model call), 하나의 도구를 가진 로컬 에이전트, 그리고 AWS에 배포된 동일한 에이전트입니다. 각 단계는 다음 AWS 계층이 무엇을 추가하는지 보여줍니다.
- 세 가지 계층: Amazon Bedrock은 모델이자 두뇌입니다. Strands는 모델에 도구와 루프 (loop)를 제공하는 하네스 (harness)입니다. Amazon Bedrock AgentCore는 이를 프로덕션 환경에서 실행합니다.
- 비용: 거의 들지 않습니다. 1장과 2장은 단순히 로컬 Node와 Bedrock 호출만 사용합니다. 3장은 마지막에 제거할 실제 리소스를 생성합니다. 프리 티어 (Free Tier) 적용 가능 계정으로 비용을 충당할 수 있으며, 신규 AWS 사용자는 최대 $200의 크레딧을 받을 수 있습니다.
- 소요 시간: 가볍게 훑어보는 데는 30분, 각 요소를 자세히 파헤치며 진행한다면 1시간 이상이 소요될 수 있습니다.
저는 AI 모델에게 저녁으로 무엇을 만들어 먹으면 좋을지 물었습니다. 모델은 몇 가지 제안을 해주었고, 제가 어떤 재료를 가지고 있는지 물었습니다.
당연한 소리죠! 무엇을 제안할지 파악하기 위해서는 매우 중요한 질문인데 모델은 전혀 알지 못했습니다. 저는 주방에 달걀, 시금치, 마늘, 쌀, 그리고 약간의 체다 치즈를 가지고 있었지만 모델은 그중 아무것도 볼 수 없었습니다. 제 세상에 접근할 권한이 없는, 단 한 번의 추측 기회만 가진 날카로운 두뇌였던 셈입니다.
이 간극(gap)이야말로 이 게시물의 전체 이야기입니다. 모델 자체는 똑똑하지만 눈이 없습니다. 이를 유용하게 만들려면 도구와 루프를 제공하는 하네스(harness)로 감싸야 합니다. 그리고 이것이 여러분의 기기에서 작동한다고 해도, 다음 벽에 부딪힙니다. 즉, 서버를 계속 돌보지 않고 다른 사람들을 위해 24시간 동안 실행하는 것입니다.
저는 똑같은 질문,

이를 AWS에 매핑하면 다음과 같습니다:
- **Amazon Bedrock**은 두뇌 역할을 합니다. Anthropic, Meta 등의 최상위 모델들을 호출할 수 있는 관리형 서버리스 (serverless) 방식이며, 대여할 GPU나 실행할 서버가 필요 없습니다. 모델을 선택하고, 프롬프트 (prompt)를 보내면, 응답을 받습니다.
- **Strands**는 하네스 (harness) 역할을 합니다. AWS에서 제공하는 오픈 소스 SDK로, 여러분을 대신해 도구 호출 (tool-calling) 루프를 실행하며 거의 모든 모델과 함께 작동합니다.
- **AgentCore**는 완성된 에이전트가 프로덕션 (production) 환경에서 실행되는 곳입니다. 에이전트를 위한 관리형 서버리스 호스팅을 제공하며, 메모리 (memory), API 게이트웨이 (gateway), 관측성 (observability) 등 실제 운영에 필요한 추가 기능들을 제공합니다.
서로 맞물리는 세 가지 계층입니다. 두뇌를 선택하고, 에이전트를 구축하고, 실제로 실행하세요. 이 포스트의 나머지 내용은 바로 그 문장을 코드로 구현하는 과정입니다.
사전 요구 사항 (Prerequisites)
- AWS 계정. 개인 계정도 괜찮습니다. 프리 티어 (Free Tier) 적용 가능 계정을 사용하면 이 모든 과정을 커버할 수 있으며, 신규 AWS 사용자는 최대 $200의 크레딧을 받을 수 있습니다.
- Bedrock 모델 액세스. 이 데모에서는 Claude를 사용하지만, 원하는 어떤 모델이든 사용할 수 있습니다. Amazon Bedrock 콘솔에서 선호하는 리전(Region)에 대해 해당 모델이 활성화되어 있는지 확인하세요.
- Node.js 22 이상. 저는 v24를 실행했습니다.
node --version으로 확인해 보세요. - 설정된 AWS CLI v2.
aws configure(또는 SSO)를 실행하여 기본 리전(Region)을 설정한 다음,aws sts get-caller-identity로 확인하세요. 계정 정보가 반환된다면 준비가 된 것입니다. 설치 가이드는 여기를 참조하세요. - 리전 (Region). 저는 모든 작업에 us-east-1을 사용했습니다.
us.*모델 추론 프로필(model inference profiles)은 해당 리전에서 해결되며, AgentCore Runtime도 그곳에서 사용할 수 있습니다. 다른 리전을 선택하는 경우, 시작하기 전에 모델과 AgentCore Runtime이 모두 해당 리전에 존재하는지 다시 확인하세요.
챕터 3(배포)을 위해서는 두 가지가 더 필요합니다. 챕터 1과 2에서는 필요하지 않으므로 나중에 설치해도 됩니다:
- AWS CDK:
npm install -g aws-cdk를 통해 전역(globally)으로 설치합니다. - 계정 및 리전에 대한 1회성 CDK 부트스트랩 (bootstrap): 이에 대한 자세한 내용은 해당 단계에서 다룹니다. 요약하자면, 계정에
CDKToolkit이라는 이름의 작은 CloudFormation 스택을 생성합니다. 이는 프로젝트 폴더가 아닌 클라우드에 존재하며, 한 번만 수행하면 됩니다. - AgentCore CLI:
npm install -g @aws/agentcore로 설치합니다.
이것이 중요한 이유: 1장과 2장은 Node와 AWS 자격 증명(credentials)만 있으면 실행할 수 있습니다. 모델의 답변을 확인하고 에이전트가 그 답변을 근거로 삼는 과정만 보고 싶다면, 2장까지만 진행하고 CDK나 AgentCore CLI를 설치하지 않아도 됩니다.
1장: 눈이 없는 뇌, Raw Bedrock
이를 위해 우리는 단순히 모델을 직접 호출합니다. 좋은 답변을 얻을 수 있지만, 결국 당신의 주방에 무엇이 있는지 묻는 것으로 끝납니다. 그 누락된 컨텍스트(context)가 바로 다음 장에서 메우게 될 간극입니다.
모델에 대하여, 그리고 왜 당신의 출력 결과가 제 것과 다르게 보일지에 대하여. 여기에 있는 모든 코드 샘플은 Claude Sonnet 5의 미국 교차 리전 추론 프로필인
us.anthropic.claude-sonnet-5를 사용합니다. 세 장 모두에서 동일한 모델을 사용하여 비교의 정직함을 유지합니다. 모델의 출력은 비결정론적(non-deterministic)이라는 점만 알아두세요. "저녁으로 무엇을 만들까요?"라고 두 번 물어보면, 같은 요리를 다른 단어로 얻을 수도 있고, 완전히 다른 요리를 얻을 수도 있습니다. 이는 예상된 결과입니다. 당신의 레시피가 제 것과 일치하지 않을 수 있으며, 당신이 두 번 실행한 결과조차 서로 일치하지 않을 수 있습니다.
프로젝트 설정
mkdir 01-bedrock-raw && cd 01-bedrock-raw
npm init -y
npm pkg set type=module
...
npm pkg set type=module 설정이 중요합니다. 코드는 ES 모듈 import 구문과 최상위 await(top-level await)를 사용하며, 이 플래그는 Node에게 해당 파일을 모듈로 취급하도록 알려줍니다. 우리는 tsx를 사용하여 TypeScript를 직접 실행하므로 별도의 컴파일 단계가 필요 없습니다.
전체 파일
bedrock.ts를 생성합니다:
import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime'
const client = new BedrockRuntimeClient({ region: 'us-east-1' })
...
각 부분을 하나씩 살펴보며 설명하겠습니다.
클라이언트는 특정 리전(Region)의 Bedrock을 가리킵니다:
const client = new BedrockRuntimeClient({ region: 'us-east-1' })
ConverseCommand는 Bedrock의 모든 채팅 모델과 통신할 수 있는 일관된 방식인 Converse API입니다. 모델의 이름을 지정하고 메시지 목록을 전달하기만 하면 됩니다:
const response = await client.send(new ConverseCommand({
modelId: 'us.anthropic.claude-sonnet-5',
messages: [
...
그 다음 응답에서 텍스트를 추출합니다. 메시지는 하나 이상의 콘텐츠 블록 (content block)을 가질 수 있기 때문에 경로가 다소 복잡해 보일 수 있으며, 따라서 첫 번째 블록에 접근합니다:
console.log(response.output?.message?.content?.[0]?.text)
실행하기
npx tsx bedrock.ts
반환된 결과
도움이 되는 일반적인 답변을 얻게 됩니다. 다음은 요약된 실행 결과입니다 (사용자의 결과는 다를 수 있으며, 전체 목록은 더 깁니다):
# 저녁 식사 아이디어
기꺼이 도와드리겠습니다! 더 좋은 제안을 드리기 위해 몇 가지 정보를 더 알면 도움이 됩니다:
...
마지막 줄을 다시 읽어보세요. 모델은 제 주방에 무엇이 있는지 묻고 있습니다. 모델은 이를 알 방법이 없으므로 학습 데이터 (training data)에서 영감을 받은 몇 가지 추천을 하고 답변을 약간 미결 상태로 남겨둡니다. 모델에 문제가 있는 것은 아닙니다. 모델은 똑똑합니다. 단지 눈이 보이지 않을 뿐이며, 답변할 기회가 단 한 번뿐인 것입니다.
제2장: 로컬 Strands 에이전트, 답변을 근거 있게 만드는 루프 (loop)
이제 동일한 두뇌에 도구 (tool) 하나와 루프 (loop)가 추가됩니다. 모델은 답변하기 전에 팬트리 (pantry, 식료품 저장고)를 확인하며, 이에 따라 답변이 완전히 달라집니다.
프로젝트 설정
mkdir 02-strands-agent && cd 02-strands-agent
npm init -y
npm pkg set type=module
...
전체 파일
agent.ts를 생성합니다:
import { Agent, tool, BedrockModel } from '@strands-agents/sdk'
const getPantry = tool({
...
여전히 짧습니다. 마지막 줄은 제1장의 것과 동일한 요청입니다. 그 위의 모든 것은 하네스 (harness, 프레임워크)입니다. 중요한 세 가지 요소를 살펴보겠습니다.
도구 (The tool). 이것은 에이전트가 제 세상과 연결되는 통로입니다:
const getPantry = tool({
name: 'get_pantry',
description: '사용자가 현재 집에 가지고 있는 재료를 반환합니다.',
...
description은 주석이 아닙니다. 모델은 도구(tool)를 언제 호출할지 결정하기 위해 이 내용을 읽으므로, 모델을 위해 작성해야 합니다. 이 도구는 인자(argument)를 받지 않으므로 추가로 선언할 것이 없습니다. callback은 모델이 도구를 호출할 때 실행되는 코드입니다. 제 코드에서는 하드코딩된 배열을 반환하며, 이는 데모용으로 완벽합니다. 실제 애플리케이션에서는 이 부분에서 데이터베이스나 API를 호출하게 될 것입니다.
에이전트 (The agent). 모델, 도구, 지침(instructions)이 하나로 연결됩니다:
const agent = new Agent({
model: new BedrockModel({ modelId: 'us.anthropic.claude-sonnet-5', region: 'us-east-1' }),
tools: [getPantry],
...
두뇌가 바뀌지 않았음을 확인할 수 있도록 의도적으로 1장에서 사용한 것과 동일한 모델을 사용했습니다. Strands TS SDK는 모델을 명시하지 않으면 기본값으로 Bedrock Claude Sonnet 모델을 사용하지만, 여기서는 명시적으로 전달했습니다. systemPrompt는 에이전트에게 무엇을 해야 할지 알려주고 도구를 가리킵니다. tools 배열은 에이전트가 사용할 수 있도록 허용된 도구 목록입니다.
호출 (The invocation). 단 한 줄입니다:
await agent.invoke('저녁으로 무엇을 만들면 좋을까?')
오케스트레이션(orchestration) 코드가 없습니다. 바로 이 부분이 주목할 만한 지점입니다.
루프가 실제로 수행하는 작업
invoke를 호출하면, Strands는 사용자가 직접 작성할 필요가 없는 사이클을 실행합니다:
- 모델이 요청을 읽고 이에 대해 추론(reasoning)합니다.
get_pantry를 호출하기로 결정합니다.- Strands가 도구를 실행하고 그 결과를 모델에 다시 전달합니다.
- 모델이 재료를 살펴보고 작업이 완료되었는지 결정합니다. 완료되지 않았다면 과정을 다시 반복합니다.
이 사이클이 바로 **에이전틱 루프 (agentic loop)**입니다. Strands와 같은 SDK를 사용하는 이유는 루프, 도구 호출(tool calling), 그리고 메시지 배관(message plumbing) 작업을 무료로 얻을 수 있기 때문입니다. 단순한 에이전트를 만드는 데 필요한 것은 도구와 프롬프트(prompt)뿐입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기