Use the OpenAI SDK
Point any OpenAI client at Nucleus and chat with your fine-tuned model without changing your code.
Nucleus speaks the OpenAI wire format at https://api.nucleus-ai.io/v1. Point any OpenAI
client at that base URL with your Nucleus API key and change nothing else: the official SDKs,
and every framework or proxy built on them, work as they are. Requests to these routes need a
key with the infer scope.
This guide covers SDK setup, model selection, the two completion routes, streaming and the reasoning controls. For the full parameter tables see the OpenAI-compatible reference.
Point the SDK at Nucleus
Pass the Nucleus base URL and your key when you construct the client. Everything else about your code stays the same.
from openai import OpenAI
client = OpenAI(
base_url='https://api.nucleus-ai.io/v1',
api_key=API_KEY, # nk_live_...
)Pick a model
The model parameter accepts either a base model ID, such as Qwen/Qwen3-8B, or the
nucleus:// path of your fine-tuned sampler weights:
nucleus://run_3Bz:train:0/sampler_weights/000240A finished fine-tuning job
reports this path as result_model, so serving your own model is a copy-paste away. See
Serving for how weights become servable.
Chat completions or completions
There are two routes, and for almost everything you want
chat completions. It takes a
messages array and renders it server-side with the model's chat template, so you never
touch tokens or templates. It is the easy on-ramp.
Completions is raw text continuation:
your prompt string goes to the model exactly as written, with no chat template applied.
Reach for it when you want the model to continue text rather than hold a conversation.
resp = client.completions.create(
model='Qwen/Qwen3-8B',
prompt='The capital of France is',
max_tokens=8,
)
print(resp.choices[0].text) # " Paris."Both routes support max_tokens, temperature, top_p and stream.
Streaming
Set stream to true and tokens arrive as server-sent events. The SDKs turn the stream into
an iterator of deltas, exactly as they do against OpenAI.
stream = client.chat.completions.create(
model='Qwen/Qwen3-8B',
messages=[{'role': 'user', 'content': 'Write a haiku about GPUs.'}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta.content:
print(delta.content, end='', flush=True)Reasoning controls
Chat completions separates the model's reasoning from its answer by default:
separate_reasoning defaults to true, and the reasoning arrives as reasoning_content on
the message while content carries only the final answer.
{
"choices": [
{
"message": {
"role": "assistant",
"reasoning_content": "17 × 23 = 391",
"content": "391"
},
"finish_reason": "stop"
}
]
}Set separate_reasoning to false to keep the reasoning inline in content.
reasoning_effort controls how hard the model thinks before answering. It accepts the named
levels from none up to xhigh, or a float between 0.0 and 0.99 for finer control.
none skips reasoning entirely, which is the cheapest and fastest setting for simple
requests.
resp = client.chat.completions.create(
model='Qwen/Qwen3-8B',
messages=[{'role': 'user', 'content': 'What is 17 x 23?'}],
reasoning_effort='high',
)
print(resp.choices[0].message.reasoning_content)
print(resp.choices[0].message.content)Chat with your fine-tuned model
End to end: take the result_model path from your finished job, point the SDK at Nucleus and
hold a conversation with your own model.
from openai import OpenAI
client = OpenAI(
base_url='https://api.nucleus-ai.io/v1',
api_key=API_KEY,
)
MODEL = 'nucleus://run_3Bz:train:0/sampler_weights/000240' # result_model from your job
history = [
{'role': 'system', 'content': 'You are a support assistant for Acme.'},
{'role': 'user', 'content': 'How do I reset my API key?'},
]
resp = client.chat.completions.create(
model=MODEL,
messages=history,
max_tokens=512,
temperature=0.2,
)
answer = resp.choices[0].message.content
print(answer)
history.append({'role': 'assistant', 'content': answer})
history.append({'role': 'user', 'content': 'And if I have lost the old one?'})
resp = client.chat.completions.create(model=MODEL, messages=history, max_tokens=512)
print(resp.choices[0].message.content)If you use the Anthropic SDK or Claude Code instead, see Use the Anthropic SDK and Claude Code.