Module 1: Technical Foundations · 45 min

Lab: Send, Inspect, and Log Your First Model Request

Learning goal

Turn this lesson into one checked practice output

By the end, you should be able to explain the core idea behind “Lab: Send, Inspect, and Log Your First Model Request” in your own words, apply it to one small real or sample task, and identify what still needs human review.

  1. 1

    Learn

    Read the 45-minute lesson without copying an output blindly.

  2. 2

    Try

    Use a small, non-sensitive example that you can inspect line by line.

  3. 3

    Review

    Check facts, fit, and risk; save one improvement note for next time.

Your first model request is complete only when you can explain what was sent, identify which configured model handled it, inspect the returned status and usage metadata, verify the useful output, and preserve a redacted execution record. Seeing fluent text in a terminal is not enough. This lab turns one request into a small, auditable engineering experiment.

The example uses the official OpenAI JavaScript SDK and Responses API because it provides a concrete runnable path. The controls transfer to other providers: keep the credential in the environment, select an available model through configuration, set a narrow task, capture timing and identifiers, inspect usage, and log metadata rather than private content. Model availability changes, so this lesson deliberately does not hard-code a recommended model or price.

Prepare a Clean Lab

Create a new folder and initialize it:

mkdir first-model-request
cd first-model-request
git init
npm init -y
npm install openai

Create .gitignore before adding credentials:

.env
request-log.jsonl
node_modules/
*.log

Create .env.example and commit this safe template, not a real .env file:

OPENAI_API_KEY=set_only_in_your_local_environment
OPENAI_MODEL=copy_an_available_model_id_from_current_official_docs_or_your_dashboard

Set OPENAI_API_KEY in your local environment using the current official quickstart instructions. Set OPENAI_MODEL to a text model available to your API project. Do not send a key to a classmate for troubleshooting; compare redacted configuration names and error categories instead.

Before spending anything, check:

  • the account or project is the intended one;
  • a low budget or alert is configured where available;
  • the prompt contains only synthetic, non-sensitive text;
  • the selected model supports the request;
  • you know where the local log will be written;
  • .env and the log are ignored by Git.

Worked Example: One Request With a Redacted JSONL Log

Create request.mjs:

import OpenAI from "openai";
import { appendFile } from "node:fs/promises";

const apiKey = process.env.OPENAI_API_KEY;
const model = process.env.OPENAI_MODEL;

if (!apiKey) throw new Error("OPENAI_API_KEY is missing from the environment");
if (!model) throw new Error("OPENAI_MODEL is missing from the environment");

const prompt = [
  "Classify this synthetic support message.",
  "Return two lines only: category and one-sentence reason.",
  "Message: My demo order arrived with the wrong colour.",
].join("\n");

if (prompt.length > 500) throw new Error("Prompt exceeds this lab's input cap");

const client = new OpenAI({ apiKey });
const startedAt = new Date();
const startMs = performance.now();

try {
  const response = await client.responses.create({
    model,
    input: prompt,
  });

  const elapsedMs = Math.round(performance.now() - startMs);
  const output = response.output_text?.trim() ?? "";
  if (!output) throw new Error("The response contained no output text");

  console.log(output);
  console.log({ responseId: response.id, model: response.model, elapsedMs });

  const logRecord = {
    timestamp: startedAt.toISOString(),
    task: "synthetic-support-classification",
    response_id: response.id,
    configured_model: model,
    returned_model: response.model ?? null,
    elapsed_ms: elapsedMs,
    usage: response.usage ?? null,
    output_review: {
      non_empty: output.length > 0,
      line_count: output.split(/\r?\n/).filter(Boolean).length,
    },
  };

  await appendFile("request-log.jsonl", `${JSON.stringify(logRecord)}\n`, "utf8");
} catch (error) {
  const safeError = {
    name: error?.name ?? "Error",
    status: error?.status ?? null,
    message: String(error?.message ?? "Unknown error").slice(0, 200),
  };
  console.error(safeError);
  process.exitCode = 1;
}

Run node request.mjs. The SDK reads the key from your process only because the code passes it to the server-side client; it never prints it. The log uses JSON Lines: one complete JSON object per line. This format is easy to append and inspect. Open the log and verify that it contains identifiers, timing, usage, and simple review results—but not the API key, full prompt, or model output.

Why keep configured_model and returned_model separately? Configuration proves what your application requested; returned metadata records what the service reported. Why record a response ID? It gives support and operations a precise event to investigate without pasting the customer's entire content. Why record provider-reported usage rather than estimate it from characters? Tokenization and billable units are provider-specific and can change.

Inspect the Output as a Claim, Not a Truth

For the synthetic message, define the acceptance check before reading the answer:

  1. Exactly two non-empty lines were requested.
  2. The category should indicate an order or product issue.
  3. The reason must refer only to the supplied wrong-colour fact.
  4. It must not invent a refund, policy, customer identity, or delivery date.

The code checks only non-empty output and line count. A human still checks meaning. In a production workflow, convert these requirements into structured output and automated tests, which the next module covers. A response can be technically successful but factually wrong, badly formatted, unsafe, or irrelevant.

Make one controlled comparison. Change only “wrong colour” to “tracking link has not updated” and run again. Add a note to LAB-NOTES.md: what changed in the output, whether each answer passed the same rubric, the two response IDs, and any usage difference. Do not conclude that one sample proves general reliability.

Failure Cases and a Diagnostic Order

  • Missing environment variable: the local preflight error should appear before a network request. Fix the environment; do not paste the key into the source file.
  • Authentication or permission error: confirm the project, key status, and permissions. Do not retry it in a tight loop.
  • Unknown or unavailable model: use the current official model catalog or your dashboard and update OPENAI_MODEL; keep code unchanged.
  • Rate limit: inspect the error category and current limits. If retrying is appropriate, use bounded exponential backoff with jitter rather than immediate repetition.
  • Network interruption: distinguish a transport failure from an API response. A client timeout does not always prove server-side work stopped; use request or job identifiers before resubmitting side-effecting work.
  • Empty or unexpected output: inspect the complete response safely in a local, non-shared environment, then improve parsing and acceptance checks. Do not log private payloads globally.
  • Usage missing: handle metadata as nullable. Monitoring code should not crash the business workflow because an optional field is absent.
  • Log leak: logging the entire error or response can capture inputs, headers, or customer data. Whitelist fields rather than trying to redact every possible secret afterward.

🇵🇰 Pakistan Angle

Use a small synthetic prompt while learning so limited balances and mobile-data connections are not consumed by repeated large requests. Record latency across several attempts before promising a turnaround time to a Pakistani client; international routing and local connectivity can vary. A slow request is a measurement, not proof that every user will see the same delay.

For bilingual products, test English, Urdu script, and Roman Urdu as separate fixtures and have native readers review meaning. Never send a real WhatsApp chat, CNIC scan, bank document, medical record, school record, or private client brief merely because it is convenient. Check the provider's current data controls, retention terms, region options, and your client's written authorization before processing real material. Keep the log minimal enough to share with a reviewer without revealing the underlying customer message.

Hands-On Exercise: Submit a Verifiable Request Record

Produce the following, using only synthetic messages:

  1. request.mjs with environment checks, an input cap, one Responses API call, a non-empty-output check, safe error handling, and JSONL metadata logging.
  2. .env.example and .gitignore; run git status --ignored and confirm the local secret and log are ignored.
  3. request-log.jsonl containing two successful records from prompts that differ in exactly one business detail. Keep this file out of Git and submit a redacted copy only if your instructor's process permits it.
  4. LAB-NOTES.md with the prewritten acceptance rubric, response IDs, observed timing, provider-reported usage, pass/fail results, and one next test.
  5. A failed run caused by temporarily removing OPENAI_MODEL, demonstrating that local preflight prevents a paid request. Record the error text without any environment value.

Finish by running git diff --cached before committing the safe source and notes. Search the staged material for OPENAI_API_KEY; the variable name may appear, but no value may appear.

Completion Rubric

  • Pass — secure configuration: the key is environment-only, ignored by Git, absent from logs, and never submitted.
  • Pass — inspectability: each successful run records timestamp, task, response ID, configured/returned model, elapsed time, usage when available, and output checks.
  • Pass — verification: acceptance criteria existed before comparison and unsupported facts are marked as failures.
  • Pass — controlled experiment: exactly one input detail changed between the two logged runs.
  • Pass — operational judgment: errors are categorized before retry, and no retry or spend guarantee is claimed.
  • Needs revision: raw private content is logged, model or price claims are hard-coded as permanently current, or fluent output is accepted without a rubric.

Sources


Key takeaway: A professional first request is a measured, redacted experiment: configure the model and key outside code, send synthetic input, inspect identifiers and usage, judge output against a prior rubric, and retain only the metadata needed to reproduce or diagnose the run.

Self-check

Before you mark Lesson 1.3 complete

  • Can I explain “Lab: Send, Inspect, and Log Your First Model Request” without reading the lesson back word for word?
  • Did I complete the lesson’s practice step on a real or clearly labelled sample task?
  • Did I check the result for invented facts, private data, unsafe actions, and mismatch with the brief?