---
title: "chat - 模型的结构化输出"
---



结构化输出（Structured Output），是指让大模型按给定的数据结构（JSON Schema）返回结果，再反序列化为 Java 对象。适合信息提取、数据入库、结果校验等场景。

Solon AI 的结构化输出有三个特点：

* **类型即契约**：直接用一个 Java Bean 声明输出结构，框架自动生成 JSON Schema
* **接口标准无关**：Schema 以指令方式注入提示语，不依赖模型的原生 json mode，任何模型都能用
* **容错提取**：响应消息自带容错的 JSON 提取与 `toBean` 一步转换


### 1、定义输出的 Java Bean

用普通的 Java 类 + `@Param` 注解即可（`@Param` 的描述、必填、默认值会并入生成的 Schema 字段）：

```java
public class ResumeInfo {
    @Param(description = "姓名", required = true)
    private String name;

    @Param(description = "年龄")
    private Integer age;

    @Param(description = "邮箱")
    private String email;

    @Param(description = "技能列表", defaultValue = "[]")
    private List<String> capabilities;

    // get set ...
}
```

### 2、三层 API：在哪里声明 outputSchema

结构化输出的 schema 可以在三个层面声明，作用范围从大到小：

* **模型级**：构建 ChatModel 时指定，对该模型的所有请求生效

```java
ChatModel chatModel = ChatModel.of("https://api.openai.com/v1/chat/completions")
        .apiKey(apiKey)
        .model("gpt-4o")
        .outputSchema(ResumeInfo.class) //模型级
        .build();
```

* **请求级**：在某次请求的选项里指定，只影响本次请求（两种写法均可，Consumer 形式更简洁）

```java
AssistantMessage message = chatModel
        .prompt("请从下面的简历文本中提取关键信息：..." + resumeText)
        .options(o -> o.outputSchema(ResumeInfo.class)) //请求级
        .call()
        .getMessage();
```

* **智能体级**：构建 Agent 时指定（需引入 `solon-ai-agent` 依赖）

```java
ReActAgent resumeAgent = ReActAgent.of(chatModel)
        .name("ResumeExtractor")
        .instruction("请从用户提供的文本中提取关键信息")
        .outputSchema(ResumeInfo.class) //智能体级
        .outputKey("extracted_resume")  //结果同时写入会话上下文
        .build();
```

如果只有 schema 字符串（比如来自外部配置），也可以直接用 `outputSchema(String)` 重载。

### 3、结果提取与反序列化

响应消息 `AssistantMessage` 提供了三个层次的取值能力：

```java
AssistantMessage message = chatModel.prompt("...").call().getMessage();

//a) 原始内容（含思维链时也会包含）
String rawContent = message.getContent();

//b) 容错提取的 JSON 片段（自动剥离 markdown 围栏与前后缀文本）
String json = message.getJsonContent();

//c) 一步转为 Java Bean
ResumeInfo info = message.toBean(ResumeInfo.class);
```

其中 `getJsonContent()` 会定位首个 `{`（或 `[`）与末个 `}`（或 `]`）之间的内容，模型偶尔加上 ` ```json ` 围栏或说明文字也不会失败。

### 4、传输机制：为什么不依赖模型的 json mode

Solon AI 在组装请求时，如果发现选项里有 outputSchema，会把它包装成指令片段追加到提示语里：

```
<output_schema>
{...生成的 JSON Schema...}
</output_schema>
```

这个动作由 `ChatDialect.prepareOutputSchemaInstruction(...)` 完成，属于接口标准（方言）层的能力。因此：

* 不需要模型支持原生的 `response_format: json_schema`，Ollama、OpenAI、DashScope、Gemini、Anthropic 等都能用
* 有特殊要求的模型，可通过定制方言覆写该行为

另外，`String`、数字、布尔、枚举、日期等简单类型会被自动忽略 schema 生成（它们不需要结构约束）。

### 5、智能体的结构化输出与下游联动

智能体场景下，`outputKey` 会把提取结果写入会话上下文，供工作流的下游节点消费：

```java
AgentSession session = InMemoryAgentSession.of("demo");

AssistantMessage message = resumeAgent
        .prompt(Prompt.of(resumeText))
        .session(session)
        .call()
        .getMessage();

//从会话上下文取结构化结果
String extracted = (String) session.getContext().get("extracted_resume");
```

### 6、生产化建议

* 用 `temperature(0.1)` 抑制格式漂移；解析失败可配合重试使用（Agent 有 `retryConfig(maxRetries, retryDelayMs)`）
* schema 只能约束"形状"，管不住"算术"——求和、统计之类的计算应放到 Java 里做
* 需要强校验的入库场景，建议在 `toBean` 之后再走一遍业务校验
