v1/messages → /responses 파라미터 매핑

v1/messages → /responses 파라미터 매핑

OpenAI 또는 Azure 모델을 대상으로 /v1/messages에 요청을 보내면, LiteLLM은 내부적으로 OpenAI Responses API를 통해 라우팅해요. 이 페이지는 모든 파라미터가 양방향으로 정확히 어떻게 변환되는지 문서화합니다.

변환은 litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py 에 있습니다.

요청: Anthropic → Responses API

Top-level 파라미터

Anthropic (/v1/messages) Responses API 비고
model model 그대로 전달
messages input 구조적으로 변환 — 아래 messages 섹션 참고
system (string) instructions 일반 문자열로 전달
system (콘텐츠 블록 목록) instructions 텍스트 블록은 \n으로 결합; 비텍스트 블록은 무시
max_tokens max_output_tokens 이름 변경
temperature temperature 그대로 전달
top_p top_p 그대로 전달
tools tools 형식 변환 — 아래 tools 섹션 참고
tool_choice tool_choice 타입 재매핑 — 아래 tool_choice 섹션 참고
thinking reasoning 예산 토큰을 effort 수준으로 매핑 — 아래 thinking 섹션 참고
output_format 또는 output_config.format text {"format": {"type": "json_schema", "name": "structured_output", "schema": ..., "strict": ...}}로 래핑. strict는 요청의 strict 플래그에서 복사되고 기본 false이므로 선택적 속성이 있는 스키마도 통과해요. OpenAI strict 모드를 선택하려면 strict: true 설정 — 모든 속성을 required에 두어야 함
context_management context_management Anthropic dict에서 OpenAI 배열 형식으로 변환 — 아래 context_management 섹션 참고
metadata.user_id user metadata 객체에서 추출, 64자로 잘림
metadata.user_id prompt_cache_key 같은 값, 64자(OpenAI 키 제한)로 잘림 — 그래서 한 사용자의 요청이 같은 프롬프트 캐시를 계속 사용. user_id가 비어 있거나 null이면 설정 안 됨. 요청 본문으로 보낸 prompt_cache_key가 파생된 값을 이김
stop_sequences 매핑 안 됨, 조용히 버려짐
top_k 매핑 안 됨, 조용히 버려짐
speed 매핑 안 됨. 네이티브 경로에서 Anthropic beta 헤더를 설정하는 데만 사용

chat-completions 경로(litellm_settings.use_chat_completions_url_for_anthropic_messages: true 및 모든 비-OpenAI 프로바이더)는 metadata.user_id에서 같은 두 파라미터를 파생하는데, 두 가지 차이가 있어요: user는 잘리지 않고 그대로 전달되고, prompt_cache_key는 대상 프로바이더의 지원 파라미터에 포함된 경우에만 설정됩니다. OpenAI, Azure OpenAI 및 기타 OpenAI 호환 프로바이더는 포함하고, Gemini, Vertex AI, Bedrock, Anthropic은 포함하지 않아요. litellm_proxy/ 배포(한 LiteLLM 프록시 앞에 다른 프록시)는 다운스트림 프록시의 실제 프로바이더를 알 수 없어 거기서 drop_params를 설정하지 않으면 거부하므로, 파생 키를 절대 받지 않아요.

messages가 변환되는 방식

각 Anthropic 메시지는 하나 이상의 Responses API input 항목으로 확장됩니다. 핵심 차이는 tool_resulttool_use 블록이 메시지 내부에 중첩되는 대신 input 배열의 top-level 항목이 된다는 점이에요.

Anthropic 메시지 Responses API input 항목
user 역할, string 콘텐츠 {"type": "message", "role": "user", "content": [{"type": "input_text", "text": "..."}]}
user 역할, {"type": "text"} 블록 user 메시지 내부의 {"type": "input_text", "text": "..."}
user 역할, {"type": "image", "source": {"type": "base64"}} user 메시지 내부의 {"type": "input_image", "image_url": "data:<media_type>;base64,<data>"}
user 역할, {"type": "image", "source": {"type": "url"}} user 메시지 내부의 {"type": "input_image", "image_url": "<url>"}
user 역할, {"type": "tool_result"} 블록 Top-level {"type": "function_call_output", "call_id": "...", "output": "..."} — 메시지에서 완전히 빠져나옴
assistant 역할, string 콘텐츠 {"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "..."}]}
assistant 역할, {"type": "text"} 블록 assistant 메시지 내부의 {"type": "output_text", "text": "..."}
assistant 역할, {"type": "tool_use"} 블록 Top-level {"type": "function_call", "call_id": "<id>", "name": "...", "arguments": "<JSON string>"} — 메시지에서 완전히 빠져나옴
assistant 역할, {"type": "thinking"} 블록 assistant 메시지 내부의 {"type": "output_text", "text": "<thinking text>"}

tools

Anthropic tool Responses API tool
type"web_search"로 시작하거나 name == "web_search"인 모든 도구 {"type": "web_search_preview"}
그 외 모든 도구 {"type": "function", "name": "...", "description": "...", "parameters": <input_schema>}

tool_choice

Anthropic tool_choice.type Responses API tool_choice
"auto" {"type": "auto"}
"any" {"type": "required"}
"tool" {"type": "function", "name": "<tool name>"}

thinking → reasoning

budget_tokens 값은 string effort 수준으로 매핑됩니다. summary는 항상 "detailed"로 설정돼요.

thinking.budget_tokens reasoning.effort
>= 10000 "high"
>= 5000 "medium"
>= 2000 "low"
< 2000 "minimal"

thinking.type"enabled"가 아니면 reasoning 필드는 전혀 보내지 않습니다.

context_management

Anthropic은 edits 배열이 있는 중첩 dict를 사용합니다. OpenAI는 compaction 객체의 평면 배열을 사용해요.

Anthropic input:
{
  "edits": [
    {
      "type": "compact_20260112",
      "trigger": {"type": "input_tokens", "value": 150000}
    }
  ]
}

Responses API output:
[
  {"type": "compaction", "compact_threshold": 150000}
]

응답: Responses API → Anthropic

Responses API 응답이 돌아오면, LiteLLM은 그것을 Anthropic AnthropicMessagesResponse로 변환해요.

Responses API 필드 Anthropic 응답 필드 비고
response.id id
response.model model 없으면 "unknown-model"로 폴백
ResponseReasoningItemsummary[*].text 콘텐츠 블록 {"type": "thinking", "thinking": "..."} 비어 있지 않은 각 summary 텍스트가 thinking 블록이 됨
ResponseOutputMessagecontent[*]type == "output_text" 콘텐츠 블록 {"type": "text", "text": "..."}
ResponseFunctionToolCall{call_id, name, arguments} 콘텐츠 블록 {"type": "tool_use", "id": "...", "name": "...", "input": {...}} arguments는 dict로 JSON 파싱됨
output에 function_call 존재 stop_reason: "tool_use"
response.status == "incomplete" stop_reason: "max_tokens" 기본값보다 우선
그 외 모든 것 stop_reason: "end_turn" 기본값
response.usage.input_tokens usage.input_tokens
response.usage.output_tokens usage.output_tokens
(하드코딩) type: "message" 항상 설정
(하드코딩) role: "assistant" 항상 설정
(하드코딩) stop_sequence: null 이 경로에서는 항상 null

출처: 문서

더 알아보기 (Learn more)