Claude 모델 패밀리의 컴퓨터 및 브라우저 사용(computer and browser use) 기능을 서비스에 통합하는 개발자를 위한 실전 가이드
클릭 정확도는 모든 컴퓨터 사용 통합의 기본입니다. 클릭이 정확한 위치에 닿지 않으면 이후 작업은 모두 실패합니다. 폼도 채워지지 않고, 버튼도 눌리지 않으며, 워크플로우 전체가 망가집니다. 가장 효과가 큰 최적화 방법은 동시에 가장 간단하기도 합니다. 바로 스크린샷을 API로 전송하기 전에 미리 축소(pre-downscale)하는 것입니다.
Claude의 Computer Use API에 스크린샷을 전송하면, 모델은 이미지를 확인한 뒤 여러분이 지정한 display_width_px / display_height_px 좌표 공간을 기준으로 클릭 좌표를 반환합니다. 그런데 여기서 중요한 제약이 있습니다. API 내부에는 이미지 크기에 대한 처리 한도가 있습니다. 이 한도를 초과하는 이미지는 모델이 처리하기 전에 내부적으로 축소됩니다. 즉, 모델은 품질이 저하된 이미지를 기준으로 클릭 좌표를 계산하지만, 여러분의 시스템은 원본 해상도에 맞는 좌표를 기대하는 불일치가 발생합니다.
Claude 4.6 모델 패밀리의 API 한도는 다음과 같습니다:
Opus 4.7 모델은 더 높은 해상도를 지원합니다. 한도는 다음과 같습니다:
좌표 공간과 모델이 인식하는 이미지가 일치하지 않으면, 모델이 예측한 클릭 위치가 실제 이미지와 다른 스케일에 찍힙니다. 고해상도에서 클릭 정확도가 떨어지는 주된 원인이 바로 이것입니다. 해결책은 단순합니다. 스크린샷을 API로 보내기 전에 항상 위 한도 이내로 미리 축소하세요. 이미지가 한도를 초과할 경우 정확도가 눈에 띄게 떨어지는 것을 일관되게 확인했으며, 이 한 가지 변경만으로도 다른 어떤 최적화보다 큰 효과를 볼 수 있습니다.
1280×720부터 시작하세요. 대부분의 사용 사례에서 안전하고 실용적인 기본값입니다. 픽셀 예산의 약 80%를 사용하고, 장변 및 총 픽셀 한도를 여유 있게 충족하며, 모델 학습 과정에서 충분히 노출된 표준 해상도이기도 합니다. 최신 웹 UI와 레거시 데스크톱 애플리케이션 모두에서 잘 작동합니다.
Opus 4.7을 사용한다면 1080p에서 시작하길 권장합니다. 720p 대비 품질이 눈에 띄게 향상되며, 토큰 사용량과 성능 사이에서 적절한 균형을 제공합니다.
모델이 받는 시각 정보를 최대화하고 싶은 개발자라면, 소스의 네이티브 종횡비를 기준으로 이미지별 최적 해상도를 계산하는 "API 최대 픽셀 활용" 방식도 권장합니다:
import math
# 1568 for 4.6 family, 2576 for Opus 4.7
MAX_LONG_EDGE = 1568
# 1.15MP for 4.6 family, 3.75MP for Opus 4.7
MAX_PIXELS = 1_150_000
def compute_max_api_fit(native_w, native_h):
"""Compute the largest resolution that fits API limits
while preserving aspect ratio."""
aspect = native_w / native_h
# Compute max dimensions from pixel budget
h_from_pixels = math.sqrt(MAX_PIXELS / aspect)
w_from_pixels = h_from_pixels * aspect
# Apply long edge constraint
if native_w >= native_h:
w = min(w_from_pixels, MAX_LONG_EDGE)
h = w / aspect
else:
h = min(h_from_pixels, MAX_LONG_EDGE)
w = h * aspect
# Never upscale beyond native
w = min(w, native_w)
h = min(h, native_h)
return int(w), int(h)이 방식은 구현이 다소 복잡하지만, 종횡비 왜곡을 방지하고 이미지별로 사용 가능한 픽셀 예산을 온전히 활용할 수 있습니다. 고정 해상도 1280×720 대비 정확도 향상 폭은 크지 않지만, 16:9 소스를 4:3 디스플레이 해상도로 강제 변환할 때 발생하는 왜곡을 피할 수 있는 간단한 구현 방법입니다.
피해야 할 해상도:
전송 전 스크린샷을 리사이즈하면, 모델은 여러분이 지정한 디스플레이 해상도를 기준으로 클릭 좌표를 반환합니다. 실제 클릭을 실행하기 전에 이 좌표를 실제 화면 해상도로 다시 변환해야 합니다:
# Your screen is screen_w x screen_h
# You sent a screenshot resized to display_w x display_h
scale_x = screen_w / display_w
scale_y = screen_h / display_h
screen_x = int(api_returned_x * scale_x)
screen_y = int(api_returned_y * scale_y)간단한 작업이지만 빠뜨리면 안 됩니다. 스케일링을 생략하거나 display_width_px / display_height_px가 실제로 전송한 이미지의 크기와 맞지 않으면, 모든 클릭이 일정하게 어긋납니다.
메시지 콘텐츠 배열을 구성할 때는 아래 코드 예시처럼 이미지보다 먼저 텍스트 지시사항을 배치하세요. 모델이 스크린샷을 처리하기 전에 무엇을 찾아야 하는지 미리 파악할 수 있어 클릭 정확도가 향상됩니다.
# RECOMMENDED — text instruction first, then screenshot:
content = [
{"type": "text", "text": "Click on the Submit button"},
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": screenshot_b64}},
]
# NOT RECOMMENDED — image first, then text:
content = [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": screenshot_b64}},
{"type": "text", "text": "Click on the Submit button"},
]클릭이 목표물을 벗어날 경우, 대부분 아래 원인 중 하나에 해당합니다:
내부 테스트 결과, Claude Sonnet 4.6은 클릭의 기계적 정밀도(공간 정확도, 근접 오차)가 더 뛰어나고, Claude Opus 4.6은 더 강력한 추론 능력을 보입니다. Sonnet 4.6은 소스 이미지를 대폭 축소해야 하는 상황에서도 더 강건합니다.
Opus 4.7은 이 격차를 상당 부분 좁혔습니다. 테스트 결과, Opus 4.7의 클릭 정밀도는 Sonnet 4.6과 거의 동등하며, 더 높은 해상도 한도 덕분에 축소가 덜 필요해 강력한 선택지가 됩니다. Opus 수준의 추론력과 높은 클릭 정확도를 함께 원할 때 특히 적합합니다.
대부분의 작업에서는 클릭 정확도, 추론 능력, 비용의 균형이 가장 잘 맞는 Sonnet 4.6으로 시작하길 권장합니다. 특히 고해상도 소스 이미지를 사용할 때 더 강력한 추론이 필요하다면 Opus 4.7을 선택하세요. Haiku 4.5는 지연 시간(latency)이 최우선일 때 여전히 훌륭한 옵션입니다. 고급 워크플로우에서는 추론 모델이 계획 수립과 의사결정을 담당하고 Sonnet 또는 Haiku가 기계적 클릭을 실행하는 오케스트레이터·서브에이전트 패턴이 여전히 유효할 수 있습니다.
목표물이 작아질수록 클릭 정확도가 떨어집니다. 버튼, 입력 필드, 일반 메뉴 항목처럼 크기가 큰 UI 요소는 안전 범위 내 모든 해상도에서 안정적입니다. 문제는 체크박스, 시스템 트레이 아이콘, 드롭다운 화살표, 작은 토글 스위치, 트리 뷰 확장·축소 버튼처럼 작고 미세한 목표물입니다.
작은 목표물을 자주 클릭해야 하는 애플리케이션이라면 다음 전략을 고려하세요:
밀집된 UI에는 줌(zoom)을 활용하세요. Claude 4.6 및 4.7 모델은 클릭 전에 특정 화면 영역을 더 높은 해상도로 검사할 수 있는 줌 기능을 지원합니다. 도구 설정에서 활성화하세요:
{
"type": "computer_20251124",
"name": "computer",
"display_width_px": 1280,
"display_height_px": 720,
"enable_zoom": True
}목표물을 크게 만드세요. 자동화할 UI를 직접 제어할 수 있다면, 클릭 목표물의 크기를 조금만 키워도 신뢰도가 눈에 띄게 향상됩니다. 시스템 DPI를 낮추거나, 브라우저에서 확대하거나, UI 스케일링 설정을 조정하는 방법을 활용해보세요.
작은 목표물에는 키보드 대안을 활용하세요. 시스템 트레이 아이콘이나 아주 작은 체크박스처럼 미세한 요소의 경우, 키보드 단축키나 탭 기반 내비게이션이 클릭보다 더 안정적일 수 있습니다. 워크플로우가 허용한다면, 특정 단계에서 키보드 인터랙션을 사용하도록 모델에게 지시해 성공률을 높일 수 있습니다.
소스 이미지 해상도를 고려하세요. 4K+ 디스플레이의 스크린샷을 720p로 압축하면 세부 정보가 크게 손실됩니다. 예를 들어 3840×2160 네이티브에서 16픽셀짜리 체크박스가 1280×720 디스플레이에서는 약 5픽셀로 줄어들어 목표물이 훨씬 작아지고 클릭하기 어려워집니다. 매우 고해상도 디스플레이를 사용한다면 이전 모델보다 해상도 한도가 높은 Opus 4.7을 고려하세요. 4.6 모델을 사용하는 경우, 더 낮은 DPI로 캡처하거나 디스플레이 스케일링을 통해 UI 요소를 확대하거나, 전체 화면 대신 관련 영역만 스크린샷에 담는 방법을 활용하세요. 소스 이미지 스케일이 커질수록 더 많은 압축이 필요해지며, 이에 따라 성능이 저하되는 것을 확인했습니다.
내부 평가에서 여러 인기 있는 최적화 기법을 실험했지만, 아래 방법들에서는 일관된 성능 향상을 확인하지 못했습니다. 다만 상황에 따라 결과가 다를 수 있습니다:
위의 수정 사항을 적용해도 모델이 예측하기 어렵게 동작한다면, 전체 트랜스크립트를 로깅하고 소스 스크린샷에 예측된 클릭 위치를 오버레이하여 모델이 실제로 무엇을 보고 어떤 판단을 내리는지 파악하세요.
일부 실패는 클릭 정확도 문제가 아닐 수 있습니다. 예를 들어, 특정 드롭다운 메뉴는 브라우저 뷰포트에서 캡처되지 않는 시스템 수준 UI를 호출하기도 합니다. 겉으로는 모델이 작업에 실패하는 것처럼 보이지만, 실제로는 모델이 상호작용해야 할 메뉴를 단순히 볼 수 없는 것입니다. 이런 경우 클릭 대신 JavaScript 실행, 키보드 내비게이션, DOM(document object model, 문서 객체 모델) 직접 조작 같은 대안적 방법을 활용해야 합니다.
컴퓨터 사용을 위한 이미지 스케일링 및 준비 방법
import math
from PIL import Image
import base64
import io
# 1568 for 4.6 family, 2576 for Opus 4.7
MAX_LONG_EDGE = 1568
# 1.15MP for 4.6 family, 3.75MP for Opus 4.7
MAX_PIXELS = 1_150_000
def prepare_screenshot(screenshot: Image.Image, native_w: int, native_h: int) -> tuple[str, int, int]:
"""Resize a screenshot to fit API limits and return base64 + display dimensions."""
# Option A: Fixed 720p (simple, reliable)
display_w, display_h = 1280, 720
# Option B: Max API fit (maximizes fidelity)
# display_w, display_h = compute_max_api_fit(native_w, native_h)
resized = screenshot.resize((display_w, display_h), Image.LANCZOS)
buffer = io.BytesIO()
resized.save(buffer, format="PNG")
b64 = base64.standard_b64encode(buffer.getvalue()).decode()
return b64, display_w, display_h
def scale_coordinates(api_x: int, api_y: int, display_w: int, display_h: int,
screen_w: int, screen_h: int) -> tuple[int, int]:
"""Scale API-returned coordinates back to native screen space."""
screen_x = int(api_x * (screen_w / display_w))
screen_y = int(api_y * (screen_h / display_h))
return screen_x, screen_y
def compute_max_api_fit(native_w: int, native_h: int) -> tuple[int, int]:
"""Compute the largest resolution that fits API limits while preserving aspect ratio."""
aspect = native_w / native_h
h_from_pixels = math.sqrt(MAX_PIXELS / aspect)
w_from_pixels = h_from_pixels * aspect
if native_w >= native_h:
w = min(w_from_pixels, MAX_LONG_EDGE)
h = w / aspect
else:
h = min(h_from_pixels, MAX_LONG_EDGE)
w = h * aspect
w = min(w, native_w)
h = min(h, native_h)
return int(w), int(h)사용 예시:
import anthropic
from PIL import Image
client = anthropic.Anthropic()
# Capture screenshot (your method here)
screenshot = Image.open("screenshot.png")
native_w, native_h = screenshot.size
# Prepare for API
b64, display_w, display_h = prepare_screenshot(screenshot, native_w, native_h)
# Send to Claude — text before image
response = client.beta.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
betas=["computer-use-2025-11-24"],
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Click on the Submit button"},
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": b64}},
]
}],
tools=[{
"type": "computer_20251124",
"name": "computer",
"display_width_px": display_w,
"display_height_px": display_h,
}],
)
# Scale coordinates back for execution
api_x, api_y = extract_click_coords(response) # your parsing logic
screen_x, screen_y = scale_coordinates(api_x, api_y, display_w, display_h, native_w, native_h)Claude의 최신 모델은 적응형 사고(adaptive thinking)를 지원합니다. 이는 Claude가 행동하기 전에 중간 단계를 얼마나 깊이 추론할지 스스로 결정하는 설정입니다. 사고 토큰 예산을 수동으로 지정하는 대신, 각 요청의 복잡도에 따라 확장된 사고(extended thinking)를 언제, 얼마나 활용할지 Claude가 동적으로 판단합니다. 컴퓨터 사용에서 이는 Claude가 화면에 표시된 내용을 파악하고, 다단계 인터랙션을 계획하며, 클릭이나 키 입력을 실행하기 전에 스스로 수정할 수 있음을 의미합니다.
적응형 사고를 사용할 때, Claude의 사고 깊이는 thinking 파라미터의 노력 수준(effort level)으로 제어합니다. 옵션은 low, medium, high, xhigh(Opus 4.7에서 사용 가능), max입니다. 사고량이 많을수록 행동당 추론이 깊어지지만, 출력 토큰 수가 늘어나고 지연 시간과 비용도 함께 증가합니다.
자연스러운 의문이 생깁니다. 모델별로 컴퓨터 사용에 최적인 사고량은 얼마일까요?
데스크톱 애플리케이션, 브라우저, 멀티 애플리케이션 워크플로우를 아우르는 종단간(end-to-end) UI 자동화 작업 세트에서 각 사고 노력 수준을 테스트했습니다.

Opus 4.7이 4.6 패밀리보다 성능이 뛰어납니다. OSWorld Verified 벤치마크에서 동일한 토큰 사용량과 노력 설정을 기준으로, Opus가 4.6 패밀리 모든 모델을 앞선다는 것을 확인했습니다. Opus 4.7 low 노력은 Sonnet 4.6 max와 비슷한 성능을 내면서 작업당 토큰 사용량은 약 1/10에 불과합니다. 난이도 높은 작업이라면 Opus 4.7이 명확한 선택입니다.
high 노력 설정은 max 대비 출력 토큰을 약 절반만 사용하면서도 최고 수준의 작업 성공률에 근접합니다. Opus 4.6과 비교했을 때, low·medium·high 모두 토큰 사용량은 비슷하면서 OSWorld 점수는 높아졌습니다. 내부 테스트에서 max 노력은 토큰을 가장 많이 사용했지만 최고 점수를 기록했습니다. 아래 표는 각 사고 노력 수준에 대한 권장 시나리오를 정리한 것입니다.
데스크톱 애플리케이션, 브라우저, 멀티 애플리케이션 워크플로우를 아우르는 종단간 UI 자동화 작업 세트에서 각 사고 노력 수준을 테스트했습니다.

두 가지 패턴이 두드러집니다:
medium 노력이 최적의 선택입니다. medium으로 설정하면 high 대비 출력 토큰을 약 절반만 사용하면서도 최고 수준의 작업 성공률에 근접합니다. medium을 넘어서면 성능이 어느 정도 정체됩니다. 특히 작업을 재시도할 경우 medium과 high의 성공률이 같아집니다. 즉, high 노력은 어려운 작업을 첫 시도에 성공시키는 데 도움이 될 수 있지만, 여러 번 시도할 경우 medium도 더 낮은 비용으로 비슷한 성공률에 도달할 수 있습니다.
조금만 생각해도 큰 차이가 납니다. low 노력은 놀라울 만큼 강력한 선택지입니다. 사고를 완전히 비활성화했을 때보다 총 출력 토큰이 더 적으면서도(오류가 줄어 재시도 횟수가 감소함), 정확도는 사고 없는 상태와 같거나 약간 더 높습니다. 따라서 비용에 민감하고 처리량이 많은 워크로드에 가장 적합한 옵션입니다. 아래 표는 노력 수준별 권장 설정을 정리한 것입니다.
컴퓨터 사용에서는 max 노력을 권장하지 않습니다. 테스트 결과 high 대비 정확도 향상 없이 출력 토큰 비용만 더 높아졌습니다. UI 작업은 깊은 논리적 추론보다는 지각(perception)과 기계적 실행에 가깝기 때문에, 추가 추론 예산이 활용되지 않거나 오히려 과잉 사고로 이어집니다. 다만 이 권장 사항은 모델이 발전함에 따라 달라질 수 있습니다.
import anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-sonnet-4-6",
max_tokens=16000,
betas=["computer-use-2025-11-24"],
thinking={"type": "adaptive"},
output_config={"effort": "medium"},
messages=[...],
tools=[
{
"type": "computer_20251124",
"name": "computer",
"display_width_px": 1280,
"display_height_px": 720,
}
],
)UI 자동화 작업은 코딩이나 수학 문제와 근본적으로 다릅니다. 대부분의 컴퓨터 사용 행동은 올바른 요소를 찾아 정확한 위치를 클릭하는 것처럼 지각적·기계적 성격을 띠며, 깊은 논리적 추론이 필요하지 않습니다. 사고가 가장 도움이 되는 상황은 다음과 같습니다:
이 섹션에서는 프롬프트 인젝션(prompt injection) 방어 기능을 다룹니다. 공식 컴퓨터 사용 도구 헤더를 사용하면 기본적으로 무료로 제공됩니다. 커스텀 컴퓨터 또는 브라우저 사용 도구에서도 이 기능을 활성화하고 싶다면 프롬프트 인젝션 분류기 관심 등록 양식을 작성해 주세요.
컴퓨터 사용 에이전트는 설계상 신뢰할 수 없는 콘텐츠와 상호작용합니다. Claude가 처리하는 모든 스크린샷, 웹 페이지, 애플리케이션 UI에는 에이전트의 동작을 탈취하려는 악의적인 지시사항이 포함될 수 있습니다. 숨겨진 텍스트, 조작된 이미지, 기만적인 UI 요소, 소셜 엔지니어링 시도 등이 그 예입니다. 이 공격 표면은 입력을 직접 제어하는 일반적인 API 통합과 근본적으로 다릅니다. 컴퓨터 사용에서 모델 입력은 열린 인터넷과 에이전트가 탐색하는 소프트웨어 전체입니다.
컴퓨터 사용 에이전트의 능력이 높아지고 배포 범위가 넓어질수록 프롬프트 인젝션의 위험성도 커집니다. 클릭·타이핑·탐색이 가능한 에이전트는 폼 작성, 파일 다운로드, 악성 URL 접속 같은 실제 행동을 취하도록 조작될 수 있습니다. 프로덕션 배포에서 이러한 공격에 대한 강력한 방어 체계를 구축하는 것은 필수입니다.
브라우저 및 컴퓨터 사용을 위한 프롬프트 인젝션 방어 접근 방식에 대해 자세히 기술한 바 있습니다. 당사의 방어 전략은 여러 계층에서 작동합니다:
학습 단계에서의 강건성 확보. 강화학습(reinforcement learning)을 통해 프롬프트 인젝션 저항성을 Claude의 기본 역량으로 내재화합니다. 학습 과정에서 Claude는 시뮬레이션된 웹 페이지와 애플리케이션 UI에 삽입된 악성 콘텐츠에 노출되며, 악의적인 지시사항을 정확히 식별하고 거부할 때 보상을 받습니다. 즉, Claude의 첫 번째 방어선은 모델 자체입니다. 정상적인 사용자 지시사항과 작업 중 마주치는 악의적 콘텐츠를 구별하는 능력을 학습한 것입니다.
실시간 분류기. Claude의 컨텍스트 창으로 유입되는 콘텐츠를 스캔하고 잠재적인 프롬프트 인젝션 시도를 탐지하는 프로브(probe)를 운영합니다. 이 프로브는 페이지 콘텐츠에 숨겨진 텍스트, 이미지에 삽입된 지시사항, 에이전트를 속이려는 기만적 UI 요소 등 다양한 형태의 공격을 감지하고, 공격이 확인되면 Claude의 동작을 조정합니다.
지속적인 레드팀(red teaming). 보안 연구원들이 이 방어 체계를 지속적으로 검증하며, 진화하는 공격 기법에 대한 강건성을 측정하기 위해 외부 적대적 평가에도 참여합니다.
초기 컴퓨터 사용 리서치 프리뷰 이후, 이 세 가지 계층 모두에 지속적으로 투자해왔습니다. 새로운 모델 세대마다 학습 단계의 방어가 강화되고 분류기 성능이 개선되며, 레드팀이 검증하는 공격 기법의 범위도 확대되고 있습니다.
API를 통해 Claude의 공식 컴퓨터 사용 도구를 사용하면, 프롬프트 인젝션 분류기가 모든 요청에 자동으로 실행됩니다. 이 분류기는 메인 모델 추론과 병렬로 동작하며, 추가 지연 시간과 추가 비용 없이 작동합니다.
이 보호 기능을 활성화하기 위해 별도로 설정할 필요가 없습니다. 공식 computer_20251124 도구 타입을 사용하면 기본으로 활성화됩니다. 분류기는 스크린샷 및 기타 콘텐츠에서 프롬프트 인젝션 징후를 평가하고 그에 따라 Claude의 응답에 영향을 줍니다.
# Classifiers run automatically when using the official CU tool — no extra config needed
tools = [
{
"type": "computer_20251124",
"name": "computer",
"display_width_px": 1280,
"display_height_px": 720,
}
]많은 개발자들이 공식 computer_20251124 도구 타입 대신 커스텀 도구 정의로 컴퓨터 사용 통합을 구현합니다. 예를 들어 자체적으로 스크린샷 및 클릭 도구를 정의하는 방식입니다. 이 경우 앞서 설명한 내장 분류기는 현재 해당 요청에 실행되지 않습니다.
이러한 커스텀 구현에도 프롬프트 인젝션 방어를 확장하는 방법을 적극적으로 모색하고 있습니다. 공식 도구 타입 없이 컴퓨터 또는 브라우저 사용 통합을 구현 중이고 프롬프트 인젝션 분류기에 관심이 있다면, 관심 등록 양식을 작성해 주시면 기능 제공 시점에 연락드리겠습니다.
분류기는 방어의 한 계층일 뿐, 완전한 해결책이 아닙니다. 컴퓨터 사용 배포 시 다음 사항을 권장합니다:
고위험 행동에는 휴먼-인-더-루프(human-in-the-loop)를 구현하세요. 폼 제출, 결제, 메시지 전송, 데이터 수정처럼 되돌릴 수 없는 행동 전에 에이전트가 일시 중지하고 사용자 확인을 요청하도록 하세요. 분류기 성능과 무관하게 프롬프트 인젝션에 대한 가장 효과적인 단일 대응 방법입니다.
에이전트 권한 범위를 제한하세요. 에이전트가 할 수 있는 일을 최소화하세요. 워크플로우에서 파일 다운로드가 필요하지 않다면 해당 권한을 부여하지 마세요. 이메일 전송이 필요하지 않다면 이메일 클라이언트에 접근할 수 없도록 하세요. 인젝션 공격 자체를 막는 것만큼이나 성공 시 피해 범위를 줄이는 것이 중요합니다.
에이전트 행동을 모니터링하고 기록하세요. 각 단계의 스크린샷을 포함한 에이전트의 전체 행동 순서를 기록하세요. 이를 통해 이상 동작을 감지하고, 문제 발생 시 감사(audit)하며, 시스템의 강건성을 지속적으로 개선하는 피드백 루프를 구축할 수 있습니다.
모든 웹 콘텐츠를 신뢰할 수 없는 것으로 취급하세요. 에이전트의 시스템 프롬프트에서 사용자의 지시사항과 작업 중 마주치는 콘텐츠를 명확히 구분하세요. 웹 페이지, 이메일, 애플리케이션 UI에서 발견된 텍스트는 사용자로부터 온 것이 아니며 지시사항으로 처리해서는 안 된다고 모델에게 명시적으로 상기시키세요.
컴퓨터 사용 에이전트를 구축하다 보면 스크린샷이 빠르게 쌓입니다. 행동마다 새 이미지가 생성되고, 해상도에 따라 이미지 하나당 약 1,000~1,800 토큰을 소모합니다. 시스템 프롬프트, 도구 정의, 텍스트 콘텐츠까지 고려하면 20만 토큰 컨텍스트 창이 스크린샷 100장도 안 되어 가득 찰 수 있습니다.
컨텍스트를 효과적으로 관리하는 목표는 두 가지입니다. 첫째, 총 토큰 수를 일정 범위 내로 유지하는 것, 둘째, 동일한 프리픽스에 대해 매번 전체 비용을 지불하지 않도록 프롬프트 캐싱을 효과적으로 활용하는 것입니다. 효과적인 컨텍스트 관리가 다른 어떤 최적화보다 장기 실행 에이전트의 비용과 지연 시간에 더 큰 영향을 미친다는 것을 확인했습니다. 이 섹션에서는 유기적으로 결합되는 세 가지 계층을 다룹니다. 캐시 브레이크포인트 배치, 캐시를 깨지 않으면서 오래된 스크린샷 제거, 제거만으로 부족할 때의 히스토리 요약입니다.
프롬프트 캐싱은 브레이크포인트가 여러 턴에 걸쳐 반복되는 콘텐츠에 위치할 때만 효과가 있습니다. API는 총 네 개의 캐시 브레이크포인트를 지원합니다. 네 개 모두 안정적인 프리픽스(시스템 프롬프트, 도구 정의)에 배치하면 낭비입니다. 해당 프리픽스는 세션 내에서 한 번 히트되고 무효화되지 않으니 하나로 충분합니다. 나머지 세 개는 무효화 위험이 가장 높고 장기 세션에서 절감 효과가 누적되는 최근 히스토리에 사용하는 것이 더 효율적입니다.
권장 사항:
최근 위치에 브레이크포인트를 분산하면 점진적 성능 저하를 방지할 수 있습니다. 이미지 제거, 압축(compaction), 도구 정의 변경 등으로 가장 최근 브레이크포인트가 무효화되더라도, 이전 브레이크포인트가 히트되어 전체 입력 비용의 100%가 아닌 10%만 지불하게 됩니다.
캐시 제어 및 브레이크포인트 설정 예시:
def set_trailing_cache_control(messages, max_breakpoints=3):
"""Place up to `max_breakpoints` ephemeral cache_control markers on the
most recent tool_result blocks, after clearing any existing markers."""
for msg in messages:
for block in msg.get("content", []):
if isinstance(block, dict):
block.pop("cache_control", None)
placed = 0
for msg in reversed(messages):
for block in reversed(msg.get("content", [])):
if placed >= max_breakpoints:
return
if isinstance(block, dict) and block.get("type") == "tool_result":
block["cache_control"] = {"type": "ephemeral"}
placed += 1토큰 수를 일정 범위 내로 유지하는 가장 간단한 방법은 가장 최근 N개의 스크린샷만 유지하고 나머지를 제거하는 것입니다. 각 API 호출 전에 메시지 배열을 순회하며 오래된 이미지 블록을 짧은 플레이스홀더(예: "[Image omitted]" 텍스트 블록)로 교체하세요.
이 패턴의 단순한 구현 방식은 스크린샷이 오래될 때마다 하나씩 제거하는 것인데, 이렇게 하면 매 턴마다 프리픽스가 변경되어 프롬프트 캐시가 지속적으로 무효화됩니다. 롤링 버퍼가 캐싱을 깨뜨린다는 평판을 얻게 된 이유가 바로 이것입니다. 해결책은 배치(batch) 단위로 제거하여 프리픽스가 여러 턴 동안 바이트 단위로 동일하게 유지된 후 한 번만 무효화되고 다시 안정화되도록 하는 것입니다.
실제로 테스트한 구체적인 패턴은 다음과 같습니다:
적절한 기본값은 keep_n = 3, interval = 25입니다. 조정 가능한 값이며, interval이 클수록 제거 이벤트가 줄어들어(캐시 효율 향상) 원본 해상도 스크린샷이 더 많이 컨텍스트에 남아 있게 됩니다(토큰 증가). 대표적인 실행 경로에서 캐시 히트율과 총 입력 토큰을 측정하며 조정하세요.
캐시 브레이크포인트를 유지하면서 이전 스크린샷을 제거하는 예시:
def prune_old_screenshots(messages, keep_n=3, interval=25):
"""Replace older screenshots with text placeholders in batches.
Only prunes when the total count exceeds keep_n + interval, so the
message prefix stays byte-stable for `interval` turns between prunes."""
image_positions = [
(msg_idx, block_idx)
for msg_idx, msg in enumerate(messages)
for block_idx, block in enumerate(msg.get("content", []))
if isinstance(block, dict) and block.get("type") == "image"
]
if len(image_positions) <= keep_n + interval:
return messages
to_prune = image_positions[:-keep_n][-interval:]
for msg_idx, block_idx in to_prune:
messages[msg_idx]["content"][block_idx] = {
"type": "text",
"text": "[Image omitted]",
}
return messages롤링 버퍼에는 실질적인 한계가 있습니다. 버퍼 밖의 내용은 모두 사라진다는 점입니다. 원래 지시사항, 에이전트가 이미 시도한 것, 작업의 현재 진행 상황이 제거된 스크린샷과 함께 사라집니다. 짧은 작업(약 50번 미만의 행동)이라면 문제없지만, 더 긴 작업에서는 압축(compaction)을 함께 활용하세요.
오래된 이미지를 조용히 삭제하는 대신, 전체 대화를 버리기 전에 요약하세요. 요약본에는 무슨 일이 있었는지, 사용자가 무엇을 요청했는지, 무엇이 완료됐는지, 어디서 재개해야 하는지가 담깁니다. 최근 스크린샷 몇 장은 에이전트가 현재 화면을 볼 수 있도록 함께 유지됩니다.
압축과 캐시 인식 롤링 버퍼는 상호 보완적입니다. 롤링 버퍼는 턴마다 토큰 증가를 관리하는 데 사용하고, 압축은 이전 컨텍스트를 잃지 않으면서 나머지 창을 확보하는 데 가끔 사용하세요. 각 압축 이벤트는 설계상 캐시 무효화를 수반하므로, 몇 턴마다가 아니라 드물게 발생하도록 해야 합니다.
아래 예시 프롬프트는 각 섹션이 특정 실패 유형을 대상으로 하는 구조를 제공합니다. 프롬프트는 에이전트가 원래 대화를 다시 읽지 않아도 작업을 이어갈 수 있도록 필요한 모든 정보를 담아야 합니다:
COMPACT_PROMPT = """Your task is to create a detailed summary of this conversation that
will REPLACE the conversation history. The agent will continue working with only this
summary and a few recent screenshots as context.
CRITICAL: Preserve ALL user instructions verbatim. User instructions are the most
critical element. If they are lost, the agent will deviate from the task.
Before providing your summary, analyze the conversation in tags:
1. Extract every user instruction, requirement, and constraint
2. Identify if this is a repeatable workflow (e.g., processing N items)
3. Chronologically trace what actions were taken and what happened
Your summary MUST include these sections:
1. USER INSTRUCTIONS:
- Complete initial task definition (verbatim when possible)
- ALL specific requirements and criteria
- Every "DO NOT", "ALWAYS", "MUST" instruction
- Any corrections or feedback that changed the approach
2. TASK TEMPLATE (if this is a repeatable workflow):
- The pattern being repeated
- Decision criteria for each iteration
- Standard workflow steps
- Example of one completed iteration
3. CONSTRAINTS AND RULES:
- All user-specified rules and restrictions
- Edge cases and exceptions discovered
4. ACTIONS TAKEN:
- Pages visited and elements interacted with
- Forms filled and buttons clicked
5. ERRORS AND FIXES:
- What went wrong and how it was resolved
- Approaches that failed (so they aren't retried)
6. PROGRESS TRACKING:
- Items completed vs. remaining
- Current position in the workflow
7. CURRENT STATE:
- Current application, URL and domain (optional)
- Important page state (logged in, form progress, etc.)
8. NEXT STEP:
- Exactly what should be done next to continue
"""위 프롬프트에서 사용자 지시사항(User Instructions)은 작업 목적의 이탈을 방지합니다. 없으면 압축 후 에이전트가 방향을 잃습니다. 작업 템플릿(Task Template)은 반복 가능한 패턴을 포착하여 압축 후에도 워크플로우를 처음부터 다시 도출하지 않고 계속 진행할 수 있게 합니다. 제약 사항 및 규칙(Constraints and Rules)은 작업 전 설정했거나 수행 중 발견한 제약과 예외 사례를 보존하여, 에이전트가 이미 알고 있던 규칙을 위반하지 않도록 합니다. 수행한 행동(Actions Taken)은 이전 진행 상황을 추적하는 데 도움이 됩니다. 오류 및 수정 사항(Errors and Fixes)은 실패한 접근 방식의 재시도를 방지합니다("Submit을 클릭해 봤는데, 약관 체크박스를 먼저 체크해야 작동함"). 진행 상황 추적(Progress Tracking)은 재시작과 항목 건너뜀을 방지합니다. 현재 상태(Current State) & 다음 단계(Next Step)는 재개를 위한 명확한 진입점을 제공합니다.
이 프롬프트를 가장 간단하게 활용하는 방법은 API의 서버 측 압축(베타) 기능을 통해 압축을 위임하는 것입니다. context_management의 instructions 파라미터로 커스텀 요약 프롬프트를 전달하면, 입력 토큰이 지정된 임계값을 초과할 때 API가 자동으로 요약을 실행합니다. instructions 파라미터는 기본 요약 프롬프트를 완전히 대체하므로, 위 섹션들이 모델이 따르는 지침이 됩니다. pause_after_compaction를 설정하면 압축 이벤트 전후에 걸쳐 가장 최근 메시지(스크린샷 포함)가 유지됩니다.
자동 압축 도구 사용 예시:
# Minimal — turn on autocompaction with API defaults
response = client.beta.messages.create(
model="claude-opus-4-7",
max_tokens=16000,
betas=["compact-2026-01-12", "computer-use-2025-11-24"],
context_management={"edits": [{"type": "compact_20260112"}]},
messages=[...],
tools=[...],
)
# Customized — set your own trigger threshold and summarization prompt
response = client.beta.messages.create(
model="claude-opus-4-7",
max_tokens=16000,
betas=["compact-2026-01-12", "computer-use-2025-11-24"],
context_management={
"edits": [
{
"type": "compact_20260112",
"trigger": {"type": "input_tokens", "value": 150_000},
"instructions": COMPACT_PROMPT,
}
]
},
messages=[...],
tools=[...],
)API가 서버 측 압축을 실행하면 서버 측에서는 압축 이전 콘텐츠가 교체되지만, 로컬 메시지 배열에는 전체 히스토리가 그대로 남아 있습니다. 이후 턴마다 전체 히스토리를 계속 전송하면 서버가 더 이상 필요하지 않은 토큰 비용을 지불하게 되고, 롤링 버퍼 제거 로직이 서버가 실제로 보는 메시지 슬라이스와 다른 범위에서 동작하게 되어, 앞서 정교하게 유지한 캐시 안정 프리픽스가 깨질 수 있습니다.
해결책은 아래 코드 예시처럼 클라이언트 측에서도 서버의 트런케이션을 동기화하는 것입니다. 응답에서 압축 발생이 보고되면, 다음 턴 전에 로컬 메시지 배열에서 압축 마커 이전의 모든 내용을 제거하세요. 이렇게 하면 클라이언트와 서버의 뷰가 일치하고 롤링 버퍼가 올바르게 계속 작동합니다.
def truncate_to_last_compaction(messages, response):
"""If the server compacted on this turn, drop pre-compaction messages
locally so the next turn's cache prefix matches what the server sees."""
context_mgmt = getattr(response, "context_management", None)
if not context_mgmt or not context_mgmt.get("applied_edits"):
return messages
compaction = next(
(e for e in context_mgmt["applied_edits"] if e["type"] == "compact"),
None,
)
if compaction is None:
return messages
keep_from = compaction["message_index_after_compaction"]
return messages[keep_from:]서버 측 압축을 지원하지 않는 모델을 사용하거나 완전한 제어가 필요하다면, 동일한 프롬프트로 클라이언트 측에서 압축을 구현하세요. 각 API 호출 후 응답의 usage 필드에서 총 입력 토큰 수를 확인하세요. 이 값이 임계값(예: 컨텍스트 창의 90%)을 넘으면, COMPACT_PROMPT를 시스템 프롬프트로 사용해 대화를 요약 모델에 전송하세요. 메시지 히스토리를 요약본과 최근 스크린샷 몇 장으로 교체한 뒤 에이전트 루프를 계속하세요.
장기 실행 컴퓨터 사용 에이전트의 좋은 기본 구성은 다음과 같습니다:
이 세 가지 계층이 갖춰지면, 일반적인 장기 컴퓨터 사용 세션에서 대부분의 턴에서 프롬프트 캐시가 히트되고, 총 입력 토큰이 컨텍스트 창 한도 훨씬 아래에서 유지되며, 압축 이벤트 전후로 에이전트가 작업 내용을 놓치지 않을 만큼 충분한 히스토리가 보존됩니다.
아래 패턴들은 자체 구현에서 테스트 중인 기법으로, 가능성은 확인됐지만 아직 전반적인 권장 사항으로 채택하지 않은 것들입니다. 각 기법은 복잡도나 비용을 감수하는 대신 특정 유형의 워크로드에서 성능 향상을 기대할 수 있습니다. 여러분의 워크플로우에서 직접 시험해볼 수 있도록 소개하지만, 이 섹션의 내용은 빠르게 변할 수 있습니다.
업데이트된 참조 구현에서는 표준 컴퓨터 및 브라우저 도구와 함께 computer_batch와 browser_batch 두 가지 도구를 추가로 제공합니다. 각 도구는 하위 행동 목록을 받아 단일 도구 호출로 실행합니다. 예를 들어 클릭, 타이핑, 키 입력을 각각 따로 처리하는 대신, 모델이 세 가지 행동을 모두 포함한 computer_batch 호출 하나를 실행할 수 있습니다.
효율성이 장점입니다. N개의 기계적 행동으로 이루어진 워크플로우가 N번의 왕복 대신 한 번의 왕복으로 처리되어, 장기 작업에서 실행 시간과 출력 토큰 비용을 의미 있게 줄입니다. 위험은 오류의 연쇄입니다. 두 번째 행동이 첫 번째 행동으로 변경된 시각적 상태에 의존하는데 첫 번째 행동이 실패하면, 나머지 배치가 잘못된 가정 위에서 실행되어 에이전트가 실제 상태의 스크린샷을 한 번도 보지 못한 채 방향을 잃을 수 있습니다.
하위 행동들이 독립적이고 서로의 시각적 결과에 의존하지 않는 경우(폼의 여러 필드 채우기, 키보드 단축키 연속 실행, 스크롤 후 알려진 목표물 클릭 등)에 배치 도구를 권장합니다. 탐색적 내비게이션, 오류 복구 순서, "행동 1이 실패하면 재계획이 필요한" 상황에서는 피하는 것이 좋습니다.
배치 도구는 자체 커스텀 정의이므로 표준 컴퓨터 또는 브라우저 도구와 깔끔하게 병행 사용할 수 있습니다. 두 가지를 모두 제공하고 모델이 선택하도록 두세요.
어드바이저 도구는 실행자(executor) 모델과 더 높은 지능의 어드바이저 모델을 결합합니다. 실행자가 필요할 때 어드바이저에게 전략적 조언을 구할 수 있는 방식입니다. 실행자가 루프를 실행하다가 더 깊은 추론이 필요한 상황에 부딪히면 어드바이저를 호출하고, 계획이나 수정 방향을 받아 계속 진행합니다. 이 과정은 서버 측에서 단일 요청 안에서 처리되므로 여러분 측에서 추가 왕복이 발생하지 않습니다.
컴퓨터 사용에서 이 패턴은 특히 장기 작업에서 유용합니다. 대부분의 턴은 기계적 클릭이지만, 어떤 탭을 열지 결정하거나 예상치 못한 모달에서 복구하거나 전략을 포기할지 판단하는 등 가끔 계획이 필요한 순간에 Opus 수준의 추론이 빛을 발합니다. 토큰 생성의 대부분은 실행자 비율로 이루어지면서 어드바이저 단독과 근접한 품질을 얻을 수 있습니다.
어드바이저 도구 활성화 예시:
response = client.beta.messages.create(
model="claude-sonnet-4-6",
max_tokens=16000,
betas=["advisor-tool-2026-03-01", "computer-use-2025-11-24"],
tools=[
{
"type": "advisor_20260301",
"name": "advisor",
"model": "claude-opus-4-7",
},
{
"type": "computer_20251124",
"name": "computer",
"display_width_px": 1280,
"display_height_px": 720,
},
],
messages=[...],
)어드바이저 도구에서 유용한 제어 옵션:
max_uses: 요청당 어드바이저 호출 횟수 상한 설정. 최악의 경우 비용을 제한하고 싶을 때 유용합니다.알아두면 좋은 두 가지 사항이 있습니다. 어드바이저는 도구 없이, 컨텍스트 관리 없이 실행되므로 직접 클릭하거나 탐색할 수 없으며 텍스트 조언만 반환합니다. 그리고 실행자 모델이 장기 작업에서 어드바이저의 존재를 항상 기억하지 못할 수 있으므로, 아래의 리마인더 넛지(nudge) 섹션을 참고하세요.
어드바이저 도구가 실행되면, 실행자는 name: "advisor"를 가진 server_tool_use 블록을 생성하고 이어서 반환된 콘텐츠에 advisor_tool_result 블록이 추가됩니다. 이 블록들은 다른 모든 내용과 함께 메시지 배열에 존재합니다.
이후 대화 전체 호출 횟수 한도 도달, 설정 변경, 모델 전환 등의 이유로 도구 배열에서 어드바이저 도구를 제거하면, 이전의 server_tool_use / advisor_tool_result 블록이 고아 상태가 됩니다. 참조된 도구가 더 이상 선언되지 않아 다음 요청에서 API가 400 오류를 반환합니다.
해결 방법은 간단하다. 메시지를 전송하기 전에 한 번 훑어보는 과정을 추가하면 된다. 어드바이저가 특정 턴에서 비활성화된 경우, 메시지 히스토리를 순회하며 name이 "advisor"인 server_tool_use 타입의 콘텐츠 블록과 advisor_tool_result 블록을 제거한다.
오래된 어드바이저 블록 제거 예시:
def strip_orphaned_advisor_blocks(messages):
"""Remove advisor server_tool_use / tool_result blocks from history.
Call this before any request that doesn't include the advisor tool."""
for msg in messages:
content = msg.get("content")
if not isinstance(content, list):
continue
msg["content"] = [
block for block in content
if not (
isinstance(block, dict)
and (
(block.get("type") == "server_tool_use"
and block.get("name") == "advisor")
or block.get("type") == "advisor_tool_result"
)
)
]
return messages세션이 길어지면 실행자(executor) 모델이 사용 가능한 도구나 우선적으로 써야 할 도구를 잊어버리는 경우가 생긴다. 테스트 결과, 두 가지 짧은 리마인더 패턴이 효과적이었다.
배치 리마인더. computer_batch나 browser_batch를 표준 도구와 함께 제공했을 때, 배치 처리가 적합한 상황에서도 모델이 단일 액션 호출을 연달아 실행한다면, 다음 도구 결과 뒤에 짧은 시스템 레벨 넛지를 추가하자. "중간 스크린샷에 의존하지 않는 순차적 액션은 computer_batch을 사용해 단일 도구 호출로 묶을 수 있습니다"라는 내용이면 충분하다. 정확히 언제 배치를 써야 하는지 지시하기보다는, 모델이 자연스럽게 배치 처리 방향으로 돌아오도록 유도하는 것이 목표다.
어드바이저 리마인더. 실행자는 어드바이저 도구의 존재를 쉽게 잊어버린다. 특히 여러 턴 동안 한 번도 호출하지 않은 경우라면 더욱 그렇다. 어드바이저 호출 없이 약 20턴 이상 진행된 세션에서는, 계획 수립이나 방향 수정이 필요한 순간에 어드바이저를 활용할 수 있다는 짧은 리마인더를 추가하자. 참조 구현에서는 20턴 주기로 한 줄짜리 힌트를 추가하는 방식을 사용하고 있다.
두 넛지 모두 시스템 프롬프트를 다시 쓰는 것이 아니라, 컨텍스트에 가볍게 내용을 추가하는 방식이다. 추가할 때마다 입력 토큰이 수십 개 정도 소모된다. 시스템 프롬프트가 이미 길거나 캐시 브레이크포인트를 정밀하게 배치해 둔 경우라면, 이 방식으로 얻는 효과가 캐시 무효화 위험을 감수할 만한지 신중히 판단하자.
무언가 잘못 동작하는데 문제가 하네스(harness)에 있는지, 스크린샷에 있는지, 아니면 모델 자체에 있는지 불분명할 때, 로그를 추가하기 전에 먼저 참조 구현의 세 가지 유틸리티를 활용해 보자.
이 도구들은 통합 서비스를 구축하는 데 반드시 필요한 것은 아니다. 로그를 찍고, 다시 실행하고, 트랜스크립트를 들여다보는 기본적인 피드백 루프만으로는 충분히 빠른 디버깅이 어려울 때를 위한 보조 수단이다.
Claude가 특정 워크플로를 올바르게 수행할 때까지 텍스트 프롬프트를 반복적으로 수정하는 대신, 올바른 동작을 직접 보여주는 방법이 있다. 각 단계마다 스크린샷과 액션, 선택적으로 음성 해설까지 캡처하며 직접 작업을 수행하는 과정을 녹화한 뒤, Claude가 동일한 워크플로를 실행할 때 그 데모를 컨텍스트로 제공하면 된다. 이렇게 만들어진 녹화본은 재사용 가능한 명세서가 되어, Claude가 실제 UI 상태의 차이에 적응하면서 따라올 수 있게 해준다.
이 패턴은 Claude in Chrome 내부에서도 활용하고 있으며(내부적으로는 "티치 모드(Teach Mode)"라고 부른다), 컴퓨터 사용 또는 브라우저 사용 제품을 만드는 누구에게나 폭넓게 유용한 접근 방식이라 판단해 여기서 공유한다. 이 방법은 두 가지 면에서 도움이 된다. 하나는 Claude가 대체로 잘 처리하지만 간혹 실수하는 워크플로의 안정성을 높이는 것이고, 다른 하나는 텍스트 프롬프트만으로는 완료할 수 없었던 워크플로를 새롭게 실현하는 것이다. 핵심 아이디어(데모를 캡처하고 컨텍스트로 다시 제공하기)는 구현이 간단하며 브라우저와 데스크톱 환경 모두에 잘 적용된다.
기존 프롬프트 엔지니어링은 사용자가 원하는 것을 말로 설명하고, AI가 잘못 이해하면 반복적으로 수정하는 방식이다. 이 패턴은 그 방향을 뒤집는다. 사용자가 직접 작업을 시연하는 동안 시스템이 액션, 스크린샷, 선택적으로 음성 해설을 기록한다. 재생 시에는 Claude가 전체 데모를 컨텍스트로 받아 동일한 단계를 순서대로 수행하되, 현재 UI 상태의 차이에 맞게 적응한다.
여기서 핵심은 재생이 단순한 반복 재현이 아니라는 점이다. Claude는 데모를 지침으로 삼으면서도 실제 환경을 직접 추론한다. 버튼 위치가 바뀌거나 메뉴가 재구성된 경우, 기록된 좌표를 맹목적으로 클릭하는 대신 현재 UI에서 동일한 요소를 찾아낸다.
기본 단위는 "워크플로 단계(workflow step)"로, 녹화 중 캡처된 단일 액션이다. 각 단계에는 무엇을 했는지, 어디서 했는지, 그 시점의 화면은 어땠는지가 함께 담긴다.
from dataclasses import dataclass, field
from typing import Literal, Optional
@dataclass
class WorkflowStep:
action: Literal["click", "type", "navigate", "scroll", "select"]
description: str # Human-readable, e.g. "Click the Submit button"
timestamp: float
selector: Optional[str] = None # CSS selector or XPath
coordinates: Optional[dict] = None # {"x": int, "y": int}
url: Optional[str] = None
screenshot: Optional[str] = None # Base64-encoded screenshot
viewport_dimensions: Optional[dict] = None # {"width": int, "height": int}
speech_transcript: Optional[str] = None # Voice narration, if captured
value: Optional[str] = None # For type actions
@dataclass
class SavedWorkflow:
id: str
name: str # e.g. "Submit expense report"
steps: list[WorkflowStep] = field(default_factory=list)
description: Optional[str] = None # AI-generated summary of the workflow
start_url: Optional[str] = None
created_at: float = 0.0
usage_count: int = 0셀렉터와 좌표를 모두 캡처하는 것은 의도적인 설계다. 셀렉터는 레이아웃 변경에 더 강하지만, 셀렉터가 깨졌을 때 Claude가 활용할 수 있는 시각적 폴백으로 좌표가 유용하기 때문이다. 녹화 환경과 재생 환경이 다를 때 좌표를 올바르게 조정할 수 있도록 뷰포트 크기도 함께 저장한다.
최소한 클릭 이벤트, 키보드 입력, 내비게이션 변경, 그리고 각 액션 시점의 스크린샷을 캡처해야 한다. 클릭마다 사람이 읽을 수 있는 설명(aria-label, 텍스트 콘텐츠, 또는 Claude 호출을 통해 생성)을 만들고, 클릭 위치에 시각적 마커를 스크린샷에 표시한다.
def on_click(event):
step = WorkflowStep(
action="click",
selector=generate_selector(event.target),
coordinates={"x": event.client_x, "y": event.client_y},
url=current_url(),
description=generate_description(event.target),
timestamp=now(),
viewport_dimensions=get_viewport_size(),
)
# Annotate screenshot with a circle at the click position
screenshot = capture_screenshot()
step.screenshot = annotate_with_circle(screenshot, event.client_x, event.client_y)
workflow_steps.append(step)이 어노테이션(클릭 위치의 색상 원)은 두 가지 역할을 한다. 사용자가 녹화가 올바른 요소를 캡처했는지 확인하는 데 도움을 주고, 재생 시에는 Claude에게 액션이 발생한 정확한 위치를 보여준다. 재생 프롬프트에서는 이 마커가 녹화 시의 아티팩트일 뿐 실제 UI의 일부가 아님을 Claude에게 명확히 알려야 한다.
이 부분이 가장 중요하다. 사용자가 저장된 워크플로를 실행하면, 세 가지 요소를 담은 메시지를 Claude에게 전달한다. 사용자의 의도, 데모 형식을 설명하는 컨텍스트 블록, 그리고 녹화된 스크린샷이다.
컨텍스트 블록은 Claude에게 어노테이션이 달린 스크린샷을 해석하는 방법과 실제 UI가 다를 때 적응하는 방법을 알려준다.
def generate_playback_context(steps: list[WorkflowStep]) -> str:
steps_description = "\n".join(
f"Step {i+1}: {step.description}"
for i, step in enumerate(steps)
)
return f"""<demonstration_context>
The user has recorded a demonstration showing how to perform this task.
RECORDED STEPS:
{steps_description}
ABOUT THE SCREENSHOTS:
- Each screenshot shows the screen state when an action was taken
- BLUE CIRCLES mark where the user clicked — these are recording annotations
- The blue highlighting is NOT part of the actual interface
- Your own screenshots will NOT have these markers
HOW TO USE THIS DEMONSTRATION:
1. Review all steps and screenshots to understand the complete workflow
2. Take your own screenshot to see the CURRENT page state
3. The blue highlights show which element to interact with — find it in your current view
4. Follow the same sequence of actions, adapting to any differences
5. If the UI has changed significantly, use judgment to find equivalent elements
</demonstration_context>"""그런 다음 사용자의 프롬프트, 컨텍스트 블록, 각 단계의 스크린샷을 이미지로 포함해 전체 메시지를 조합한다.
import anthropic
client = anthropic.Anthropic()
content = [
{"type": "text", "text": user_prompt},
{"type": "text", "text": generate_playback_context(workflow.steps)},
]
for i, step in enumerate(workflow.steps):
if step.screenshot:
content.append({"type": "text", "text": f"[Step {i+1}: {step.description}]"})
content.append({
"type": "image",
"source": {"type": "base64", "media_type": "image/jpeg", "data": step.screenshot},
})
response = client.beta.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
betas=["computer-use-2025-11-24"],
messages=[{"role": "user", "content": content}],
tools=[{
"type": "computer_20251124",
"name": "computer",
"display_width_px": 1280,
"display_height_px": 720,
}],
)모든 워크플로가 동일한 수준의 데모 준수를 필요로 하는 것은 아니다. 일부 워크플로는 너무 길어서 입력 토큰을 과도하게 소모하고, 결국 지연 시간 증가와 비용 상승으로 이어진다. 컨텍스트 프롬프트에 엄격도(strictness) 파라미터를 포함하는 것을 고려해 보자.
엄격(Strict): 단계를 정확히 따르되, UI가 너무 많이 변경된 경우 중단하고 보고한다. 정확한 순서가 중요한 컴플라이언스 민감 워크플로에 적합하다.
적응(Adaptive): 데모를 지침으로 삼되 UI 변경에 맞게 적응한다. 대부분의 사용 사례에서 가장 적합한 기본값으로, 사소한 레이아웃 변경, 버튼 레이블 업데이트, 메뉴 재구성 등을 자연스럽게 처리한다.
목표 지향(Goal-oriented): 최종 결과에 집중하며, 녹화된 단계를 지시가 아닌 힌트로 활용한다. UI는 자주 바뀌지만 목표는 동일한 경우에 유용하다. 다음 절에서 설명하는 전략과 유사한 방식으로 모델을 활용해 녹화된 데모를 요약한 뒤, 그 요약본을 컴퓨터 사용(CU) 모델에 전달한다.
저장된 워크플로가 실제로 어떻게 동작하는지 살펴보자. 이 워크플로는 경비 양식으로 이동, 경비 유형 선택, 드롭다운에서 "출장(Travel)" 선택, 금액 입력, 제출 클릭의 다섯 단계로 구성된다.
expense_workflow = SavedWorkflow(
id="wf_abc123",
name="Submit Expense Report",
start_url="https://expenses.company.com/new",
steps=[
WorkflowStep(
action="navigate",
url="https://expenses.company.com/new",
description="Navigate to new expense form",
timestamp=1700000000,
),
WorkflowStep(
action="click",
selector="#expense-type-dropdown",
coordinates={"x": 400, "y": 200},
description="Click on expense type dropdown",
timestamp=1700000001,
),
WorkflowStep(
action="click",
selector="[data-value='travel']",
coordinates={"x": 400, "y": 280},
description='Select "Travel" expense type',
timestamp=1700000002,
),
WorkflowStep(
action="type",
selector="#amount-input",
value="150.00",
description="Enter expense amount",
timestamp=1700000003,
),
WorkflowStep(
action="click",
selector="#submit-expense-btn",
coordinates={"x": 1150, "y": 420},
description="Click the Submit button",
speech_transcript="Now I'll click submit to send the report for approval",
timestamp=1700000004,
),
],
)나중에 사용자가 "팀 점심 식사 경비 보고서를 제출해 줘 ($85.50)"라고 말하면, 재생 서비스는 데모 컨텍스트, 어노테이션이 달린 스크린샷 다섯 장, 그리고 새 요청의 구체적인 값들로 프롬프트를 구성한다. Claude는 어디를 클릭해야 하는지, 어떤 순서로 진행해야 하는지 정확히 파악하고, 금액과 설명은 현재 작업에 맞게 조정한다. 입력 토큰 수 때문에 이 방식을 그대로 적용하기 어려울 만큼 워크플로가 길다면, 예시로 활용하기 전에 먼저 워크플로를 압축하는 방안을 고려하자. 컨텍스트 관리 팁은 다음 절을 참고하자.
이 내용은 프로덕션 환경에서 컴퓨터 사용 통합을 안정적으로 운영하는 방법에 대한 현재 시점의 최선의 이해를 담고 있다. Claude 4.6 모델 패밀리와 Opus 4.7에 적용되며, 새로운 모델과 기법이 등장하면 계속 업데이트될 예정이다.
통합이 성숙해질수록 가장 중요한 패턴은 각자의 환경, 대상 애플리케이션, 안정성 요구사항에 따라 달라진다.
컴퓨터 사용 문서에서 시작하거나, 컴퓨터 사용 최초 연구 게시물을 다시 살펴보며 이 기능이 어떻게 구축되었고 앞으로 어떤 방향으로 나아가는지 배경을 확인해 보자.
감사의 글: 이 아티클과 해당 데모는 Lucas Gonzalez와 Luca Weihs가 작성했습니다. 저자들은 Molly Vorwerck, Javier Rando, Maya Nielan, Gabe Mulley, Brigit Brown의 기여에 감사드립니다.