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_result와 tool_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"로 폴백 |
ResponseReasoningItem — summary[*].text |
콘텐츠 블록 {"type": "thinking", "thinking": "..."} |
비어 있지 않은 각 summary 텍스트가 thinking 블록이 됨 |
ResponseOutputMessage — content[*] 중 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 |
출처: 문서