에이전트의 프롬프트는 한 개의 긴 문자열이 아니다. 지침, 대화 이력, 도구 정의를 조립한 요청이며, 캐시는 그 요청의 변하지 않는 앞부분을 재사용한다.

  • 출발점: Claude Code의 프롬프트 조립 경로와 실행 구조를 읽으며 생긴 질문들.
  • 범위: 개별 지침 파일의 문장보다, 어디에 들어가고 언제 바뀌며 어떻게 재사용되는지에 집중한다.
  • 구성: 조립 구조 → 실행 토폴로지 → 요청 payload → 단일·멀티턴 → 두 종류의 캐시 → 제공사와 프레임워크 비교.

2026년 10월 4일 정리. 구현 분석에서 확인한 구조는 역할 중심으로 일반화했으며 내부 파일 경로와 식별자는 싣지 않았다. 다이어그램과 payload는 설명용 재구성으로, 실제 실행 로그나 네트워크 캡처가 아니다. 구현 관찰과 공개 API 계약을 구분하고, 현재 제품의 모든 실행 모드에 같은 동작을 보장하지 않는다.

프롬프트는 세 경로로 조립된다

Claude Code · 프롬프트 조립 구조세 개의 요청 필드로 합류하는 조립 구조와 실행 관계를 역할 중심으로 표시했다. 점선은 결과가 대화에 돌아가는 경로다. Claude Code · 프롬프트 조립 구조 선택·추가 선택된 지침 system 입력·문맥 messages 스키마 변환 tools tool_use 결과 → 다음 요청 기본 지침과 실행 설정 정적 규칙 · 메모리 안내 · 환경 · MCP 시스템 지침 선택 대화형 / SDK 실행 모드 system 블록 구성 저장소 문맥 + 식별 정보 + 캐시 경계 프로젝트 문맥과 사용자 입력 CLAUDE.md · 날짜 · 입력 · 첨부 메인 대화 루프 대화 이력 · 압축 · 초기 문맥 앞삽입 messages 정규화 첨부 변환 · 도구 결과 짝 맞춤 사용 가능한 도구 집합 내장 도구 · MCP · 에이전트 · 스킬 tools 스키마 구성 설명 + input_schema · 지연 로딩 모델 API 요청 { system, messages, tools } 도구 실행과 결과 수집 tool_use → 실행 → tool_result

그림 1. 프롬프트 조립 구조. 그림을 누르면 확대할 수 있다. 인터랙티브 조립 구조도에서는 system·messages·tools 경로를 따로 선택할 수 있다.

요청 필드 주요 입력 조립 과정
system 기본 행동 지침, 선택한 실행 모드의 지침, 환경·저장소 문맥 지침 선택 → 세션 문맥 추가 → text 블록과 캐시 경계 구성
messages 초기 프로젝트 문맥, 사용자 입력, 이전 답변, 도구 결과, 동적 알림 이력 준비·필요시 압축 → 문맥 앞삽입 → API 메시지 정규화
tools 내장 도구와 외부 도구의 설명·입력 스키마 사용 가능한 집합 결정 → 필터링·지연 로딩 → API 스키마 변환

지침의 출처와 API에서의 역할은 별개다.

  • 분석한 경로에서는 초기 CLAUDE.md 내용과 날짜를 user 역할의 문맥으로 대화 앞에 넣는다.
  • 호출한 스킬 본문도 일반 실행 경로에서는 사용자 메시지로 확장된다. 별도 에이전트에서 실행하는 분기는 구분해야 한다.
  • <system-reminder>는 본문 안의 구분용 태그다. 그 이름이 메시지를 API의 system 역할로 바꾸지는 않는다.
  • 도구의 사용 원칙은 지침에 들어갈 수 있지만, 도구의 이름·설명·입력 스키마는 별도 tools 필드에도 전달된다.
  • 대화형 실행과 SDK 실행, 사용자 지정 지침, 하위 에이전트에 따라 기본 지침의 선택·교체·추가 방식이 달라질 수 있다.

여기서 system은 서버에 한 번 등록하는 전역 설정이 아니다. 이번 모델 요청에 적용할 시스템 지침을 담는 필드다. 같은 필드를 반복해서 보내는 비용을 줄이는 일은 별도의 프롬프트 캐시가 담당한다. Anthropic Messages API

실행 토폴로지: 메인과 하위 에이전트가 같은 API 계층을 사용한다

Claude Code · 실행 토폴로지대화형과 SDK 진입점이 메인 루프에 연결되고 하위 에이전트도 공통 모델 API를 사용한다. Claude Code · 실행 토폴로지 선택한 지침 조립한 지침 모델 호출 tool_use 실행 작업 위임 루프 시작 같은 패킹 경로 Skill 호출 대화형 진입점 지침 우선순위 선택 SDK / 비대화형 진입점 기본·사용자 지침 조립 메인 대화 루프 지침 · 문맥 · 도구 · 이력 공통 모델 API 계층 system / messages / tools 패킹 도구 실행 경로 내장 도구 · MCP · 스킬 · 에이전트 하위 에이전트 실행기 에이전트별 지침과 도구 선택 하위 에이전트 루프 별도 이력 · 모델 · 도구 문맥 스킬 본문 확장 SKILL.md → user 메시지

그림 2. 호출 방향을 표시한 실행 토폴로지. 반환 결과는 호출한 루프로 돌아간다. 인터랙티브 실행 토폴로지에서도 연결 관계를 탐색할 수 있다.

실행 경로 준비하는 문맥 모델 호출 이후
메인 루프 선택한 지침, 대화 이력, 현재 도구 집합 답변을 내보내거나 도구를 실행하고 다시 요청
독립 하위 에이전트 전용 지침과 환경 정보, 별도 작업 메시지, 허용된 도구 자체 이력으로 작업한 결과를 부모에 반환
부모 문맥을 상속하는 하위 실행 부모의 지침·이력·도구 집합을 전달하는 경로 공통 prefix 재사용 가능성을 유지하며 별도 작업 수행
스킬 실행 스킬 본문과 관련 문맥 현재 대화에 넣거나 별도 실행 경로로 분기
  • 위임 방식에 따라 같은 모델이라도 실제 입력이 달라진다.
  • 부모의 지침만 복사하고 도구 스키마나 대화 순서를 바꾸면 동일한 캐시 prefix라고 볼 수 없다.
  • 모델 이름, 도구 정의, 실행 설정과 대화 이력은 함께 확인해야 한다.

모델 API 호출 직전의 payload

최종 요청에서는 지침·도구·대화가 각각의 필드로 합류한다. 아래는 공개 Anthropic API 형태를 사용하는 설명용 예시다.

  • 모델 이름과 출력 토큰 수는 자리표시자·예시값이다.
  • 지침 본문과 도구 스키마는 축약했다. 그대로 실행하는 예제가 아니다.
  • 식별용 메타데이터, thinking, beta 설정, 출력 형식, 재시도·캐시 편집 등의 선택 필드는 생략했다.
  • 캐시 마커는 정적 부분과 대화 끝을 구분해 보여 주기 위한 배치다. 특정 실행 모드의 요청을 그대로 복사한 것은 아니다.
{
  "model": "<선택한 모델 ID>",
  "max_tokens": 8192,
  "stream": true,
  "tools": [
    {
      "name": "read_file",
      "description": "지정한 파일의 내용을 읽는다.",
      "input_schema": {
        "type": "object",
        "properties": {
          "path": { "type": "string" }
        },
        "required": ["path"]
      }
    }
  ],
  "system": [
    {
      "type": "text",
      "text": "<기본 행동·작업 수행·도구 사용·출력 원칙>",
      "cache_control": { "type": "ephemeral" }
    },
    {
      "type": "text",
      "text": "<세션의 환경·언어·메모리 사용 안내·추가 지침>"
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "<system-reminder>초기 프로젝트 지침과 날짜</system-reminder>"
        },
        {
          "type": "text",
          "text": "이 프로젝트의 구조를 설명해줘.",
          "cache_control": { "type": "ephemeral" }
        }
      ]
    }
  ]
}
  • 초기 문맥과 사용자 입력은 내부에서 따로 생성되어도 API 정규화 단계에서 연속된 user 메시지로 병합될 수 있다.
  • 도구 결과·첨부의 변환과 도구 호출/결과의 짝 맞춤도 최종 전송 전에 수행한다.
  • 이 경로는 매번 본문을 포함해 보낸다. 서버 캐시가 적중하더라도 클라이언트가 입력 본문을 생략하는 것은 아니다.
  • 제공사 전체의 공통 제약은 아니다. 예를 들어 Gemini에는 명시적 캐시 리소스를 참조하는 별도 방식도 있다. Gemini 콘텐츠 캐시

단일 턴과 멀티턴은 요청 형식이 같다

대화가 길어져도 필드 구조는 유지되고, 주로 messages의 뒤쪽이 늘어난다.

시점 요청에 포함하는 대화 이전 요청과 공유 가능한 부분
첫 사용자 질문 초기 문맥 + 질문 1 이미 같은 prefix의 캐시가 있을 때만 재사용 가능
두 번째 사용자 질문 초기 문맥 + 질문 1 + 답변 1 + 질문 2 이전 요청의 초기 문맥과 질문 1까지
세 번째 사용자 질문 기존 이력 + 답변 2 + 질문 3 두 번째 요청의 prefix까지
  • 첫 요청도 캐시 생성용 마커를 보낼 수 있다. 마커가 있다는 사실과 캐시 적중은 다르다.
  • 직전 답변은 이전 요청에서는 출력이었다. 다음 요청에서 처음 입력 이력으로 들어간다.
  • 다음은 두 번째 질문 시점의 messages 예시다. system과 tools가 유지된다고 가정한다.
[
  {
    "role": "user",
    "content": [
      { "type": "text", "text": "<초기 프로젝트 문맥>" },
      { "type": "text", "text": "이 프로젝트의 구조를 설명해줘." }
    ]
  },
  {
    "role": "assistant",
    "content": [{ "type": "text", "text": "<첫 번째 답변>" }]
  },
  {
    "role": "user",
    "content": [
      {
        "type": "text",
        "text": "프롬프트 조립 부분을 자세히 설명해줘.",
        "cache_control": { "type": "ephemeral" }
      }
    ]
  }
]

분석한 일반 요청 경로는 마지막 메시지의 마지막 콘텐츠 블록에 메시지용 마커 하나를 붙이는 방식이었다. 이전 요청의 마커를 이력 전체에 계속 쌓는 방식과는 다르다.

  • 일부 보조 실행은 공유하는 이력까지만 캐시 대상으로 삼기 위해 끝에서 두 번째 메시지에 경계를 둔다.
  • thinking 블록, 추가 첨부, 캐시 편집과 같은 예외는 별도 처리한다.
  • 이것은 해당 구현의 전략이다. 공개 API에는 요청 최상위에 cache_control을 두고 경계를 자동으로 이동시키는 방식도 있다. Anthropic 자동 캐싱

사용자 턴 하나가 API 호출 여러 번이 될 수 있다

한 사용자 턴 안의 모델 재호출사용자, 실행 루프, 모델 API, 도구 사이의 요청과 반환. 도구 결과를 받은 실행 루프는 누적 이력을 다시 전송한다. 한 사용자 턴 ≠ 한 API 호출 사용자 실행 루프 모델 API 도구 질문 1 요청 A: 지침 + 도구 + 질문 tool_use 도구 실행 tool_result 요청 B: 기존 이력 + 호출 + 결과 최종 답변 사용자에게 답변 요청 B도 전체 payload를 보낸다. 동일한 앞부분은 서버 캐시로 재사용할 수 있다.

그림 3. 사용자 입력은 한 번이지만 모델 요청은 A와 B 두 번이다. 도구 호출이 반복되면 같은 패턴이 이어진다.

경우 다음 모델 요청에 추가하는 내용
단일 턴, 도구 사용 없음 답변으로 종료하면 후속 요청 없음
단일 턴, 도구 사용 모델의 tool_use와 실행 결과인 tool_result
멀티턴 이전 assistant 답변과 새 user 입력

도구 실행 후 재호출에서는 다음 두 메시지를 기존 이력 뒤에 추가한다.

[
  {
    "role": "assistant",
    "content": [
      {
        "type": "tool_use",
        "id": "toolu_example",
        "name": "read_file",
        "input": { "path": "/project/main.py" }
      }
    ]
  },
  {
    "role": "user",
    "content": [
      {
        "type": "tool_result",
        "tool_use_id": "toolu_example",
        "content": "<파일 내용>",
        "cache_control": { "type": "ephemeral" }
      }
    ]
  }
]
  • 실제 재요청에는 위 조각뿐 아니라 앞선 전체 이력도 포함된다.
  • 호출 ID와 결과의 참조 ID가 대응해야 한다.
  • 도구 결과 뒤에 추가 알림 블록이 붙는다면 마지막 캐시 마커 위치도 달라질 수 있다.
  • 단일 턴이라고 캐시가 쓸모없는 것은 아니다. 한 사용자 턴 안의 반복 호출에서도 공통 prefix가 생긴다. 도구 호출과 프롬프트 캐시

로컬 캐시와 API 프롬프트 캐시는 다른 일을 줄인다

로컬 캐시는 프롬프트를 만드는 작업을, API 캐시는 모델이 반복 입력을 처리하는 작업을 줄인다.

기준 로컬 캐시 API 프롬프트 캐시
위치 에이전트 프로세스 메모리 모델 API 서버
저장 대상 조립한 지침 문자열·문맥·도구 스키마 입력 prefix를 처리한 모델의 계산 상태
주요 효과 파일 읽기·문자열 생성·스키마 변환 반복 감소 반복 입력의 연산·지연·비용 감소
제어 메모이제이션, 세션별 자료구조 제공사의 캐시 옵션과 일치 조건
유효 기간 캐시 종류별 세션·초기화 시점 TTL과 제공사 정책
다음 요청 저장된 문자열로 payload 구성 받은 prefix가 기존 캐시와 일치하면 재사용
첫 요청
파일·설정 읽기 → 문맥 조립 → payload 전송 → 모델 입력 처리
                 ↓ 로컬 보관                ↓ 서버 캐시

다음 요청
저장된 문맥 재사용 ───────→ payload 전송 → 같은 prefix 계산 재사용
  • 로컬 캐시 적중이 API 캐시 적중을 보장하지 않는다. 서버 TTL이 지났거나 도구·지침·이력이 달라졌을 수 있다.
  • 로컬에서 매번 다시 만들어도 결과 prefix가 같다면 서버 캐시를 재사용할 수 있다.
  • 로컬 캐시는 성능 외에도 프롬프트 문자열을 안정적으로 유지하는 역할을 한다.
  • 특히 도구 설명과 스키마를 세션 동안 고정하면, 중간 설정 변화가 요청 앞부분을 불필요하게 바꾸는 일을 줄일 수 있다.

서버 캐시의 계산 상태와 캐시 토큰 관측은 OpenAI 프롬프트 캐시 문서에서도 설명한다. 이 개념과 클라이언트의 문자열 캐시는 별개의 계층이다.

정적·동적 분리는 변경 주기를 기준으로 읽는다

동적이라는 이름은 매 요청마다 다른 문자열이라는 뜻도, 캐시할 수 없다는 뜻도 아니다.

구성 요소 변하는 시점 배치·재사용 전략
기본 행동·도구 사용 원칙 버전·실행 모드·기능 구성 변경 앞쪽의 안정적인 지침으로 배치
환경·언어·출력 스타일·메모리 안내 세션이나 설정 변경 처음 계산한 내용을 가능한 한 재사용
초기 프로젝트 지침·날짜 세션 초기화 또는 재구성 대화 앞부분의 문맥으로 유지
새 입력·도구 결과 각 모델 재호출 기존 이력 뒤에 추가
날짜·외부 도구 안내 변경 실행 도중 상태 변경 지원 경로에서는 변경 알림을 뒤에 추가
  • 분석한 경로에서는 세션별 섹션도 대개 재사용하며, 대화 초기화·압축 등에서 다시 계산할 수 있다.
  • 외부 도구 서버가 연결·해제되며 바뀌는 안내처럼 매번 확인해야 하는 예외가 있다.
  • 이를 시스템 지침에 다시 쓰는 대신 변경분을 대화 뒤에 기록하는 경로도 있다.
  • 날짜가 바뀌었을 때 초기 날짜를 덮어쓰기보다 뒤에 새 날짜를 알리면, 기존 prefix를 유지할 수 있다.
  • 외부 파일을 수정했다고 이미 만들어 둔 초기 문맥이 곧바로 갱신된다고 가정하면 안 된다. 문맥의 재로딩 시점과 서버 캐시의 만료는 서로 다른 문제다.

정적·동적 섹션을 논리적으로 나누는 것과 API의 text 블록을 나누는 것도 구분해야 한다.

관찰한 조건부 경로 시스템 지침을 다루는 방식
정적 지침을 더 넓은 범위에서 재사용하는 경로 정적 지침 끝에 경계를 두고 세션별 지침을 뒤에 배치
사용자별 외부 도구 때문에 공유를 제한하는 경로 일반 범위의 캐시 구성으로 전환
사용자 지정 지침으로 기본 구성을 교체하는 경로 기본 조립 경계가 없을 수 있으므로 별도 분기
캐싱을 끈 경로 입력은 구성하지만 API 캐시 마커는 생략
  • 위 표는 분석한 구현의 분기를 일반화한 것이다. 제공사 내부용 확장을 공개 API의 범용 옵션으로 제시하지 않는다.
  • Anthropic 캐시의 prefix는 tools → system → messages 순서로 구성된다. 앞선 JSON 예시의 키를 위아래로 옮기는 것으로 이 순서를 바꾸지는 못한다.
  • 블록에 자체 마커가 없어도 뒤의 마커가 그 블록까지 포함한 prefix를 대상으로 삼을 수 있다.
  • 도구 정의와 시스템 지침을 바꾸면 뒤에 있는 대화의 캐시까지 영향을 줄 수 있다. 캐시 계층과 도구 변경

cache_control은 무엇을 지정하는가

cache_control은 답변 자체를 저장하는 응답 캐시가 아니라, 해당 위치까지의 입력 prefix를 재사용하기 위한 옵션이다.

{
  "type": "text",
  "text": "여러 요청에서 같은 내용으로 사용하는 지침",
  "cache_control": {
    "type": "ephemeral",
    "ttl": "1h"
  }
}
필드 값 의미
콘텐츠의 type text 본문의 콘텐츠 종류
cache_control.type ephemeral 공개 SDK 타입에서 제공하는 임시 캐시 종류
cache_control.ttl 5m 또는 1h 캐시 유지 시간. 생략하면 기본 5분
  • static, dynamic, persistent를 캐시 type으로 고르는 구조가 아니다.
  • 요청 최상위에 두는 자동 캐싱과 개별 콘텐츠 블록에 두는 명시적 경계 방식이 있다.
  • 캐시 범위·기능 지원·최소 길이 등의 조건도 충족해야 한다. 마커만으로 적중을 보장하지 않는다.
  • 이 글의 예시는 공개 SDK가 정의한 기본 형태를 사용한다. 공식 캐시 타입

system 필드와 system 메시지는 같은가

시스템 지침의 개념은 공통이지만, 제공사의 요청 계약은 다르다.

계층 / API 초기 시스템 지침을 표현하는 방법
Anthropic Messages 최상위 system
Google Gemini 별도 systemInstruction; Python SDK에서는 system_instruction
OpenAI Chat Completions messages의 system 또는 developer 역할
OpenAI Responses 최상위 instructions 또는 호환되는 시스템·개발자 입력 메시지
LangChain 모델 호출 전에 SystemMessage 등 공통 메시지 객체로 표현
Deep Agents system_prompt로 받아 추가 지침과 조립한 뒤 모델 계층에 전달

공식 형식: Gemini 요청 · OpenAI 메시지 역할 · Responses 매핑

LangChain의 메시지 목록이 그대로 HTTP payload가 되는 것은 아니다.

from langchain.messages import SystemMessage, HumanMessage

# model은 제공사별로 미리 구성한 LangChain 채팅 모델이다.
messages = [
    SystemMessage(content="너는 코드 리뷰어다."),
    HumanMessage(content="이 코드를 검토해줘."),
]
response = model.invoke(messages)
  • Anthropic 어댑터는 앞의 시스템 지침을 분리해 최상위 system에 넣는다.
  • OpenAI·Gemini 어댑터는 각각 선택한 API가 요구하는 형식으로 변환한다.
  • 따라서 캐시를 확인할 때는 프레임워크의 메시지 객체와 실제 전송 payload를 구분한다. LangChain 메시지 · Anthropic 어댑터 구현
from deepagents import create_deep_agent

agent = create_deep_agent(
    model=model,
    system_prompt="너는 코드 리뷰어다.",
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "이 코드를 검토해줘."}]
})
  • Deep Agents는 설정된 프로필·미들웨어의 지침을 조립하고 LangChain 에이전트에 전달한다.
  • 최종 필드 위치는 선택한 모델 어댑터가 결정한다.
  • 캐시 마커를 붙이는 미들웨어와 프롬프트 조립 자체도 별도 책임이다. Deep Agents 설정 · 조립 구현

최신 Anthropic API의 일부 모델은 대화 중간의 role: "system"도 지원한다. 초기 시스템 지침과 나중에 추가한 시스템 지침은 적용 위치·시점이 다르다. 이 글의 초기 조립 구조를 모든 모델의 메시지 역할 제약으로 일반화해서는 안 된다. 대화 중 시스템 지침

위치만 잘 조절하면 캐시와 성능이 같은가

어댑터를 거친 최종 입력이 같다면 표현 방식 때문에 차이가 생기지는 않는다. 그러나 같은 문장을 다른 필드로 옮기는 것까지 동등하다고 보장할 수는 없다.

변경 캐싱·동작에 대한 판단
공통 메시지 객체를 제공사 필드로 정상 변환 같은 최종 입력과 설정이면 프레임워크의 표현 차이는 사라짐
payload에서 지침을 다른 역할·시점으로 이동 토큰 순서·역할 경계·적용 시점이 달라질 수 있음
JSON 객체의 필드 표시 순서만 변경 텍스트 편집기의 키 순서가 모델 프롬프트 순서를 정하지는 않음
앞쪽 시스템 지침을 매 턴 수정 변경 지점 뒤의 캐시 재사용에 영향을 줄 수 있음
기존 이력을 유지하며 새 문맥을 뒤에 추가 공통 prefix를 유지하는 데 유리
제공사·모델·도구·출력 설정까지 변경 캐시 및 동작 조건을 다시 확인해야 함
  • 속도·비용: 재사용된 입력 토큰의 양, 새로 처리한 입력, 첫 토큰까지의 지연을 확인한다.
  • 답변 품질: 캐싱 자체와 지침의 역할·순서 변경은 다른 문제다. 캐시를 사용해도 답변은 새로 생성된다.
  • 비교 방법: 같은 모델·설정·지침을 유지하고 최종 요청과 사용량을 함께 비교한다.
  • 관측값: Anthropic의 캐시 읽기·생성 입력 토큰, OpenAI의 입력 토큰 상세 내 캐시 토큰, 실제 응답 지연을 확인한다. OpenAI 캐시 관측

다음 지침 파일을 리뷰할 때는 문장 내용에 앞서 네 가지를 확인하면 된다.

  1. 어느 필드와 역할에 들어가는가? 시스템 지침, 사용자 문맥, 도구 설명을 구분한다.
  2. 언제 다시 읽거나 조립하는가? 로컬 캐시의 초기화·무효화 시점을 확인한다.
  3. 요청의 어느 부분을 바꾸는가? 앞부분 수정과 뒤쪽 추가를 구분한다.
  4. 최종 payload와 캐시 사용량이 예상과 일치하는가? 지침의 의미와 캐시 효과를 각각 검증한다.

다이어그램과 참고 자료