Code
LiteLLM
Point LiteLLM at nokeep with the openai/ prefix and api_base. It works in the proxy and in the Python SDK.
Checked 29 October 2026
The proxy
model_list:
- model_name: deepseek-v4.1-flash-uncensored
litellm_params:
model: openai/deepseek-v4.1-flash-uncensored
api_base: https://nokeep.ai/v1
api_key: os.environ/NOKEEP_API_KEY
model_info:
input_cost_per_token: 0.00000045
cache_read_input_token_cost: 0.000000011
output_cost_per_token: 0.00000175
- model_name: glm-5.3-flash-uncensored
litellm_params:
model: openai/glm-5.3-flash-uncensored
api_base: https://nokeep.ai/v1
api_key: os.environ/NOKEEP_API_KEY
model_info:
input_cost_per_token: 0.0000002
cache_read_input_token_cost: 0.00000004
output_cost_per_token: 0.00000065pip install 'litellm[proxy]'
export NOKEEP_API_KEY="sk-nokeep-test" # your own key once it connects
litellm --config config.yamlYour apps then call the proxy (by default http://0.0.0.0:4000) with the model_name, and the proxy calls nokeep. model_info gives LiteLLM nokeep’s prices, per token, so its spend tracking matches your bill. Without it, LiteLLM has no price for nokeep’s models and can’t count what the calls cost.
The Python SDK
pip install litellm
export NOKEEP_API_KEY="sk-nokeep-test" # your own key once it connectsimport os
import litellm
reply = litellm.completion(
model="openai/deepseek-v4.1-flash-uncensored",
api_base="https://nokeep.ai/v1",
api_key=os.environ["NOKEEP_API_KEY"],
messages=[{"role": "user", "content": "Name three good names for a tavern."}],
)
print(reply.choices[0].message.content)
print(reply.usage)A native nokeep provider has been proposed to LiteLLM. Until it is released, the openai/ prefix with api_base is the way in; it sends the request as it is.
Stream
import os
import litellm
stream = litellm.completion(
model="openai/deepseek-v4.1-flash-uncensored",
api_base="https://nokeep.ai/v1",
api_key=os.environ["NOKEEP_API_KEY"],
messages=[{"role": "user", "content": "Tell me a story in three lines."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="", flush=True)
if getattr(chunk, "usage", None):
print("\n", chunk.usage)Tools, thinking and samplers
import os
import litellm
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the weather in a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
reply = litellm.completion(
model="openai/deepseek-v4.1-flash-uncensored",
api_base="https://nokeep.ai/v1",
api_key=os.environ["NOKEEP_API_KEY"],
messages=[{"role": "user", "content": "What's the weather in Lisbon?"}],
tools=tools,
reasoning_effort="high",
max_tokens=4000,
extra_body={"min_p": 0.05}, # fields LiteLLM has no argument for
)
print(reply.choices[0].message.tool_calls)With the openai/ prefix, reasoning_effort and tools pass through unchanged. In the proxy, set fixed fields per model under litellm_params (for example reasoning_effort: high), or let each caller send their own. See Tool calls and Thinking.
Gotchas
- `reasoning_effort` takes only the model’s own values.
deepseek-v4.1-flash-uncensoredtakesnone,low,high,max;glm-5.3-flash-uncensoredtakeslow,high. Other apps’minimal,mediumandxhighrun at the model’s nearest level (mediumashigh,xhighasmaxwhere the model has it); any other value gets400 invalid_reasoning_effort. See Thinking. - GLM picks its own tools.
glm-5.3-flash-uncensoredtakestool_choiceautoornoneonly. Forcing a tool (required, or naming a function) gets400 unsupported_tool_choice. Use DeepSeek when you need to force one. - Fields a model can’t take are dropped, not refused. The call still answers, and the
x-nokeep-ignoredresponse header names what was left out. GLM keeps onlytools,tool_choiceandreasoning_effort, so itstemperatureandresponse_formatare dropped. See which fields each model takes. - Content parts are text and pictures only.
image_urlparts work ondeepseek-v4.1-flash-uncensored; GLM reads text alone. Audio and file parts (a PDF) get400 unsupported_input. - `n` must be 1. Ask for several replies with several calls.
drop_params: true makes LiteLLM drop the fields it believes a provider can’t take before the call. nokeep already drops what a model can’t take and names it in x-nokeep-ignored, so you don’t need it.
Questions
Do I put my nokeep key in config.yaml?
No. Write api_key: os.environ/NOKEEP_API_KEY and LiteLLM reads the key from the environment when it starts.
Why does LiteLLM show no cost for nokeep calls?
It doesn’t know nokeep’s prices. Add the model_info block from the config above; the prices in it come from the same table as your bill. The bill itself rounds each call up to a whole credit.