Module 1 · Technical Foundations · 45 min
Lab: Send, Inspect, and Log Your First Model Request
Is lesson ke baad tum
record what actually ran, check format and meaning separately, and keep provider identifiers and usage distinct from local fixtures.
In this lesson
Run one small classification experiment and keep a metadata-only record. Start in fixture mode, which needs Node but no account, SDK, or paid request. The optional live route needs the official OpenAI SDK, an authorized API project with available quota/credits or billing, a permitted model, and a protected API key. A ChatGPT subscription does not establish API access or an API spending allowance.
Prepare the Lab
Create a new folder, run npm init -y, and create .gitignore before any secret or log:
.env
request-log.jsonl
node_modules/
*.logCreate .env.example with names and placeholders only:
LAB_MODE=fixture
LAB_CASE=wrong-colour
OPENAI_API_KEY=set_only_for_authorized_live_mode
OPENAI_MODEL=choose_an_available_text_model_for_your_API_projectThe script reads process environment variables. Merely creating .env.example does not load them or make a request. The defaults below select fixture mode; downloads and API-account setup are separate from the core activity.
Worked Example
Save this as request.mjs. Fixture outputs are deliberately supplied answers, not measured model results:
import { appendFile } from "node:fs/promises";
const fixtures = {
"wrong-colour": {
message: "My demo order arrived with the wrong colour.",
output: "category: product issue\nreason: The delivered colour differs from the order."
},
"tracking": {
message: "My demo order tracking link has not updated.",
output: "category: tracking issue\nreason: The tracking information has not updated."
}
};
try {
const mode = process.env.LAB_MODE ?? "fixture";
if (!["fixture", "live"].includes(mode)) throw new Error("Invalid LAB_MODE");
const caseId = process.env.LAB_CASE ?? "wrong-colour";
if (!Object.hasOwn(fixtures, caseId)) throw new Error("Unknown LAB_CASE");
const sample = fixtures[caseId];
const prompt = "Classify this synthetic support message. Return two lines only: "
+ "category and one-sentence reason. Do not invent policy or actions. Message: "
+ sample.message;
if (prompt.length > 500) throw new Error("Input cap exceeded");
const configuredModel = mode === "live" ? process.env.OPENAI_MODEL : null;
if (mode === "live" && (!process.env.OPENAI_API_KEY || !configuredModel)) {
throw new Error("Live mode needs OPENAI_API_KEY and OPENAI_MODEL");
}
const startedAt = new Date().toISOString();
const startMs = performance.now();
let response;
if (mode === "fixture") {
response = {status:"completed", output_text:sample.output,
id:null, model:null, usage:null};
} else {
const {default: OpenAI} = await import("openai");
const client = new OpenAI({apiKey:process.env.OPENAI_API_KEY,
maxRetries:0, timeout:30_000});
response = await client.responses.create({model:configuredModel,
input:prompt, max_output_tokens:1024, store:false});
}
if (response.status !== "completed") throw new Error("Response incomplete");
const output = response.output_text?.trim() ?? "";
const lineCount = output.split(/\r?\n/).filter(Boolean).length;
if (!output || lineCount !== 2) throw new Error("Expected two nonempty lines");
const record = {timestamp:startedAt, mode, case_id:caseId,
response_id:response.id ?? null, configured_model:configuredModel,
returned_model:response.model ?? null,
elapsed_ms:Math.round(performance.now()-startMs), usage:response.usage ?? null,
output_review:{non_empty:true,line_count:lineCount}};
console.log(output); // only synthetic text belongs in this lab
await appendFile("request-log.jsonl", JSON.stringify(record)+"\n", "utf8");
console.log(record);
} catch (error) {
console.error({category:Number.isInteger(error?.status)
? "api_error" : "local_or_transport_error",
status:Number.isInteger(error?.status) ? error.status : null});
process.exitCode = 1;
}Run node request.mjs. Expect the two supplied wrong-colour lines and a record with mode fixture, case_id wrong-colour, and null provider ID/model/usage fields. The measured elapsed time is local fixture-processing time, not model latency. JSON Lines means one complete JSON object per line in the log.
The code enforces nonempty output and exactly two lines. It does not judge meaning. Check that the reason follows only from the supplied message and does not invent a refund, policy, customer identity, or delivery date. A completed API response can still fail this semantic check.
Hands-On Exercise
In PowerShell set $env:LAB_CASE="tracking" and rerun. On macOS/Linux use LAB_CASE=tracking node request.mjs. Inspect the two log records and write which one business detail changed.
Check: the second output concerns tracking, not a product colour. Both records say fixture, retain null provider usage, and omit the full prompt and output from the JSONL file. Do not rename them live results or invent response IDs. Your short notes should record the meaning check as well as the format check.
Change LAB_CASE to unknown and run once. Expect a nonzero exit with the safe local_or_transport_error category and no appended success record. Restore a valid case afterward. The error category is intentionally broad; diagnose configuration locally without printing secret values or an entire SDK error object.
Optional Live Request
After reviewing current model access, pricing, data controls, and a small spending limit, install the SDK with npm install openai. Set the key securely in your local process using official setup guidance and set OPENAI_MODEL to an available compatible text model. Then set LAB_MODE to live and run one synthetic case. Never place the actual key in source, a submitted runbook, shell screenshots, or browser code.
The live path disables automatic SDK retries and sets a 30-second client timeout. If the request times out, it may still consume provider work; do not infer zero cost or retry without a budget decision. The 1,024-token output cap can include reasoning tokens, so an incomplete result needs a deliberate review of its cause. store:false controls Responses application storage; it does not independently enable Zero Data Retention or remove every provider log.
Record the actual response ID, configured/returned model, elapsed time, usage, and human meaning check. Keep request-log.jsonl out of Git. A fixture pass does not certify the model; a single live success also does not establish general reliability.
Completion Rubric
Sources
6 reference sources. Open the source to check the details.
- help.openai.comOpenAI: ChatGPT and API billing are separate
- developers.openai.comOpenAI: developer quickstart
- developers.openai.comOpenAI: Responses API differences
- developers.openai.comOpenAI: rate limits and retries
- developers.openai.comOpenAI: API data controls
- developers.openai.comOpenAI: spend limits
Practice quiz
Check yourself
4 questions · practise what you just learned
1 / 4 · diagnose
The first fixture record has null response_id, returned_model, and usage. What should the learner do?
Apna kaam check karo.
Practice complete ki? Result ko example aur lesson ke checks se compare karo.
This is your own completion record, not a graded assessment.