Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

callback
A function the library calls at fixed points in a run, such as when a step starts or ends.
chain
A series of steps where each one passes its result to the next, ending in the answer.
invoke
The method that runs a step once with one input and returns its result.
memory
Stored history from earlier turns, added back to a request so the model can refer to what was said.
message
One labelled turn in a chat request, marked as coming from the system, the user or the model.
model
The trained program that reads a message list and returns the next turn.
output parser
The step that turns a model's raw text into a value your program can use, or raises an error.
pipe
The operator that joins two steps into one new step, running the left side first.
prompt
The text a model receives for one request, built from fixed wording and the values filled into it.
prompt template
A reusable prompt with named blanks that are filled in for each request.
runnable
Any step with a standard way to run it, so steps can be joined without knowing each other's code.
streaming
Sending a reply in pieces as it is produced, rather than waiting for the whole text.
tool
A function exposed to a model, with a name, described inputs and a result.
tool call
A model's request to run a named tool with specific arguments, which your code may accept or refuse.

LangChain from the ground up

Output parsers

A model returns text; your program needs data. A parser is the boundary where that text becomes a value you can trust — or an error you can handle.

Part 4 of 10

Intermediate15 min readBack to Courses

Text is not a data structure

The moment a reply is used by code rather than shown to a person, it has to be parsed. “The sentiment is positive” is a sentence; {"sentiment": "positive"} is a value you can branch on, count and store. The parser is the step that makes that conversion explicit.

Doing the conversion implicitly — a regular expression here, a .split() there, scattered through the application — is how a formatting change in the prompt breaks three unrelated features. One parser, in one place, with one set of tests.

A worked failure: a reply is parsed with a regular expression in one place and split on a colon in another. The prompt later changes from “Sentiment: positive” to a JSON object, and only one of the two parsers breaks. The feature that still works hides the one that does not, so the bug surfaces days later in a report. One parser with one test would have failed at the change.

Ask for the shape you intend to parse

Parsers work best when the prompt states the format exactly: which keys, which types, whether extra text is allowed. If the prompt says “reply in JSON” and nothing else, the model may add a friendly sentence before the object, wrap it in a code fence, or invent a key.

A schema in the prompt and a parser in the code are two halves of the same contract. The parser should reject what the prompt did not promise, and the prompt should be written with the parser’s strictness in mind.

A parser that declares its own format

from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field

class Verdict(BaseModel):
    sentiment: str = Field(description="positive, negative or neutral")
    confidence: float = Field(description="between 0 and 1")

parser = JsonOutputParser(pydantic_object=Verdict)

prompt = ChatPromptTemplate.from_messages([
    ("system", "Reply only with JSON.\n{format}"),
    ("human", "{text}"),
]).partial(format=parser.get_format_instructions())

chain = prompt | model | parser
print(chain.invoke({"text": "The update broke everything."}))

Parse labelled lines

The parser reads `key: value` lines. Feed it a reply with a missing colon and a duplicate key, and decide which of the two should be an error.

Output
Click "Run" to execute your code

Strictness is a choice you document

Decide what the parser accepts and write it down. A duplicate key can be an error, a last-wins overwrite, or a first-wins keep; each is defensible, and none is obvious to the next reader. The same goes for a missing optional field: absent and null are different values, and the rest of the program will treat them differently.

A common mistake is a lenient parser that silently repairs the reply. It lowercases a label, strips a prefix, coerces a number from a string. Each repair hides a prompt that is drifting. The symptom is a parser that never fails and a downstream value that is occasionally wrong; log the repairs and treat a rising count as a prompt bug.

Every parser needs a failure path

A parser will eventually meet something it cannot read: a truncated reply, a code fence, an apology instead of an object. What happens next is a design decision. Retrying with the error message appended is often enough; refusing and surfacing the raw text is always acceptable; silently returning an empty value is not.

The worst failure is a lenient parser that guesses. {"sentiment": "pos"} becoming positive is fine if the mapping is written down, and dangerous if it is a side effect of prefix matching that also turns positive-ish, maybe negative into positive.

Give the retry a small budget — two attempts is usually enough — and log the raw reply on the final failure. A parser that retries forever turns a formatting problem into an outage, and the log is the only thing that survives it. The retry budget belongs beside the parser, not in the caller, so every path through the code gets the same policy.

Never let parsing exceptions disappear into a bare except. The raw reply is the only evidence of what went wrong, and it is gone the moment the exception is swallowed.

Parse once, then pass objects

After the parser, the rest of the program should never see the raw string again. A dictionary or a typed object can be validated, logged and tested; the text it came from is an implementation detail of the model call.

That boundary also gives you a place to record the failures that matter: how often parsing fails is a quality signal about the prompt, and a number worth watching rather than a surprise in production.

JSON in a code fence

Models often wrap JSON in a fence. Strip it robustly, parse it, and return a clear error when the text is not JSON at all.

Output
Click "Run" to execute your code

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

Why parse a reply explicitly instead of using it as text?