Use KoboldCpp as an OpenAI-compatible server
KoboldCpp OpenAI API in short: set your OpenAI client's base URL to http://localhost:5001/v1 and it talks to KoboldCpp instead of OpenAI. The API key can be any placeholder unless KoboldCpp was started with --password, in which case it must be that password. The model field is ignored: the loaded model answers. Chat, completions, streaming, JSON schema output, embeddings, the Responses API and the Anthropic SDK worked in our tests on KoboldCpp 1.124.2.
Checked against KoboldCpp 1.124.2 · updated 13 Nov 2026
- lab-lnx: Linux test VM · 4 vCPU · 15 GB · no GPU
On this page
- Endpoints at a glance
- KoboldCpp OpenAI API: the base URL
- What “API key” means here
- The model field
- Use it from the official SDKs
- Chat versus text completions
- Streaming
- Tools and function calling
- JSON mode and structured output
- Images, audio and vision through /v1
- Embeddings
- Responses API and Anthropic Messages
- Anthropic Messages
- Coming from Ollama
- Differences from OpenAI to expect
Endpoints at a glance
These are the OpenAI-style and Anthropic routes. Our status says “works” only where we called the route and got an answer: F23 for the first captures, F72 for the SDK tests. The full list is on the API page.
| Main parameters | ||||||
|---|---|---|---|---|---|---|
| GET | /v1/models | OpenAI | OpenAI-style model list: the loaded model, plus admin-dir configs in router mode. | yes | works F23 | |
| POST | /v1/completions | OpenAI | OpenAI text completions (supports streaming and KoboldCpp sampler extras). | model prompt max_tokens max_completion_tokens temperature top_p | yes | works F23 |
| POST | /v1/chat/completions | OpenAI | OpenAI chat completions with streaming, tools/function calling, vision/audio content and JSON/structured output. | model messages max_tokens max_completion_tokens temperature top_p | yes | works F23 |
| POST | /v1/responses | OpenAI | Experimental emulation of the OpenAI Responses API. | model input instructions max_tokens temperature top_p | yes | works F72 |
| POST | /v1/embeddings | OpenAI | OpenAI-style embedding vectors (needs --embeddingsmodel). | model input encoding_format truncate | yes | works F23 |
| POST | /v1/images/generations | OpenAI | OpenAI-style image generation (needs --sdmodel). | model prompt size response_format n | yes | untested |
| POST | /v1/images/edits | OpenAI | OpenAI-style multipart image edit with optional mask. | image mask prompt model size response_format | yes | untested |
| GET | /v1 | OpenAI | Bare /v1 root; returns a short pointer response. | no | untested | |
| POST | /v1/messages | Anthropic | Anthropic Messages API emulation (system, tools, streaming, thinking). | model messages system max_tokens temperature top_p | yes | works F72 |
Speech routes (/v1/audio/transcriptions, /v1/audio/speech) are in the voice guide.
KoboldCpp OpenAI API: the base URL
http://localhost:5001/v1. On another device or through a tunnel only the host changes (remote access). KoboldCpp also answers OpenAI paths without /v1, so an app that adds /v1 itself works with the bare address, and in our test an SDK given the bare address worked too F72. If the app says “endpoint does not exist”, see the URL mistakes.
What “API key” means here
| KoboldCpp started without --password | Any non-empty text, such as placeholder | The SDK refused an empty key before sending anything; a placeholder worked (F72) |
| Started with --password X | X, sent as a Bearer token | Right key: 200. Wrong key: 401 (F72, F25) |
| A tunnel or a shared server | Always set a password | A password is not a firewall: remote access page |
KoboldCpp has no accounts, keys or billing: the only key is the password you choose. Any page that tells you to get an API key from a dashboard is wrong. Do not commit a real --password value into a code repository.
The model field
/v1/models returns the loaded model with the id koboldcpp/<file name>. The value you send as model is ignored: in our test anything-at-all and gpt-4o both got an answer from the loaded model, and the reply’s model field said koboldcpp/qwen2.5-0.5b-instruct-q4_k_m F72. In router mode (--routermode) the field picks the model; see sharing.
Use it from the official SDKs
Start KoboldCpp with a model
Load any model: see getting started.
Set the base URL
In the SDK set
base_url(Python) orbaseURL(JavaScript) tohttp://localhost:5001/v1.Set the key
A placeholder if there is no password, otherwise the password.
Send a chat
A normal chat completion. The reply’s
modelfield readskoboldcpp/...: that is how you know it worked.
from openai import OpenAI
client = OpenAI(base_url="http://localhost:5001/v1", api_key="placeholder")
r = client.chat.completions.create(
model="anything",
messages=[{"role": "user", "content": "Say OK and nothing else."}],
max_tokens=12,
)
print(r.model, r.choices[0].message.content)What each feature did, with the model we had (a 0.5B model, so we record the shape of the answer, not its quality):
| List models | works | One model, id koboldcpp/<file name> |
| Chat completions | works | Reply, usage, and the loaded model in the model field |
| Text completions | works | finish_reason length at the token limit |
| Streaming | works | Python and JavaScript; ends with a stop chunk |
| Tools (function calling), default settings | works | finish_reason tool_calls and one parsed call |
| Tools with --jinja | partial | The call came back as plain text in the message, with an empty tool_calls list |
| JSON schema output | works | Parsed, with an integer where the schema asked for one |
| json_object mode | works | Parsed as an object |
| Embeddings with a model loaded | works | 384 numbers per text with the MiniLM model |
| Embeddings with no model | empty | Status 200, empty vector, model inactive |
| Responses API | works | status completed, output_text returned |
| Anthropic Messages, with streaming | works | end_turn; bare or /v1 base URL both worked |
| Ollama emulation | works | tags, chat, generate, show answered 200 |
Chat versus text completions
Chat completions take a list of messages, and KoboldCpp turns them into one prompt with a chat template: by default it guesses one (Instruct-template adapter (JSON file or bundled name such as ChatML, Llama-3) used to format /v1/chat/completions prompts. Default AutoGuess detects it from the model.Default AutoGuessLauncher Loaded Files tab: Chat Adapter + "Pick Premade"Since v1.62All details, default AutoGuess), and Uses the model's embedded Jinja chat template (including tool calls) for chat completions, falling back to KoboldCpp's universal formatting if it fails. Since 1.123 also covers the former --jinjatools.Default falseLauncher Quick Launch tab: Use JinjaSince v1.102All details uses the model’s own template. If replies continue your prompt or contain role tags, the template is wrong. Text completions send your prompt as it is, and you format it yourself. In our test completions stopped with length after 12 tokens, and chat answered OK F72.
Streaming
Set stream: true and KoboldCpp sends server-sent events in OpenAI’s chat.completion.chunk format, ending with data: [DONE] (18 events in our capture) F23:
data: {"id": "chatcmpl-A3023341", "object": "chat.completion.chunk", "created": 1794574088, "model": "koboldcpp/qwen2.5-0.5b-instruct-q4_k_m", "choices": [{"ind…1data: [DONE]2- data: {"id": "chatcmpl-A3023341", "object": "chat.completion.chunk", ": The first chunk, shortened.
- data: [DONE]: The stream ends with this line.
Models that think write their reasoning in a separate field since 1.111, which broke some clients (per the release notes). We have not tested a thinking model.
Tools and function calling
KoboldCpp has supported tools since 1.70, automatic tool choice since 1.87, and --jinja for Jinja-based tool templates (from the release notes). In our test a tools request returned a parsed tool call on the default settings, and with --jinja the call arrived as text F72. We used a 0.5B model, so this says nothing about how well larger models choose tools. Users report wrong-tool and empty-output problems (#1696, #1448): if tool calls misbehave, try both settings and a model made for tools.
JSON mode and structured output
A strict json_schema response format returned valid JSON with the right keys and an integer where the schema asked for one, and json_object parsed F72. KoboldCpp added OpenAI structured outputs in 1.90 (release notes), and /api/extra/json_to_grammar converts a schema to a grammar.
Images, audio and vision through /v1
An image_url data URI in a chat message worked with a small vision model, and /v1/audio/transcriptions transcribed a sample correctly F27. /v1/audio/speech and /v1/images/generations need a speech or image model loaded; we have not tested them. See vision, voice and images.
Embeddings
With GGUF embedding model to serve /v1/embeddings and /api/extra/embeddings.Default Launcher Loaded Files tab: Embeds Model + ECtx + GPUSince v1.87All details and a GGUF embedding model loaded, /v1/embeddings returned 384-number vectors from the 22 MB MiniLM model F27 F72.
Responses API and Anthropic Messages
/v1/responses is an emulation added in 1.111 (release notes). The official OpenAI SDK’s responses.create returned completed with the text F72.
Anthropic Messages
/v1/messages (the Anthropic API) was basic in 1.111 and complete in 1.115 (release notes). The official Anthropic Python SDK worked for a normal and a streamed message, with the base URL given as the bare address or with /v1 F72.
Coming from Ollama
KoboldCpp emulates Ollama’s /api/chat, /api/generate, /api/tags, /api/embed and /api/show. In our test /api/tags, /api/chat, /api/generate and /api/show returned 200 and /api/tags listed the loaded model F72. Point the Ollama app at http://localhost:5001. /api/version answers 0.7.0, an emulated Ollama version rather than KoboldCpp’s, and /slots answers 501. We did not test an Ollama-only app, and we did not test /api/embed. Model files differ: Ollama stores its own blobs, while KoboldCpp loads a GGUF from Hugging Face.
Differences from OpenAI to expect
- One model at a time, unless you use router or admin mode.
- Requests queue one at a time by default F26.
- The default reply length is 2048 tokens when
max_tokensis missing F05. - A password protects generation but not
/v1/models: with--password, a wrong key still got the model list F72. - The request body can be up to 32 MB.
Frequently asked questions
What is the KoboldCpp OpenAI base URL?
http://localhost:5001/v1. It works with the official OpenAI Python and JavaScript SDKs. In our test the bare address http://localhost:5001 also worked, because KoboldCpp serves the OpenAI paths without the /v1 prefix too, but SDKs and apps are written for /v1.
What do I put as the OpenAI API key?
Any non-empty text if you did not start KoboldCpp with --password. The OpenAI SDK refuses an empty key before it sends anything, so use a placeholder. If you did set --password, use that password as the key: a wrong one gets a 401 error. KoboldCpp has no accounts or billing, so any page that tells you to get a key from a dashboard is wrong.
Does KoboldCpp support function calling?
Yes, in a limited way. In our test, a request with tools returned a tool call on the default settings, and with --jinja the same request returned the call as plain text instead of a parsed tool call. We used a 0.5B model, which shows the shape of the answer and not model quality; users report wrong-tool and empty-output problems with some models.
Does streaming work with the OpenAI SDK?
Yes. With stream set to true KoboldCpp sends server-sent events in OpenAI's chunk format and ends with [DONE]. The Python and JavaScript SDKs both streamed correctly in our test.
Does it support the Anthropic API?
Yes: /v1/messages works with the official Anthropic Python SDK, including streaming. In our test the base URL worked both as the bare address and with /v1 added. KoboldCpp's release notes say basic support came in 1.111 and the full API in 1.115.
Can Ollama apps use KoboldCpp?
Often. KoboldCpp emulates Ollama's chat, generate, tags and show routes, and we got a 200 from each. Point the app at http://localhost:5001. Its /api/version answers with an emulated Ollama version, not KoboldCpp's, and apps that need other Ollama features may not work.
Why do I get empty embeddings?
No embeddings model is loaded. KoboldCpp then answers the request with status 200 and an empty vector, and the model name inactive. Start it with --embeddingsmodel and a GGUF embedding model: with the 22 MB MiniLM model we got 384 numbers per text. Always check the vector length.