Adapters: chat markers or JSON
The adapter decides the prompt format and how replies are parsed. ChatAdapter uses field markers; JSONAdapter asks for a JSON object.
inputs = {"ticket": "My parcel never arrived"}
for adapter in [dspy.ChatAdapter(), dspy.JSONAdapter()]:
messages = adapter.format(Triage, demos=[], inputs=inputs)
print(f"--- {type(adapter).__name__}")
print(messages[-1]["content"])The signature and inputs are unchanged; only the instructions for the answer differ. JSONAdapter asks for a JSON object with the output fields as keys, and it asks providers that support it to enforce JSON output.
print(dspy.JSONAdapter().parse(Triage, '{"category": "shipping"}'))When a reply cannot be parsed
with dspy.context(adapter=dspy.JSONAdapter()):
dspy.Predict(Triage)(ticket="My parcel never arrived")dspy.context(adapter=...) switches the adapter like it switched the model. The stand-in only writes markers, so JSONAdapter cannot parse its reply, and the error includes the reply it got. A real model follows whichever format the prompt asks for.
The opposite direction is handled for you: when ChatAdapter cannot parse a reply, it retries the request once with JSONAdapter before raising. Models that ignore the markers often manage JSON.
| Adapter | Use it when |
|---|---|
ChatAdapter | The default. Works with any chat model. |
JSONAdapter | The provider supports structured output, or answers have nested types. |
XMLAdapter | The model is trained to read and write XML tags. |
TwoStepAdapter | A reasoning model writes freely and a second, cheaper model extracts the fields. |
- Format
Triagewithdspy.XMLAdapter()and print the user message. - Parse
'{"category": "refunds"}'withJSONAdapter. - Configure
adapter=dspy.JSONAdapter()globally and run the mock from lesson 2.
This is what real progress feels like.