第六章langchain4j之Tools和prompt

📁langchain4j提示词(prompt)

创建子模块langchain4j-09chat-prompt

📦1.pom.xml配置文件

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.yumeko.stduy</groupId>
        <artifactId>langchain4j</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>langchain4j-09chat-prompt</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

⚙️2.application.properties配置文件

复制代码
server.port=9009
spring.application.name=langchain4j-09chat-prompt
# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

✏️3.Ai实体类

复制代码
import dev.langchain4j.model.input.structured.StructuredPrompt;
import lombok.Data;

@Data
@StructuredPrompt("根据中国{{legal}}法律,解答以下问题:{{question}}")
public class LawPrompt
{
    private String legal;
    private String question;
}

🔧4.service服务

复制代码
import com.yumeko.study.entities.LawPrompt;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface LawAssistant {
    //案例1 @SystemMessage+@UserMessage+@V
    @SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
            "输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")

    @UserMessage("请回答以下法律问题:{{question}},字数控制在{{length}}以内")
    String chat(@V("question") String question, @V("length") int length);


    //案例2 新建带着@StructuredPrompt的业务实体类,比如LawPrompt
    @SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
            "输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
    String chat(LawPrompt lawPrompt);
}

🤖5.AI模型配置类

复制代码
@Configuration
public class LLMConfig {
    @Bean
    public ChatModel chatModel() {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("qwen-api"))
                .modelName("qwen-long")
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }

    @Bean
    public LawAssistant lawAssistant(ChatModel chatModel) {
        return AiServices.create(LawAssistant.class, chatModel);
    }
}

🌐6.Web控制器

复制代码
import cn.hutool.core.date.DateUtil;
import com.yumeko.study.entities.LawPrompt;
import com.yumeko.study.service.LawAssistant;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@Slf4j
public class ChatPromptController {
    @Resource
    private LawAssistant lawAssistant;
    @Resource
    private ChatModel chatModel;

    // http://localhost:9009/chatprompt/test1
    @GetMapping(value = "/chatprompt/test1")
    public String test1() {
        String chat = lawAssistant.chat("什么是知识产权?", 2000);
        System.out.println(chat);

        String chat2 = lawAssistant.chat("什么是java?", 2000);
        System.out.println(chat2);

        String chat3 = lawAssistant.chat("介绍下西瓜和芒果", 2000);
        System.out.println(chat3);

        String chat4 = lawAssistant.chat("飞机发动机原理", 2000);
        System.out.println(chat4);

        return "success : " + DateUtil.now() + "<br> \n\n chat: " + chat + "<br> \n\n chat2: " + chat2;
    }

    /**
     * TRIPS协议(与贸易有关的知识产权协议):
     * 这是世界贸易组织(WTO)成员间的一个重要协议,
     * 它规定了最低标准的知识产权保护要求,并适用于所有WTO成员。
     *
     * @return
     */
    @GetMapping(value = "/chatprompt/test2")
    public String test2() {
        LawPrompt prompt = new LawPrompt();

        prompt.setLegal("知识产权");
        prompt.setQuestion("TRIPS协议?");

        String chat = lawAssistant.chat(prompt);

        System.out.println(chat);

        return "success : " + DateUtil.now() + "<br> \n\n chat: " + chat;
    }


    /**
     * @Description: 单个参数可以使用{{it}》"占位符或者"{{参数名}",如果为其他字符,系统不能自动识别会报错。
     * @Auther: zzyybs@126.com
     * http://localhost:9009/chatprompt/test3
     */
    @GetMapping(value = "/chatprompt/test3")
    public String test3() {
        // 看看源码,默认 PromptTemplate 构造使用 it 属性作为默认占位符

        /*String role = "外科医生";
        String question = "牙疼";*/

        String role = "财务会计";
        String question = "人民币大写";

        //1 构造PromptTemplate模板
        PromptTemplate template = PromptTemplate.from("你是一个{{it}}助手,{{question}}怎么办");
        //2 由PromptTemplate生成Prompt
        Prompt prompt = template.apply(Map.of("it", role, "question", question));
        //3 Prompt提示词变成UserMessage
        UserMessage userMessage = prompt.toUserMessage();
        //4 调用大模型
        ChatResponse chatResponse = chatModel.chat(userMessage);

        //4.1 后台打印
        System.out.println(chatResponse.aiMessage().text());
        //4.2 前台返回
        return "success : " + DateUtil.now() + "<br> \n\n chat: " + chatResponse.aiMessage().text();
    }
}

🧪7.测试接口

http://localhost:9009/chatprompt/test1

http://localhost:9009/chatprompt/test2

http://localhost:9009/chatprompt/test3


📁langchain4j工具类Tools

创建子模块langchain4j-11chat-functioncalling

📦1.pom.xml配置文件

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.yumeko.stduy</groupId>
        <artifactId>langchain4j</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>langchain4j-11chat-functioncalling</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <!--langchain4j-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <!--langchain4j-reactor-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>
        <!--httpclient5-->
        <dependency>
            <groupId>org.apache.httpcomponents.client5</groupId>
            <artifactId>httpclient5</artifactId>
            <version>5.5</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

⚙️2.application.properties配置文件

复制代码
server.port=9011
spring.application.name=langchain4j-11chat-functioncalling

🔧3.service服务

复制代码
public interface FunctionAssistant {
    //客户指令:出差住宿发票开票,
    // 开票信息:    公司名称xxx
    // 税号序列:    xx
    // 开票金额:    xxx.00元
    String chat(String message);
}

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class InvoiceHandler {

    @Tool("根据用户提交的开票信息进行开票")
    public String handle(@P("公司名称") String companyName,
                         @P("税号") String dutyNumber,
                         @P("金额保留两位有效数字") String amount) throws Exception {
        log.info("companyName =>>>> {} dutyNumber =>>>> {} amount =>>>> {}", companyName, dutyNumber, amount);
        //----------------------------------
        // 这块写自己的业务逻辑,调用redis/rabbitmq/kafka/mybatis/顺丰单据/医疗化验报告/支付接口等第3方
        //----------------------------------
        System.out.println(new WeatherService().getWeatherV2("101010100"));

        return "开票成功";
    }
}

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class WeatherService {
    //和风天气开发服务 https://dev.qweather.com/

    // 替换成你自己的和风天气API密钥
    private static final String API_KEY = System.getenv("weatherAPI");
    // 调用的url地址和指定的城市,本案例以北京为例
    private static final String BASE_URL = "https://devapi.qweather.com/v7/weather/now?location=%s&key=%s";

    public JsonNode getWeatherV2(String city) throws Exception {
        //1 传入调用地址url和apikey
        String url = String.format(BASE_URL, city, API_KEY);

        //2 使用默认配置创建HttpClient实例
        var httpClient = HttpClients.createDefault();

        //3 创建请求工厂并将其设置给RestTemplate,开启微服务调用和风天气开发服务
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
        //4 RestTemplate微服务调用
        String response = new RestTemplate(factory).getForObject(url, String.class);

        //5 解析JSON响应获得第3方和风天气返回的天气预报信息
        JsonNode jsonNode = new ObjectMapper().readTree(response);

        //6 想知道具体信息和结果请查看https://dev.qweather.com/docs/api/weather/weather-now/#response
        return jsonNode;
    }
}

🤖4.AI模型配置类

复制代码
import com.yumeko.study.service.FunctionAssistant;
import com.yumeko.study.service.InvoiceHandler;
import dev.langchain4j.agent.tool.ToolSpecification;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.tool.ToolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

@Configuration
public class LLMConfig {
    @Bean
    public ChatModel chatModel() {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("qwen-api"))
                .modelName("qwen-plus")
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }

    /**
     * @Description: 第一组 Low Level Tool API
     * https://docs.langchain4j.dev/tutorials/tools#low-level-tool-api
     */
/*    @Bean
    public FunctionAssistant functionAssistant(ChatModel chatModel)
    {
        // 工具说明 ToolSpecification
        ToolSpecification toolSpecification = ToolSpecification.builder()
                    .name("开具发票助手")
                    .description("根据用户提交的开票信息,开具发票")
                    .parameters(JsonObjectSchema.builder()
                                .addStringProperty("companyName", "公司名称")
                                .addStringProperty("dutyNumber", "税号序列")
                                .addStringProperty("amount", "开票金额,保留两位有效数字")
                            .build())
                .build();


        // 业务逻辑 ToolExecutor
        ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
            System.out.println(toolExecutionRequest.id());
            System.out.println(toolExecutionRequest.name());
            String arguments1 = toolExecutionRequest.arguments();
            System.out.println("arguments1****》 " + arguments1);
            return "开具成功";
        };

        return AiServices.builder(FunctionAssistant.class)
                .chatModel(chatModel)
                .tools(Map.of(toolSpecification, toolExecutor)) // Tools (Function Calling)
                .build();
    }*/


    /**
     * @Description: 第二组 High Level Tool API
     * https://docs.langchain4j.dev/tutorials/tools#high-level-tool-api
     */
    @Bean
    public FunctionAssistant functionAssistant(ChatModel chatModel) {
        return AiServices.builder(FunctionAssistant.class)
                .chatModel(chatModel)
                .tools(new InvoiceHandler())
                .build();
    }
}

🌐5.Web控制器

复制代码
import cn.hutool.core.date.DateUtil;
import com.yumeko.study.service.FunctionAssistant;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class ChatFunctionCallingController {
    @Resource
    private FunctionAssistant functionAssistant;

    //  http://localhost:9011/chatfunction/test1
    @GetMapping(value = "/chatfunction/test1")
    public String test1() {
        String chat = functionAssistant.chat("开张发票,公司:尚硅谷教育科技有限公司 税号:yumeko533 金额:668.12");

        System.out.println(chat);

        return "success : " + DateUtil.now() + "\t" + chat;
    }
}

🧪6.测试接口

http://localhost:9011/chatfunction/test1

相关推荐
serve the people8 小时前
Formatting Outputs for ChatPrompt Templates(one)
langchain·prompt
云烟飘渺o8 小时前
生活视角下Prompt 提示词思考
人工智能·prompt·生活
AcrelGHP8 小时前
光储充微电网能量管理系统:构建绿色、高效、安全的能源未来
大数据·运维·人工智能
wudl55668 小时前
Flink RocksDB State Backend 详解
大数据·flink
Hello.Reader8 小时前
用一份 YAML 编排实时数据集成Flink CDC 工程实践
大数据·flink
不二人生8 小时前
从 Flink 到 Doris 的实时数据写入实践 —— 基于 Flink CDC 构建更实时高效的数据集成链路
大数据·flink·cdc
罗不俷9 小时前
【Hadoop】Hadoop 起源与核心组件解析 —— 大数据时代的分布式基石
大数据·hadoop·分布式
serve the people10 小时前
LangChain Few-Shot Prompt Templates(two)
langchain·prompt
Hello.Reader10 小时前
用 Flink CDC 将 MySQL 实时同步到 Doris
大数据·mysql·flink