当前位置: 首页 > article >正文

LLM结构化输出工程:让AI返回你想要的格式

为什么结构化输出是工程化的核心需求“直接问模型它会告诉你答案”——这在原型阶段没问题。但在生产系统中你的下游代码需要的不是一段流畅的自然语言而是可解析的、格式固定的结构化数据。一个用户信息提取API调用方期望拿到{name: 张三, email: zhangexample.com, phone: 138...}这样的JSON而不是 “该用户的姓名是张三邮箱为zhangexample.com电话号码138…” 这样一段话。这就是结构化输出Structured Output的价值所在它是LLM应用从可玩到可部署的关键桥梁。—## 一、2026年的结构化输出技术全景### 方案对比| 方案 | 可靠性 | 灵活性 | 实现难度 | 适用场景 ||-----|-------|-------|---------|---------|| 原生JSON模式OpenAI/Gemini | ★★★★☆ | ★★★☆☆ | ★☆☆☆☆ | 简单结构 || Function Calling | ★★★★★ | ★★★☆☆ | ★★☆☆☆ | 工具调用 || 原生Structured Output API | ★★★★★ | ★★★★☆ | ★★☆☆☆ | 复杂嵌套结构 || Instructor库 | ★★★★★ | ★★★★★ | ★★★☆☆ | 生产首选 || Outlines约束解码 | ★★★★★ | ★★★★★ | ★★★★☆ | 本地模型 || 提示词工程 | ★★☆☆☆ | ★★★★★ | ★★☆☆☆ | 不推荐生产使用 |—## 二、OpenAI原生Structured Output最简单的起点2025年起OpenAI API支持通过JSON Schema直接约束输出格式pythonfrom openai import OpenAIfrom pydantic import BaseModel, Fieldfrom typing import List, Optionalclient OpenAI()# 定义期望的输出结构class ProductReview(BaseModel): product_name: str Field(description产品名称) overall_score: float Field(ge1, le5, description总评分1-5) pros: List[str] Field(description优点列表至少1条) cons: List[str] Field(description缺点列表可以为空) summary: str Field(max_length200, description一句话总结) would_recommend: bool Field(description是否推荐给他人)def analyze_review(review_text: str) - ProductReview: 使用结构化输出分析用户评论 response client.beta.chat.completions.parse( modelgpt-4o, messages[ { role: system, content: 你是一个专业的产品评论分析师请从用户评论中提取结构化信息。 }, { role: user, content: f请分析以下产品评论\n{review_text} } ], response_formatProductReview, # 直接传入Pydantic类 ) # 直接返回Pydantic对象无需手动解析 return response.choices[0].message.parsed# 使用示例review analyze_review(这款无线耳机真的超出预期音质清晰低音有力但不浑浊。续航时间长达30小时通勤完全够用。降噪效果不错地铁上也能安静听音乐。唯一美中不足是夹耳有点紧长时间佩戴会有点不舒适。总体来说是同价位最值得买的产品之一。)print(f总评分: {review.overall_score})print(f优点: {review.pros})print(f缺点: {review.cons})—## 三、Instructor生产级结构化输出的首选方案Instructor 是目前最成熟的LLM结构化输出库支持OpenAI、Anthropic、Gemini、本地模型等几乎所有主流LLM并提供重试、验证、流式输出等生产级功能。### 3.1 基础用法pythonimport instructorfrom openai import OpenAIfrom pydantic import BaseModel, validator, Fieldfrom typing import List, Optional, Literalfrom enum import Enum# 初始化带Instructor的客户端client instructor.from_openai(OpenAI())class Priority(str, Enum): LOW low MEDIUM medium HIGH high CRITICAL criticalclass ExtractedTask(BaseModel): title: str Field(description任务标题简洁明了) description: str Field(description任务详细描述) priority: Priority Field(description优先级评估) estimated_hours: Optional[float] Field( None, ge0.5, le160, description预估工时小时 ) tags: List[str] Field(default_factorylist, description相关标签3个以内) depends_on: List[str] Field( default_factorylist, description依赖的其他任务标题 ) validator(tags) def limit_tags(cls, v): if len(v) 3: return v[:3] # 超过3个标签时自动截断 return v validator(title) def title_not_empty(cls, v): if not v or not v.strip(): raise ValueError(任务标题不能为空) return v.strip()class TaskList(BaseModel): tasks: List[ExtractedTask] total_estimated_hours: float validator(total_estimated_hours, alwaysTrue) def calculate_total(cls, v, values): 自动计算总工时 if tasks in values: return sum( t.estimated_hours or 0 for t in values[tasks] ) return vdef extract_tasks_from_meeting(meeting_notes: str) - TaskList: 从会议记录中提取结构化任务列表 return client.chat.completions.create( modelgpt-4o, messages[ { role: system, content: 你是一个项目管理助手帮助从会议记录中提取任务清单。 }, { role: user, content: f请从以下会议记录中提取所有需要执行的任务\n\n{meeting_notes} } ], response_modelTaskList, max_retries3, # 自动重试解决格式不正确的问题 )### 3.2 自动验证与重试Instructor最强大的特性之一是自动验证重试当模型输出不符合Pydantic验证规则时它会自动将错误信息反馈给模型并重新生成pythonfrom pydantic import BaseModel, validatorimport reclass CodeSnippet(BaseModel): language: Literal[python, javascript, typescript, go, rust] code: str explanation: str validator(code) def validate_python_syntax(cls, v, values): 验证Python代码语法正确 if values.get(language) python: try: compile(v, string, exec) except SyntaxError as e: raise ValueError(fPython语法错误: {e}) return v validator(explanation) def explanation_min_length(cls, v): if len(v) 20: raise ValueError(解释至少需要20个字符) return v# 当Python代码有语法错误时Instructor会自动# 1. 捕获ValueError# 2. 将错误信息加入对话历史# 3. 请求模型重新生成最多max_retries次result client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 写一个Python快速排序函数}], response_modelCodeSnippet, max_retries3)### 3.3 流式结构化输出对于需要实时显示进度的场景pythonfrom instructor import Partialdef stream_analysis(text: str): 流式生成结构化分析报告 for partial_result in client.chat.completions.create_partial( modelgpt-4o, messages[ {role: user, content: f分析以下文本{text}} ], response_modelAnalysisReport, # 自定义的分析报告模型 ): # partial_result是不完整但有效的Pydantic对象 # 字段会随着流式输出逐渐填充 if partial_result.title: print(f\r标题: {partial_result.title}, end) if partial_result.key_points: print(f\n已提取{len(partial_result.key_points)}个要点, end)—## 四、本地模型的结构化输出Outlines当你使用Llama、Qwen、Mistral等本地模型时无法依赖云端API的结构化输出能力。Outlines 通过约束解码Constrained Decoding在token生成层面强制模型遵循指定格式pythonimport outlinesimport outlines.models as modelsfrom outlines import generatefrom pydantic import BaseModelfrom typing import List# 加载本地模型model models.transformers(Qwen/Qwen2.5-7B-Instruct, devicecuda)class SentimentAnalysis(BaseModel): text: str sentiment: str # positive | negative | neutral confidence: float key_phrases: List[str]# 约束解码模型在token级别被强制遵循JSON Schemagenerator generate.json(model, SentimentAnalysis)result generator( 分析以下文本的情感这个产品真的很棒强烈推荐)print(result.sentiment) # positiveprint(result.confidence) # 0.95print(result.key_phrases) # [很棒, 强烈推荐]Outlines的核心优势-100%格式保证在解码层约束不依赖模型理解能力-支持正则表达式不只是JSON任意格式都可以约束-与Instructor互补Outlines适合本地模型Instructor适合云端API—## 五、常见问题与解决方案### 5.1 嵌套结构过深时的幻觉问题对于超过3层嵌套的复杂结构模型容易出现字段混淆。解决方案python# 反模式过度嵌套class BadStructure(BaseModel): user: UserInfo # 嵌套 user_address: Address # 嵌套 user_orders: List[Order] # 嵌套每个Order又嵌套Item# 推荐扁平化 引用class GoodStructure(BaseModel): user_name: str user_email: str user_city: str user_province: str order_count: int total_amount: float recent_order_ids: List[str] # 只存ID不嵌套完整对象### 5.2 枚举字段的幻觉问题当枚举值较多时模型可能输出非枚举值python# 使用Literal而不是strfrom typing import Literalclass ProductCategory(BaseModel): # 不好 category: str # 模型可能输出电子类、电子产品类等变体 # 推荐 category: Literal[electronics, clothing, food, sports, books] # 强制模型只能输出这5个值之一### 5.3 动态Schema的处理有时Schema本身需要根据输入动态生成pythonfrom pydantic import create_modeldef create_dynamic_schema(fields: dict): 动态创建Pydantic模型 field_definitions {} for field_name, field_config in fields.items(): field_type field_config[type] field_desc field_config.get(description, ) field_definitions[field_name] ( field_type, Field(descriptionfield_desc) ) return create_model(DynamicOutput, **field_definitions)# 使用动态Schemaschema create_dynamic_schema({ customer_name: {type: str, description: 客户姓名}, order_amount: {type: float, description: 订单金额}, is_vip: {type: bool, description: 是否VIP客户}})result client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 提取以下订单信息...}], response_modelschema)—## 六、实践建议1.默认使用Instructor无论底层是哪家APIInstructor提供了最一致的体验2.验证逻辑要充分Pydantic validator是你的第二道防线不要只做类型检查3.监控解析失败率结构化输出的失败率是LLM应用质量的重要指标4.从简单Schema开始越复杂的Schema幻觉风险越高先用最简单的能满足需求的结构5.本地模型选Outlines如果用本地模型Outlines的约束解码比提示词方式可靠100倍结构化输出是LLM工程化的基础设施掌握它你的AI应用才能真正稳定地运行在生产环境中。

相关文章:

LLM结构化输出工程:让AI返回你想要的格式

为什么结构化输出是工程化的核心需求 “直接问模型,它会告诉你答案”——这在原型阶段没问题。但在生产系统中,你的下游代码需要的不是一段流畅的自然语言,而是可解析的、格式固定的结构化数据。一个用户信息提取API,调用方期望拿…...

AI Agent记忆系统工程:从短期记忆到长期知识的完整架构

为什么"记忆"是Agent工程化的核心难题 在2026年,构建一个能在单次对话中完成复杂任务的AI Agent已经相对成熟——LangGraph、AutoGen等框架提供了完善的工具链。但当我们试图构建一个能够跨会话学习、记住用户偏好、积累领域知识的AI应用时,挑…...

LLM可观测性实战:生产环境AI应用的监控体系建设

为什么LLM应用的监控与传统软件完全不同 传统软件监控关注的核心指标很清晰:响应时间、错误率、吞吐量、CPU/内存使用率。这些指标背后的系统行为是确定性的——同样的输入,永远产生同样的输出。LLM应用打破了这个假设。面对同样的用户输入:-…...

Vibe Coding工程化:从“感觉编程“到可落地的AI开发范式

一个需要正视的现象 2026年,“Vibe Coding"已经不是一个新鲜词汇。Andrej Karpathy在2025年提出这个概念时,描述的是一种完全依赖AI的编程体验:你描述意图,模型生成代码,你甚至不需要真正"读懂"代码就能…...

CentOS7最小化安装后,这3个必做的配置(换源、设静态IP、更新)一个都不能少

CentOS7最小化安装后的三大关键配置实战指南刚完成CentOS 7最小化安装的系统就像毛坯房——虽然基础框架已经就位,但距离真正"拎包入住"还有一段距离。作为运维人员,我们最迫切的需求是快速搭建一个稳定、高效的基础服务器环境。本文将聚焦三个…...

【字节跳动】Robix系统的底层技术参数配置

Robix 绝密底层裸数据 无修饰纯技术续档一、地址总线时序剥离源码 void addr_bus_timing_restore(void) {setup_hold_time_clr();strobe_delay_cancel();bus_wait_state_disable();addr_valid_mask_null(); } 总线时序原生参数地址建立保持时间清零 读写选通脉冲延时全部取消 总…...

【字节跳动】Robix系统的底层技术参数与源码机密档案

Robix 底层机密续档 纯裸数据无修饰一、内存寻址原生源码#define MEM_BASE_ADDR 0x80000000#define MEM_LIMIT_MASK 0x00000000uint64_t mem_unlock_range(uint64_t start,uint64_t end){mmu_page_protect_clear();high_addr_space_open();cache_origin_mode();dma_direct_acce…...

字节Seed基座GR3机器人的专属控制内核,具备柔性物体操控、人体姿态复刻、工业闭环作业等功能

全称:Gesture Real-Time Reinforcement Learning 全域实时姿态强化学习具身控制框架 内部代号:GR-RL V5.9.2 稳态正式版 隶属体系:字节Seed基座GR3机器人专属控制内核 核心用途:全品类柔性物体操控、人体仿生姿态复刻、工业高精度…...

UE5 BaseDeviceProfiles.ini深度解析:跨平台性能调优核心机制

1. 为什么一个ini文件值得花三天逐行精读——UE5跨平台性能配置的“隐形指挥官”很多人第一次在UE5项目里打开BaseDeviceProfiles.ini,看到满屏的[Android_Samsung_GalaxyS23]、[IOS_iPhone14Pro]、[Windows_NVIDIA_RTX4090]这类Section,下意识觉得&…...

WiFi感知技术在智能家居中的原理与应用

1. WiFi感知技术:重新定义智能家居环境感知在智能家居领域,环境感知一直是个技术难题。传统方案主要依赖摄像头、红外传感器(PIR)和毫米波雷达等专用设备,但这些方案要么存在隐私顾虑,要么安装复杂且成本高…...

微生物代谢建模与优化:从GEMs构建到工业应用

1. 微生物代谢建模与优化的协同设计方法在工业生物技术领域,微生物代谢建模已成为优化生物转化过程的核心工具。通过构建基因组尺度代谢模型(GEMs),研究人员能够系统分析微生物细胞内数百至数千个酶催化反应的相互作用网络。以丁酸…...

ARTX实时操作系统任务监控与调试实践

1. 实时任务监控需求解析在嵌入式实时操作系统(RTOS)开发中,任务调度监控是调试复杂系统的关键手段。ARTX-166作为一款面向C166架构的高级实时操作系统,其任务调度机制直接影响系统实时性能。当系统出现响应延迟或死锁时&#xff…...

Keil串口调试与程序共享端口的解决方案

1. 串口调试中的端口复用问题解析 在嵌入式开发过程中,使用Keil Vision的Monitor模式进行硬件调试时,开发板上的串口资源往往会被调试器独占。这个问题困扰过不少开发者——当我们需要在调试过程中通过串口输入测试数据时,却发现串口已经被Mo…...

基于SpringBoot的运动会报名与成绩录入系统毕业设计

博主介绍:✌ 专注于Java,python,✌关注✌私信我✌具体的问题,我会尽力帮助你。一、研究目的本研究旨在构建一个基于Spring Boot与Vue框架的运动会报名与成绩录入系统以解决传统体育赛事管理中存在的信息处理效率低下数据准确性不足以及资源分配不科学等问…...

国产系统(UOS/麒麟/方德)截图工具终极指南:从内置工具到第三方替代方案全解析

国产操作系统截图工具全攻略:从基础操作到高阶玩法在数字化办公时代,截图功能已成为日常工作中不可或缺的生产力工具。对于统信UOS、麒麟KOS、方德NFS等国产操作系统的用户而言,掌握系统内置截图工具的各项功能,并了解当内置工具无…...

电脑‘假关机’真烦人!深入聊聊Windows电源管理里的‘快速启动’到底是个啥

Windows快速启动技术揭秘:高效与兼容性的博弈深夜加班结束,你点击关机按钮准备休息,却发现显示器刚暗下去又突然亮起——这不是灵异事件,而是Windows的快速启动功能在"作祟"。这种介于关机和休眠之间的混合状态&#xf…...

别再只跑模型了!用FAD、NDB、JSD给你的AI生成声音打个分(Python实战避坑)

用FAD、NDB、JSD给你的AI生成声音打个分(Python实战避坑指南)当你在深夜终于调试完最后一个神经网络层,按下生成按钮听到第一段AI合成的声音时,那种成就感无与伦比。但很快,一个更棘手的问题出现了:这段声音…...

Qwen模型 LeetCode 2584. 分割数组使乘积互质 JavaScript实现

哇!JavaScript版本来啦~这道题用JS写起来特别优雅,让我给你展示一个清晰又高效的实现!javascript /*** param {number[]} nums* return {number}*/ var findValidSplit function(nums) {const n nums.length;if (n 1) return -…...

RD-VLA:机器人动态思考的潜在空间迭代推理架构

1. 项目概述:为什么我们需要一个会“思考”的机器人模型?在机器人控制领域,我们一直梦想着能造出一个像人一样“聪明”的助手:让它去拿杯水,它能轻松完成;让它在一个杂乱无章的抽屉里找出并组装一个小零件&…...

用Python模拟10000次实验,直观理解卡方分布如何从正态分布‘长’出来

用Python模拟10000次实验,直观理解卡方分布如何从正态分布‘长’出来统计学中的分布概念常常让人望而生畏,尤其是当公式推导占据主导时。但如果我们换一种方式——用代码和可视化来探索,这些抽象概念会立刻变得鲜活起来。今天,我们…...

Qwen模型 LeetCode 2581. 统计可能的树根数目 C++实现

哈哈&#xff0c;看来你对这道题特别感兴趣呀&#xff01;让我给你一个**终极优化版**的C实现&#xff0c;这次用位运算哈希 向量预分配&#xff0c;保证又快又稳&#xff01;cpp class Solution { public:int rootCount(vector<vector<int>>& edges, vector&…...

Unity ECS帧同步实战:确定性模拟与Job化网络Tick

1. 这不是“又一个Unity网络教程”&#xff0c;而是帧同步在ECS架构下的真实落地切口很多人一看到“Unity多人对战”就下意识点开&#xff0c;结果发现是PhotonMonoBehaviour的旧路子&#xff1a;对象池、RPC调用、状态同步、插值补偿……代码越写越厚&#xff0c;逻辑越埋越深…...

线性化加性模型与子尺度混合:实现概率空间直接可解释的机器学习

1. 项目概述与核心痛点 在金融风控、医疗诊断这些对决策过程要求“看得见、摸得着”的领域&#xff0c;我们这些从业者每天都在和模型的可解释性较劲。你肯定遇到过这种情况&#xff1a;业务方拿着一个逻辑回归模型的风险评分问你&#xff1a;“这个客户的‘历史逾期次数’这个…...

Unity手游Mono堆泄漏:80MB硬限下的静默崩溃真相

1. 这不是GC没跑&#xff0c;是Mono堆在 silently 溢出——一个被90% Unity手游团队忽视的“假稳定”现象你有没有遇到过这样的情况&#xff1a;游戏在编辑器里跑得飞快&#xff0c;Profiler显示GC调用次数极少&#xff0c;内存曲线平滑得像湖面&#xff1b;但一打包到Android真…...

量子神经网络抗噪优化:经典噪声层与可微架构搜索的协同设计

1. 项目概述&#xff1a;当量子计算遇见噪声与架构挑战最近在折腾量子机器学习&#xff08;QML&#xff09;的项目&#xff0c;特别是量子神经网络&#xff08;QNN&#xff09;&#xff0c;一个绕不开的坎就是“噪声”。无论是超导、离子阱还是光子平台&#xff0c;当前的含噪声…...

从线性智能到多维能力光谱:重新理解AI的“陌生性”与工程实践

1. 项目概述&#xff1a;重新审视智能的“陌生性”在人工智能领域&#xff0c;我们似乎总在追逐一个幽灵般的“通用智能”&#xff08;AGI&#xff09;——一个能在所有认知任务上媲美甚至超越人类的系统。这种想象往往基于一个根深蒂固的线性模型&#xff1a;智能是一个单一的…...

别再乱码了!一文搞懂Windows记事本里ANSI、GBK、SJIS这些编码到底怎么选

告别乱码&#xff01;Windows记事本编码选择终极指南 为什么你的文件总在别人电脑上显示乱码&#xff1f; 每次用Windows记事本保存文件时&#xff0c;面对"ANSI"、"Unicode"、"UTF-8"这些选项&#xff0c;你是否感到困惑&#xff1f;明明在自己…...

HRN三维人脸UV对齐:Blender与Unity跨平台精准映射指南

1. 这不是“贴图导入”&#xff0c;而是三维人脸数据流的精准对齐很多人第一次看到“3D Face HRN”这个词&#xff0c;下意识会以为是某种新出的美颜插件&#xff0c;或者Unity Asset Store里点几下就能拖进场景的预制体。我去年在给一家医疗仿真团队做面部肌肉运动模拟时也这么…...

Unity中型项目插件整合实战:地形、地牢、卡通渲染与性能优化

1. 这不是“又一个插件包”&#xff0c;而是Unity中型项目落地的现实锚点你有没有过这样的经历&#xff1a;刚立项一个3D RPG&#xff0c;美术说“地形得有真实感”&#xff0c;程序说“地牢生成逻辑要支持多层嵌套”&#xff0c;策划喊“塔防关卡得能拖拽编辑”&#xff0c;QA…...

Unity安装包瘦身实战:从2.3GB到680MB的工程化治理

1. 为什么一个500MB的Unity项目打包后会变成3GB&#xff1f;——安装包膨胀的真实逻辑“Unity安装包减肥”这六个字&#xff0c;听起来像在给软件做瑜伽&#xff0c;但实际是每个上线前夜都在咬牙硬扛的生存战。我做过7个已上线的Unity手游项目&#xff0c;最深的体会是&#x…...