Use case

LLM pipelines and serverless AI workflows

Stage retrieval, moderation, tool calls, and summarization as separate functions so retries, traces, and cost control apply per step—not to one oversized prompt.

Last updated: 2026-06-28

Direct answer

LLM pipelines and serverless AI workflows. Each stage is deployable and loggable; compose with pipelines for async gaps between model calls.

When it fits

  • Multi-model flows
  • Human-in-the-loop handoffs
  • Long-running enrichment

Tradeoffs

  • Exploratory notebooks lack durable graphs, retries, and cost control for production AI workflows.

Why single-prompt LLM workflows are hard to retry

One mega-prompt cannot retry retrieval without re-running moderation or tool calls—LLM pipelines need boundaries.

Costs balloon when every branch re-embeds the same context instead of caching structured retrieval output.

Why notebook scripts do not replace LLM pipelines

Exploratory notebooks lack durable graphs, retries, and cost control for production AI workflows.

Stage LLM work as deployable functions

Each stage is deployable and loggable; compose with pipelines for async gaps between model calls.

Tool calls stay HTTP functions with explicit auth—consistent with serverless AI agents elsewhere.

LLM pipeline stages to split for observability

Retrieve

Isolate embedding and search calls so retrieval can be retried and cached independently.

Moderate

Run moderation first so unsafe requests fail fast, before you pay for expensive generation.

Call tools

Keep tool calls behind tight input validation and explicit auth, like any production endpoint.

Summarize

Compress results for storage or user display in a final, independently retryable step.

How to stage LLM work with Inquir pipelines

1

Draw dataflow

Name the inputs and outputs of every stage before writing code.

2

Codify

Implement each stage as a function or pipeline step with its own logs.

3

Measure cost

Track tokens and wall time per stage.

Document analysis LLM pipeline

A graph pipeline wires a trigger to a chain of function nodes with edges—the same shape as in the console and docs. Each stage is a separate function: retry retrieval without re-running classify, track token cost per step, and inspect traces when one model call fails.

pipelines/document-analysis.json (pipeline graph)
{
  "schemaVersion": 1,
  "nodes": [
    { "id": "t1", "kind": "manualTrigger", "name": "Start", "position": { "x": 0, "y": 0 }, "config": {} },
    { "id": "extract", "kind": "lambda", "name": "Extract text", "position": { "x": 220, "y": 0 }, "config": { "functionId": "extract-text", "onError": "failPipeline" } },
    { "id": "classify", "kind": "lambda", "name": "Classify document", "position": { "x": 440, "y": 0 }, "config": { "functionId": "classify", "onError": "failPipeline" } },
    { "id": "retrieve", "kind": "lambda", "name": "Retrieve context", "position": { "x": 660, "y": 0 }, "config": { "functionId": "retrieve", "onError": "failPipeline" } },
    { "id": "summarize", "kind": "lambda", "name": "Summarize", "position": { "x": 880, "y": 0 }, "config": { "functionId": "summarize", "onError": "failPipeline" } },
    { "id": "store", "kind": "lambda", "name": "Store and notify", "position": { "x": 1100, "y": 0 }, "config": { "functionId": "store-and-notify", "onError": "failPipeline" } }
  ],
  "edges": [
    { "id": "e1", "sourceNodeId": "t1", "targetNodeId": "extract", "sourceHandle": "default" },
    { "id": "e2", "sourceNodeId": "extract", "targetNodeId": "classify", "sourceHandle": "success" },
    { "id": "e3", "sourceNodeId": "classify", "targetNodeId": "retrieve", "sourceHandle": "success" },
    { "id": "e4", "sourceNodeId": "retrieve", "targetNodeId": "summarize", "sourceHandle": "success" },
    { "id": "e5", "sourceNodeId": "summarize", "targetNodeId": "store", "sourceHandle": "success" }
  ]
}
functions/extract-text.mjs (node 1)
export async function handler(event) {
  const { documentUrl } = event; // trigger body flows into the first node
  const text = await extractText(documentUrl); // PDF/HTML/DOCX → plain text
  return { text, charCount: text.length };
}
jobs/retrieve.mjs (step 3 — retries skip extract/classify)
export async function handler(event) {
  const { text, category } = event.previousOutput ?? {};
  const related = await vectorSearch(text, { filter: { category } });
  return { ...event.previousOutput, related };
}

Use pipelines when…

When this works

  • Multi-model flows
  • Human-in-the-loop handoffs
  • Long-running enrichment

When to skip it

  • Single prompt demos

FAQ

Why split an LLM workflow into stages?

Retries, cost attribution, and debugging improve when retrieval, moderation, tool calls, and summarization are separate steps with their own logs.

Streaming tokens to end users?

Keep user-visible streaming at the boundary; internal stages can use request/response for simpler failure handling and replays.

How do I control cost across stages?

Measure tokens and wall time per stage in observability; cap expensive steps with budgets and short-circuit when moderation fails.