본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 08. 17:07

【AWS】Bedrock AgentCore를 사용하여 AI가 Python 데이터 분석을 수행하는 Code Interpreter를 사용하게 해보기!

요약

Amazon Bedrock AgentCore와 Strands Agents를 활용하여 AI 에이전트가 Python Code Interpreter를 실행하고 그 실행 흔적을 검증하는 환경 구축 방법을 소개합니다. CloudWatch Logs와 Runtime 응답을 통해 툴 호출 여부를 명확히 확인할 수 있는 구성이 핵심입니다.

핵심 포인트

  • Bedrock AgentCore 기반의 Code Interpreter 실행 환경 구축
  • Strands Agents의 callback handler를 이용한 실행 로그(Trace) 확보
  • AWS CDK를 활용한 에이전트의 Docker화 및 ECR/Runtime 배포
  • 모델의 답변이 아닌 실제 툴 호출 여부를 로그로 검증하는 방법

안녕하세요. 이번에는 Amazon Bedrock AgentCore를 사용하여 AI 에이전트에게 Code Interpreter를 실행시키고, 그 실행 흔적(証跡, Trace)까지 확인할 수 있는 검증 환경을 만들어 보았습니다.

단순히 "답이 맞다"는 것만으로는 정말로 Code Interpreter를 사용했는지 알 수 없습니다. 그래서 이번에는 Strands Agents의 callback handler와 metrics를 사용하여, code_interpreter의 실행 시작, 결과, 소요 시간을 CloudWatch Logs와 Runtime 응답(Response) 양쪽 모두에 남기는 구성으로 만들었습니다.

이 기사는 다음과 같은 분들을 위해 작성되었습니다.

  • Amazon Bedrock AgentCore를 사용해보고 싶은 분
  • Strands Agents에서 AgentCore Code Interpreter를 사용하고 싶은 분
  • AWS CDK (Python)로 Amazon Bedrock AgentCore Runtime에 에이전트를 배포하고 싶은 분
  • "Code Interpreter를 사용했다는 증거"를 로그로 남기고 싶은 분

실제로 구동해보고 싶으신 분은 아래를 참조해 주세요.

이번 목표는 다음 3가지입니다.

  • Strands Agents로 작성한 Python 에이전트를 Docker화하기
  • CDK로 ECR과 Bedrock AgentCore Runtime에 배포하기
  • 에이전트가 code_interpreter를 실제로 사용했음을 응답(Response)과 CloudWatch Logs로 확인할 수 있게 하기

포인트는 마지막의 "흔적(証跡)"입니다. 모델이 답변 문구로 "Python으로 계산했습니다"라고 말하더라도, 그것만으로는 증거로서 약합니다. 그래서 Strands가 발행하는 current_tool_use 이벤트와 toolResult, 그리고 metrics.tool_metrics를 대조하여 실제로 툴(Tool)이 호출되었는지 여부를 판정합니다.

mkdir bedrock-agentcore-code-interpreter-demo && cd $_

먼저 CDK의 의존 관계를 정의합니다.

aws-cdk-lib==2.255.0
constructs>=10.0.0,<11.0.0
cdk-ecr-deployment>=4.0.0,<5.0.0
-r requirements.txt
pytest>=8.0.0,<9.0.0

cdk-ecr-deployment는 CDK가 빌드한 Docker 이미지를 전용 ECR Repository로 복사하기 위해 사용합니다.

app.py는 일반적인 CDK 엔트리 포인트(Entry point)입니다.

#!/usr/bin/env python3
import os
import aws_cdk as cdk
...

cdk.json은 항상 이 프로젝트의 가상 환경을 사용하도록 설정해 둡니다.

{
"app": ".venv/bin/python app.py",
"context": {
...

.venv/bin/python을 고정해 두면, 가상 환경을 활성화(activate)하지 않은 상태에서도 CDK가 동일한 Python 환경을 사용해 줍니다.

python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt -r agent/requirements.txt

AWS 인증과 리전(Region)을 확인합니다.

aws sts get-caller-identity
export AWS_REGION=ap-northeast-1

필요하다면 bootstrap 합니다.

cdk bootstrap

에이전트 구현은 agent/code_interpreter_agent/agent.py에 둡니다.

import os
import boto3
from strands import Agent
...

여기서 사용하고 있는 aws.codeinterpreter.v1은 AWS 관리형 버전의 Code Interpreter입니다. 따라서 이번에는 AWS::BedrockAgentCore::CodeInterpreterCustom은 만들지 않습니다.

이번에는 "정말로 도구를 사용했는지"를 확인하고 싶기 때문에, 시스템 프롬프트(System Prompt)에서도 계산이나 데이터 처리 시에는 code_interpreter를 사용하도록 명시적으로 지시하고 있습니다.

SYSTEM_PROMPT = """당신은 계산, 데이터 분석, 코드 검증을 수행하는 일본어 어시스턴트입니다.
계산, 통계, 데이터 처리, 알고리즘 또는 코드 검증을 요청받은 경우,
추측만으로 답변하지 말고, 반드시 code_interpreter 도구를 사용하여 실제로 코드를 실행하십시오.
...

단순히 최종 답변만 봐서는 모델이 머릿속으로 계산한 것인지, Code Interpreter를 사용한 것인지 구분할 수 없습니다.

그래서 이번에는 다음 정보를 기록합니다.

toolUseId

phase

:started

/completed

/failed

action

language

  • 실행 코드
  • 실행 결과
    durationMs

Strands에서는 도구 실행 중에 current_tool_use가 콜백(callback)으로 흘러 들어옵니다. 이를 사용하여 Code Interpreter의 시작 시점을 잡습니다.

def callback(self, **kwargs: Any) -> None:
current_tool_use = kwargs.get("current_tool_use")
if isinstance(current_tool_use, dict):
...

Code Interpreter의 입력은 스트리밍 도중에 JSON 문자열의 파편으로 도착할 수 있기 때문에, 입력이 완성된 타이밍에 action이나 code를 해석하도록 하고 있습니다.

도구 실행 후에는 message.content[].toolResult가 도착하므로, 이를 통해 completed인지 failed인지를 판정합니다.

def _result_status(tool_result: dict[str, Any]) -> bool:
status = str(tool_result.get("status", "success")).lower()
return status not in {"error", "failed", "failure"}

콜백뿐만 아니라 최종적인 AgentResult.metrics.tool_metrics도 참조합니다. 이를 통해 성공 횟수나 총 실행 시간도 확인할 수 있습니다.

metric = result.metrics.tool_metrics["code_interpreter"]
metric.call_count
metric.success_count
...

이 값을 콜백에서 기록한 정보와 대조함으로써, 응답으로 반환할 invocationCountdurationMs의 정밀도를 높이고 있습니다.

로그는 1행 JSON으로 출력합니다.

event = {
"event": "code_interpreter_evidence",
"requestId": self.request_id,
...

코드나 실행 결과가 너무 길면 로그를 읽기 어려워지므로, 4000자 상한으로 자르고(truncate), truncatedoriginalChars도 남겨두고 있습니다.

runtime_app.py에서는 각 요청마다 requestId를 발행하고, 에이전트 실행 후에 증적(evidence) 요약을 응답에 포함합니다.

def invoke_agent(payload: dict) -> dict:
prompt = payload.get("prompt")
if not isinstance(prompt, str) or not prompt.strip():
...

응답 예시는 다음과 같습니다.

{
"response": "처음 10개의 피보나치 수는 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 입니다.",
"evidence": {
...

여기서 중요한 점은, used는 모델의 자기 신고가 아니라 실제로 current_tool_use가 발생했을 때만 true가 된다는 점입니다.

AgentCore Runtime에 올리기 위해 에이전트를 Docker화합니다.

FROM public.ecr.aws/docker/library/python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
...

의존성(Dependencies)은 에이전트용으로 분리했습니다.

bedrock-agentcore>=1.3.0,<2.0.0
strands-agents>=1.0.0,<2.0.0
strands-agents-tools>=0.2.0,<1.0.0
...

먼저 전용 ECR Repository를 생성합니다.

image_repository = ecr.Repository(
self,
"AgentImageRepository",
...

CDK 표준의 DockerImageAsset만 사용하면 전용 Repository를 사용하기 어렵기 때문에, cdk-ecr-deployment를 사용하여 복사합니다.

image_asset = ecr_assets.DockerImageAsset(
self,
"AgentImageAsset",
...

AgentCore Runtime이 필요로 하는 권한을 부여합니다.

runtime_role.add_to_policy(
iam.PolicyStatement(
actions=[
...

여기에 더해, ECR pull, CloudWatch Logs, bedrock:InvokeModel도 부여하고 있습니다.

마지막으로 Runtime 본체입니다.

runtime = bedrock_agentcore.CfnRuntime(
self,
"AgentRuntime",
...

이번에는 "증적(Evidence)이 정말로 남는가"가 중요하므로, 그 부분을 중점적으로 테스트하고 있습니다.

예를 들어 다음과 같은 관점입니다.

  • startedcompleted 로그가 출력되는가
  • Code Interpreter를 사용하지 않았을 때 used: false가 되는가
  • 여러 번 호출했을 때 invocationCount가 올바르게 증가하는가
  • 긴 코드나 결과가 잘리는가
  • 분할된 JSON 입력에서도 최종적으로 action이나 code를 올바르게 가져올 수 있는가

예:

def test_collects_successful_code_interpreter_evidence(caplog) -> None:
collector = CodeInterpreterEvidenceCollector(
request_id="request-1",
...

CDK 측에서도 ECR, Runtime, 환경 변수, IAM 권한을 assertions로 검증하고 있습니다.

pytest
cdk synth
cdk deploy

이번에는 피보나치 수열 계산을 시켜보려고 합니다. 다음 작업을 수행하여 런타임 플레이그라운드 (Runtime Playground) 화면으로 이동해 주세요.

  • Bedrock AgentCore 콘솔로 이동
  • 왼쪽 메뉴의 테스트 (Test) 섹션 아래에 있는 **런타임 플레이그라운드 (Runtime Playground)**를 클릭
  • 런타임 에이전트에서 이번에 생성한 런타임 이름을 선택하고, 엔드포인트가 DEFAULT로 되어 있는지 확인

그럼, 입력창에 다음을 입력합니다. 증적 확보를 위해 Python 코드도 명시하도록 합니다.

{"prompt": "Python으로 처음 10개의 피보나치 수를 계산해 주세요. 계산에 사용한 Python 코드를 명시해 주세요."}

실행 (Run) 버튼을 클릭하면 다음과 같이 응답이 돌아올 것입니다. (조금 보기 불편할 수 있지만, 정렬하면 다음과 같습니다!)

## 실행 결과
---
### 📝 사용한 Python 코드
...

이어서 CloudWatch Logs에서 동일한 requestId를 검색하여, 다음과 같은 code_interpreter_evidence 로그를 확인합니다.

{
"event": "code_interpreter_evidence",
"requestId": "xxxxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxx",
...

이로써 "최종 답변이 맞는지"뿐만 아니라, "실제로 Code Interpreter가 호출되어 무엇을 실행했고 성공했는지"까지 추적할 수 있게 됩니다.

이번에는 Amazon Bedrock AgentCore Runtime에 Strands Agent를 배포하고, AWS 관리형 Code Interpreter를 사용하는 구성을 만들어 보았습니다.

구성 자체는 비교적 간단하지만, 실제 운영이나 검증 단계에서는 "정말로 도구(Tool)를 사용했는가"를 확인하고 싶은 상황이 많을 것이라고 생각합니다. 그 부분을 Strands의 callback handler와 metrics, CloudWatch Logs, 그리고 Runtime 응답을 조합하여 확인할 수 있도록 만든 것이 이번의 핵심 포인트입니다.

다음 단계로는 CSV 분석이나 그래프 생성 등, Code Interpreter다운 유스케이스(Use case)로 확장해 나가면 재미있을 것 같습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0