بنقرة واحدة
structured-output
从 LLM 可靠获取结构化 JSON——工具调用强制结构化、Pydantic 验证、失败重试、批量提取
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
从 LLM 可靠获取结构化 JSON——工具调用强制结构化、Pydantic 验证、失败重试、批量提取
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Execute the check workflow from this AI development team preset. Use when the user writes /check, asks for check, or wants the corresponding team process in Codex.
Execute the dev workflow from this AI development team preset. Use when the user writes /dev, asks for dev, or wants the corresponding team process in Codex.
Execute the fix workflow from this AI development team preset. Use when the user writes /fix, asks for fix, or wants the corresponding team process in Codex.
Execute the plan workflow from this AI development team preset. Use when the user writes /plan, asks for plan, or wants the corresponding team process in Codex.
Execute the project-preset workflow from this AI development team preset. Use when the user writes /project-preset, asks for project-preset, or wants the corresponding team process in Codex.
Execute the review-all workflow from this AI development team preset. Use when the user writes /review-all, asks for review-all, or wants the corresponding team process in Codex.
| name | structured-output |
| description | 从 LLM 可靠获取结构化 JSON——工具调用强制结构化、Pydantic 验证、失败重试、批量提取 |
本技能默认给 Python 实现。TypeScript 用户:用 Vercel AI SDK 的
generateObject+ Zod,见下方"TypeScript 版"。
工具调用比"请输出 JSON"更可靠,因为 Claude 经过专门训练来正确填写工具 schema。
import anthropic
from pydantic import BaseModel, Field
from typing import TypeVar
client = anthropic.AsyncAnthropic()
T = TypeVar("T", bound=BaseModel)
async def extract(text: str, schema: type[T], instruction: str = "") -> T:
"""通用结构化提取:传入 Pydantic 模型,返回实例"""
response = await client.messages.create(
model="claude-haiku-4-5-20251001", # 结构化任务用 Haiku,又快又省钱
max_tokens=1024,
tools=[{
"name": "submit_result",
"description": f"提交提取结果(必须调用)。{instruction}",
"input_schema": schema.model_json_schema(),
}],
tool_choice={"type": "any"}, # 强制必须调用工具,不允许纯文本回复
messages=[{
"role": "user",
"content": f"从以下内容中提取信息并提交:\n\n{text}",
}],
)
tool_use = next(b for b in response.content if b.type == "tool_use")
return schema.model_validate(tool_use.input)
class DocumentSummary(BaseModel):
title: str = Field(description="文档标题,10字以内")
key_points: list[str] = Field(description="3-5个核心要点,每条不超过50字")
sentiment: str = Field(description="情感倾向:positive / negative / neutral")
confidence: float = Field(ge=0.0, le=1.0, description="置信度,0.0-1.0")
class EntityExtraction(BaseModel):
people: list[str] = Field(default_factory=list, description="文中提到的人名")
organizations: list[str] = Field(default_factory=list, description="机构/公司名称")
locations: list[str] = Field(default_factory=list, description="地名")
dates: list[str] = Field(default_factory=list, description="日期/时间表达")
class ClassificationResult(BaseModel):
label: str = Field(description="分类标签,必须是预定义类别之一")
confidence: float = Field(ge=0.0, le=1.0)
reasoning: str = Field(description="分类理由,方便调试和审核")
class EvalScore(BaseModel):
score: float = Field(ge=0.0, le=1.0, description="评分 0.0-1.0")
passed: bool = Field(description="是否达到及格线")
explanation: str = Field(description="评分理由")
issues: list[str] = Field(default_factory=list, description="存在的问题列表")
from tenacity import retry, stop_after_attempt, wait_exponential
import logging
logger = logging.getLogger(__name__)
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(min=1, max=10),
reraise=True,
)
async def extract_with_retry(text: str, schema: type[T]) -> T:
try:
return await extract(text, schema)
except Exception as e:
logger.warning("structured_extract_failed", error=str(e), schema=schema.__name__)
raise
async def batch_extract(
texts: list[str],
schema: type[T],
concurrency: int = 10, # 控制并发,避免超 rate limit
) -> list[T | None]:
semaphore = asyncio.Semaphore(concurrency)
async def safe_extract(text: str) -> T | None:
async with semaphore:
try:
return await extract_with_retry(text, schema)
except Exception as e:
logger.error("batch_extract_failed", error=str(e))
return None
return await asyncio.gather(*[safe_extract(t) for t in texts])
class JudgeResult(BaseModel):
faithfulness: float = Field(ge=0.0, le=1.0, description="答案是否完全基于上下文")
relevance: float = Field(ge=0.0, le=1.0, description="答案是否回答了问题")
reasoning: str = Field(description="评分理由")
async def judge_rag_answer(question: str, context: str, answer: str) -> JudgeResult:
prompt = f"""请评估以下 RAG 系统的输出质量:
问题:{question}
检索到的上下文:
{context}
系统给出的答案:
{answer}"""
return await extract(prompt, JudgeResult, instruction="客观评估答案质量,注重忠实度和相关性")
response_format={"type": "json_object"}:不如工具调用可靠,且不能约束 schema 结构response.content[0].text:容易被 markdown 代码块和换行符干扰description:LLM 靠 description 理解该填什么,不要依赖字段名称Field(default_factory=list) 代替 = []:Pydantic 最佳实践,避免共享默认值generateObject 用 Zod schema 强制结构化,等价于 Python 的工具调用强制法,类型自动推导。
import { generateObject } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
const ClassificationSchema = z.object({
label: z.string().describe('分类标签,必须是预定义类别之一'),
confidence: z.number().min(0).max(1),
reasoning: z.string().describe('分类理由,便于调试'),
});
export async function classify(text: string) {
const { object } = await generateObject({
model: anthropic('claude-haiku-4-5-20251001'), // 结构化任务用 Haiku
schema: ClassificationSchema,
prompt: `对以下内容分类:\n\n${text}`,
maxRetries: 3, // SDK 内置重试
});
return object; // 已通过 Zod 校验,完全类型安全
}
// 批量提取(控制并发)
export async function batchExtract<T>(
texts: string[],
fn: (t: string) => Promise<T>,
concurrency = 10,
): Promise<(T | null)[]> {
const results: (T | null)[] = [];
for (let i = 0; i < texts.length; i += concurrency) {
const batch = texts.slice(i, i + concurrency);
const settled = await Promise.allSettled(batch.map(fn));
results.push(...settled.map((s) => (s.status === 'fulfilled' ? s.value : null)));
}
return results;
}
避坑同 Python:schema 层级不超 3 层、每个字段加 .describe()、不要让模型输出裸 JSON 字符串再 parse(用 generateObject 而非解析 text)。