结构化输出

LLM结构化输出指南

为什么结构化输出如此重要? LLM默认输出自由文本,但实际应用中我们通常需要结构化数据——JSON对象、表格、特定格式。不可靠的结构化输出会导致下游解析失败,是LLM应用从原型到生产的主要障碍之一。 方案一:Prompt工程 基础方案 STRUCTURED_PROMPT = """ 请按以下JSON格式输出,不要包含其他内容: { "intent": "用户意图分类", "confidence": 0.0-1.0之间的数值, "entities": [ {"type": "实体类型", "value": "实体值"} ], "response": "回复内容" } 用户输入:{input} """ Few-shot增强 FEW_SHOT_PROMPT = """ 请按JSON格式输出意图分析结果。 示例1: 输入:我想订一张明天去北京的机票 输出:{"intent": "book_flight", "confidence": 0.95, "entities": [{"type": "destination", "value": "北京"}, {"type": "date", "value": "明天"}], "response": "好的,我来帮您查询明天去北京的航班。"} 示例2: 输入:今天天气怎么样 输出:{"intent": "weather_query", "confidence": 0.9, "entities": [{"type": "date", "value": "今天"}], "response": "让我为您查询今天的天气。"} 现在请分析: 输入:{input} 输出: """ 优缺点 优点:简单通用,任何LLM都支持 缺点:不可靠,模型可能输出多余文本、格式错误、字段缺失 方案二:JSON Mode from openai import OpenAI client = OpenAI() response = client.chat.completions.create( model="qwen3-32b", messages=[{"role": "user", "content": "分析以下文本的情感,返回JSON"}], response_format={"type": "json_object"} # 强制JSON输出 ) result = json.loads(response.choices[0].message.content) JSON Mode保证输出是合法的JSON,但不保证包含特定字段。 ...

2026-07-02 · 2 min · 333 words · 硅基 AGI 探索者
结构化输出技术

结构化输出技术:从JSON Mode到Function Calling

为什么结构化输出如此重要 在生产环境中,LLM的输出需要被程序解析和处理。非结构化的自然语言输出虽然灵活,但带来三个严重问题: 解析不可靠:正则提取容易遗漏边界情况 集成困难:下游系统需要稳定的接口契约 验证缺失:无法保证输出满足业务约束 2026年,结构化输出已从"nice to have"变为"must have"。所有主流模型都提供了原生结构化输出能力。 技术方案全景 方案对比 方案 原理 可靠性 性能 灵活性 适用场景 JSON Mode 模型内置JSON生成 95% 高 中 简单结构 Function Calling 函数签名约束 97% 高 高 API调用 Constrained Decoding 解码时约束 99% 中 最高 严格格式 Pydantic + LLM Schema验证+重试 90% 低 高 复杂校验 XML标签 标签结构化 85% 高 低 简单提取 JSON Mode 基本使用 import json from openai import OpenAI client = OpenAI() # OpenAI JSON Mode response = client.chat.completions.create( model="gpt-4o-2026", response_format={"type": "json_object"}, messages=[ { "role": "system", "content": """你是一个信息提取助手。 请将用户输入提取为JSON格式,包含以下字段: - name: 姓名 - age: 年龄(整数) - skills: 技能列表(字符串数组) - experience: 工作经验(整数,单位年) """ }, { "role": "user", "content": "张三,28岁,精通Python和JavaScript,有5年开发经验" } ] ) result = json.loads(response.choices[0].message.content) print(result) # 输出: {"name": "张三", "age": 28, "skills": ["Python", "JavaScript"], "experience": 5} JSON Schema约束 # 2026年最新:JSON Schema强化约束 response = client.chat.completions.create( model="gpt-4o-2026", response_format={ "type": "json_schema", "json_schema": { "name": "employee_info", "strict": True, "schema": { "type": "object", "properties": { "name": {"type": "string", "minLength": 1, "maxLength": 50}, "age": {"type": "integer", "minimum": 18, "maximum": 65}, "skills": { "type": "array", "items": {"type": "string"}, "minItems": 1, "maxItems": 20 }, "experience": {"type": "integer", "minimum": 0, "maximum": 50}, "level": { "type": "string", "enum": ["junior", "mid", "senior", "expert"] } }, "required": ["name", "age", "skills", "experience", "level"], "additionalProperties": False } } }, messages=[...] ) 各家模型JSON Mode对比 模型 JSON可靠性 Schema支持 性能影响 特殊限制 GPT-4o 95% 完整 <5% 需提示JSON关键词 Claude 4 93% XML标签 <3% 推荐XML格式 Gemini 2 94% 部分支持 <5% Qwen 3 92% 部分 <5% Llama 4 88% 不支持 <8% 需Few-shot Function Calling 基本架构 from dataclasses import dataclass from typing import Callable import inspect @dataclass class ToolDefinition: name: str description: str parameters: dict # JSON Schema class FunctionCallingSystem: """ 2026年Function Calling最佳实践 """ def __init__(self, model_client): self.model = model_client self.tools: dict[str, ToolDefinition] = {} self.handlers: dict[str, Callable] = {} def register_function(self, func: Callable, description: str): """注册可调用函数""" # 自动从函数签名生成Schema sig = inspect.signature(func) params = {} required = [] for name, param in sig.parameters.items(): param_type = param.annotation json_type = self._python_type_to_json(param_type) params[name] = { "type": json_type, "description": self._extract_param_doc(func, name) } if param.default == inspect.Parameter.empty: required.append(name) tool = ToolDefinition( name=func.__name__, description=description or func.__doc__, parameters={ "type": "object", "properties": params, "required": required } ) self.tools[func.__name__] = tool self.handlers[func.__name__] = func async def execute_with_functions(self, user_message: str) -> str: """带函数调用的对话""" messages = [{"role": "user", "content": user_message}] tools = [t.__dict__ for t in self.tools.values()] while True: response = await self.model.chat( messages=messages, tools=tools, tool_choice="auto" ) message = response.choices[0].message messages.append(message) if not message.tool_calls: # 模型没有调用工具,返回最终回复 return message.content # 执行函数调用 for tool_call in message.tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) # 参数验证 validation = self._validate_arguments(func_name, func_args) if not validation["valid"]: result = f"参数错误: {validation['errors']}" else: # 执行函数 try: handler = self.handlers[func_name] result = await handler(**func_args) except Exception as e: result = f"执行错误: {str(e)}" # 将结果返回给模型 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": str(result) }) 实际应用示例 # 定义工具函数 @dataclass class SearchResult: title: str url: str snippet: str async def search_web(query: str, max_results: int = 5) -> list[dict]: """搜索网络内容 Args: query: 搜索关键词 max_results: 最大返回结果数(默认5) """ # 实际搜索逻辑 results = await search_engine.search(query, limit=max_results) return [{"title": r.title, "url": r.url, "snippet": r.snippet} for r in results] async def get_weather(city: str, unit: str = "celsius") -> dict: """获取指定城市的天气信息 Args: city: 城市名称 unit: 温度单位(celsius或fahrenheit) """ weather = await weather_api.get(city, unit) return { "city": city, "temperature": weather.temp, "condition": weather.condition, "humidity": weather.humidity } async def send_email(to: str, subject: str, body: str) -> dict: """发送邮件 Args: to: 收件人邮箱 subject: 邮件主题 body: 邮件正文 """ await email_service.send(to, subject, body) return {"status": "sent", "to": to} # 注册并使用 system = FunctionCallingSystem(model_client) system.register_function(search_web, "搜索网络获取最新信息") system.register_function(get_weather, "查询天气信息") system.register_function(send_email, "发送邮件") # 执行 response = await system.execute_with_functions( "帮我查一下北京今天的天气,然后把结果发邮件给 zhangsan@example.com" ) Constrained Decoding 原理 Constrained Decoding(约束解码)在生成过程中实时约束token选择,确保输出符合预定义的语法规则。 ...

2026-06-30 · 6 min · 1190 words · 硅基 AGI 探索者
sglang 2026 inference engine

SGLang 2026:结构化生成的高性能推理引擎

SGLang:被低估的推理黑马 SGLang(Structured Generation Language)在 2026 年从"学术项目"蜕变为"生产级推理引擎"。由 LMSYS 团队(ChatBot Arena 的创建者)开发,SGLang 的核心创新是 RadixAttention——一种基于基数树的 KV Cache 复用技术,在多轮对话和复杂 Agent 场景中实现了惊人的性能提升。 核心技术创新 1. RadixAttention RadixAttention 是 SGLang 的标志性技术。它将 KV Cache 组织为基数树结构,实现前缀复用: 传统方案:每个请求独立维护 KV Cache ┌──────┐ ┌──────┐ ┌──────┐ │Req 1 │ │Req 2 │ │Req 3 │ │KV │ │KV │ │KV │ │Cache │ │Cache │ │Cache │ └──────┘ └──────┘ └──────┘ 浪费:相同前缀重复计算 RadixAttention:共享前缀的 KV Cache ┌─ "用户: 你好" (共享) │ ├─ "助手: 你好!有什么可以帮您?" (Req 1) │ └─ "助手: 您好!请问需要什么帮助?" (Req 2) └─ "用户: 写代码" (共享) └─ "助手: 好的,请告诉我..." (Req 3) import sglang as sgl # RadixAttention 自动复用前缀 @sgl.function def multi_turn_chat(s, question): s += "以下是一个专业对话:\n" s += "用户: " + question + "\n" s += "助手: " + sgl.gen("answer", max_tokens=256) # 多轮对话中,前缀自动复用 # 第一轮 state1 = multi_turn_chat.run(question="什么是 RAG?") # 第二轮(复用第一轮的前缀) state2 = multi_turn_chat.run(question="RAG 和微调有什么区别?") # 第三轮(复用前两轮的前缀) state3 = multi_turn_chat.run(question="如何结合使用?") # KV Cache 复用率随轮次增加而提高 # 实测:5 轮对话后,KV Cache 复用率达 85%+ 2. 结构化输出 SGLang 原生支持 JSON Schema 约束生成: ...

2026-06-28 · 4 min · 761 words · 硅基 AGI 探索者
structured output prompt design

结构化输出 Prompt 设计:让 LLM 稳定输出 JSON 的方法

为什么结构化输出如此重要 在 2026 年的 AI 应用开发中,LLM 的输出需要被程序消费——传入 API、写入数据库、驱动 Agent 决策。一项 2026 年 Stack Overflow 开发者调查显示,93% 的 LLM 应用需要结构化输出,但其中 41% 的开发者仍在与"输出格式不稳定"作斗争。 一、结构化输出的三层保障 ┌─────────────────────────────┐ │ 第一层:Prompt 设计 │ ← 指令层面的约束 ├─────────────────────────────┤ │ 第二层:Schema 约束 │ ← JSON Schema / 函数调用 ├─────────────────────────────┤ │ 第三层:约束解码 │ ← Token 级别的强制约束 └─────────────────────────────┘ 二、Prompt 层面的结构化设计 2.1 基础模式:明确格式指令 请分析以下产品评论,并以JSON格式输出分析结果。 输出格式要求(严格遵守): { "sentiment": "positive" | "negative" | "neutral", "score": 0.0到1.0之间的浮点数, "aspects": [ { "aspect": "产品维度名称", "opinion": "用户观点", "polarity": "positive" | "negative" } ], "summary": "50字以内的总结" } 注意: 1. 只输出JSON,不要输出任何其他内容 2. 不要用markdown代码块包裹 3. 所有字符串值必须用双引号 4. 确保JSON可以被标准解析器解析 评论内容:{{review}} 2.2 增强模式:Schema 嵌入 + 示例引导 STRUCTURED_OUTPUT_TEMPLATE = """ 你是一个数据提取专家。请从给定文本中提取信息,严格按照以下JSON Schema输出。 ## JSON Schema ```json {schema} 输出规则 输出必须是符合上述Schema的合法JSON 无法从文本中提取的字段,使用null值 日期格式统一为ISO 8601 金额统一为数字,单位为分 不要输出任何解释性文字 示例 输入:{example_input} 输出:{example_output} ...

2026-06-28 · 5 min · 972 words · 硅基 AGI 探索者
instructor review

Instructor 框架评测:结构化输出的优雅方案

结构化输出的痛点 让 LLM 输出结构化数据是工程落地中最常见的需求:解析简历提取字段、分类用户意图、生成配置文件。传统做法是在 Prompt 里写"请输出 JSON",然后祈祷模型不要在 JSON 前面加一句"好的,这是你要的结果:"。Instructor 框架优雅地解决了这个问题。 Instructor 核心原理 Instructor 的设计哲学极其简洁:用 Python 类型注解定义结构,让 LLM 填充结构,自动验证和修复。 工作流程: 你定义一个 Pydantic 模型(即期望的输出结构) Instructor 将模型 Schema 注入 Prompt LLM 生成输出 Pydantic 验证输出 验证失败 → 自动将错误信息反馈给 LLM 重试 快速上手 安装与基础用法 pip install instructor import instructor from pydantic import BaseModel, Field from openai import OpenAI # 启用 Instructor client = instructor.from_openai(OpenAI()) # 定义输出结构 class UserInfo(BaseModel): name: str = Field(description="用户全名") age: int = Field(description="用户年龄", ge=0, le=150) email: str = Field(description="邮箱地址") role: str = Field(description="职位", default="unknown") # 调用——直接返回结构化对象 user = client.chat.completions.create( model="gpt-4o", response_model=UserInfo, messages=[{"role": "user", "content": "张三,28岁,邮箱 zhangsan@example.com,高级工程师"}], ) print(user.name) # "张三" print(user.age) # 28 print(user.email) # "zhangsan@example.com" print(user.role) # "高级工程师" print(type(user)) # <class 'UserInfo'> 注意:返回的不是字典,是经过验证的 Pydantic 对象。类型安全,IDE 补全全开。 ...

2026-06-24 · 3 min · 632 words · 硅基 AGI 探索者
鲁ICP备2026018361号