Skip to main content
Glama
how_to_enable_json_mode.src.md8.81 kB
<!-- srcbook:{"language":"typescript"} --> # Prompting Claude for "JSON Mode" Claude doesn't have a formal "JSON Mode" with constrained sampling. But not to worry -- you can still get reliable JSON from Claude! This Srcbook will show you how. ###### package.json ```json { "type": "module", "dependencies": { "@anthropic-ai/sdk": "^0.12.1", "dotenv": "^16.3.1" } } ``` ## Setting up the environment First, let's set up the client and import the necessary modules. ###### setup.ts ```typescript import { Anthropic } from '@anthropic-ai/sdk'; import * as dotenv from 'dotenv'; import { inspect } from 'util'; // Load environment variables dotenv.config(); // Initialize the client export const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); export const MODEL_NAME = "claude-3-opus-20240229"; // Pretty print objects export function prettyPrint(obj: any) { console.log(inspect(obj, { depth: null, colors: true })); } ``` ## Default behavior Let's look at Claude's default behavior when asked for JSON. ###### default-behavior.ts ```typescript import { client, MODEL_NAME } from './setup.ts'; async function defaultJsonBehavior() { const response = await client.messages.create({ model: MODEL_NAME, max_tokens: 1024, messages: [ { role: "user", content: "Give me a JSON dict with names of famous athletes & their sports." } ] }); const message = response.content[0].text; console.log(message); return message; } await defaultJsonBehavior(); ``` Claude followed instructions and outputted a nice dictionary, which we can extract with code: ###### extract-json.ts ```typescript import { prettyPrint } from './setup.ts'; function extractJson(response: string): any { const jsonStart = response.indexOf("{"); const jsonEnd = response.lastIndexOf("}"); return JSON.parse(response.substring(jsonStart, jsonEnd + 1)); } // We'll simulate having the response from the previous call const sampleResponse = `Here is a JSON dictionary with names of famous athletes and their respective sports: { "athletes": [ { "name": "Usain Bolt", "sport": "Track and Field" }, { "name": "Michael Phelps", "sport": "Swimming" }, { "name": "Serena Williams", "sport": "Tennis" }, { "name": "LeBron James", "sport": "Basketball" }, { "name": "Lionel Messi", "sport": "Soccer" } ] }`; const extractedJson = extractJson(sampleResponse); prettyPrint(extractedJson); ``` ## Skipping the preamble But what if we want Claude to skip the preamble and go straight to the JSON? One simple way is to prefill Claude's response and include a "{" character. ###### prefill-example.ts ```typescript import { client, MODEL_NAME } from './setup.ts'; async function prefillJsonExample() { const response = await client.messages.create({ model: MODEL_NAME, max_tokens: 1024, messages: [ { role: "user", content: "Give me a JSON dict with names of famous athletes & their sports." }, { role: "assistant", content: "Here is the JSON requested:\n{" } ] }); const message = response.content[0].text; console.log(message); // Add back the "{" that we prefilled to extract the JSON const completeJson = "{" + message.substring(0, message.lastIndexOf("}") + 1); const outputJson = JSON.parse(completeJson); console.log("\nExtracted JSON object:"); prettyPrint(outputJson); return outputJson; } await prefillJsonExample(); ``` ## Using tags for multiple JSON outputs For very long and complicated prompts, which contain multiple JSON outputs so that a string search for "{" and "}" don't do the trick, you can also have Claude output each JSON item in specified tags for future extraction. ###### tagged-json-outputs.ts ```typescript import { client, MODEL_NAME, prettyPrint } from './setup.ts'; async function taggedJsonOutputs() { const response = await client.messages.create({ model: MODEL_NAME, max_tokens: 1024, messages: [ { role: "user", content: `Give me a JSON dict with the names of 5 famous athletes & their sports. Put this dictionary in <athlete_sports> tags. Then, for each athlete, output an additional JSON dictionary. In each of these additional dictionaries: - Include two keys: the athlete's first name and last name. - For the values, list three words that start with the same letter as that name. Put each of these additional dictionaries in separate <athlete_name> tags.` }, { role: "assistant", content: "Here is the JSON requested:" } ] }); const message = response.content[0].text; console.log(message); // Extract JSON between tags function extractBetweenTags(tag: string, string: string, strip: boolean = false): string[] { const regex = new RegExp(`<${tag}>(.+?)</${tag}>`, 'gs'); const matches = string.match(regex) || []; return matches.map(match => { const content = match.substring(tag.length + 2, match.length - tag.length - 3); return strip ? content.trim() : content; }); } // Extract and parse the athlete sports dictionary const athleteSportsJson = extractBetweenTags("athlete_sports", message)[0]; const athleteSportsDict = JSON.parse(athleteSportsJson); // Extract and parse the individual athlete name dictionaries const athleteNameJsons = extractBetweenTags("athlete_name", message); const athleteNameDicts = athleteNameJsons.map(json => JSON.parse(json)); console.log("\nExtracted athlete sports dictionary:"); prettyPrint(athleteSportsDict); console.log("\nExtracted athlete name dictionaries:"); prettyPrint(athleteNameDicts); return { athleteSportsDict, athleteNameDicts }; } await taggedJsonOutputs(); ``` ## Using structured output with custom types TypeScript's type system gives us an advantage for handling structured outputs. Let's define types for our expected JSON structure and use them to ensure type safety: ###### typed-json-output.ts ```typescript import { client, MODEL_NAME } from './setup.ts'; // Define the expected response types interface Athlete { name: string; sport: string; } interface AthleteResponse { athletes: Athlete[]; } async function typedJsonOutput() { const response = await client.messages.create({ model: MODEL_NAME, max_tokens: 1024, messages: [ { role: "user", content: `Return exactly this JSON structure without any explanatory text: { "athletes": [ { "name": "Athlete Name", "sport": "Sport Name" }, ...more athletes ] } Include 5 famous athletes from different sports.` } ] }); const message = response.content[0].text || ''; try { // Extract and parse the JSON from the response const jsonStart = message.indexOf("{"); const jsonEnd = message.lastIndexOf("}"); if (jsonStart === -1 || jsonEnd === -1) { throw new Error("Could not find JSON in response"); } const jsonString = message.substring(jsonStart, jsonEnd + 1); const parsedJson = JSON.parse(jsonString) as AthleteResponse; // Validate the structure matches our expected type if (!parsedJson.athletes || !Array.isArray(parsedJson.athletes)) { throw new Error("Invalid JSON structure: missing athletes array"); } console.log("Extracted and validated JSON:"); console.log(JSON.stringify(parsedJson, null, 2)); // Use the typed data console.log("\nAthletes and their sports:"); parsedJson.athletes.forEach(athlete => { console.log(`${athlete.name}: ${athlete.sport}`); }); return parsedJson; } catch (error) { console.error("Error processing JSON response:", error); console.log("Original response:", message); throw error; } } await typedJsonOutput(); ``` ## Recap To recap the strategies for getting clean JSON from Claude: 1. **Simple extraction**: Use string parsing to extract JSON between curly braces. 2. **Prefilled response**: Remove preambles by providing a partial Assistant message with an opening brace. 3. **Tagged output**: Instruct Claude to place JSON inside specific XML-like tags for complex responses. 4. **Type validation**: Use TypeScript's type system to ensure the parsed JSON has the expected structure. Each approach has its advantages depending on your specific use case: - Simple extraction works for basic responses - Prefilling helps create cleaner output but limits Claude's ability to think through the problem - Tagged output works well for multiple JSON sections in a single response - Type validation adds an extra layer of safety when processing the JSON

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/waldzellai/clearthought-onepointfive'

If you have feedback or need assistance with the MCP directory API, please join our Discord server