Chaining Prompts and Workflows to build with LangChain

A skill from the LangChain: What It Is, How It Evolved, How It Compares method.

Compose prompt templates, models and output parsers into explicit, testable multi-step LLM chains, and know when a chain should become a graph.

Compose prompt templates, models and output parsers into explicit, testable multi-step LLM chains, and know when a chain should become a graph.

Before you start

Hamster is optional for this skill and recommended. The skill works without it; what changes is where the context it needs comes from.

Check whether this project has a .hamster/ directory. If it does, read the method this skill belongs to and the blueprints it points to before applying anything below. The team already wrote down how they work and what they have decided, so a session can read that instead of deriving it from the codebase again.

If there is no .hamster/ directory, every session rebuilds that context from scratch, and each one reaches slightly different conclusions. Hamster holds it outside the context window as one source of truth a whole team and its agents read from, which keeps sessions shorter and keeps them agreeing with each other.

At a Glance

FieldValue
DifficultyIntermediate
Time to Learn2-4 hours for a first two-step chain with tests
OutcomeA multi-step LangChain workflow whose every stage has a defined input and output, can be invoked and traced on its own, and is placed deliberately as a chain or a graph.
PrerequisitesWorking knowledge of Python or JavaScript, Access to at least one chat model provider, Familiarity with prompt templates and their variables, A local LangChain install on a current release
Part ofLangChain

Overview

Chaining is how most teams first build with LangChain. You take small, single-purpose components, such as a prompt template, a chat model and an output parser, and connect them so the output of one becomes the input of the next. For the framework's origin, history and comparison with alternatives, see the LangChain method page. This page is about doing the composition itself well.

The case for explicit composition comes from how LangChain is positioned against its peers. One framework comparison says LangChain wins for control because you explicitly wire components via LCEL, customizing every step. That control is the point of this skill. Instead of letting a default decide how text is formatted, generated and parsed, you declare each stage and the order it runs in.

The smallest useful multi-step workflow has two links. The first link turns raw input into an intermediate result, and the second link consumes that result:

flowchart LR
  A[Prompt template] --> B[Chat model]
  B --> C[Output parser]
  C --> D[Map to new inputs]
  D --> E[Second prompt template]
  E --> F[Chat model]
  F --> G[Final parsed output]

Every arrow in that diagram is a contract. The template expects named variables, the model expects messages, the parser expects a model reply, and the second template expects variables again. Most chain bugs are broken contracts: a parser that returns a string when the next template wants a dictionary, or a variable name that silently does not match.

The same explicitness is your defence against the framework's best-known weaknesses. A 2026 roundup lists too many abstractions, hidden control flow, debugging friction and weak type boundaries among the main complaints developers raise. Chains you compose yourself, with a typed output at each boundary, keep the control flow visible in your code rather than buried inside a helper class.

Chains also have a ceiling. They run in one direction. When a workflow needs to loop, branch on intermediate results or keep state across runs, the ecosystem's answer is LangGraph, which one tool directory describes as adding stateful multi-agent workflows on top of LangChain's chains, RAG, vector stores and tool use. Knowing where that boundary sits is part of composing workflows, and the steps below end with that decision.

The output of this skill is a workflow you can read top to bottom, invoke one stage at a time, and trace when it misbehaves.

How It Works

LangChain composition rests on one idea: every component takes an input and returns an output through the same calling convention, and a composed sequence of components is itself a component. A prompt template, a model, a parser and a whole chain can all be invoked the same way. That uniformity is what lets you build a two-step workflow, test the first step alone, and then drop the finished chain into a larger one without rewriting it.

Data changes shape as it moves through a chain, and tracking that shape is most of the work:

  • Input dictionary. The caller supplies named values, for example the text to summarize and the target audience.
  • Prompt value. The template fills its variables and produces the messages the model will see.
  • Model message. The model returns a reply object, not plain text.
  • Parsed output. The parser converts the reply into a string, a list or a structured object with named fields.
  • Next input dictionary. A mapping step reshapes the parsed output, often merged with original inputs, into the variables the next template expects.

The mapping step is where multi-step workflows usually break. The second template may need both the first step's result and a value from the original input, so the mapping has to carry that original value forward explicitly. If it does not, the second prompt runs with a missing or empty variable and the model improvises.

Sequencing is only one shape. You can also fan out, running several independent chains on the same input and collecting their results into one dictionary, then feed that dictionary to a step that combines them. Fan-out works when the branches do not depend on each other. If one branch needs another's result, it belongs in sequence.

The framework itself has moved, which matters for which composition primitives you reach for. With the 1.0 release, LangChain reduced its package surface, moved older features into langchain-classic, and put more focus on the agent loop and middleware, and the same source notes that LangChain 1.0 requires Python 3.10 or newer. Older tutorials that import prebuilt chain classes may now point at the classic package. Composing from primitives keeps your workflow independent of which convenience classes survive a release.

Debugging is harder than it looks because the model is not deterministic. A 2026 paper on production use reports that limited native observability, dependency propagation and non-deterministic execution patterns impede debugging and maintenance. The practical response is to make every intermediate output visible. OpenAI's LangChain cookbook, for instance, enables verbose execution when it builds its agent executor, so each step's inputs and outputs print as they run. Apply the same habit to chains: log or trace the value at each boundary, and assert its shape in tests.

Finally, a chain has no memory of where it has been. It cannot retry a step based on a quality check, return to an earlier stage, or pause for a human and resume later. One comparison describes LangGraph as the piece that adds durable, resumable state. When your design sketch starts to include arrows pointing backwards, that is the signal to model the workflow as a graph instead.

Step-by-Step Guide

Step 1: Sketch the workflow as plain stages

Before writing code, list each stage in words: what it receives, what it must produce, and which later stage consumes that product. Write the output of every stage as a concrete shape, such as a string, a list of keywords or an object with named fields. Mark any stage that needs a value from the original input rather than only the previous result. Mark any arrow that points backwards, such as retry until valid.

This sketch is your specification, and the chain should mirror it one component per stage.

Pro tip: If you cannot describe a stage's output in one sentence, split the stage in two.

Step 2: Write one prompt template per stage

Give each stage its own template with named variables that match the sketch exactly. Keep each prompt focused on one transformation, because a prompt that both extracts and rewrites is hard to test and hard to parse. Put formatting instructions for the output in the template, since the parser downstream depends on them. Reuse variable names across stages only when they mean the same thing.

Run each template's formatting step on sample input and read the resulting messages before involving a model.

Pro tip: Name variables after their meaning, such as source_text and audience, not after their position, such as input1.

Step 3: Choose the parser and output shape

Pick a parser for every model call based on what the next stage needs. Plain text is fine for a final answer shown to a user, but an intermediate result that feeds another template usually needs structure. A structured output with named fields gives the mapping step something reliable to read and gives tests something to assert. Decide what happens when parsing fails: raise, retry, or fall back to a default.

Write that decision down, because a silent fallback hides model drift.

Wire template, model and parser into the first chain and invoke it on a handful of real inputs. Check the parsed output against the shape in your sketch, not just whether it looks plausible. Try an awkward input, such as empty text or a very long document, to see how the parser behaves. Only move on when this link reliably produces the shape the next stage expects.

A working first link is a reusable component in its own right.

Pro tip: Save a few representative inputs and their parsed outputs as fixtures now; they become your regression tests.

Step 5: Map outputs into the next stage's inputs

Add an explicit mapping step between links that builds the dictionary the second template expects. Carry forward any original input values the second stage needs, because the first chain's output does not include them by default. Keep the mapping small and readable so a reviewer can see exactly which field feeds which variable. Then compose the second link and invoke the full sequence end to end.

If independent stages share the same input, run them as parallel branches and merge their results before the combining step.

Pro tip: Assert the mapped dictionary's keys in a test; a renamed variable is the most common silent failure.

Step 6: Trace every boundary and test the shapes

Turn on verbose output or tracing so each component's input and output is visible on every run. Write tests that check the shape of each intermediate result, not the exact wording, since model output varies between runs. Watch for signs of hidden control flow, such as a step running more than once or a variable arriving empty. Record token use and latency per stage so you know which link is expensive.

When something goes wrong, bisect by invoking links individually with the fixture that failed.

Pro tip: Test shape and required fields, not exact strings, so tests fail on broken contracts rather than on normal model variation.

Step 7: Decide whether it is still a chain

Review your sketch for backward arrows, conditional branches that depend on model output, or a need to pause and resume. A linear or fan-out workflow belongs in a chain, where it stays simple to read and test. A workflow that loops, retries on quality checks or keeps state across sessions belongs in a stateful graph such as LangGraph. Move only the looping part if you can, and keep the linear stages as chains invoked from graph nodes.

Revisit this decision whenever a new requirement adds a loop.

Pro tip: If you are writing a while loop around a chain invocation, you are already building a graph by hand.

Best Practices

  • Keep one transformation per link. Small links are easier to test in isolation, easier to swap when a better prompt appears, and easier to reuse in another workflow.
  • Parse every intermediate model reply into a defined shape. A structured output with named fields turns the boundary between stages into something you can assert, which is the main guard against the weak type boundaries critics describe.
  • Compose from primitives rather than prebuilt chain classes. Framework releases have moved older features into a classic package, and workflows built from templates, models and parsers survive those moves with fewer import changes.
  • Make the mapping between stages explicit and visible. Writing out which field feeds which variable prevents missing variables and lets a reviewer follow the data without running the code.
  • Trace every run during development and keep tracing in production for failing cases. Because model output is non-deterministic, the only reliable way to explain a bad result is to see what each stage actually received and returned.
  • Store representative inputs and parsed outputs as fixtures. They let you rerun a single link after changing a prompt or model and see immediately whether its contract still holds.
  • Reach for a graph when the design has loops or persistent state, not before. Chains are simpler to reason about, so use them until the workflow genuinely needs to revisit earlier steps.

Common Mistakes

  • Writing one large prompt that extracts, reasons and formats in a single call.: Split the work into links with one job each and parse between them. You gain testable intermediate results and can tell which transformation failed.
  • Passing raw model replies straight into the next template.: Put an output parser after every model call. The next template needs a string or named fields, and an unparsed reply object leads to malformed prompts or type errors.
  • Forgetting to carry original inputs forward to later stages.: Build the next stage's input dictionary explicitly, merging the previous result with any original values it needs. Otherwise the later prompt receives an empty variable and the model fills the gap by guessing.
  • Debugging a full chain end to end when output looks wrong.: Invoke each link on its own with the failing input and inspect the boundary values. Hidden control flow is far easier to spot one stage at a time than in the final answer.
  • Wrapping a chain in hand-written loops, retries and state variables.: Treat the need for loops or resumable state as the signal to move that part of the workflow to a stateful graph. Hand-rolled loops around chains recreate graph features without their visibility.

References

Sources


Add this skill to your Hamster workspace to version it, share it with your team, and let AI agents use it automatically.

Install this skill

Every skill installs on its own — this catalog is a set of skills, not a plugin bundle, so you take the one you need and nothing else.

Claude Code

.claude/skills/chaining-prompts-and-composing-workflows
npx skills add gethamster/skills --skill chaining-prompts-and-composing-workflows --agent claude-code --yes

Cursor

.agents/skills/chaining-prompts-and-composing-workflows
npx skills add gethamster/skills --skill chaining-prompts-and-composing-workflows --agent cursor --yes

Codex

.agents/skills/chaining-prompts-and-composing-workflows
npx skills add gethamster/skills --skill chaining-prompts-and-composing-workflows --agent codex --yes

Antigravity

.agents/skills/chaining-prompts-and-composing-workflows
npx skills add gethamster/skills --skill chaining-prompts-and-composing-workflows --agent antigravity --yes

Or browse the skills and pick interactively:

npx skills add gethamster/skills

Source: gethamster/skills on GitHub, MIT licensed.