1. 基础类型
以Boolean为例,在Agent中可以用于判定用于的内容的2个分支,不同分支走不同的逻辑
可以接受一些对象,布尔值等
下面也是一种简单的Agent
-
Boolean类型的返回
import lombok.AllArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@AllArgsConstructor
@RestController
public class ChatClientOutputController {
private final DeepSeekChatModel deepSeekChatModel;
@RequestMapping(value = "/promptOutput", produces = "text/stream;charset=UTF-8")
public String promptOutput() {
ChatClient chatClient = ChatClient.builder(deepSeekChatModel)
//.defaultSystem(prompt)
.build();
Boolean isComplain = chatClient.prompt().system("""
请判断用户信息是否表达了投诉意图?
只能用 true 或 false 回答,不要输出多余内容
""")
.user("你们商家的快递迟迟不到,我要退货!")
.call()
.entity(Boolean.class);
if (Boolean.TRUE.equals(isComplain)) {
System.out.println("用户是投诉,转接人工客服!");
} else {
System.out.println("用户不是投诉,自动流转客服机器人");
}
return "" + isComplain;
}
}
2. POJO类型
用购物APP应该见过复制一个地址,自动为你填入每个输入框,这种例子用大模型可以轻松完成!
@RequestMapping(value = "/promptOutputPojo", produces = "text/stream;charset=UTF-8")
public void promptOutputPojo() {
ChatClient chatClient = ChatClient.builder(deepSeekChatModel)
//.defaultSystem(prompt)
.build();
Address address = chatClient.prompt().system("""
请从下面这条文本中提取收货信息
""")
.user("收货人:张三,电话13199999999,地址:上海市松江区人民路枫林郡小区2号楼1单元801室")
.call()
.entity(Address.class);
System.out.println(address);
}
/***
* 内部类
*/
public record Address(String name, // 收件人姓名
String phone, // 联系电话
String province, // 省
String city, // 市
String district, // 区/县
String detail) // 详细地址
{ }
注意:对象中的属性名不能乱定义,需要能被大模型理解
3. 原理
核心:结构化输出转换器 StructuredOutputConverter
使用通用补全 API 从大型语言模型(LLMs)生成结构化输出时,需要对输入和输出进行精细处理。其中,结构化输出转换器在调用 LLM 之前和之后都起着关键作用,确保最终输出符合预期的结构。
在调用 LLM 之前,转换器会将格式说明附加到提示词中,为模型提供明确的指导,说明所需的输出结构。这些说明就像一份蓝图,引导模型生成符合特定格式的响应。
在调用 LLM 之后,转换器会将模型输出的文本转换为结构化类型的实例。这个转换过程包括解析原始文本输出,并将其映射为对应的结构化数据表示形式,例如 JSON、XML 或领域特定的数据结构。
底层呢还是要告诉大模型,输出结果的格式的,但是ChatClient默认给做了封装,不需要我们显示地去给大模型指示返回格式。下面是原始的处理。BeanOutputConverter.getFormat()会返回大模型的格式转换指令。
通过核心的转换器,自动提供了转换指令。告诉大模型应该提取哪些内容,用什么样的格式进行响应。
public record Address(String name, // 收件人姓名
String phone, // 联系电话
String province, // 省
String city, // 市
String district, // 区/县
String detail) // 详细地址
{
}
@RequestMapping(value = "/promptOutputPojoRaw", produces = "text/stream;charset=UTF-8")
public void promptOutputPojoRaw() {
ChatClient chatClient = ChatClient.builder(deepSeekChatModel)
//.defaultSystem(prompt)
.build();
BeanOutputConverter<Address> beanOutputConverter = new BeanOutputConverter<>(Address.class);
String format = beanOutputConverter.getFormat();
PromptTemplate promptTemplate = PromptTemplate.builder().template("""
请从下面的文本中提取收货信息
{format}
{text}
""").variables(Map.of("format", format, "text", "收货人:张三,电话13199999999,地址:上海市松江区人民路枫林郡小区2号楼1单元801室"))
.build();
ChatResponse response = deepSeekChatModel.call(promptTemplate.create());
Address address = beanOutputConverter.convert(response.getResult().getOutput().getText());
System.out.println(address);
}
debug format的内容
Your response should be in JSON format.
Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.
Do not include markdown code blocks in your response.
Remove the ```json markdown from the output.
Here is the JSON Schema instance your output must adhere to:
```{
"$schema" : "https://json-schema.org/draft/2020-12/schema",
"type" : "object",
"properties" : {
"city" : {
"type" : "string"
},
"detail" : {
"type" : "string"
},
"district" : {
"type" : "string"
},
"name" : {
"type" : "string"
},
"phone" : {
"type" : "string"
},
"province" : {
"type" : "string"
}
},
"additionalProperties" : false
}```