AgentCore Harness 개요
선언적 배포의 갈림길 — CreateHarness·InvokeHarness, 선언 스펙 구성, Runtime vs Harness
AgentCore Harness
선언적 배포의 갈림길 — CreateHarness·InvokeHarness, 선언 스펙 구성, Runtime vs Harness
코드가 아니라 선언으로 배포한다
CreateHarness 한 번으로 — 오케스트레이션은 AgentCore가 실행
왜 선언적 배포인가
Runtime 커스텀 배포와의 갈림길
완성된 에이전트, 남은 배포
Runtime 커스텀 배포가 요구하는 것들 — 전부 개발자의 몫
코드 작성
main.py + @app.entrypoint
- 프레임워크 선택 — Strands, LangGraph 등
- ReAct 루프 등 오케스트레이션을 직접 구현
패키징 · 배포
ZIP 또는 컨테이너 이미지
- 의존성 관리와 빌드 파이프라인 필요
- 배포 산출물을 만들어 업로드
변경마다 재배포
프롬프트 한 줄도 코드 수정
- 수정 → 빌드 → 재배포 사이클 반복
- 롤백·버전 관리도 개발자 몫
모델 + 프롬프트 + 도구 조합이 표준적이라면 — 이 과정 전부를 API 선언 1번으로 대신할 수 있을까?
그 답이 Managed Agent Harness입니다.
Managed Agent Harness
에이전트를 "코드"가 아니라 "스펙"으로 정의 — 실행은 AgentCore 소유
Managed Agent Harness
모델·프롬프트·도구·메모리를 선언 스펙으로 제출하면, AgentCore가 에이전트를 실행합니다
- GA — AgentCore 지원 15개 리전
- 오케스트레이션 엔진: Strands Agents
- 에이전트 정의: API 파라미터 (JSON 스펙)
- 에이전트 코드 0줄
"무엇을 할지"만 선언하면 "어떻게 실행할지"는 서비스가 처리합니다 — ReAct 루프는 Strands 엔진이 대신 수행합니다.
하네스란 무엇인가 — Agent = Model + Harness
모델을 감싸는 나머지 전부 — 도구·메모리·컨텍스트·샌드박스·오케스트레이션·서빙을 누가 소유하는가의 문제
같은 에이전트, 두 가지 배포 방식
Runtime과 Harness — 정의·오케스트레이션·배포·변경의 구조적 차이
| 항목 | Runtime (커스텀 배포) | Harness (선언적 배포) |
|---|---|---|
| 에이전트 정의 | Python/Node.js 코드 | API 파라미터 (JSON 스펙) |
| 오케스트레이션 | 개발자가 구현 (Strands, LangGraph 등) | AgentCore가 실행 (Strands 기반) |
| 배포 산출물 | ZIP 또는 컨테이너 이미지 | CreateHarness 호출 1번 |
| 프레임워크 자유도 | 무제한 | 선언 스펙 범위 내 |
| 변경 방법 | 코드 수정 → 재배포 | UpdateHarness (새 버전 자동 생성) |
| 시작 속도 | 코드 작성 필요 | 이름 + IAM 역할만으로 생성 가능 |
자유도와 시작 속도의 교환입니다 — 어느 쪽이 유리한지는 Part 4의 선택 기준에서 판단합니다.
Harness 구조
CreateHarness · InvokeHarness · CLI · 컨트롤/데이터 플레인
Harness API
선언(CreateHarness)과 호출(InvokeHarness)의 2단 구조
Harness API
스펙을 제출하면 리소스가 생기고, 메시지를 보내면 스트리밍으로 응답합니다
- CreateHarness — 컨트롤 플레인에서 선언
- InvokeHarness — 데이터 플레인에서 스트리밍 호출
- 최소 파라미터: harnessName + executionRoleArn
- UpdateHarness — 새 버전 자동 생성 · 롤백 가능
기억할 API는 단 2개 — 만들 때 CreateHarness, 부를 때 InvokeHarness입니다.
Harness 라이프사이클 — Create · Invoke · Update
컨트롤 플레인에서 선언, 데이터 플레인에서 호출, 다시 컨트롤 플레인에서 갱신
버전과 엔드포인트
UpdateHarness가 쌓는 기록과, 호출이 들어오는 진입점 — Runtime과 같은 운영 문법
버전 — 배포의 기록
- UpdateHarness마다 새 버전 자동 생성 — 이전 버전 보존(롤백 안전망)
- ListHarnessVersions로 이력 조회
- 엔드포인트의 targetVersion이 가리키는 대상
엔드포인트 — 호출의 진입점
- DEFAULT 엔드포인트 자동 생성 — 항상 최신 버전을 추적
- CreateHarnessEndpoint(endpointName·targetVersion)로 dev·test·prod 분리
- 커스텀 엔드포인트는 지정 버전에 고정 — 프로덕션 트래픽 보호
Harness는 논리 리소스입니다 — 뒤에서 관리형 AgentCore Runtime이 실행하므로, 세션·호출·스로틀링 쿼터는 Runtime과 동일하게 적용됩니다.
컨트롤 플레인 vs 데이터 플레인
boto3 서비스명이 다름 — 바꿔 쓰면 API를 찾지 못하는 함정
bedrock-agentcore-control
컨트롤 플레인 — 리소스 관리 전용
- CreateHarness · GetHarness
- UpdateHarness · DeleteHarness
- ListHarnesses · ListHarnessVersions
- CreateHarnessEndpoint
스펙을 만들고 고치는 쪽 — UpdateHarness는 기존 버전을 보존한 채 새 버전을 자동 생성해 롤백 안전망이 됩니다.
bedrock-agentcore
데이터 플레인 — 호출 전용
- InvokeHarness
- 스트리밍 이벤트 스트림 반환
- runtimeSessionId로 세션 유지
- Per-invocation Override 파라미터 수용
만들어진 Harness에 메시지를 보내는 쪽 — 생성은 control, 호출은 데이터 플레인으로 기억하세요.
CreateHarness — 최소 선언
이름 + IAM 역할 — 파라미터 2개로 생성되는 에이전트
핵심 포인트
- harnessName
- 영숫자+밑줄, 최대 40자 — 생성 후 변경 불가
- executionRoleArn
- Harness가 리소스에 접근할 IAM 역할 — 필수 2개 중 하나
- 기본 모델
- 모델 미지정 시 Claude Sonnet 4.6 자동 적용
- 빌트인 도구
- 도구 미지정 시 shell + file_operations 자동 포함
코드
import boto3
# 생성은 컨트롤 플레인 — bedrock-agentcore-control
client = boto3.client('bedrock-agentcore-control')
# 최소 선언 2개 — 이름 + IAM 역할만으로 에이전트 생성
response = client.create_harness(
harnessName='helpdesk_harness',
executionRoleArn='arn:aws:iam::123456789012:role/HarnessRole',
)
# 모델 미지정 → Claude Sonnet 4.6 · 도구 미지정 → 빌트인 자동 포함
print(response['harnessArn'])
InvokeHarness — 스트리밍 호출
세션 ID로 대화 유지, 응답은 토큰 단위 스트림으로 수신
핵심 포인트
- runtimeSessionId
- 33~100자 필수 — 짧으면 ValidationException, UUID(36자) 권장
- 세션 유지
- 같은 ID로 재호출하면 이전 대화 컨텍스트 유지, 새 ID면 새 세션
- messages
- Converse 형식 — role + content 배열
- response['stream']
- 이벤트 스트림 — contentBlockDelta의 delta.text로 텍스트 수신, messageStop에 stopReason
- toolResultMetadata
- MCP 도구 결과 메타데이터 전용 델타 채널 — 텍스트 델타와 별도 이벤트로 스트리밍 수신
코드
import boto3, uuid
# 호출은 데이터 플레인 — bedrock-agentcore
client = boto3.client('bedrock-agentcore')
# runtimeSessionId — 33~100자 필수, UUID(36자) 사용 권장
response = client.invoke_harness(
harnessArn=HARNESS_ARN,
runtimeSessionId=str(uuid.uuid4()),
# messages — Converse 형식 (role + content 배열)
messages=[{'role': 'user', 'content': [{'text': 'VPN 연결이 안 됩니다'}]}],
)
# 이벤트 스트림 — contentBlockDelta에서 텍스트 추출
for event in response['stream']:
if 'contentBlockDelta' in event:
delta = event['contentBlockDelta']['delta']
print(delta.get('text', ''), end='')
워크플로 속의 Harness — Step Functions
InvokeHarness를 워크플로의 한 스텝으로 — 문서 분류·추출 같은 추론 태스크를 파이프라인에 삽입
Optimized 통합 리소스
invokeHarness를 스텝으로 선언
- Resource는 arn:aws:states::: 뒤에 bedrockagentcore:invokeHarness
- Step Functions URI만 하이픈 없이 bedrockagentcore
Arguments + JSONata
{% … %} 표현식으로 인자 전달
- HarnessArn · RuntimeSessionId 지정
- Messages는 Converse 형식 그대로
Request-Response 전용
.sync · .waitForTaskToken 미지원
- 스텝 최대 실행 15분
Override 그대로
스텝에서도 per-invocation override
- model·systemPrompt 등 사용 가능
- Harness 중복 생성 불필요
세션 ID를 워크플로 실행 간 유지하면 에이전트 컨텍스트가 이어집니다 — 병렬·순차 에이전트 실행과 human approval 스텝을 조합합니다 (harness 가용 리전 전체에서 사용 가능).
CLI로 같은 일 — create · deploy · invoke
API가 정의라면 CLI는 지름길 — 위저드가 스펙 작성을 대신하는 경로
터미널 — Managed Harness 실습 경로
1
2
3
선언 스펙 구성
모델 · 도구 · Memory · Skills · 실행 정책
선언 스펙
에이전트를 이루는 여섯 조각 — 전부 CreateHarness의 파라미터
선언 스펙
모델 + 프롬프트 + 도구 + 메모리 + Skills + 실행 정책
- model — 4종 소스 Tagged Union
- tools — type 5종 + 빌트인 자동
- memory 3모드 · skills 4소스
- 실행 정책 · truncation · 환경 · 인증
코드에서 오케스트레이션 로직으로 표현하던 것들이 전부 JSON 스펙의 필드로 바뀝니다.
선언 스펙의 뼈대
코드로 만들던 모든 것이 CreateHarness의 파라미터 트리로 — 필수는 단 두 개, 나머지는 전부 선택
이 파트는 이 트리를 왼쪽부터 하나씩 내려갑니다 — 모델 → 도구 → Skills → 컨텍스트·환경·인증 → 전체 조립 → Override 순서입니다.
모델 소스 4종 — 멀티 프로바이더 선언
model은 Tagged Union — 4종 소스 중 하나만 지정, 미지정 시 Claude Sonnet 4.6
| 소스 | config 키 | 특징 · 이럴 때 |
|---|---|---|
| Bedrock (기본 선택) | bedrockModelConfig | Bedrock 전 모델(modelId=추론 프로파일) — AWS 안에서 통합 운영 |
| OpenAI | openAiModelConfig | api.openai.com 직접 — 기존 계약·튜닝 유지 |
| Gemini | geminiModelConfig | Google Gemini 직접 연결 |
| LiteLLM | liteLlmModelConfig | Anthropic·Azure·Vertex 등 — 호환 게이트웨이는 api-base, 멀티 벤더 라우팅 |
실행 시 영향 — 지정 모델이 루프의 추론 엔진. 교체는 UpdateHarness 한 번, 비-Bedrock 키는 Token Vault ARN, Bedrock은 실행 역할만으로 충분합니다.
도구 선언 — type 5종 + 빌트인
설정 없이 오는 빌트인부터, 관리형 서비스 연결과 직접 연결까지 — tools 배열의 type이 경로를 결정
빌트인 도구
설정 없이 자동 포함
- shell — 셸 명령 실행
- file_operations — 파일 읽기/쓰기
관리형 연결
AgentCore 서비스를 type으로 연결
- agentcore_gateway — 도구 허브의 MCP 타깃 전체
- agentcore_browser · agentcore_code_interpreter
직접 연결
외부 MCP·클라이언트 측 함수
- remote_mcp — 원격 MCP 서버 직접 연결
- inline_function — 호출 측이 실행하고 결과 반환 (stopReason: tool_use)
실행 시 영향 — tools 선언이 곧 에이전트의 행동 반경입니다. 실제로 쓸 수 있는 도구는 allowedTools 글롭과의 교집합이고, inline_function만은 호출 측이 실행을 책임집니다(stopReason: tool_use로 반환). Skills는 tools가 아닌 별도 skills 파라미터 — 지식·지침 패키지(awsSkills · git · s3 · path 4소스)입니다.
Skills — 선언 스펙에 지식 주입
도구가 "할 수 있는 일"이라면 Skills는 "알고 있는 것" — Agent Skills 표준 기반 지식 패키지
핵심 포인트
- Agent Skills 표준
- Kiro·Claude Code 등 코딩 에이전트와 같은 형식 — SKILL.md 하나를 양쪽에서 재사용
- awsSkills · paths
- AWS 큐레이티드 카탈로그를 paths 글롭(core-skills/* 등)으로 골라 활성화
- git · s3 · path
- 태그드 유니언 최상위 키로 조직 자체 Skills 연결 — git은 url 필수, path·auth 선택
- Harness 전용
- Gateway·Runtime 미지원 — 필요할 때만 로드되어 컨텍스트 절약
코드
# 카탈로그에서 골라 쓰기 — paths 글롭으로 활성화
skills=[{'awsSkills': {'paths': ['core-skills/*']}}]
# 조직 자체 Skills — 태그드 유니언 최상위 키 (s3·path도 동일 구조)
skills=[{'git': {'url': 'https://github.com/org/skills.git',
'path': 'skills/'}}]
SKILL.md — 코딩 에이전트와 한 파일
개발 때 Kiro가 쓰던 스킬을 프로덕션 에이전트가 그대로 쓰는 구조
핵심 포인트
- 구성 4섹션
- Description · Instructions · Knowledge · Workflow — 마크다운 한 장
- 코딩 에이전트용
- .kiro/skills/{이름}/SKILL.md로 저장하면 Kiro·Claude Code가 로드
- 프로덕션용
- 같은 파일을 skills의 git·s3 소스로 연결하면 Harness가 로드
- 운영 팁
- 스킬 리포 하나를 조직 표준으로 — 개발과 프로덕션이 같은 지식으로 움직임
SKILL.md
# order-domain/SKILL.md
## Description
고객 주문 처리 에이전트를 위한 도메인 지식
## Instructions
- 환불은 결제 수단 기준 3영업일 안내
- 주문 변경은 배송 시작 전까지만 허용
## Knowledge
- 주문 상태: CREATED → PAID → SHIPPED → DONE
## Workflow
1. 주문 조회 → 2. 정책 확인 → 3. 처리·안내
나머지 조각 — 컨텍스트 · 환경 · 인증
긴 대화와 특수 의존성, 호출 통제까지 — 전부 CreateHarness 파라미터로 선언
컨텍스트
truncation — 컨텍스트가 모델 한도를 넘을 때
- sliding_window · summarization · none 3전략
- Strands ConversationManager에 대응
환경
environment · environmentArtifact · environmentVariables
- AgentCore Runtime 환경 설정 — 네트워크·라이프사이클
- 커스텀 컨테이너 이미지로 추가 의존성
- 런타임 환경 변수 최대 50개 — 코드 없이 설정 주입
인증 · 통제
authorizerConfiguration · allowedTools 글롭
- Inbound 인증 — 누가 이 Harness를 호출할 수 있는지 (Runtime·Gateway와 같은 authorizer 체계)
- '*'(전체) · '@builtin'(빌트인 전체) · '@서버명/도구명' 패턴 화이트리스트 — create·invoke 양쪽 지원
실행 시 영향 — truncation은 컨텍스트가 한도를 넘는 순간 무엇이 잘릴지를, environment는 에이전트가 어떤 네트워크·의존성 위에서 돌지를, authorizer·allowedTools는 누가 부르고 무엇까지 허용되는지를 결정합니다. 코드로 만들던 것들이 전부 스펙의 필드가 된 셈입니다.
선언 스펙 전체 — 한 번에 선언
다섯 계층 전부 create_harness 한 호출의 파라미터 — 필수는 맨 아래 정체성 2개뿐
통제·환경 — 상한 3종 · authorizer · environment
maxIterations·maxTokens·timeoutSeconds가 폭주의 정지선, 인증이 호출자의 경계
기억·컨텍스트 — memory · truncation
세션 너머의 기억과 한도 초과 시 잘라내는 방식
능력 — tools · skills
행동 반경과 도메인 지식 — 실행 중 무엇을 할 수 있고 무엇을 아는지
두뇌 — model · systemPrompt
루프의 추론 엔진과 페르소나 — 도구 선택·완료 판단의 주체
정체성 — harnessName · executionRoleArn
필수 2개 — 리소스 이름과 실행 권한. Bedrock 호출·Token Vault 접근이 전부 이 역할로
호출 시점 정책 — Per-invocation Override
재배포 없이, 이번 호출만 다른 모델·프롬프트·도구로 실행
핵심 포인트
- 최상위 파라미터
- 별도 override 객체 없음 — InvokeHarness에 직접 전달
- model
- 모델 디커플링 — 세션 중간에 전환해도 컨텍스트 유지
- allowedTools
- 이번 호출에서 쓸 도구를 화이트리스트로 제한
- 범위
- model·systemPrompt·allowedTools 외에 tools·skills·actorId·실행 상한도 지정 가능
코드
# 재배포 없이 이번 호출만 — override 객체 없이 최상위 파라미터로
response = client.invoke_harness(
harnessArn=HARNESS_ARN,
runtimeSessionId=SESSION_ID,
messages=[{'role': 'user', 'content': [{'text': '요약해주세요'}]}],
# model — 이번 호출만 다른 모델 (세션 중간 전환에도 컨텍스트 유지)
model={'bedrockModelConfig': {'modelId': 'us.anthropic.claude-opus-4-8'}},
# systemPrompt — 이번 호출만 다른 역할·지시
systemPrompt=[{'text': '짧게 3줄로 요약합니다.'}],
# allowedTools — 나열된 도구만 허용하는 화이트리스트
allowedTools=['shell'],
)
Runtime vs Harness
선택 기준 · 하이브리드 경로
선택 기준
하나로 수렴하는 질문 — 커스텀 오케스트레이션의 필요 여부
Runtime vs Harness
오케스트레이션을 직접 소유해야 하면 Runtime, 선언 스펙 범위로 충분하면 Harness
- Runtime — 커스텀 루프 · 프레임워크 자유
- Harness — 빠른 MVP · 운영 단순화
- 갈림길은 일방통행이 아님
- agentcore export — Strands 코드 전환
기능의 우열이 아니라 소유의 문제입니다 — 코드를 소유할 이유가 없다면 선언이 빠릅니다.
Runtime vs Harness — 각자의 자리
어느 쪽이 낫냐가 아니라, 어떤 요구에 어느 쪽이 맞느냐의 문제
Runtime
오케스트레이션을 직접 소유할 때
- 커스텀 루프·그래프 등 자체 오케스트레이션
- LangGraph · CrewAI 등 프레임워크 자유
- 시스템 라이브러리 · 특수 컨테이너 환경
- 산출물 — ZIP(Direct Code) 또는 컨테이너
무제한의 자유도 — 대신 코드 작성부터 재배포 사이클까지 전부 개발자의 책임입니다.
Harness
선언 스펙 범위로 충분할 때
- 빠른 MVP — CreateHarness 1번으로 가동
- 표준 도구 연결 — 빌트인 · Gateway · MCP · Browser · Code Interpreter
- 운영 단순화 — 버전 자동 관리 · 롤백
- 호출별 변경 — Per-invocation Override
선언 범위 안이라면 가장 빠른 길 — 실행·확장·버전 관리를 AgentCore가 대신합니다.
선택 가이드 — 두 번의 질문
커스텀 오케스트레이션 여부에서 시작해 배포 형태까지 내려가는 결정 트리
하이브리드 경로 — 선언으로 시작, 코드로 확장
갈림길은 일방통행이 아님 — agentcore export가 끊는 락인
export는 스캐폴딩이 아니라 탈출구입니다 — 지금까지 쌓은 버전·세션·Memory는 그대로 두고 오케스트레이션 소유권만 가져옵니다.
전환 후에도 Gateway·Memory·Identity 같은 AgentCore 서비스는 계속 사용합니다.
실습
Managed Harness 배포 · 하네스 엔지니어링
실습 — 갈림길의 양쪽을 모두
Managed Harness 선언적 배포와 Strands SDK 커스텀 하네스 설계, 두 실습으로 갈림길을 직접 비교합니다
학습 목표
- Harness 생성·배포·호출 — 선언적 배포 흐름 체험 (세션 유지·스트리밍 수신)
- 스펙 변경 후 버전 자동 생성 확인
- Strands SDK로 Build-Verify · Generator-Evaluator 하네스 패턴 설계
- 하네스 변경이 에이전트 성능에 미치는 영향 비교
CreateHarness · InvokeHarness — 락인 없는 선언적 배포