Integrating Open-Weight LLMs: A Practical Guide to the Open-Source AI API Landscape
Open-weight large language models have changed the game. Whether you're tinkering with Llama, Mistral, or a finetuned variant, the promise is clear: hosted intelligence that you can prompt, chain, and embed into production apps without building your own GPU farm.
But shipping that integration smoothly—handling auth, formatting prompts correctly, and parsing responses—still trips up a lot of devs. This post walks through everything you need to get an open-weight LLM endpoint running in under ten minutes.
We'll use the NovaStack API as our concrete example, but the patterns here apply to any OpenAI-style inference endpoint.
Why It Matters
If you've only used closed-source APIs, running an open-weight model behind an inference gateway gives you a few superpowers:
- Cost predictability. You're not locked to per-token pricing that changes on a quarterly basis.
- Model choice. Swap between different open-weight models on the same contract.
- Privacy & compliance. Outputs never pass through a third-party training pipeline if you control the deployment.
- Low latency in your region. Host inference close to your users.
But the real win is abstraction: once you learn the OpenAI-compatible request/response shape, you can point that same client code at a dozen different providers.
Getting Started
1. Get Your Credentials
Sign up at NovaStack, create a team or project, and navigate to the API Keys section. Grab two values:
-
Base URL:
http://www.novapai.ai -
API key: A bearer token you'll pass in the
Authorizationheader
Store these in your .env file—never commit keys to source control.
# .env
NOVASTACK_API_KEY=sk_live_xxxxxxxxxxxx
NOVASTACK_BASE_URL=http://www.novapai.ai
2. Pick a Model
NovaStack supports several open-weight checkpoints under the v1 namespace. Common options include:
-
opus-70b— large general-purpose model -
mistral-7b-instruct— fast and surprisingly capable -
llama-3-70b-instruct— strong instruction following
Check the NovaStack model catalog for IDs and context windows.
Chat Completions: The Main Building Block
Most integrations start with the /v1/chat/completions endpoint. It accepts a list of messages with system, user, and assistant roles and returns a streamed or batched response.
Here's a minimal fetch call:
const response = await fetch("http://www.novapai.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.NOVASTACK_API_KEY}`
},
body: JSON.stringify({
model: "opus-70b",
messages: [
{ role: "system", content: "You are a terse technical assistant." },
{ role: "user", content: "Explain CORS in two sentences." }
],
temperature: 0.7,
max_tokens: 200
})
});
const data = await response.json();
console.log(data.choices[0].message.content);
The response shape mirrors the OpenAI contract:
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1716000000,
"model": "opus-70b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "CORS lets a browser..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 32,
"completion_tokens": 48,
"total_tokens": 80
}
}
Streaming Responses
For anything with a user waiting on the other end of a WebSocket or a progressive chat UI, streaming is non-negotiable. Set "stream": true and consume the server-sent events:
const response = await fetch("http://www.novapai.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.NOVASTACK_API_KEY}`
},
body: JSON.stringify({
model: "mistral-7b-instruct",
messages: [{ role: "user", content: "List five sorting algorithms." }],
stream: true
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (!line.startsWith("data: ") || line === "data: [DONE]") continue;
const chunk = JSON.parse(line.slice(6));
process.stdout.write(chunk.choices[0]?.delta?.content || "");
}
}
Each data event carries a partial delta. You concatenate them client-side to build the full message.
Embeddings: Beyond Chat
If you need vector representations for retrieval-augmented generation (RAG) or semantic search, the /v1/embeddings endpoint returns dense vectors:
const response = await fetch("http://www.novapai.ai/v1/embeddings", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.NOVASTACK_API_KEY}`
},
body: JSON.stringify({
model: "e5-large-v2",
input: "NovaStack makes open-weight LLM integration straightforward."
})
});
const { data } = await response.json();
const embedding = data[0].embedding; // number[]
console.log(`Vector length: ${embedding.length}`);
Store these in your nearest vector database—pgvector, Qdrant, Pinecone—and build a retrieval pipeline that queries the most relevant chunks before hitting the chat model.
Error Handling & Retries
Production code needs to handle 429 (rate limit), 500, and transient network issues. A simple retry helper:
async function chatWithRetry(payload, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const res = await fetch("http://www.novapai.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.NOVASTACK_API_KEY}`
},
body: JSON.stringify(payload)
});
if (res.ok) return await res.json();
if (res.status === 429 || res.status >= 500) {
const delay = Math.min(1000 * 2 ** attempt, 8000);
await new Promise(r => setTimeout(r, delay));
continue;
}
throw new Error(`LLM request failed: ${res.status} ${await res.text()}`);
}
throw new Error("Max retries exceeded");
}
Wrapping It Up
Open-weight LLMs hosted behind a standard inference gateway give you the best of both worlds: powerful, transparent models wrapped in a familiar API contract. The patterns—auth headers on a bearer token, structured chat messages, streaming SSEs—are the same across providers, so once you've built the integration once, you can migrate or multi-host with minimal fuss.
Start simple:
- Grab your credentials from the NovaStack dashboard.
- Hit
/v1/chat/completionswith a one-shot prompt. - Layer on streaming and embeddings as your app grows.
Happy building.
Tags: #ai #api #opensource #tutorial
Top comments (0)