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
Answer first
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.
Workload and what breaks
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.
Where shortcuts fail
Why notebook scripts do not replace LLM pipelines
Exploratory notebooks lack durable graphs, retries, and cost control for production AI workflows.
How Inquir helps
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.
What you get
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.
What to do next
How to stage LLM work with Inquir pipelines
Draw dataflow
Name the inputs and outputs of every stage before writing code.
Codify
Implement each stage as a function or pipeline step with its own logs.
Measure cost
Track tokens and wall time per stage.
Code example
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.
{ "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" } ] }
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 }; }
export async function handler(event) { const { text, category } = event.previousOutput ?? {}; const related = await vectorSearch(text, { filter: { category } }); return { ...event.previousOutput, related }; }
When it fits
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
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.