热爱技术,追求卓越
不断求索,精益求精

Langchain4j实现多agent协作

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

如图:

image

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,或者用本地的部署的大模型。

赞(0)
未经允许不得转载:LoveCTO » Langchain4j实现多agent协作

热爱技术 追求卓越 精益求精