FLOWLOGIC
module /llm-integration-basics

unit U33 of 4

Failure modes

refusals, timeouts, schema drift

An LLM call fails in ways an ordinary HTTP request never does. The transport can return a clean 200 while the body is a polite refusal, a truncated half-object because you hit max_tokens, or valid JSON whose priority field arrived as a number instead of your expected string. None of these throw at the network layer, so a naive flow treats them as success and writes nonsense downstream. In production you must inspect the semantic result, not just the status code.

The engine gives you the branches to handle this. On the HTTP Request Piece, set a request timeout and enable retry-on-failure with backoff so a slow provider under load doesn’t wedge the run. Read the response’s finish or stop reason: a value of length means the output was cut off and your JSON is incomplete; a refusal or safety stop means there is no data to parse at all. Feed the parsed object through a Code Piece that checks each field’s type against the contract, then use a Router step to send clean results, refusals, and drift down separate paths.

Where it breaks: the single happy path. A flow that pipes the model output straight into a database write, with no branch for the abnormal cases, corrupts a row the first time the model refuses or drifts — and because nothing threw, no alert ever fires. Build the failure branches before you go live, not after the client finds bad data sitting in their CRM.

worked example

A guard in a Code Piece rejecting refusals, truncation, and schema drift before an invoice-extraction result is stored.

export const code = async (inputs) => {
  const res = inputs.modelResponse;              // mapped from the HTTP step

  if (res.stop_reason === 'refusal') {
    throw new Error('model refused — route to needs_human');
  }
  if (res.stop_reason === 'max_tokens') {
    throw new Error('output truncated — raise max_tokens or shrink input');
  }

  const out = JSON.parse(res.content);
  if (typeof out.total !== 'number' || typeof out.currency !== 'string') {
    throw new Error('schema drift — total/currency wrong type');
  }

  return out;
};

field checklist

common failure — A 200 that was actually a refusal

An invoice extractor treated every 200 as success and fed the body straight into an accounting sync. One vendor PDF tripped a safety refusal, so the model returned an apology sentence rather than JSON; a lenient parser defaulted the missing total to zero, and a bogus invoice entered the ledger. Nothing errored, so it surfaced only at month-end reconciliation. Read stop_reason first, validate field types, and branch refusals to a human queue.

check your understanding

An HTTP 200 came back from the model. Select everything that must still be verified before the parsed result is written downstream.

  • select every one that applies — partial answers are marked wrong

next unit opens once this is passed

sandbox validation

The check above confirms you followed the unit. Marking the module COMPLETED takes more: build the automation in your own engine and submit the exported flow and its run evidence, signed, to your unique validation URL. See the module page for that spec.