[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"academy-blogs-en-1-1-all-golang-the-series-ep147-structured-output-ai-json-all--*":3,"academy-blog-translations-ebouzt297etn6ns":93},{"data":4,"page":79,"perPage":79,"totalItems":79,"totalPages":79},[5],{"alt":6,"collectionId":7,"collectionName":8,"content":9,"cover_image":10,"cover_image_path":11,"created":12,"created_by":13,"expand":14,"id":87,"keywords":88,"locale":61,"published_at":89,"scheduled_at":13,"school_blog":83,"short_description":90,"status":81,"title":91,"updated":92,"updated_by":13,"slug":84,"views":86},"Implementation of JSON Mode and Structured Output in Go using OpenAI API","sclblg987654321","school_blog_translations","\u003Cp>Welcome to EP.147! In our previous episode, we mastered the art of writing prompts to communicate with AI. However, the most persistent headache for Gophers is the \"chatty\" nature of AI. It often insists on adding polite fluff like, \u003Cem>\"Certainly! Here is the JSON you requested...\"\u003C\u002Fem> or concluding with, \u003Cem>\"I hope this helps!\"\u003C\u002Fem>\u003C\u002Fp>\u003Cp>These extra sentences are the primary culprits that cause Go’s \u003Ccode>json.Unmarshal\u003C\u002Fcode> function to crash, simply because the response isn't Pure JSON. Today, we’re going to solve this once and for all using Structured Output techniques to force the AI to return data that fits our Go structs with 100% precision.\u003C\u002Fp>\u003Ch2>Designing Go Structs for AI Output\u003C\u002Fh2>\u003Cp>The core idea isn't just creating a random struct; it’s about making that struct serve as a Contract between your Go code and the AI. There are three key areas to focus on:\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>JSON Tags are the Law:\u003C\u002Fstrong> The names defined in \u003Ccode>json:\"...\"\u003C\u002Fcode> are the exact field names the AI must output. Remember, these are case-sensitive!\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Appropriate Data Types:\u003C\u002Fstrong> If you need a numeric score, use \u003Ccode>int\u003C\u002Fcode> or \u003Ccode>float64\u003C\u002Fcode>. This allows Go to automatically validate the data type during unmarshaling.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Data Possibility:\u003C\u002Fstrong> If a field might be missing or \"null\" from the AI's perspective, consider using \u003Cstrong>Pointers\u003C\u002Fstrong> (e.g., \u003Ccode>*string\u003C\u002Fcode>) to handle those null values gracefully without failing.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Ch3>Example Structure:\u003C\u002Fh3>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>type AnalysisResult struct {\n    \u002F\u002F Use standard, descriptive field names\n    Sentiment string   `json:\"sentiment\"` \n    Score     int      `json:\"score\"`\n    Keywords  []string `json:\"keywords\"`\n    Summary   string   `json:\"summary\"`\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>💡 Pro-Tip for Gophers:\u003C\u002Fh3>\u003Cp>Using descriptive English names in your JSON tags (like \u003Ccode>sentiment\u003C\u002Fcode> instead of just \u003Ccode>s\u003C\u002Fcode>) significantly helps the AI understand the context of the data it needs to provide. You barely need to explain the fields in your prompt because the AI is already trained to understand the semantic meaning of well-named variables!\u003C\u002Fp>\u003Ch2>JSON Mode and System Prompts\u003C\u002Fh2>\u003Cp>In the past, we had to pray that the AI would obey our \"Please respond in JSON\" command. Today, modern APIs like GPT-4o, or even local models running via Ollama, feature a specialized JSON Mode. This enforces a constraint at the engine level: \"You must not return anything except valid JSON.\"\u003C\u002Fp>\u003Ch3>The Golden Rule!\u003C\u002Fh3>\u003Cp>Even with this mode enabled, OpenAI has a strict requirement: You must include the word \"JSON\" in your messages (ideally within the System Prompt). If you forget to mention it, the API will immediately return an error.\u003C\u002Fp>\u003Ch3>Configuration Example in Go:\u003C\u002Fh3>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>req := openai.ChatCompletionRequest{\n    Model: openai.GPT4o,\n    \u002F\u002F CRITICAL: Enforce structure at the JSON Object level\n    ResponseFormat: &amp;openai.ChatCompletionResponseFormat{\n        Type: openai.ChatCompletionResponseFormatTypeJSONObject,\n    },\n    Messages: []openai.ChatCompletionMessage{\n        {\n            Role:    openai.ChatMessageRoleSystem,\n            \u002F\u002F The word \"JSON\" must be present here!\n            Content: \"You are a helpful assistant designed to output JSON.\",\n        },\n        {\n            Role:    openai.ChatMessageRoleUser,\n            Content: \"Analyze this feedback: 'I love this gopher tool!'\",\n        },\n    },\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>🛡️ Why use JSON Mode?\u003C\u002Fh3>\u003Cp>Using this mode guarantees that the output won't contain introductory fluff like \u003Cem>\"Here is your data:\"\u003C\u002Fem>. The resulting JSON will always be \u003Cstrong>well-formed\u003C\u002Fstrong> (properly closed braces), significantly reducing the burden of complex error handling in our Go code.\u003C\u002Fp>\u003Ch2>Parsing and Error Handling\u003C\u002Fh2>\u003Cp>Once the AI responds with a JSON string, our job as Go developers is to transform that data into a \u003Cstrong>Typed Struct\u003C\u002Fstrong>. This allows us to access fields safely (\u003Cstrong>Type Safety\u003C\u002Fstrong>) using the \u003Ccode>json.Unmarshal\u003C\u002Fcode> function.\u003C\u002Fp>\u003Ch3>Implementation Example:\u003C\u002Fh3>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>var result AnalysisResult\n\n\u002F\u002F Extract content from AI Response\ncontent := resp.Choices[0].Message.Content\n\n\u002F\u002F Convert from String\u002FByte Slice into the Struct\nerr := json.Unmarshal([]byte(content), &amp;result)\nif err != nil {\n    \u002F\u002F In production, log\u002Falert or implement Retry Logic\n    log.Printf(\"Error: AI returned invalid JSON: %v\", err)\n    return\n}\n\n\u002F\u002F Access data immediately with Strong Typing!\nfmt.Printf(\"Sentiment: %s (Score: %d)\\n\", result.Sentiment, result.Score)\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>⚠️ Warning: Don't Trust the AI 100%\u003C\u002Fh3>\u003Cp>Even with JSON Mode active, a professional developer builds a \u003Cstrong>Robust\u003C\u002Fstrong> system that survives edge cases using these techniques:\u003C\u002Fp>\u003Col>\u003Cli>\u003Cp>\u003Cstrong>Validation:\u003C\u002Fstrong> After unmarshaling, validate the values (e.g., Is the \u003Ccode>Score\u003C\u002Fcode> actually between 0-100?). The AI might provide a correct JSON structure but hallucinate the actual content.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Graceful Recovery:\u003C\u002Fstrong> Instead of using \u003Ccode>log.Fatalf\u003C\u002Fcode> (which kills your program), handle errors gracefully. Return a default value or send a follow-up prompt to the AI to fix its own mistake (\u003Cstrong>Self-Correction\u003C\u002Fstrong>).\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>The \"Markdown Trap\":\u003C\u002Fstrong> Some models (especially Local LLMs) might still wrap the JSON in markdown blocks (e.g., \u003Ccode>json ... \u003C\u002Fcode>). It is best practice to write a small helper function to \u003Cstrong>Trim\u003C\u002Fstrong> or strip these characters before passing the string to \u003Ccode>json.Unmarshal\u003C\u002Fcode>.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Fol>\u003Ch2>Why use Structured Output?\u003C\u002Fh2>\u003Cp>For a Gopher, having an AI communicate in JSON isn't just about convenience—it’s about transforming the AI into a reliable \u003Cstrong>Microservice\u003C\u002Fstrong> within your architecture.\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>Reliability:\u003C\u002Fstrong> Your system becomes significantly more stable. Because we know the data type in advance, we don't have to worry about the AI responding with prose or poetry. This drastically reduces the chances of your program encountering a \u003Cstrong>Panic\u003C\u002Fstrong> or unexpected errors.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Automation:\u003C\u002Fstrong> Once data is in JSON format, you can plug it into your workflow immediately. Whether it's inserting results into a \u003Cstrong>Database\u003C\u002Fstrong>, firing a \u003Cstrong>Webhook\u003C\u002Fstrong> to your support team, or passing the data to other services in your system, it happens seamlessly without manual intervention.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Type Safety:\u003C\u002Fstrong> We leverage the core strengths of the Go language—performing strict validation, checking for missing fields, and managing complex nested structures with absolute confidence.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>🎯 Daily Mission\u003C\u002Fh2>\u003Cp>To put this into practice, try building a small Go program that takes a Product Review from a user and uses a prompt to extract data into the following JSON struct:\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>type ReviewAnalysis struct {\n    IsPositive  bool   `json:\"is_positive\"`\n    ProductName string `json:\"product_name\"`\n    DefectFound string `json:\"defect_found\"`\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>The Homework Challenge:\u003C\u002Fh3>\u003Cp>Try sending sentences that \u003Cstrong>\"do not mention a product name\"\u003C\u002Fstrong> or \u003Cstrong>\"have no defects reported.\"\u003C\u002Fstrong> Observe how the AI handles it. Will it return an empty string \u003Ccode>\"\"\u003C\u002Fcode>, a \u003Ccode>null\u003C\u002Fcode>, or skip the field entirely?\u003C\u002Fp>\u003Cblockquote>\u003Cp>\u003Cstrong>Hint:\u003C\u002Fstrong> Try updating your struct to use \u003Cstrong>Pointers\u003C\u002Fstrong> (e.g., \u003Ccode>*string\u003C\u002Fcode>) and observe the difference during unmarshaling. You'll see how much better it handles data that \"wasn't sent\"!\u003C\u002Fp>\u003C\u002Fblockquote>\u003Cdiv data-type=\"horizontalRule\">\u003Chr>\u003C\u002Fdiv>\u003Ch2>Conclusion\u003C\u002Fh2>\u003Cp>Implementing Structured Output is what evolves an AI from a chatty bot into a professional Data Processor that speaks the same language as our backend. When you control the output 100%, the boundaries of what you can build expand exponentially.\u003C\u002Fp>\u003Ch3>Coming Up Next | EP.148: Handling Streams\u003C\u002Fh3>\u003Cp>Now that we can manage data with precision, it's time to impress users with speed! We’ll be building a real-time chat system using Go Channels to stream text just like the real ChatGPT. Get ready to dive deep into Go Concurrency—see you there!\u003C\u002Fp>\u003Cp>\u003Cstrong>Follow Superdev Academy on all platforms:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>🔵 Facebook: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.facebook.com\u002Fsuperdev.academy.th\">\u003Cstrong>Superdev Academy Thailand\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 YouTube: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.youtube.com\u002F@SuperdevAcademy\">\u003Cstrong>Superdev Academy Channel\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>📸 Instagram: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.instagram.com\u002Fsuperdevacademy\u002F\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 TikTok: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.tiktok.com\u002F@superdevacademy?lang=th-TH\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🌐 Website: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fsuperdevacademy.com\">\u003Cstrong>superdevacademy.com\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>","14b80ve8vfuk_y7vv87hxnq.png","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Fjjgu4gwkz176pyv\u002F14b80ve8vfuk_y7vv87hxnq.png","2026-05-19 08:47:50.662Z","",{"keywords":15,"locale":55,"school_blog":65},[16,23,28,33,37,42,46,50],{"collectionId":17,"collectionName":18,"created":19,"created_by":13,"id":20,"name":21,"updated":22,"updated_by":13},"sclkey987654321","school_keywords","2026-03-04 08:44:51.471Z","hlato0hav8vo8wm","Golang The Series","2026-04-10 16:12:50.850Z",{"collectionId":17,"collectionName":18,"created":24,"created_by":13,"id":25,"name":26,"updated":27,"updated_by":13},"2026-03-04 08:20:14.253Z","ah6lvy4x8qe08l5","Golang","2026-04-10 16:07:26.172Z",{"collectionId":17,"collectionName":18,"created":29,"created_by":13,"id":30,"name":31,"updated":32,"updated_by":13},"2026-03-04 08:20:11.547Z","ey3puyme01a9bsw","Go","2026-04-10 16:07:25.893Z",{"collectionId":17,"collectionName":18,"created":34,"created_by":13,"id":35,"name":36,"updated":34,"updated_by":13},"2026-05-19 08:32:18.052Z","66k5o80r7j94uwg","JSON Mode",{"collectionId":17,"collectionName":18,"created":38,"created_by":13,"id":39,"name":40,"updated":41,"updated_by":13},"2026-03-04 08:46:24.109Z","o8xfgwdh6k03hxd","JSON","2026-04-10 16:13:13.679Z",{"collectionId":17,"collectionName":18,"created":43,"created_by":13,"id":44,"name":45,"updated":43,"updated_by":13},"2026-05-19 08:32:29.838Z","mif39xe74sr3dat","Structured Output",{"collectionId":17,"collectionName":18,"created":47,"created_by":13,"id":48,"name":49,"updated":47,"updated_by":13},"2026-05-19 08:32:40.909Z","y6cwydp81xsem1f","AI API",{"collectionId":17,"collectionName":18,"created":51,"created_by":13,"id":52,"name":53,"updated":54,"updated_by":13},"2026-04-03 10:57:34.421Z","azixuoag5jisout","Backend Development","2026-04-10 16:14:47.389Z",{"code":56,"collectionId":57,"collectionName":58,"created":59,"flag":60,"id":61,"is_default":62,"label":63,"updated":64},"en","pbc_1989393366","locales","2026-01-22 11:00:02.726Z","twemoji:flag-united-states","qv9c1llfov2d88z",false,"English","2026-04-10 15:42:46.825Z",{"category":66,"collectionId":67,"collectionName":68,"created":69,"expand":70,"id":83,"slug":84,"updated":85,"views":86},"wqxt7ag2gn7xcmk","pbc_2105096300","school_blogs","2026-05-19 08:32:51.300Z",{"category":71},{"blogIds":72,"collectionId":73,"collectionName":74,"created":75,"created_by":13,"id":66,"image":76,"image_alt":13,"image_path":77,"label":78,"name":21,"priority":79,"publish_at":80,"scheduled_at":13,"status":81,"updated":82,"updated_by":13},[],"sclcatblg987654321","school_category_blogs","2026-03-04 08:33:53.210Z","59ty92ns80w_15oc1implw.png","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002F59ty92ns80w_15oc1implw.png",{"en":21,"th":21},1,"2026-03-16 04:39:38.440Z","published","2026-04-25 02:32:15.470Z","ebouzt297etn6ns","golang-the-series-ep147-structured-output-ai-json","2026-06-01 06:30:38.161Z",128,"jjgu4gwkz176pyv",[20,25,30,35,39,44,48,52],"2026-06-01 04:42:02.691Z","Master the art of forcing AI to return 100% valid JSON matching your Go structs. Learn JSON Mode configuration, robust parsing, and error handling for production-ready AI backends.","Golang The Series EP.147: Structured Output - Enforcing JSON Responses","2026-06-01 04:42:02.692Z",{"th":84,"en":84}]