How to get answers as JSON (structuredOutput)
This guide shows how to make an agent answer only with JSON of a shape you declare, so that a script, jq or another agent can use the answer. It assumes you already run mm with a configuration file, on a server that supports response_format: json_schema (llama.cpp, so dmr, llamacpp, llmman; Ollama; the OpenAI API). The demos/structured-output/ directory holds the files used below.
Steps
-
Write a configuration file for a JSON-only agent, with every tool off — an answer constrained to a schema leaves no room for a tool call, and mm refuses to start otherwise:
bashTool: false editTools: false planTool: false skillsDir: no-skills # a directory that does not exist: no read_skill toolLeave out
mmConfigs,lspandmcp. -
Declare the shape of the answer under
structuredOutput, as Go types and onevarnaming the root:structuredOutput: | type Language struct { Name string `json:"name"` // the language's name, in English Official bool `json:"official"` // true when it has an official status at the national level } type Country struct { Name string `json:"name"` // the country's common name, in English Capital *string `json:"capital"` // the capital CITY (not the country), in English; null when unknown Languages []Language `json:"languages"` // the main languages only, at most 4, most spoken first, each once } // One entry per country named in the question, in the order asked. var Countries = []Country{}The
jsontags give the keys. The comments are what the model reads to fill each field: write them as instructions. -
Ask a question with
-pand pipe the answer:mm agent.countries.yaml -p "languages spoken in France, Canada, Vietnam and the US" | jq -c '.[] | {name, capital}'{"name":"France","capital":"Paris"} {"name":"Canada","capital":"Ottawa"} {"name":"Vietnam","capital":"Hanoi"} {"name":"United States","capital":"Washington, D.C."}stdout carries the JSON alone; the exit status is 1 when the answer is missing or invalid.
Variants
- Let another agent use the JSON. Give a coordinator — an agent with tools — the JSON agent in its
mmConfigs; it calls it withask_agentand gets the JSON as the tool's result. See How to let your agent call other agents anddemos/structured-output/agent.coordinator.yaml. The coordinator itself cannot have astructuredOutput: it has tools. - Ask the JSON agent through the coordinator's config, from a shell:
mm agent.coordinator.yaml --ask countries -p "capital of Vietnam" | jq .(see How to ask another agent from a skill or a script). - In the terminal or the window, the agent answers each question with JSON, shown like any answer.
- For the OpenAI hosted API, make the root a struct (
var Answer = Triage{}): its strict mode demands an object at the top. llama.cpp and Ollama accept an array. - Optional fields: a pointer (
*string) orjson:",omitempty"lets the value benull; the key is always present.
If it goes wrong
the answer was cut off by max_tokens before its JSON was complete— a small model can repeat list items until the limit. Bound the lists in their comments (at most 4,each once), or raisesampling.max_tokens.- A field holds the wrong thing (a country's name in
capital) — sharpen its comment. With llama.cpp the model writes the keys in alphabetical order whatever the declaration order, so a field may be filled before the one it depends on: make each comment self-sufficient. structuredOutput cannot be used with tools — this agent declares: …— turn off the tools listed.structuredOutput:<line>:<col>: …— the declaration at that line of the block is not supported; see thestructuredOutputreference.- A thinking model is slow to answer: turn its reasoning off for a lookup agent (How to turn a model's reasoning off).
See also
structuredOutputreference — the type mapping, the errors- Prompt mode specifics — what
-pprints - Structured output — explanation — why Go declarations, why no tools
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
|