langchain4j 学习系列(6)-结构化输出(参数提取)
继续学习langchain4j,玩过dify的朋友想必对"参数提取器"这个节点很熟悉,示例:

参数提取器可以很方便的从“非结构的自然语言”中,提取出结构化的结果。

下面来看看langchain4j如何实现类似功能:
public static final String TEST_DATA = """
金庸(1924年3月10日—2018年10月30日),本名查良镛,浙江省海宁市人,祖籍江西省婺源县浙源乡凤山村 [10] [146-147],1948年移居香港。
当代武侠小说作家、新闻学家、企业家、政治评论家、社会活动家,被誉为“香港四大才子”之一,与古龙、梁羽生、温瑞安并称为“中国武侠小说四大宗师”。 [1-4]
1944年,考入重庆中央政治大学外交系。1946年秋,进入上海《大公报》任国际电讯翻译。1948年,毕业于上海东吴大学法学院,并被调往《大公报》香港分社 [5]。
1952年调入《新晚报》编辑副刊,并写出《绝代佳人》《兰花花》等电影剧本。1959年,金庸等人于香港创办《明报》 [6]。
1985年起,历任香港特别行政区基本法起草委员会委员、政治体制小组负责人之一,基本法咨询委员会执行委员会委员,以及香港特别行政区筹备委员会委员。
1994年,受聘北京大学名誉教授 [7]。
2000年,获得大紫荆勋章。2007年,出任香港中文大学文学院荣誉教授 [5]。
2009年9月,被聘为中国作协第七届全国委员会名誉副主席 [8];同年荣获2008影响世界华人终身成就奖 [9]。2010年,获得剑桥大学哲学博士学位 [2]。
"2018年10月30日,在香港逝世,享年94岁。
""";
@GetMapping(value = "/extract", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> extract() {
try {
Prompt prompt = PromptTemplate.from("请从以下生平介绍中,提取出该人物的基本信息,以json格式输出,参考格式:{{json_output_sample}} \n{{test_data}}")
.apply(Map.of("json_output_sample", "{\"name\":\"张三\",\"age\":10,\"birthDay\":\"2000-01-01\",\"isAlive\":false,\"deathDate\":\"2040-02-01\",\"degree\":\"本科\"}",
"test_data", TEST_DATA));
String text = ollamaChatModel.chat(prompt.toUserMessage()).aiMessage().text();
return ResponseEntity.ok(text);
} catch (Exception e) {
log.error("extract", e);
return ResponseEntity.ok("{\"error\":\"extract error: " + e.getMessage() + "\"}");
}
}
代码很简单,直接在prompt提示词里,告诉LLM怎么做就行,输出结果:

不过,这个输出结果是个string,还不能算是结构化的输出,可以再改进一下:
/**
* Person 记录类,用于表示一个人的基本信息
* 使用 Java record 类型实现,自动生成构造函数、getter 方法、equals()、hashCode() 和 toString() 方法
*
* @param name 人的姓名
* @param age 人的年龄
* @param birthDay 人的出生日期
* @param isAlive 人是否仍然活着
* @param deathDate 人的死亡日期(如果已故)
* @param degree 人的学位
*/
record Person(String name, int age, Date birthDay, boolean isAlive, Date deathDate, String degree) {
// 这是一个记录类声明,包含了表示个人基本信息的数据字段
// 所有字段都是 final 的,且自动生成对应的访问器方法
}
/**
* 人员信息提取接口
* 该接口定义了一个从生平介绍中提取人员信息的方法
*/
interface PersonExtractor {
/**
* 从生平介绍中提取人员主要信息
*
* @param biography 人员的生平介绍文本
* @return 包含提取信息的Person对象
*/
@SystemMessage("""
你的任务是从生平介绍中,提取出该人的主要信息:
name[姓名],age[年龄], birthDay[出生日期], isAlive[是否健在], deathDate[死亡日期(如果已逝世)], degree[最高学历]
""")
Person extractPerson(String biography);
}
/**
* 处理GET请求,提取人员信息并以JSON格式返回
*
* @return 返回包含提取的人员信息的ResponseEntity对象
*/
@GetMapping(value = "/extract2", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> extract2() {
try {
// 创建PersonExtractor实例,使用AiServices和ollamaChatModel
PersonExtractor personExtractor = AiServices.create(PersonExtractor.class, ollamaChatModel);
// 使用TEST_DATA调用extractPerson方法提取人员信息
Person person = personExtractor.extractPerson(TEST_DATA);
// 返回成功响应,包含提取的人员信息
return ResponseEntity.ok(person);
} catch (Exception e) {
// 捕获异常并记录错误日志
log.error("extract2", e);
// 发生异常时返回默认的Person对象
return ResponseEntity.ok(new Person("", -1, null, false, null, ""));
}
}
这里我们用抽象级别更高的AiService来创建指定的抽取器,一步到位的输出了对象实例

下面是终端打印的日志:
2025-12-08T19:34:44.508+08:00 INFO 9196 --- [langchain4j-study] [nio-8080-exec-8] d.l.http.client.log.LoggingHttpClient : HTTP request:
- method: POST
- url: http://localhost:11434/api/chat
- headers: [Content-Type: application/json]
- body: {
"model" : "deepseek-v3.1:671b-cloud",
"messages" : [ {
"role" : "system",
"content" : "你的任务是从生平介绍中,提取出该人的主要信息:\nname[姓名],age[年龄], birthDay[出生日期], isAlive[是否健在], deathDate[死亡日期(如果已逝世)], degree[最高学历]\n"
}, {
"role" : "user",
"content" : "金庸(1924年3月10日—2018年10月30日),本名查良镛,浙江省海宁市人,祖籍江西省婺源县浙源乡凤山村 [10] [146-147],1948年移居香港。\n当代武侠小说作家、新闻学家、企业家、政治评论家、社会活动家,被誉为“香港四大才子”之一,与古龙、梁羽生、温瑞安并称为“中国武侠小说四大宗师”。 [1-4]\n1944年,考入重庆中央政治大学外交系。1946年秋,进入上海《大公报》任国际电讯翻译。1948年,毕业于上海东吴大学法学院,并被调往《大公报》香港分社 [5]。\n1952年调入《新晚报》编辑副刊,并写出《绝代佳人》《兰花花》等电影剧本。1959年,金庸等人于香港创办《明报》 [6]。\n1985年起,历任香港特别行政区基本法起草委员会委员、政治体制小组负责人之一,基本法咨询委员会执行委员会委员,以及香港特别行政区筹备委员会委员。\n1994年,受聘北京大学名誉教授 [7]。\n2000年,获得大紫荆勋章。2007年,出任香港中文大学文学院荣誉教授 [5]。\n2009年9月,被聘为中国作协第七届全国委员会名誉副主席 [8];同年荣获2008影响世界华人终身成就奖 [9]。2010年,获得剑桥大学哲学博士学位 [2]。\n\"2018年10月30日,在香港逝世,享年94岁。\n\nYou must answer strictly in the following JSON format: {\n\"name\": (type: string),\n\"age\": (type: integer),\n\"birthDay\": (type: date string (2023-12-31)),\n\"isAlive\": (type: boolean),\n\"deathDate\": (type: date string (2023-12-31)),\n\"degree\": (type: string)\n}"
} ],
"options" : {
"stop" : [ ]
},
"stream" : false,
"tools" : [ ]
}
从user提示词中最后的“\n\nYou must answer strictly in the following JSON format: {\n\"name\": (type: string),\n\"age\": (type: integer),\n\"birthDay\": (type: date string (2023-12-31)),\n\"isAlive\": (type: boolean),\n\"deathDate\": (type: date string (2023-12-31)),\n\"degree\": (type: string)\n” 这段可以看出,langchain4j将Person类的信息,转换成了自描述的schema发给了LLM
作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
浙公网安备 33010602011771号