~/tools / 서버에서 로컬 LLM 실행하기 / Ollama OpenAI Converter
Ollama OpenAI Converter — 채팅 요청과 응답을 Ollama /api/chat과 /v1/chat/completions 사이에서 변환
채팅 요청을 Ollama 고유의 /api/chat과 OpenAI 호환 /v1/chat/completions 사이에서 어느 방향으로든 변환하고, /api/chat 응답을 /v1/chat/completions가 반환하는 형태의 응답으로 바꿉니다. 변환은 Ollama의 소스 코드를 따르며, 이름이 바뀌거나 버려지거나 대응하는 것이 없는 필드를 모두 목록으로 보여 줍니다. 데이터는 브라우저 밖으로 나가지 않습니다.
OpenAI 호환 요청(/v1/chat/completions)(으)로 읽었습니다.
- Ollama는 다음 필드를 읽지 않고 버립니다: tool_choice
curl
localhost:11434의 Ollama로 보냅니다. Ollama가 다른 곳에서 실행 중이면 주소를 바꾸세요.
curl http://localhost:11434/api/chat -d '{"model":"qwen2.5:7b","messages":[{"role":"system","content":"Answer in one sentence."},{"role":"user","content":"What is the weather in Toronto?"},{"role":"assistant","content":"","tool_calls":[{"id":"call_1","function":{"name":"get_weather","arguments":{"city":"Toronto"}}}]},{"role":"tool","content":"11 degrees, cloudy","tool_name":"get_weather","tool_call_id":"call_1"}],"stream":false,"options":{"stop":["END"],"num_predict":200,"temperature":0.2},"tools":[{"type":"function","function":{"name":"get_weather","description":"Weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]}'Ollama /api/chat 요청
{
"model": "qwen2.5:7b",
"messages": [
{
"role": "system",
"content": "Answer in one sentence."
},
{
"role": "user",
"content": "What is the weather in Toronto?"
},
{
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_1",
"function": {
"name": "get_weather",
"arguments": {
"city": "Toronto"
}
}
}
]
},
{
"role": "tool",
"content": "11 degrees, cloudy",
"tool_name": "get_weather",
"tool_call_id": "call_1"
}
],
"stream": false,
"options": {
"stop": [
"END"
],
"num_predict": 200,
"temperature": 0.2
},
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string"
}
},
"required": [
"city"
]
}
}
}
]
}변환된 필드
| 변환 전 | 변환 후 |
|---|---|
| tool_choice | 전달되지 않음 |
| stop | options.stop |
| max_tokens | options.num_predict |
| temperature | options.temperature |
| stream | stream(설정하지 않았으므로 원래 엔드포인트의 기본값) |
/api/chat은 기본적으로 스트리밍하고 /v1/chat/completions는 그렇지 않습니다. 변환된 요청에는 항상 stream이 들어가, 원래 요청처럼 동작합니다.
OpenAI 호환 API에는 컨텍스트 길이(num_ctx)를 위한 필드가 없습니다. Ollama의 문서는 Modelfile의 PARAMETER num_ctx로 모델을 만들고 그 이름으로 호출하라고 제안합니다.
변환은 Ollama v0.40.14를 따릅니다. 이전 버전에서는 요청이 temperature와 top_p를 보내지 않으면 OpenAI 호환 엔드포인트가 둘을 1.0으로 설정했고, content 배열이 비어 있는 assistant 메시지의 도구 호출은 이전 메시지에 붙었습니다.
변환은 Ollama의 소스 코드(v0.40.14, openai/openai.go)와 OpenAI 호환성 페이지를 따랐으며, 2026-11-06에 Ollama 0.40.11로 확인했습니다. Ollama: OpenAI 호환성
모든 작업은 브라우저에서 이루어집니다. 이 도구는 어디에도 연결하지 않습니다.
Ollama는 채팅 요청을 고유의 /api/chat과 OpenAI 호환 /v1/chat/completions, 두 엔드포인트에서 받습니다. 두 번째 엔드포인트는 요청을 스스로 실행하지 않습니다. Ollama의 소스 코드(openai/openai.go)에서는 요청이 먼저 /api/chat 요청으로 변환되고, 답은 다시 변환되어 돌아옵니다. 이 도구는 같은 변환을 브라우저에서 수행합니다. 요청 본문이나 응답을 붙여 넣으면 어느 쪽인지 알아냅니다. OpenAI 형식에서 Ollama로 변환할 때는 max_tokens가 options.num_predict가 되고, 단일 stop 문자열은 목록이 되며, temperature, top_p, seed와 페널티 값은 options로 옮겨 가고, response_format은 format이 되고("json" 또는 json_schema.schema의 스키마), reasoning_effort는 think가 되며(none은 false, minimal은 low, xhigh와 ultra는 max), 도구 호출의 인수는 JSON 문자열에서 객체로 바뀌고, tool 메시지에는 tool_call_id로 찾은 함수 이름이 붙습니다. content 배열의 각 부분은 각각 별도의 메시지가 되며, 이미지는 JPEG, PNG, WebP의 base64 데이터 URL이어야 합니다. 이미지 URL은 거부됩니다. tool_choice, n, user, logit_bias, max_completion_tokens처럼 Ollama의 코드에 없는 필드는 오류 없이 버려집니다. Ollama 0.40.11에서 한 우리의 테스트에서는 max_completion_tokens를 3으로 한 요청도 긴 답을 반환했습니다. Ollama는 max_tokens만 읽기 때문입니다. 반대 방향에서는 num_ctx, top_k, min_p처럼 OpenAI에 대응하는 것이 없는 options는 기록되지 않고 목록에 나타납니다. 응답에서는 done_reason이 finish_reason이 되고(모델이 도구를 호출했으면 stop이 tool_calls가 됩니다), prompt_eval_count와 eval_count는 usage가 되고, thinking은 reasoning이 되며, 소요 시간은 버려집니다. Ollama는 id를 chatcmpl-에 무작위 숫자를 붙여 쓰지만, 이 도구는 chatcmpl-0이라고 씁니다. 변환은 각 요청의 두 형식을 디버깅용 필드 _debug_render_only와 함께 Ollama 0.40.11에 보내(모델이 보게 될 프롬프트가 반환됩니다) 두 프롬프트를 비교하는 방법과, 변환한 응답을 /v1/chat/completions의 실제 답과 비교하는 방법으로 확인했습니다.
이 도구의 핵심 로직은 MIT 라이선스의 오픈 소스로 공개되어 있습니다. github.com/seigo5555/toolkitbox-lib/src/ollama-openai.ts
이럴 때 사용
- OpenAI SDK용으로 쓴 코드를 Ollama 고유의 API로, 또는 그 반대로, 필드 이름을 짐작하지 않고 옮기기
- /v1/chat/completions에 보낸 필드가 아무 효과가 없는 이유 알아내기
- OpenAI 응답을 기대하는 클라이언트가 Ollama에서 무엇을 받게 되는지 확인하기
사용법
- /v1/chat/completions 또는 /api/chat 요청 본문, 혹은 stream을 false로 해서 보낸 /api/chat 응답을 붙여 넣으세요.
- 방향은 자동으로 두거나, 붙여 넣은 형식을 도구가 알아내지 못하면 직접 고르세요.
- 변환된 JSON이나 curl 명령을 복사하고, 경고와 변환된 필드 표를 읽으세요.
FAQ
변환된 요청에는 왜 항상 stream이 들어가나요?
/api/chat은 기본적으로 스트리밍하고 /v1/chat/completions는 그렇지 않습니다. 원래 요청이 stream을 지정하지 않았다면 변환된 요청에는 원래 엔드포인트의 기본값이 들어가, 둘이 같게 동작합니다.
OpenAI 호환 API에서 컨텍스트 길이는 어떻게 설정하나요?
그것을 위한 필드는 없습니다. Ollama의 문서는 Modelfile의 PARAMETER num_ctx로 모델을 만들고 그 모델 이름으로 API를 호출하라고 제안합니다. 이 도구는 options.num_ctx를 대응하는 것이 없는 항목으로 나열합니다.
어떤 필드가 '전달되지 않음'으로 표시됩니다. Ollama가 요청을 거부하나요?
아니요. Ollama는 자신의 코드에 없는 필드를 읽지 않고 버립니다. Ollama 0.40.11에서 한 우리의 테스트에서는 tool_choice, n, user, logit_bias, max_completion_tokens를 담은 요청이 오류 없이 받아들여졌고, max_completion_tokens는 답의 길이를 제한하지 않았습니다.
Ollama v0.40.14에서 무엇이 바뀌었나요?
v0.40.14 이전에는 요청이 temperature와 top_p를 보내지 않으면 OpenAI 호환 엔드포인트가 둘을 1.0으로 설정했습니다. v0.40.14부터는 /api/chat처럼 모델 자체의 기본값이 적용됩니다. content 배열이 비어 있고 도구 호출이 있는 assistant 메시지의 처리도 달라졌습니다. 0.40.11에서 한 우리의 테스트에서는 그 도구 호출이 이전 메시지에 붙었습니다. 이 도구는 v0.40.14를 따릅니다.
OpenAI 응답을 붙여 넣을 수 없는 이유는 무엇인가요?
Ollama는 고유 응답을 OpenAI 형식으로 변환할 뿐 그 반대는 하지 않으므로, 따라 할 변환이 없습니다. 대신 /api/chat 응답을 붙여 넣으세요.
내 데이터가 어딘가로 전송되나요?
아니요. 변환은 브라우저에서 실행됩니다. curl 명령은 직접 실행할 텍스트일 뿐입니다.
관련 글
- 내 코드에서 로컬 모델 호출하기: Ollama의 구조화된 출력과 OpenAI 호환 APIJSON Schema로 로컬 모델의 출력을 제한하고 OpenAI 방식 클라이언트에서 Ollama를 호출하기: 공식 문서의 내용과 지원되지 않는 항목.
- 작은 VPS에서 Ollama의 메모리 사용량 살펴보기Ollama가 메모리에 무엇을 올려 두는지, 얼마나 오래 두는지, 어떤 설정이 이를 바꾸는지 알아봅니다. 공식 FAQ를 바탕으로 한 ollama ps, keep_alive와 각종 제한값입니다.
- 내 VPS의 Ollama에 Dify 연결하기내 VPS에서 Dify를 실행하고 Ollama를 모델로 사용하기: 설치, 플러그인 입력란, Docker 주소 문제, 임베딩을 공식 문서 기준으로 정리했습니다.