Langchain4j实现多agent协作。
1、引入依赖
<!-- 多智能体支持 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-agentic</artifactId>
<version>1.10.0-beta18</version>
</dependency>
2、创建一个写笑话的agent
package cn.lovecto.yuen.agents.agent;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
public interface JokeWriter {
/**
* <pre>
* 1、@UserMessage:写的是系统Prompt模板
* (1)限制:不超过3句话
* (2)要求:只返回笑话内容本身
* 2、@V("topic"):把上下文中的topic变量注入到{{topic}}占位符中
* 3、@Agent:告诉Langchain4j,generateJoke是一个Agent方法
* </pre
* @param topic
* @return
*/
@UserMessage("你是一名富有创造力的笑话作者。请围绕给定的主题创作一个不超过 3 句话的笑话草稿。" +
"只返回笑话内容本身,不要包含任何解释或其他文字。主题是:{{topic}}。")
@Agent(description = "根据给定主题生成一个笑话")
String generateJoke(@V("topic") String topic);
}
3、创建一个修改笑话的agent
package cn.lovecto.yuen.agents.agent;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
public interface JockEditor {
/**
* <pre>
* 1、接收2个变量
* (1)joke:上一阶段创作的笑话
* (2)audience: 目标读者(例如"女生","男生","学生"等)
* 2、Prompt中的约束
* (1)输出长度:小于3句
* (2)风格要求:生动好笑、有吸引力、通俗易懂
* (3)不要解释,只给结果文本
* </pre>
* @param joke
* @param audience
* @return
*/
@UserMessage(" 你是一名专业的笑话编辑。请将下面的笑话改写得更适合目标读者:{{audience}}。" +
"笑话长度请控制在 3 句话以内,要生动好笑、有吸引力,并且通俗易懂。" +
"只返回改写后的笑话内容,不要包含任何解释或多余文字。原始笑话如下:{{joke}}")
@Agent(description = "根据目标读者对故事进行润色与改写")
String editJoke(@V("joke") String joke,
@V("audience") String audience);
}
4、多agent配置类
package cn.lovecto.yuen.agents.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.lovecto.yuen.agents.agent.JockEditor;
import cn.lovecto.yuen.agents.agent.JokeWriter;
import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.agentic.UntypedAgent;
import dev.langchain4j.model.openai.OpenAiChatModel;
@Configuration
public class AgentsConfig {
@Autowired
private OpenAiChatModel chatModel;
/**
* 笑话创作 Agent,输出写到 agenitc scope 的 "joke" key
*
* @return
*/
@Bean
public JokeWriter jokeWriter() {
return AgenticServices.agentBuilder(JokeWriter.class)
.chatModel(chatModel)
.outputKey("joke")
.build();
}
/**
* 笑话修改 Agent,最终结果写到 "modifiedJoke"
*
* @return
*/
@Bean
public JockEditor jockEditor() {
return AgenticServices.agentBuilder(JockEditor.class)
.chatModel(chatModel)
.outputKey("modifiedJoke")
.build();
}
/**
* 多agent顺序执行
*
* @param jokeWriter 根据topic生成 joke 初稿
* @param jockEditor 根据audience 和 joke 初稿,修改后产出 modifiedJoke
* @return
*/
@Bean
public UntypedAgent jokePipeline(JokeWriter jokeWriter, JockEditor jockEditor) {
return AgenticServices.sequenceBuilder()
.subAgents(jokeWriter, jockEditor)
.outputKey("modifiedJoke")
.build();
}
}
5、对话入口
package cn.lovecto.yuen.agents.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.annotation.SaIgnore;
import dev.langchain4j.agentic.UntypedAgent;
@SaIgnore
@RestController
public class ChartController {
@Autowired
private UntypedAgent agent;
@GetMapping("/joke")
public String joke(String topic, String audience) {
return (String)agent.invoke(Map.of("topic", topic, "audience", audience));
}
}
6、调用实例
浏览器输入:
http://192.168.2.131:9999/joke?topic=%E4%B8%8A%E7%8F%AD&audience=%E7%A8%8B%E5%BA%8F%E5%91%98
如图:

7、调用日志如下
2026-01-12T11:55:20.082+08:00 INFO 37844 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP request:
- method: POST
- url: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
- headers: [Authorization: Beare...97], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "qwen3-max",
"messages" : [ {
"role" : "user",
"content" : "你是一名富有创造力的笑话作者。请围绕给定的主题创作一个不超过 3 句话的笑话草稿。只返回笑话内容本身,不要包含任何解释或其他文字。主题是:上班。"
} ],
"stream" : false
}
2026-01-12T11:55:23.073+08:00 INFO 37844 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP response:
- status code: 200
- headers: [vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding], [x-request-id: 0f161a6d-ad49-9638-bf1d-899e10083c14], [x-dashscope-call-gateway: true], [content-type: application/json], [content-length: 573], [req-cost-time: 2767], [req-arrive-time: 1768190117311], [resp-start-time: 1768190120078], [x-envoy-upstream-service-time: 2766], [date: Mon, 12 Jan 2026 03:55:19 GMT], [server: istio-envoy]
- body: {"choices":[{"finish_reason":"stop","index":0,"message":{"content":"闹钟响了,我按掉它继续睡——毕竟梦里我已经打卡上班了。 \n老板问我为什么迟到,我说:“在梦里加班太投入,现实里起不来。” \n他点点头:“那你今晚梦里记得把周报写了。”","role":"assistant"}}],"created":1768190117,"id":"chatcmpl-0f161a6d-ad49-9638-bf1d-899e10083c14","model":"qwen3-max","object":"chat.completion","usage":{"completion_tokens":54,"prompt_tokens":52,"prompt_tokens_details":{"cached_tokens":0},"total_tokens":106}}
2026-01-12T11:55:23.075+08:00 INFO 37844 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP request:
- method: POST
- url: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
- headers: [Authorization: Beare...97], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "qwen3-max",
"messages" : [ {
"role" : "user",
"content" : " 你是一名专业的笑话编辑。请将下面的笑话改写得更适合目标读者:程序员。笑话长度请控制在 3 句话以内,要生动好笑、有吸引力,并且通俗易懂。只返回改写后的笑话内容,不要包含任何解释或多余文字。原始笑话如下:闹钟响了,我按掉它继续睡——毕竟梦里我已经打卡上班了。 \n老板问我为什么迟到,我说:“在梦里加班太投入,现实里起不来。” \n他点点头:“那你今晚梦里记得把周报写了。”"
} ],
"stream" : false
}
2026-01-12T11:55:26.004+08:00 INFO 37844 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP response:
- status code: 200
- headers: [vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding], [x-request-id: 66863539-8a70-991f-8eb2-938f77c92bb2], [x-dashscope-call-gateway: true], [content-type: application/json], [content-length: 582], [req-cost-time: 2884], [req-arrive-time: 1768190120124], [resp-start-time: 1768190123009], [x-envoy-upstream-service-time: 2882], [date: Mon, 12 Jan 2026 03:55:22 GMT], [server: istio-envoy]
- body: {"choices":[{"finish_reason":"stop","index":0,"message":{"content":"闹钟响了,我按掉继续睡——毕竟梦里我已经 push 代码到主干了。 \n老板问我为啥迟到,我说:“在梦里 debug 太投入,现实起不来。” \n他点点头:“那你今晚梦里记得把周报 merge 进去。”","role":"assistant"}}],"created":1768190120,"id":"chatcmpl-66863539-8a70-991f-8eb2-938f77c92bb2","model":"qwen3-max","object":"chat.completion","usage":{"completion_tokens":60,"prompt_tokens":128,"prompt_tokens_details":{"cached_tokens":0},"total_tokens":188}}
8、配置
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: sk-xxxxxx697
model-name: qwen3-max
log-requests: true
log-responses: true
base-url为阿里白炼,自己换base-url、api-key,或者用本地的部署的大模型。
LoveCTO

