从0到1:我是如何设计大模型结构化输出系统的 从0到1我是如何设计大模型结构化输出系统的前言最近在做智能客服系统时遇到个问题大模型返回的自然语言回复不好解析。用户问今天天气怎么样模型可能返回今天北京晴转多云最高温度28度。但我需要把温度、天气状况提取出来作为结构化数据。经过调研我设计了一套基于Agent拓扑的结构化输出方案准确率提升到95%以上。一、底层原理1.1 核心机制结构化输出的关键是让大模型按照指定格式返回数据graph TD A[用户输入] -- B[Prompt模板] B -- C[大模型] C -- D{输出格式校验} D --|通过| E[JSON解析] D --|失败| F[重试机制] F -- B E -- G[业务逻辑]Prompt工程要点{ temperature: 0.0, max_tokens: 512, response_format: { type: json_object } }1.2 与同类方案的对比方案准确率灵活性成本JSON模式高中低函数调用高高中XML标签中低低正则提取低低低二、快速上手package main import ( encoding/json fmt ) type WeatherResponse struct { City string json:city Temperature int json:temperature Condition string json:condition Humidity int json:humidity } func main() { // 大模型返回的JSON字符串 modelOutput : { city: 北京, temperature: 28, condition: 晴转多云, humidity: 45 } // 解析为结构化数据 var weather WeatherResponse err : json.Unmarshal([]byte(modelOutput), weather) if err ! nil { panic(err) } fmt.Printf(城市: %s\n, weather.City) fmt.Printf(温度: %d°C\n, weather.Temperature) fmt.Printf(天气: %s\n, weather.Condition) fmt.Printf(湿度: %d%%\n, weather.Humidity) }三、核心 API / 深水区3.1 核心方法速查方法功能适用场景json.Unmarshal()JSON解析标准JSON输出json.Marshal()JSON序列化构造请求体json.Decoder.Decode()流式解析大文件处理reflect.StructTag()标签解析动态字段映射3.2 生产级配置// 带校验的结构化输出解析器 type StructuredOutputParser struct { model *LLMClient schema interface{} maxRetries int } func NewParser(model *LLMClient, schema interface{}) *StructuredOutputParser { return StructuredOutputParser{ model: model, schema: schema, maxRetries: 3, } } func (p *StructuredOutputParser) Parse(prompt string) (interface{}, error) { for i : 0; i p.maxRetries; i { response, err : p.model.Generate(p.buildPrompt(prompt)) if err ! nil { return nil, err } result, err : p.validateAndParse(response) if err nil { return result, nil } log.Printf(解析失败第%d次重试: %v, i1, err) } return nil, fmt.Errorf(超过最大重试次数) } func (p *StructuredOutputParser) buildPrompt(userInput string) string { schemaJSON, _ : json.Marshal(p.schema) return fmt.Sprintf( 请按照以下JSON格式输出结果 %s 用户输入%s , string(schemaJSON), userInput) }3.3 高级定制// 自定义JSON schema校验 func validateSchema(data []byte, schema interface{}) error { // 使用json-schema库进行校验 loader : jsonschema.NewLoader() schemaDoc, err : loader.LoadFromBytes(data) if err ! nil { return err } result, err : schemaDoc.Validate(bytes.NewReader(data)) if err ! nil { return err } if !result.Valid() { return fmt.Errorf(JSON不符合schema) } return nil }四、实战演练场景智能客服意图识别type IntentResult struct { Intent string json:intent Confidence float64 json:confidence Entities map[string]string json:entities } func parseIntent(userInput string) (*IntentResult, error) { prompt : fmt.Sprintf( 请分析用户意图 用户输入%s 输出格式 { intent: 意图名称, confidence: 置信度(0-1), entities: {实体名: 实体值} } , userInput) response, err : callLLM(prompt) if err ! nil { return nil, err } var result IntentResult err json.Unmarshal([]byte(response), result) if err ! nil { return nil, err } return result, nil }五、避坑指南与最佳实践 技巧使用JSON Schema约束输出// 定义输出schema var weatherSchema { type: object, properties: { city: {type: string}, temperature: {type: integer, minimum: -40, maximum: 60}, condition: {type: string, enum: [晴, 多云, 阴, 雨, 雪]}, humidity: {type: integer, minimum: 0, maximum: 100} }, required: [city, temperature, condition] }⚠️ 警告处理JSON解析错误func safeParse(data string, v interface{}) error { // 清理可能的干扰字符 cleaned : strings.TrimSpace(data) cleaned strings.TrimPrefix(cleaned, json) cleaned strings.TrimSuffix(cleaned, ) err : json.Unmarshal([]byte(cleaned), v) if err ! nil { return fmt.Errorf(解析失败: %w, 原始数据: %s, err, data) } return nil }✅ 推荐设置temperature为0// 结构化输出时降低随机性 request : LLMRequest{ Model: gpt-4, Temperature: 0.0, // 确定性输出 MaxTokens: 512, }六、综合实战演示package main import ( encoding/json fmt log strings ) type Parser struct { maxRetries int } type OutputSchema struct { Type string json:type Properties map[string]Schema json:properties Required []string json:required } type Schema struct { Type string json:type } func NewParser(maxRetries int) *Parser { return Parser{maxRetries: maxRetries} } func (p *Parser) Parse(userInput string, schema OutputSchema) (map[string]interface{}, error) { for attempt : 0; attempt p.maxRetries; attempt { prompt : buildPrompt(userInput, schema) response : mockLLMCall(prompt) result, err : parseResponse(response) if err nil { if validateResult(result, schema) { return result, nil } log.Printf(第%d次尝试结果不符合schema, attempt1) continue } log.Printf(第%d次尝试解析失败 %v, attempt1, err) } return nil, fmt.Errorf(超过最大重试次数) } func buildPrompt(userInput string, schema OutputSchema) string { schemaJSON, _ : json.MarshalIndent(schema, , ) return fmt.Sprintf(用户输入%s 请按照以下JSON schema输出结果 %s 输出要求 1. 只输出JSON不要任何其他文本 2. 必须包含所有required字段 3. 字段类型必须匹配, userInput, string(schemaJSON)) } func mockLLMCall(prompt string) string { // 模拟大模型响应 return { city: 上海, temperature: 32, condition: 晴, humidity: 65 } } func parseResponse(response string) (map[string]interface{}, error) { response strings.TrimSpace(response) response strings.TrimPrefix(response, json) response strings.TrimSuffix(response, ) var result map[string]interface{} err : json.Unmarshal([]byte(response), result) return result, err } func validateResult(result map[string]interface{}, schema OutputSchema) bool { for _, required : range schema.Required { if _, ok : result[required]; !ok { return false } } return true } func main() { schema : OutputSchema{ Type: object, Properties: map[string]Schema{ city: {Type: string}, temperature: {Type: integer}, condition: {Type: string}, humidity: {Type: integer}, }, Required: []string{city, temperature, condition}, } parser : NewParser(3) result, err : parser.Parse(今天上海天气怎么样, schema) if err ! nil { log.Fatal(err) } fmt.Printf(解析结果\n) for k, v : range result { fmt.Printf( %s: %v\n, k, v) } }七、总结结构化输出是大模型落地的关键一步。核心要点使用JSON模式约束输出格式设置temperature为0确保确定性实现重试机制处理解析失败使用JSON Schema进行校验核心收获好的Prompt工程能让大模型变成可靠的数据处理器。