AgentCore를 사용하여 지원 에이전트를 배포하는 첫 번째 서비스형 에이전트(Agent as a Service)
요약
본 문서는 AgentCore를 활용하여 지원 에이전트를 서비스형(Agent as a Service) 형태로 배포하는 과정을 안내합니다. 단일 명령어와 추적 기능을 통해 작게 작성하고, 어디서든 호출 가능하게 만들며, 모든 실행 기록을 확인하고 삭제할 수 있는 워크플로우를 제시합니다.
핵심 포인트
- AgentCore는 지원 에이전트의 AaaS 배포 프로세스를 간소화합니다.
- 각 세션은 자체 마이크로VM에 할당되어 격리성을 보장합니다.
- OpenTelemetry 스팬을 X-Ray에 방출하여 호출 과정을 관측 가능하게 합니다.
지원팀은 최초의 자동화를 원합니다. 이 아티클은 전체 과정을 안내합니다: 하나의 폴더, 배포를 위한 하나의 명령어, 작동 여부를 증명하기 위한 하나의 호출(invoke), 확인 가능한지 증명하는 하나의 추적(trace), 그리고 모든 것을 사라지게 할 하나의 명령어. 아래의 모든 숫자는 작성하는 동안 기록되었습니다.
사용 사례 (The use case)
3명의 직원이 운영하는 지원 데스크는 하루 종일 같은 질문들(환불 총액, 반품 기간, 정책 등)에 답합니다. 그들은 최초의 자동화를 원하지만, 팀원 누구도 서비스를 프로덕션 환경에 배포해 본 적이 없습니다. 요구 사항은 지능 자체가 아니라, 신뢰할 수 있는 루프입니다: 작게 무언가를 작성하고, 어디서든 호출 가능하게 만들고, 나중에 무엇을 했는지 확인하며, 같은 날 삭제할 수 있어야 합니다.
AgentCore가 여기서 하는 일 (What AgentCore does here)
AgentCore의 9가지 기능 중 2가지가 이 사용 사례를 처리합니다.
- 런타임(Runtime):
app/aia_uc01/을 관리형 엔드포인트로 호스팅합니다. 빌드는 CodeZip이므로 컨테이너화되지 않으며, 각 세션은 자체 마이크로VM을 할당받습니다. 프로토콜은/ping과/invocations를 통한 일반 HTTP입니다. - 관측 가능성(Observability): 모든 호출(invoke)은 OpenTelemetry 스팬을 X-Ray에 방출하며, 이는 CloudWatch를 통해 읽을 수 있습니다. 따라서 도구 호출(tool call)이 단순히 로그의 텍스트가 아니라 자체 스팬으로 표시됩니다.
나머지 7가지 기능은 사용하지 않습니다. Memory가 없으므로 에이전트는 대화 간 아무것도 기억하지 못합니다. Gateway와 Identity도 없습니다. 왜냐하면 이 데스크는 아직 연결할 외부 시스템이 없기 때문입니다. 배포된 런타임은 DEFAULT 엔드포인트 뒤의 버전 1이며, JSON을 변경하고 재배포하면 동일한 엔드포인트의 버전 2가 생성되는데, 이것이 이 수준에서의 전체 버전 관리 이야기입니다.
요구 사항 (Requirements)
- Node.js 20 이상 (여기서는 22.22.2), AgentCore CLI 0.31.1, AWS CLI 2.x, uv 0.11.9
- 호스트에서 Python 3.10부터 3.14까지 사용 가능; 여기서 런타임 대상은 인터프리터가 아닌 계약(contract)에 설정된 PYTHON_3_13입니다.
- Bedrock 모델 접근 권한이 있는 AWS 계정; 모든 것은 us-east-1 리전을 사용합니다.
- 모델: deepseek.v3.2,
MODEL_ID환경 변수를 통해 코드에 전달됩니다.
agentcore --version # 0.31.1
aws configure get region # us-east-1
aws sts get-caller-identity --query Account --output text
...
코드
https://github.com/pinxiong/bedrock-agentcore-in-action/tree/main/usecases/01-first-agent
01-first-agent/
├── run.py # 모든 작업에 사용되는 크로스 플랫폼 진입점
├── Makefile # run.py를 포워딩하며, 로직은 포함하지 않음
...
이 폴더는 make check가 이를 임시 디렉터리로 복사하고 내부에서 다시 검사를 실행하므로 자체적으로 완결성이 확보됩니다.
작동 방식
전체 에이전트 인터페이스는 main.py의 한 화면에 담겨 있습니다:
SYSTEM_PROMPT = """You are the first-line assistant for the Northwind Gear
support desk. Answer in one short sentence.
When a question involves arithmetic, call the add_numbers tool instead of
...""
프롬프트가 제품입니다. 도구는 추적 기록에 보여줄 무언가가 있도록 존재합니다. 도구를 절대 호출하지 않는 에이전트는 단일 스팬(single span)만 생성하며 거의 아무것도 증명하지 못합니다. 진입점은 비동기 제너레이터(async generator)이며, 이것이 스트리밍(streaming)이 추가 기능이라기보다는 기본 형태인 이유입니다.
복사할 가치가 있는 부분은 스트림 주변의 필터입니다. DeepSeek 모델은 때때로 자체 채팅 템플릿 마커, 예를 들어 <|DSML|function_calls를 일반 텍스트 채널에 작성합니다. 이 누출(leak)은 간헐적입니다: 본 기사를 위해 포착된 네 번의 로컬 호출과 두 번의 클라우드 호출에서는 나타나지 않았고, 이 시리즈의 이전 워크스루에서는 첫 번째 시도에서 나타났습니다. 이 정화기(sanitizer)는 마커로 성장할 수 있는 짧은 접미사(suffix)를 붙잡아 두고, 에이전트 메시지가 한 번 끝날 때마다 초기화하며, 메시지가 끝날 때 남아있는 것을 플러시합니다:
if "messageStart" in inner:
scrub = StreamSanitizer() # 에이전트 메시지당 하나의 깨끗한 필터
block_index = 0
...
자체 오프라인 테스트가 가능한 저렴한 보험과 같습니다: make unit은 기록된 마커 바이트를 대상으로 6가지 케이스를 실행하며 AWS는 관여하지 않습니다.
모델 선택은 하나의 함수로 처리되는데, 기본값이 중요하기 때문입니다:
def load_model() -> BedrockModel:
return BedrockModel(model_id=os.environ.get("MODEL_ID", DEFAULT_MODEL_ID))
만약 MODEL_ID가 누락되면, SDK 기본값이 사용자의 리전에서 거부하는 모델을 선택할 수 있습니다. 따라서 ID를 명시적으로 전달하는 것이 지리적 문제로 인해 첫 배포가 실패하는 것을 방지합니다.
배포하기 (Deploy it)
사용 사례 폴더에서 다음 명령어를 실행합니다:
make doctor
toolchain
PASS python 3.14.3 (CodeZip 3.10부터 3.14 범위 내)
PASS node v22.22.2
...
이 15가지 체크 항목은 네 가지 그룹으로 나뉩니다: 도구 체인(toolchain)용 4개, CLI용 1개, 폴더 자체용 7개, AWS 환경용 3개입니다.
make dev는 실제 모델을 사용하고 배포 없이 로컬에서 포트 8080으로 동일한 코드를 실행합니다. 로컬 호출은 약 2초 만에 도구를 통해 응답했습니다. 배포는 하나의 명령어로 끝납니다:
make deploy
AWS에 배포 ..................... 1분 27초
총 소요 시간: 1분 51초
...

CloudFormation을 합성하는 데 15.4초가 걸렸고, 나머지 1분 27초는 스택 생성에 사용되었습니다. 이 계약(contract)이 생성하는 스택은 네 가지 리소스로 구성됩니다: AWS::BedrockAgentCore::Runtime, 해당 런타임이 실행되는 AWS::IAM::Role, 그 역할의 AWS::IAM::Policy, 그리고 AWS::CDK::Metadata입니다. 이것이 전체 발자국(footprint)이며, 리소스 유형은 evidence/23-stack-resources.txt에 기록되어 있습니다. 상태 확인과 실제 호출 테스트는 다음과 같습니다:
make status
make invoke
aia_uc01: 배포됨 - 런타임: READY
arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/aiauc01_aia_uc01-R3MXCi9yld
...

네 가지 단언(assertion)은 목업(mock)이 아닌 실제 배포를 대상으로 실행됩니다:
make test
runtime
aiauc01_aia_uc01 v1 · arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/aiauc01_aia_uc01-R3MXCi9yld
PASS assert_runtime_1: the runtime exists in the target region and reports status READY
...

teardown은 두 개의 명령을 실행하는 make target 중 하나이며, 두 번째 명령이 삭제를 수행합니다. make status가 이를 확인해 줍니다:
make down
make status
All schemas reset to empty state
✓ Tear down stack
✓ Deployed to 'default' (stack: AgentCore-aiauc01-default)
...
down은 agentcore.json을 재작성하고 aws-targets.json을 비웁니다. 다시 배포하려면 두 파일 모두 git에서 복원해야 합니다.
생성된 결과물 (What it produced)
invoke는 의도적으로 평범합니다: 한 문장, 올바른 산술 계산, 그 외 아무것도 없습니다. 흥미로운 아티팩트는 trace이며, tree는 runtime 자체가 그린 에이전트 루프처럼 보입니다:
invoke_agent Strands Agents 2.50 s tools=["add_numbers"]
execute_event_loop_cycle cycle 1
chat deepseek.v3.2 0.68 s 431 in / 60 out
...


execute_tool span이 핵심입니다. 이것이
make down은 비대화형(non-interactive) 셸에서 첫 줄부터 "This command requires an interactive terminal" 오류를 발생시켰습니다. 파이프되거나 CI 환경에서 실행할 때 문제가 됩니다. 해결책은agentcore remove all에-y플래그를 사용하는 것이며, 이는 이제run.py가 전달합니다.agentcore remove all은agentcore.json을 비우고 또한aws-targets.json도 삭제하므로, 다음 배포 시 대상(target)이 없어 "No resources match the given filters"라는 응답을 받게 됩니다. 나중에 다시 배포할 계획이라면 두 파일을 git에서 복원해야 합니다.
주요 내용 (Takeaways)
- 계약(contract)은 두 개의 JSON 파일입니다. AWS 측의 나머지 모든 것은 생성되므로, 배포는 재현 가능하고 제거(teardown)는 실제 작동합니다.
- CodeZip은 Dockerfile이 필요 없다는 의미입니다: 플랫폼이
codeLocation을 압축하고, 런타임 버전과 엔드포인트는 동일한 계약에서 가져옵니다. - 에이전트는 도구 호출(tool call) 자체가 스팬(span)을 갖기 전까지 관찰 가능하지 않습니다. 필요하기 전에 이 단언(assertion)을 작성하세요.
- 스트림 정화기(stream sanitizer)는 처음부터 진입점(entrypoint)에 있어야 합니다. 왜냐하면 기본 골격 누출(scaffolding leaks)은 간헐적이며, 테스트 전용 필터는 무용지물이 되기 때문입니다.
- 전체 루프 측정 결과: 의사 검진(doctor)은 몇 초 만에, 배포(deploy)는 1분 51초, 호출(invoke)은 9.911ms, 종료(down)는 1분 28초가 소요되었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
