An LLM is not a product. It is a step behind an action you already own: classify a ticket, extract a field, draft a reply, retrieve the one paragraph a hotel manager needs on a phone. If you cannot name that action without saying “chat,” you do not have an AI feature - you have a demo with a monthly invoice.
In Node.js I treat the model as remote I/O, same as Stripe or S3. NestJS or Express owns the route. A queue owns the wait. Zod or a JSON schema owns the shape that comes back. Timeouts, retries, token caps, and a log you can open at 2 a.m. are not extras - they are the job. Streaming a vibe into the browser with the key in NEXT_PUBLIC_ is not an integration.
The patterns that earn their keep in a TypeScript service: structured output you can persist, tools bound to your own APIs, and RAG over a corpus you actually control - not “the whole Postgres.” OpenAI or Anthropic is a vendor. The contract is yours: input, tool list, max tokens, what happens when the model is slow or wrong. I will not let the model invent a write I would not code by hand.
What I refuse before the first users: an unbounded assistant over every table, a chatbot on the landing page so the deck has a buzzword, and a prompt that grew into an untested policy. Those hide cost and liability. If the first version cannot fail closed - show a draft, ask a human, write nothing - it is not ready for money or PII.
If you send me a brief, send the action, the data you already have, and who is allowed to confirm the write. I will reply with the smallest Node job I would ship: one route, one schema, one model call, and a short list of what I would not expose to the model yet. That list is the estimate.