Spring AI Structured-Output源码分析

Spring AI Structured-Output源码分析

  • 在 Spring AI 中,StructuredOutputConverter(常用的实现类是 BeanOutputConverter)的核心作用是将大模型的非结构化文本输出 转换为 Java 的结构化对象(POJO)
  • StructuredOutputConverter extends Converter<String, T>, FormatProvider
    • FormatProvider:负责将你 Java Bean 的 JSON Schema
    • Converter:负责将模型返回的字符串 通过 Jackson 反序列化转换为你的Java Bean
  • 其实结构化对象本质实现原理也是基于:JSON 解析器 + Prompt 工程 + 结果解析 机制

实现思考&源码分析

如何告知大模型需要转换格式?

  • 原理

StructuredOutputConverter 接口有一个方法 getFormat()。当你调用这个方法时,它会生成一段自然语言的指令 ,这段指令中包含了你 Java Bean 的 JSON Schema。你需要手动或自动将这段指令拼接到发给 AI 的 Prompt 中。

  • 源码
    • 将你 Java Bean 的格式为 JSON Schema,并放到请求上下文中
java 复制代码
@GetMapping("/chat-format")
public BeanEntity simpleChatFormat(@RequestParam(value = "query", defaultValue = "写诗歌") String query) {
  return chatClient.prompt(query).call()
    .format(converter.getFormat()) // 显式注入格式指令
    .entity(BeanEntity.class) // 这里内部会自动调用 format()
    ;
}

//org.springframework.ai.chat.client.DefaultChatClient.DefaultCallResponseSpec#entity(java.lang.Class<T>)
public <T> T entity(Class<T> type) {
  var outputConverter = new BeanOutputConverter<>(type);
  return doSingleWithBeanOutputConverter(outputConverter);
}

@Nullable
private <T> T doSingleWithBeanOutputConverter(StructuredOutputConverter<T> outputConverter) {
  //1. 根据泛型 T 的类型,生成标准的 JSON Schema:详见BeanOutputConverter.getFormat()
  //2. 将生成的生成标准的 JSON Schema放入到上下文中,key为:"spring.ai.chat.client.output.format"
  var chatResponse = doGetObservableChatClientResponse(this.request, outputConverter.getFormat())
    .chatResponse();
  var stringResponse = getContentFromChatResponse(chatResponse);
  //3.大模型返回的字符串反序列化为JavaBean,详见:BeanOutputConverter.convert()
  return outputConverter.convert(stringResponse);
}
  • JSON Schema添加到Prompt提示词中,在Advisor链中最后一个ChatModelCallAdvisor实现
java 复制代码
@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
  //1.增强格式指令,即提示词增强
  ChatClientRequest formattedChatClientRequest = augmentWithFormatInstructions(chatClientRequest);
  ChatResponse chatResponse = this.chatModel.call(formattedChatClientRequest.prompt());
  return ChatClientResponse.builder()
    .chatResponse(chatResponse)
    .context(Map.copyOf(formattedChatClientRequest.context()))
    .build();
}

private static ChatClientRequest augmentWithFormatInstructions(ChatClientRequest chatClientRequest) {
  //2.从请求上下文获取JSON Schema格式指令
  String outputFormat = (String) chatClientRequest.context().get(ChatClientAttributes.OUTPUT_FORMAT.getKey());
	//3.其实逻辑很简单:用户文本 + 换行 + JSON Schema格式指令
  Prompt augmentedPrompt = chatClientRequest.prompt()
    .augmentUserMessage(userMessage -> userMessage.mutate()
                        .text(userMessage.getText() + System.lineSeparator() + outputFormat)
                        .build());
  return ChatClientRequest.builder()
    .prompt(augmentedPrompt)
    .context(Map.copyOf(chatClientRequest.context()))
    .build();
}

大模型返回结果后是如何转换为对应的实体?

  • 原理

转换发生在应用层(你的服务内部),而不是模型层。模型返回的仍然是 String(一段 JSON 文本),Spring AI 在接收到这段文本后,调用 convert() 方法将其反序列化,详见:BeanOutputConverter.convert()。

  • 源码
java 复制代码
public T convert(@NonNull String text) {
  try {
    // 1. 预处理:清洗文本
    // 大模型经常喜欢返回 ```json { ... } ```这种 Markdown 格式
    // 这里会去除首尾的 Markdown 标记,只保留纯 JSON 字符串
    text = this.textCleaner.clean(text);

    // 2. 反序列化
    // 使用 Jackson 的 ObjectMapper 将 JSON 字符串转为 Java 对象
    return (T) this.objectMapper.readValue(text, this.objectMapper.constructType(this.type));
  }
  catch (JsonProcessingException e) {
    throw new RuntimeException(e);
  }
}

注意事项

  • 如果你使用了 StructuredOutputConverter(或者 .entity() 方法),请不要在你的 User Prompt 中再手写任何关于格式(Format)的指令,避免提示词冲突,只关注业务内容即可。
相关推荐
wal13145206 小时前
OpenClaw v2026.4.8 发布:记忆系统重大升级 + 多项安全修复
人工智能·安全·openclaw
Deepoch6 小时前
VLA 端侧智能赋能:Deepoc 开发板重构除草机器人自主作业能力
人工智能·科技·机器人·具身模型·deepoc·除草
m0_372257026 小时前
bert和LLM训练的时候输入输出的格式是什么有什么区别
人工智能·深度学习·bert
han_hanker7 小时前
@Validated @Valid 用法
java·spring boot
紧固视界7 小时前
2026上海紧固件专业展,紧固件设备集中展示平台
大数据·人工智能·上海紧固件展·紧固件展·上海紧固件专业展
小CC吃豆子7 小时前
详细介绍一下静态分析工具 SonarQube
java
DevOpenClub7 小时前
全国三甲医院主体信息 API 接口
java·大数据·数据库
杨夏同学7 小时前
AI入门——如何计算神经网络的参数
人工智能·深度学习·神经网络
言慢行善7 小时前
SpringBoot中的注解介绍
java·spring boot·后端
好运的阿财7 小时前
大模型热切换功能完整实现指南
人工智能·python·程序人生·开源·ai编程