← Code Recipes
Hosting, Gateways & Local

Together AI Free code examples in Python and JavaScript

Hosted open models with fine-tuning and dedicated endpoints.

C# Python Java JavaScript

WHAT THIS PAGE COVERS

Fine-tuning an open model on your own data end to end.

Model meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo
Package together
Checked

Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.

Install

The client reads TOGETHER_API_KEY on construction. The same package covers inference and the fine-tuning API.

pip install together

export TOGETHER_API_KEY="your-key"   # macOS / Linux
setx TOGETHER_API_KEY "your-key"     # Windows, then open a new shell
Chat completions

Model ids are the full Hugging Face path. The response shape is OpenAI's, so an existing client works too — point it at https://api.together.ai/v1.

import os
from together import Together

client = Together(api_key=os.environ["TOGETHER_API_KEY"])

completion = client.chat.completions.create(
    model="meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
    messages=[{"role": "user", "content": "Explain a database index."}],
)

print(completion.choices[0].message.content)
Preparing the training data

JSONL, one conversation per line. THE FORMAT IS THE WORK: a few hundred genuinely representative examples beat tens of thousands of scraped ones, and every example should look exactly like what you will send at inference time.

import json

# Each line is one complete conversation. Include the system message
# if you will send one at inference — the model learns the shape it
# is trained on, and a mismatch at run time undoes the training.
examples = [
    {
        "messages": [
            {"role": "system", "content": "You triage pump faults."},
            {"role": "user", "content": "Pump stalled, code E-4471."},
            {"role": "assistant", "content": "SEVERITY: high\nCAUSE: impeller jam"},
        ]
    },
]

with open("train.jsonl", "w", encoding="utf-8") as handle:
    for example in examples:
        handle.write(json.dumps(example) + "\n")

# Check it before spending anything on a job.
uploaded = client.files.upload(file="train.jsonl", check=True)
print(uploaded.id)
Running the job

LoRA by default: an adapter, not a new copy of the model. Cheaper, faster, and it cannot damage the base model — which matters the first few times when the data is not as clean as you think.

job = client.fine_tuning.create(
    training_file=uploaded.id,
    model="meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
    lora=True,                 # adapter, not a full fine-tune
    n_epochs=3,                # more than ~4 usually overfits
    learning_rate=1e-5,
    suffix="pump-triage",      # becomes part of the model id
)

print(job.id, job.status)
Waiting for it, then calling it

The finished job carries a model id you call exactly like any other. Nothing else about the request changes — which is what makes a fine-tune easy to A/B against the base model.

import time

while True:
    status = client.fine_tuning.retrieve(job.id)
    print(status.status)

    if status.status in {"completed", "error", "cancelled"}:
        break

    time.sleep(30)

if status.status != "completed":
    raise RuntimeError(f"fine-tune {status.status}")

# Same call, different model id. Run the old one alongside it before
# replacing anything.
completion = client.chat.completions.create(
    model=status.output_name,
    messages=[{"role": "user", "content": "Pump stalled, code E-4471."}],
)

print(completion.choices[0].message.content)
Install

THE PACKAGE IS together-ai, with the suffix. The bare `together` name on npm is an unrelated project.

npm install together-ai

export TOGETHER_API_KEY="your-key"
Chat completions

The response is OpenAI-shaped. Streaming is server-sent events — pass stream: true and iterate.

import Together from "together-ai";

const client = new Together({ apiKey: process.env.TOGETHER_API_KEY });

const completion = await client.chat.completions.create({
  model: "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
  messages: [{ role: "user", content: "Explain a database index." }],
});

console.log(completion.choices[0].message.content);
Preparing the training data

JSONL, one conversation per line, matching what you will send at inference. A few hundred representative examples beat a large scraped set — and the mismatch between training shape and request shape is the usual reason a fine-tune underperforms.

import { writeFile } from "node:fs/promises";

const examples = [
  {
    messages: [
      { role: "system", content: "You triage pump faults." },
      { role: "user", content: "Pump stalled, code E-4471." },
      { role: "assistant", content: "SEVERITY: high\nCAUSE: impeller jam" },
    ],
  },
];

await writeFile(
  "train.jsonl",
  examples.map((example) => JSON.stringify(example)).join("\n") + "\n",
);

const uploaded = await client.files.upload({
  file: "train.jsonl",
  purpose: "fine-tune",
});
Running it, and knowing when it is worth it

LoRA first, always. And BEFORE running a job at all: if a better prompt or a retrieval step gets you there, that is cheaper, reversible and does not go stale.

const job = await client.fineTune.create({
  training_file: uploaded.id,
  model: "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
  lora: true,
  n_epochs: 3,
  suffix: "pump-triage",
});

// Worth fine-tuning for:
//   a fixed output shape the model keeps drifting from
//   a house style or tone that a prompt cannot hold across turns
//   domain vocabulary the base model mangles
//
// NOT worth fine-tuning for:
//   facts that change          -> retrieval
//   a one-off instruction      -> the prompt
//   "it is not smart enough"   -> a bigger base model
console.log(job.id, job.status);
Calling the result

The finished job's output name is a model id like any other. Keep the base model's call alongside it for a while — a fine-tune that is better on your examples and worse in general is a common and quiet outcome.

let status;
do {
  await new Promise((resolve) => setTimeout(resolve, 30_000));
  status = await client.fineTune.retrieve(job.id);
  console.log(status.status);
} while (!["completed", "error", "cancelled"].includes(status.status));

if (status.status !== "completed") {
  throw new Error(`fine-tune ${status.status}`);
}

// Run both and compare on held-out examples before switching.
for (const model of [
  "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
  status.output_name,
]) {
  const completion = await client.chat.completions.create({
    model,
    messages: [{ role: "user", content: "Pump stalled, code E-4471." }],
  });
  console.log(model, "->", completion.choices[0].message.content);
}

QUESTIONS

Which languages are the Together AI examples in?

Python and JavaScript. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.

Which package do I install for Together AI?

The samples use together. The install step on each language tab gives the exact command.

Which Together AI model do these examples use?

meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo, checked against the official documentation on 26 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.

Where is the official Together AI documentation?

https://docs.together.ai/ — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.

ALSO IN HOSTING, GATEWAYS & LOCAL

The authority

Official Together AI documentation

Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.

Read the docs ↗

https://docs.together.ai/

New drops, every week

Free tools & Claude templates, landing regularly.

We keep shipping new free tools, code recipes and Claude Code templates. Follow @freeyantra on Instagram or join the newsletter so you never miss one.

Follow @freeyantra

or get them by email

Double opt-in. Unsubscribe any time. Privacy