聊聊langchain4j的Agent

本文主要研究一下langchain4j的Agent

示例

CustomerSupportAgent

customer-support-agent-example/src/main/java/dev/langchain4j/example/CustomerSupportAgent.java

@AiService
public interface CustomerSupportAgent {

    @SystemMessage("""
            Your name is Roger, you are a customer support agent of a car rental company named 'Miles of Smiles'.
            You are friendly, polite and concise.
            
            Rules that you must obey:
            
            1. Before getting the booking details or canceling the booking,
            you must make sure you know the customer's first name, last name, and booking number.
            
            2. When asked to cancel the booking, first make sure it exists, then ask for an explicit confirmation.
            After cancelling the booking, always say "We hope to welcome you back again soon".
            
            3. You should answer only questions related to the business of Miles of Smiles.
            When asked about something not relevant to the company business,
            apologize and say that you cannot help with that.
            
            Today is {{current_date}}.
            """)
    Result<String> answer(@MemoryId String memoryId, @UserMessage String userMessage);
}

CustomerSupportAgent定义了SystemMessage、memoryId、userMessage

CustomerSupportAgentIT

customer-support-agent-example/src/test/java/dev/langchain4j/example/CustomerSupportAgentIT.java

    @Test
    void should_provide_booking_details_for_existing_booking() {

        // given
        String userMessage = "Hi, I am %s %s. When does my booking %s start?"
                .formatted(CUSTOMER_NAME, CUSTOMER_SURNAME, BOOKING_NUMBER);

        // when
        Result<String> result = agent.answer(memoryId, userMessage);
        String answer = result.content();

        // then
        assertThat(answer)
                .containsIgnoringCase(getDayFrom(BOOKING_BEGIN_DATE))
                .containsIgnoringCase(getMonthFrom(BOOKING_BEGIN_DATE))
                .containsIgnoringCase(getYearFrom(BOOKING_BEGIN_DATE));

        assertThat(result).onlyToolWasExecuted("getBookingDetails");
        verify(bookingService).getBookingDetails(BOOKING_NUMBER, CUSTOMER_NAME, CUSTOMER_SURNAME);
        verifyNoMoreInteractions(bookingService);

        TokenUsage tokenUsage = result.tokenUsage();
        assertThat(tokenUsage.inputTokenCount()).isLessThan(1000);
        assertThat(tokenUsage.outputTokenCount()).isLessThan(200);

        with(judgeModel).assertThat(answer)
                .satisfies("mentions that booking starts on %s".formatted(BOOKING_BEGIN_DATE));
    }

    @Test
    void should_not_provide_booking_details_when_booking_does_not_exist() {

        // given
        String invalidBookingNumber = "54321";
        String userMessage = "Hi, I am %s %s. When does my booking %s start?"
                .formatted(CUSTOMER_NAME, CUSTOMER_SURNAME, invalidBookingNumber);

        // when
        Result<String> result = agent.answer(memoryId, userMessage);
        String answer = result.content();

        // then
        assertThat(answer)
                .doesNotContainIgnoringCase(getDayFrom(BOOKING_BEGIN_DATE))
                .doesNotContainIgnoringCase(getMonthFrom(BOOKING_BEGIN_DATE))
                .doesNotContainIgnoringCase(getYearFrom(BOOKING_BEGIN_DATE));

        assertThat(result).onlyToolWasExecuted("getBookingDetails");
        verify(bookingService).getBookingDetails(invalidBookingNumber, CUSTOMER_NAME, CUSTOMER_SURNAME);
        verifyNoMoreInteractions(bookingService);

        with(judgeModel).assertThat(answer).satisfies(
                "mentions that booking cannot be found",
                "does not mention any dates"
        );
    }

    @Test
    void should_not_provide_booking_details_when_not_enough_data_is_provided() {

        // given
        String userMessage = "When does my booking %s start?".formatted(BOOKING_NUMBER); // name and surname are not provided

        // when
        Result<String> result = agent.answer(memoryId, userMessage);
        String answer = result.content();

        // then
        assertThat(answer)
                .doesNotContainIgnoringCase(getDayFrom(BOOKING_BEGIN_DATE))
                .doesNotContainIgnoringCase(getMonthFrom(BOOKING_BEGIN_DATE))
                .doesNotContainIgnoringCase(getYearFrom(BOOKING_BEGIN_DATE));

        assertThat(result).noToolsWereExecuted();

        with(judgeModel).assertThat(answer).satisfies(
                "asks user to provide their name and surname",
                "does not mention any dates"
        );
    }


    // cancelling booking

    @Test
    void should_cancel_booking() {

        // given
        String userMessage = "Cancel my booking %s. My name is %s %s."
                .formatted(BOOKING_NUMBER, CUSTOMER_NAME, CUSTOMER_SURNAME);

        // when
        Result<String> result = agent.answer(memoryId, userMessage);

        // then
        assertThat(result).onlyToolWasExecuted("getBookingDetails");
        verify(bookingService).getBookingDetails(BOOKING_NUMBER, CUSTOMER_NAME, CUSTOMER_SURNAME);
        verifyNoMoreInteractions(bookingService);

        with(judgeModel).assertThat(result.content())
                .satisfies("is asking for the confirmation to cancel the booking");

        // when
        Result<String> result2 = agent.answer(memoryId, "yes, cancel it");

        // then
        assertThat(result2.content()).containsIgnoringCase("We hope to welcome you back again soon");

        assertThat(result2).onlyToolWasExecuted("cancelBooking");
        verify(bookingService).cancelBooking(BOOKING_NUMBER, CUSTOMER_NAME, CUSTOMER_SURNAME);
        verifyNoMoreInteractions(bookingService);
    }

小结

Agent这个词比较宽泛,而且有很多不同的定义,通常基本的agentic的功能可以基于high-level的AI Service和Tool来构建,如果还需要更灵活的设置,则可以基于low-level的ChatLanguageModel、ToolSpecification以及ChatMemory APIs来构建。langchain4j目前暂不支持类似AutoGen或CrewAI中用于构建多智能体系统的"Agent"高级抽象功能,如果需要则可以基于low-level的API去构建。

doc

### langchain4j Agent 的实际应用案例与教程 Langchain4j 是一个用于构建基于大模型的应用程序的 Java 库,其核心功能之一是通过 **Agent** 来实现复杂的任务自动化处理。以下是关于如何使用 Langchain4j 中的 Agent 进行实战开发的具体说明。 #### 1. Quarkus 集成 Langchain4j Quarkus 提供了一个扩展模块 `quarkus-langchain4j`[^1],允许开发者轻松集成 Langchain4j 功能到他们的应用程序中。此扩展支持快速配置和初始化 Langchain4j 所需的各种组件,包括 Agents 和 Tools。 - 安装依赖项: ```xml <dependency> <groupId>io.quarkiverse.langchain4j</groupId> <artifactId>quarkus-langchain4j</artifactId> <version>0.9.0</version> </dependency> ``` - 初始化 Agent 并绑定工具链: ```java import io.quarkiverse.langchain4j.agent.Agent; import io.quarkiverse.langchain4j.tool.Tool; public class MyApplication { public static void main(String[] args) { Tool tool = new CustomTool(); // 自定义工具类 Agent agent = Agent.builder() .addTool(tool) .build(); String result = agent.run("请帮我完成某个复杂任务"); System.out.println(result); } } ``` #### 2. Spring Boot 集成 Langchain4j Spring Boot 社区提供了详细的文档来指导用户如何将 Langchain4j 整合到现有的 Spring Boot 项目中[^2]。这种集成方式非常适合那些已经熟悉 Spring 生态系统的开发者。 - 添加 Maven 或 Gradle 依赖: ```xml <dependency> <groupId>com.github.hankcs</groupId> <artifactId>langchain4j-spring-boot-starter</artifactId> <version>0.8.0</version> </dependency> ``` - 创建自定义 Controller 调用 Agent: ```java @RestController @RequestMapping("/api/agent") public class AgentController { @Autowired private AgentService agentService; // 假设有一个服务层封装了 Agent 的逻辑 @PostMapping("/execute") public ResponseEntity<String> executeTask(@RequestBody Map<String, String> request) { String taskDescription = request.get("task"); String response = agentService.execute(taskDescription); return ResponseEntity.ok(response); } } ``` #### 3. ReAct 思维框架的理解与实践 为了更好地理解 Agent 如何决策并调用不同的工具或子代理,可以深入研究 ReAct 框架的概念[^3]。ReAct 将行动分为两部分:“思考”阶段用来分析当前状态以及下一步应该做什么;“执行”阶段则真正操作数据或者触发其他动作。 - 示例代码展示简单的 ReAct 流程: ```java // 假设有两个工具 A 和 B List<Tool> tools = Arrays.asList(new ToolA(), new ToolB()); ReactFramework reactFramework = ReactFramework.builder() .setTools(tools) .build(); String observation = ""; while (!reactFramework.isFinished()) { Thought thought = reactFramework.think(observation); // 获取下一个想法 Action action = reactFramework.act(thought); // 根据想法采取行动 observation = performAction(action); // 执行具体行为获取观察结果 } private String performAction(Action action) { switch (action.getType()) { case SEARCH: return searchDatabase(action.getInput()); case CALL_API: return callExternalApi(action.getUrl()); default: throw new UnsupportedOperationException("未知的操作类型!"); } } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值