为什么要使用"结构化输出"?
核心是让AI回复json格式的结果 ,便于我们按照实际业务需求进行解析。
虽然已经能够调用AI生成代码,但直接返回字符串的方式不便于后续解析 代码并保存为文件。因此我们需要将AI的输出转换为结构化的对象,利用LangChain4j的结构化输出特性可以轻松实现。
一、结构化输出【基本实现】
1. 创建AI回复的json格式结果(即model数据模型)
java
@Data
public class HtmlCodeResult {
private String htmlCode;
private String description;
}
2. 修改AI服务接口,让方法返回结构化对象
java
/**
* 生成 HTML 代码
*
* @param userMessage 用户消息
* @return 生成的代码结果
*/
@SystemMessage(fromResource = "prompt/codegen-html-system-prompt.txt")// 系统提示词
HtmlCodeResult generateHtmlCode(String userMessage);
3. 使用AiServices.create创建AI服务接口generateHtmlCode的proxy代理对象(同时传入ChatModel与模型交互客户端,包含base_url、api_key、mode-name等信息)
本质是利用工厂模式使用create方法创建统一的代理对象。
java
@Configuration
public class AiCodeGeneratorServiceFactory {
@Resource
private ChatModel chatModel;
@Bean
public AiCodeGeneratorService aiCodeGeneratorService() {
return AiServices.create(AiCodeGeneratorService.class, chatModel);
}
}
4. 编写单元测试方法进行验证
java
@SpringBootTest
class AiCodeGeneratorServiceTest {
@Resource
private AiCodeGeneratorService aiCodeGeneratorService;
@Test
void generateHtmlCode() {
HtmlCodeResult result = aiCodeGeneratorService.generateHtmlCode("做个程序员algo的计算器小工具,只实现加法计算逻辑,不要写复杂代码,禁止扩展功能");
Assertions.assertNotNull(result);
}
}
可以看到,输入时userMessage向模式传递了结构化输出的json格式:

而输出时,结果也遵循我们的json输出格式:

如此,我们可以实现基本的结构化输出需求。
二、OutputStruct的优化技巧(重点json_schema,其它了解即可)
参考文档:【结构化输出 - 千问AI平台】【JSON Output | DeepSeek API Docs】
1. 设置max_tokens(看需求进行设置,一般禁用即可)
设置原则:
若模型输出发现缺少内容,被截断部分,可以调大max_tokens;
若模型当前情况输出没有异常,禁用max_tokens,防止消耗过多token造成成本增加。
设置一下输出长度,防止AI生成的json被半路截断,AI返回给我们的内容显示不全。
如qwen3.8-flash:【Qwen3.8-Flash - 千问AI平台】

最大输出是131k,那我们的max_tokens最大值为131 * 1024 = 134144
bash
langchain4j:
open-ai:
chat-model:
max-tokens: 134144 # 1024 * 131
2. 使用json_object使模型返回json格式响应内容
参考文档:【JSON Output | DeepSeek API Docs】
yml设置:(基于前面的基本实现,我们只需要添加yml中关于json_object的配置即可)
bash
langchain4j:
open-ai:
chat-model:
strict-json-schema: true
response-format: json_object
用户传入的 system 或 user prompt 中必须含有 json 字样 ,并给出希望模型输出的 JSON 格式的样例,以指导模型来输出合法 JSON:

效果:
向模型输入:

模型输出:


3. 使用json_schema使模型严格返回json格式⭐(必须掌握)
参考文档 【OpenAI | LangChain4j】【结构化输出 - 千问AI平台】
JSON Schema 模式下,提示词无需包含 "JSON" 关键词。
要求: system_prompt中一定要包含json字样的提示。缺点:AI回复的json格式可能不统一,若需要传递给下游服务器,可以重试或者使AI生成新的json格式。但建议生产环境使用严格的json_schema格式传递给下游。
LangChain4j-OpenAI中设置json_schema:(OpenAIChatModel的builder对象属性对应着我们yml中关于chatModel的配置属性)

使用步骤如下:
1. 设置yml:(开启严格模式的json_schema)
bash
langchain4j:
open-ai:
chat-model:
strict-json-schema: true # 强制严格遵循 schema 定义
response-format: json_schema # 开启 json_schema 模式
2. 定义输出POJO(基本实现中已定义)
java
@Data
public class HtmlCodeResult {
private String htmlCode;
private String description;
}
3. 定义AI服务接口,【模型输出结果格式】指定json_schema (已定义)
java
/**
* 生成 HTML 代码
*
* @param userMessage 用户消息
* @return 生成的代码结果
*/
@SystemMessage(fromResource = "prompt/codegen-html-system-prompt.txt")// 系统提示词
HtmlCodeResult generateHtmlCode(String userMessage);
效果如下:
向模式输入(可以看到json_schema形式标准字段):

模型输出:(包含required必须字段)


4. 添加POJO的字段描述⭐(为结果类和属性添加详细的描述信息,便于Al理解)
参考文档【Structured Outputs | LangChain4j】
POJO添加@Description:
java
/**
* html代码的结构化输出json-schema
*/
@Description("生成 HTML 代码文件的结果\"")
@Data
public class HtmlCodeResult {
@Description("HTML代码")
private String htmlCode;
@Description("生成代码的描述")
private String description;
}
效果如下:
输入给模型:

模型输出:

5. 提示词优化
参考文档:【结构化输出 - 千问AI平台】
在系统提示词 中明确要求输出JSON格式,这样可以进一步提高成功率
要求:
system_prompt有json字眼,不区分大小写
给出可供模型参考的json返回格式样例,供模型学习(参考示例可以给出多场景你期望的json返回格式)
system_prompt演示:
bash
请从用户输入中提取个人信息并按照指定的JSON Schema格式输出:
【输出格式要求】
输出必须严格遵循以下JSON结构:
{
"info": {
"name": "字符串类型,必需字段,用户姓名",
"age": "字符串类型,必需字段,格式为'数字+岁',例如'25岁'",
"email": "字符串类型,必需字段,标准邮箱格式,例如'user@example.com'"
},
"hobby": ["字符串数组类型,非必需字段,包含用户的所有爱好,如未提及则完全不输出此字段"]
}
【字段提取规则】
1. name: 从文本中识别用户姓名,必需提取
2. age: 识别年龄信息,转换为"数字+岁"格式,必需提取
3. email: 识别邮箱地址,保持原始格式,必需提取
4. hobby: 识别用户爱好,以字符串数组形式输出,如未提及爱好信息则完全省略hobby字段
【参考示例】
示例1(包含爱好):
Q:我叫张三,今年25岁,邮箱是zhangsan@example.com,爱好是唱歌
A:{"info":{"name":"张三","age":"25岁","email":"zhangsan@example.com"},"hobby":["唱歌"]}
示例2(包含多个爱好):
Q:我叫李四,今年30岁,邮箱是lisi@example.com,平时喜欢跳舞和游泳
A:{"info":{"name":"李四","age":"30岁","email":"lisi@example.com"},"hobby":["跳舞","游泳"]}
示例3(不包含爱好):
Q:我叫赵六,今年28岁,我的邮箱是zhaoliu@example.com
A:{"info":{"name":"赵六","age":"28岁","email":"zhaoliu@example.com"}}
示例4(不包含爱好):
Q:我是孙七,35岁,邮箱sunqi@example.com
A:{"info":{"name":"孙七","age":"35岁","email":"sunqi@example.com"}}
请严格按照上述格式和规则提取信息并输出JSON。如果用户未提及爱好,则不要在输出中包含hobby字段。
6. 生产环境使用建议
参考文档【结构化输出 - 千问AI平台】
建议:
禁用max_tokens
使用json_schema
使用 SDK 辅助生成 Schema,避免手动维护出错