#结构化输出
内置的 generate_object 工具会让配置的 LLM 生成 JSON 对象,对响应执行你提供的
JSON Schema 校验,并且只在零退出码结果中返回校验后的对象。当你需要机器可读的结果时
使用它:抽取、分类、配置生成,或者作为另一个程序的输入。
你可以通过 session.tool('generate_object', ...) 直接调用它。工具结果会把校验后的对象以 JSON 形式放在 result.output 上——解析它并读取 object 字段。同一个工具也支持 agent 自主调用,即模型在 send 过程中自行决定调用它。
#直接工具调用
最简单的方式:直接调用 generate_object,先检查工具退出码,再从结果中解析出校验后的对象。
use a3s_code_core::Agent;use serde_json::{json, Value};#[tokio::main]async fn main() -> a3s_code_core::Result<()> {let agent = Agent::new("agent.acl").await?;let session = agent.session_builder(".").build().await?;let result = session.tool("generate_object",json!({"schema": {"type": "object","required": ["name", "age", "skills"],"properties": {"name": { "type": "string" },"age": { "type": "integer", "minimum": 0 },"skills": {"type": "array","items": { "type": "string" },"minItems": 1}}},"prompt": "提取:Alice 今年 28 岁,擅长 Rust、TypeScript 和 Python。","schema_name": "developer","mode": "tool"}),).await?;if result.exit_code != 0 {return Err(a3s_code_core::CodeError::Tool {tool: "generate_object".into(),message: result.output,});}let value: Value = serde_json::from_str(&result.output)?;println!("{}", value["object"]);session.close().await;agent.close().await;Ok(())}
import { Agent } from '@a3s-lab/code';const agent = await Agent.create('agent.acl');const session = agent.session('.');const result = await session.tool('generate_object', {schema: {type: 'object',required: ['name', 'age', 'skills'],properties: {name: { type: 'string' },age: { type: 'integer', minimum: 0 },skills: {type: 'array',items: { type: 'string' },minItems: 1,},},},prompt: 'Extract: "Alice is 28, skilled in Rust, TypeScript, and Python."',schema_name: 'developer',mode: 'tool',});if (result.exitCode !== 0) {throw new Error(result.output);}const { object } = JSON.parse(result.output);console.log(object);// { name: "Alice", age: 28, skills: ["Rust", "TypeScript", "Python"] }session.close();
import jsonfrom a3s_code import Agentagent = Agent.create('agent.acl')session = agent.session('.')result = session.tool("generate_object", {"schema": {"type": "object","required": ["name", "age", "skills"],"properties": {"name": {"type": "string"},"age": {"type": "integer", "minimum": 0},"skills": {"type": "array","items": {"type": "string"},"minItems": 1,},},},"prompt": 'Extract: "Alice is 28, skilled in Rust, TypeScript, and Python."',"schema_name": "developer","mode": "tool",})if result.exit_code != 0:raise RuntimeError(result.output)obj = json.loads(result.output)["object"]print(obj)# {"name": "Alice", "age": 28, "skills": ["Rust", "TypeScript", "Python"]}session.close()
package mainimport ("context""encoding/json""fmt""log"code "github.com/A3S-Lab/Code/sdk/go/v6")func main() {ctx := context.Background()agent, err := code.Create(ctx, "agent.acl")if err != nil {log.Fatal(err)}defer agent.Close(context.Background())session, err := agent.Session(ctx, ".", nil)if err != nil {log.Fatal(err)}defer session.Close(context.Background())result, err := session.Tool(ctx, "generate_object", map[string]any{"schema": map[string]any{"type": "object","required": []string{"name", "age", "skills"},"properties": map[string]any{"name": map[string]any{"type": "string"},"age": map[string]any{"type": "integer", "minimum": 0},"skills": map[string]any{"type": "array", "items": map[string]any{"type": "string"},"minItems": 1,},},},"prompt": "提取:Alice 今年 28 岁,擅长 Rust、TypeScript 和 Python。","schema_name": "developer","mode": "tool",})if err != nil {log.Fatal(err)}if result.ExitCode != 0 {log.Fatal(result.Output)}var value struct {Object map[string]any `json:"object"`}if err := json.Unmarshal([]byte(result.Output), &value); err != nil {log.Fatal(err)}fmt.Println(value.Object)}
校验后的值位于解析输出的 object 键上。当 result.exitCode(Node)/
result.exit_code(Python)为零时,required 中声明的字段已经通过运行时校验。
如果模型在修复重试后仍无法满足 schema,工具会报告非零退出码。
#枚举分类
用 enum 把字段约束到一个固定集合。这会把自由文本分类变成带 schema 闸门的结果。
use serde_json::{json, Value};let result = session.tool("generate_object",json!({"schema": {"type": "object","required": ["sentiment", "confidence"],"properties": {"sentiment": {"type": "string","enum": ["positive", "negative", "neutral"]},"confidence": {"type": "number","minimum": 0,"maximum": 1}}},"prompt": "判断情感:这是我用过最差的产品。","schema_name": "sentiment"}),).await?;let value: Value = serde_json::from_str(&result.output)?;println!("{} {}",value["object"]["sentiment"],value["object"]["confidence"]);
const result = await session.tool('generate_object', {schema: {type: 'object',required: ['sentiment', 'confidence'],properties: {sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },confidence: { type: 'number', minimum: 0, maximum: 1 },},},prompt: 'Classify sentiment: "This is the worst product I have ever used."',schema_name: 'sentiment',});const { object } = JSON.parse(result.output);console.log(object.sentiment, object.confidence); // "negative" 0.97
result = session.tool("generate_object", {"schema": {"type": "object","required": ["sentiment", "confidence"],"properties": {"sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},"confidence": {"type": "number", "minimum": 0, "maximum": 1},},},"prompt": 'Classify sentiment: "This is the worst product I have ever used."',"schema_name": "sentiment",})obj = json.loads(result.output)["object"]print(obj["sentiment"], obj["confidence"]) # "negative" 0.97
result, err := session.Tool(ctx, "generate_object", map[string]any{"schema": map[string]any{"type": "object","required": []string{"sentiment", "confidence"},"properties": map[string]any{"sentiment": map[string]any{"type": "string", "enum": []string{"positive", "negative", "neutral"},},"confidence": map[string]any{"type": "number", "minimum": 0, "maximum": 1,},},},"prompt": "判断情感:这是我用过最差的产品。","schema_name": "sentiment",})if err != nil {return err}var value struct {Object map[string]any `json:"object"`}if err := json.Unmarshal([]byte(result.Output), &value); err != nil {return err}fmt.Println(value.Object["sentiment"], value.Object["confidence"])
#嵌套模式与数组
Schema 可以任意深度地嵌套对象和数组,运行时会校验整个结构。这能在一次调用中建模真实的配置文件、清单或 API 载荷。
use serde_json::{json, Value};let result = session.tool("generate_object",json!({"schema": {"type": "object","required": ["items"],"properties": {"items": {"type": "array","minItems": 3,"maxItems": 5,"items": {"type": "object","required": ["name", "category"],"properties": {"name": { "type": "string" },"category": {"type": "string","enum": ["fruit", "vegetable", "grain"]}}}}}},"prompt": "列出 3 种食物及其类别。","schema_name": "food_list"}),).await?;let value: Value = serde_json::from_str(&result.output)?;let items = value["object"]["items"].as_array().unwrap();println!("{} {:?}", items.len(), items);
const result = await session.tool('generate_object', {schema: {type: 'object',required: ['items'],properties: {items: {type: 'array',minItems: 3,maxItems: 5,items: {type: 'object',required: ['name', 'category'],properties: {name: { type: 'string' },category: { type: 'string', enum: ['fruit', 'vegetable', 'grain'] },},},},},},prompt: 'List 3 food items with their categories.',schema_name: 'food_list',});const { items } = JSON.parse(result.output).object;console.log(items.length,items.map((i) => i.name),);
result = session.tool("generate_object", {"schema": {"type": "object","required": ["items"],"properties": {"items": {"type": "array","minItems": 3,"maxItems": 5,"items": {"type": "object","required": ["name", "category"],"properties": {"name": {"type": "string"},"category": {"type": "string", "enum": ["fruit", "vegetable", "grain"]},},},},},},"prompt": "List 3 food items with their categories.","schema_name": "food_list",})items = json.loads(result.output)["object"]["items"]print(len(items), [i["name"] for i in items])
result, err := session.Tool(ctx, "generate_object", map[string]any{"schema": map[string]any{"type": "object","required": []string{"items"},"properties": map[string]any{"items": map[string]any{"type": "array", "minItems": 3, "maxItems": 5,"items": map[string]any{"type": "object","required": []string{"name", "category"},"properties": map[string]any{"name": map[string]any{"type": "string"},"category": map[string]any{"type": "string","enum": []string{"fruit", "vegetable", "grain"},},},},},},},"prompt": "列出 3 种食物及其类别。","schema_name": "food_list",})if err != nil {return err}var value struct {Object struct {Items []map[string]any `json:"items"`} `json:"object"`}if err := json.Unmarshal([]byte(result.Output), &value); err != nil {return err}fmt.Println(len(value.Object.Items), value.Object.Items)
#智能体自主调用
你也可以让 agent 自行决定何时使用结构化输出。让它在 send 过程中调用 generate_object;它会先收集上下文,再输出对象。
let result = session.send("使用 generate_object 从下面内容提取电影标题、年份和类型:\《盗梦空间》于 2010 年上映,是一部科幻惊悚片。",None,).await?;println!("工具调用:{},令牌:{}",result.tool_calls_count,result.usage.total_tokens);
const result = await session.send('Use the generate_object tool to extract the following into an object ' +'with fields "title" (string), "year" (integer), "genre" (string): ' +'The movie "Inception" was released in 2010 and is a sci-fi thriller.',);console.log(`tool calls: ${result.toolCallsCount}, tokens: ${result.totalTokens}`,);
result = session.send('Use the generate_object tool to produce a JSON object with schema ''{"type":"object","required":["language","paradigm"],"properties":''{"language":{"type":"string"},"paradigm":{"type":"string"}}} ''for: "Rust is a systems programming language with a focus on safety."')print(f"tool calls: {result.tool_calls_count}, tokens: {result.total_tokens}")
result, err := session.Run(ctx,"使用 generate_object 从下面内容提取电影标题、年份和类型:"+"《盗梦空间》于 2010 年上映,是一部科幻惊悚片。",)if err != nil {return err}fmt.Printf("工具调用:%d,令牌:%d\n",result.ToolCallsCount,result.Usage.TotalTokens,)
#模式校验覆盖
内置校验器支持:
type(包括 nullable 数组如["string", "null"])required、properties、additionalPropertiesenum、constanyOf、oneOfminLength、maxLength、patternminimum、maximum、exclusiveMinimum、exclusiveMaximumminItems、maxItems、items- 嵌套对象和数组校验
#说明
- 校验后的值位于解析后
result.output的object键上。当前跨 provider 默认路径传mode: 'tool',仅 prompt 的回退方式传mode: 'prompt'。auto、strict和json在当前运行路径中都会解析为tool。 - 把你依赖的每个字段都列入
required——运行时会强制执行,因此缺失或类型错误的字段会导致校验失败,而不是悄悄返回部分数据。 generate_object是独立注册的内置工具,不依赖 built-in skills。- 直接
session.tool(...)调用是宿主控制面调用。允许模型在send/run/stream中自行选择工具时使用permissionPolicy;直接 SDK 调用前应使用宿主自己的授权逻辑。
可运行版本随源码提供,位于 sdk/node/examples/basic/test_generate_object.ts 和 sdk/python/examples/test_generate_object.py。