LangChain4j 学习

探索大模型世界_什么是大模型

大模型(Large Model),通常是指参数量非常庞大的深度学习模型,特别是在自然语言处理(NLP)、计算机视觉(CV)等领域中,模型参数数量达到数十亿甚至数千亿的规模。

大模型的特点

特点

  1. 庞大的参数量
  2. 海量的数据训练
  3. 强大的计算能力

大模型的分类

  • 语言大模型:专注于解析和理解文本
  • 视觉大模型:擅长图像识别和分析
  • 多模态大模型:则能够综合处理包括文本、图像和音频在内的多种数据类型

按照应用领域的不同,大模型主要可以分为 L0、L1、L2 三个层级

L0(高中生):通用模型,知识面广,但不够深入,能做基础工作。

L1(大学生):行业模型,针对某个领域有深入理解,能解决更复杂的问题,但还有限制。

L2(研究生):垂直模型,专注于一个领域,深度专业,能够处理高难度、细节化的问题。

大语言模型LLM的应用场景

  • 智能客服与聊天机器人

  • 内容创作与生成

  • 翻译与多语言处理

  • 文档摘要与信息提取

  • 搜索与推荐系统

  • 情感分析与情感计算

  • 代码自动化与开发辅助

探索大模型世界_AI会替代程序员吗

替代的是搜索引擎不是程序员

编程的魅力:不仅仅是写代码

无法被 AI 取代的部分,主要有几方面:

  1. 需要大量沟通理解的领域模型和业务逻辑,我们不能指望 AI 和人聊后,把业务逻辑梳理清楚。
  2. 对可用性质量要求比较高的部分,例如调度系统、中间件、存储核心系统。
  3. 其实也就是暗含在 2 中的,就是逻辑极度复杂的场景,短期模型能力好像还不够。

复杂绕口的业务逻辑:

其中用户首先需要通过多重身份验证访问一个分层的决策树。每个节点代表不同的决策路径,取决于用户的历史行为、实时数据分析和外部市场波动。例如,如果用户在节点A选择了路径1,系统需要立即调用一个外部API获取实时数据,然后根据该数据及用户的地理位置、时间戳和最近的购买历史,再决定是否允许其进入节点B。若进入,节点B的逻辑会涉及到与供应链管理系统的交互,以实时调整产品可用性,进而影响下一步的推荐算法,从而实现个性化推荐,最终将用户引导至一个动态生成的、可能与其过往行为完全无关的新产品展示界面。这一过程必须在毫秒级响应内完成,以保证用户体验的流畅性。

探索大模型世界_Java AI 开发工具

为了弥补Java开发者在AI领域的工具短板,市面上已经出现了几款针对Java的AI开发工具。

LangChain4J

  • 提供标准化API,支持超过15个主流大模型提供商和嵌入存储,
  • 提供工具箱,从低级提示词模板到高级AI服务,适合构建聊天机器人和检索增强生成(RAG)管道。
  • 社区支持活跃,能够快速整合最新的AI技术,便于Java开发者将AI功能集成到现有项目中。

Spring Al

  • 深度集成到Spring框架中,Java开发者可以轻松将AI功能嵌入到现有Spring项目中。
  • 尽管Spring Al仍处于发展阶段,尚未发布正式版本,但其凭借Spring生态系统,具备了极强的扩展性和集成能力。

Spring AI Alibaba

  • 提供多种大模型服务对接能力,包括主流开源与阿里云通义大模型服务(百炼)等
  • 支持的模型类型包括聊天、文生图、音频转录、文生语音等

对比

LangChain4J Spring AI Spring AI Alibaba
功能成熟度 功能全面,适合大规模AI应用 发展中,功能有待完善 功能全面,适合大规模AI应用
集成能力 支持多种LLM和嵌入存储,适合多样化场景 集成到Spring项目中,扩展性强 集成到Spring项目中,扩展性强
社区支持 社区活跃,反馈迅速 项目正在成长,API变更较大 社区活跃
兼容性 Java8 + Java17 + SpringBoot3 JDK 要求 17 及以上版本

Java AI 开发工具_介绍LangChain4j

介绍

LangChain4j 是一个专为Java开发者设计的开源库,旨在简化将大型语言模型(LLM)集成到Java应用程序中的过程。它于2023年初开发,灵感来源于Python和JavaScript的LLM库,特别是为了填补Java领域在这一方面的空白。

官网 https://docs.langchain4j.dev/intro

LangChain4j 的核心功能

  1. 统一API:LangChain4j 提供统一 API,避免了学习和实现每个 API 的特定 API。
  2. 全面的工具箱:该框架包含多种工具,从低级的提示模板、聊天记忆管理到高级模式(如AI服务和RAG)。
  3. 大量的示例:LangChain4j提供大量的使用示例,与 Quarkus 和 Spring Boot 的集成等。

能干什么

  • 集成了 15+个 语言大模型 15+ LLM providers
  • 集成了 15+个 向量数据库 15+ embedding (vector) stores
  • 集成了 10+个 嵌入模型 10+ embedding models
  • 集成了 4个 图片大模型 4 cloud and local image generation models
  • 集成了 2个 评分重排名模型 2 scoring (re-ranking) models
  • 集成 1个 OpenAI 审核模型(检测prompt与响应是否有有害内容)
  • 支持文本和图像作为输入(多模态)
  • 更高层次的抽象,针对复杂的场景更方便集成。 AI Services
  • 支持提示词模板、聊天记忆、聊天持久化、聊天记忆淘汰算法(消息窗口和令牌窗口) chat memory
  • 支持同步/流式响应,支持常见 Java 类型和自定义 POJO 的输出解析器
  • 支持工具(函数调用)Tools (function calling), 动态工具(执行动态生成LLM的代码)
  • 支持检索增强生成技术 RAG (Retrieval-Augmented-Generation)

LangChain4j支持的LLMs

Java AI 开发工具_Langchain4j入门示例

介绍

如何通过低级 API 接入阿里百炼平台的通义模型 qwen-max。通过使用 LangChain4j 框架,开发者可以轻松调用该模型并集成到 Java 应用中。

阿里云百练:https://bailian.console.aliyun.com/?switchAgent=10032291&productCode=p_efm&switchUserType=3#/model-market

Maven 依赖配置

首先,需要在项目中引入以下 Maven 依赖,用于集成 LangChain4j 与 DashScope:

XML 复制代码
<dependencies>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>


  <!-- 加载bom 后,所有langchain4j引用不需要加版本号 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-bom</artifactId>
        <version>0.35.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

YML 配置文件

在项目的 application.yml 中设置所使用的通义模型 qwen-max,以下是示例配置:

XML 复制代码
langchain4j:
  open-ai:
   chat-model:
   # 课程测试 KEY,需要更换为实际可用 KEY  
    api-key: sk-xx
    model-name: qwen-xxx
   # 百炼兼容OpenAI接口规范,base_url为https://dashscope.aliyuncs.com/compatible-mode/v1
    base-url: https://dashscope.aliyuncs.com/compatible-mode/v1

代码实现

使用以下代码,快速启动一个基于 LangChain4j 和 Spring Boot 的 Java 应用,集成并调用阿里百炼平台的通义大语言模型。

java 复制代码
/**
 * 用于处理与通义模型的交互请求测试。
 */
@RestController
public class ChatController {


  @Autowired
  private ChatLanguageModel chatLanguageModel;


  /**
   * 聊天
   * @param message
   * @return
   */
  @GetMapping("/ai/generate")
  public String testChat(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message){
    String generate = chatLanguageModel.generate(message);
    return generate;
   }
  
}

Java AI 开发工具_LangChain4j 高级API

创建子项目模块

创建子模块langchain4j_chatapi

Maven 依赖配置

pom.xml中添加以下依赖:

XML 复制代码
 <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j</artifactId>
    </dependency>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

配置模型元信息

新建LLMConfig文件,配置 ChatLanguageModel 提供模型元信息。

java 复制代码
@Bean
public ChatLanguageModel chatLanguageModel() {
  return OpenAiChatModel.builder()
       .apiKey(System.getenv("DASHSCOPE_KEY"))
       .modelName("qwen-turbo")
       .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
       .build();
}

编写控制器

java 复制代码
@RestController
public class ChatController {


  @Autowired
  ChatLanguageModel chatLanguageModel;


  @GetMapping("/ai/generate")
  public String testChat(String msg){
    String generate = chatLanguageModel.generate(msg);
    System.out.println(generate);
    return generate;
   }
}

Java AI 开发工具__LangChain4j 高级LLM API

为了简化开发,LangChain4j提供了高层API,使开发者能够更专注于业务逻辑,而无需关注底层实现细节。高层API中,AiService 用于定义一个集成大模型的服务。

定义AI Service

java 复制代码
/**
 *  AI 助手接口
 */
public interface ChatAssistant {


  /**
   * 聊天
   * @param message
   * @return {@link String}
   */
  String chat(String message);


}

注入模型

java 复制代码
/**
 * 大模型配置
 */
@Configuration(proxyBeanMethods = false)
public class LLMConfig
{


  @Bean
  public ChatLanguageModel chatLanguageModel() {
    return OpenAiChatModel.builder()
//         .apiKey(System.getenv("sk-46aeef92a70d4a86bc04e6c9d04d9db1"))
         .apiKey("sk-46aeef92a70d4a86bc04e6c9d04d9db1")
         .modelName("qwen-plus")
         .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
         .build();
   }




  @Bean
  public ChatAssistant chatAssistant() {
    return AiServices.builder(ChatAssistant.class)
         .chatLanguageModel(chatLanguageModel())
         .build();
   }
  
}

测试功能

java 复制代码
@RestController
public class ChatController {
  
  @Autowired
  private ChatAssistant chatAssistant;




  /**
   * 测试高级LLM API
   * @param msg
   * @return
   */
  @GetMapping("/ai/chatassistant")
  public String testChat2(String msg){
    String response = chatAssistant.chat(msg);
    return response;
   }
}

Java AI 开发工具_LangChain4j日志配置

日志配置 (Logging)

LangChain4j 使用 SLF4J 作为日志接口,支持集成各种日志后端,如 Logback 或 Log4j。

Spring Boot 环境

在 Spring Boot 集成时,可以通过 application.yml 文件配置日志级别:

langchain4j.open-ai.chat-model.log-requests = true

langchain4j.open-ai.chat-model.log-responses = true

logging.level.dev.langchain4j = DEBUG

logging.level.dev.ai4j.openai4j = DEBUG

监控

LangChain4j 提供了一些语言模型(如 ChatLanguageModelStreamingChatLanguageModel),支持通过 ChatModelListener 监听以下事件:

  • 请求到达 LLM
  • LLM 返回的响应
  • 错误处理

事件监听:

java 复制代码
package com.itbaizhan.config;


import dev.langchain4j.model.chat.listener.*;
import lombok.extern.slf4j.Slf4j;


import java.util.Map;


/**
 * 测试大模型调用监听器
 */
@Slf4j
public class TestChatModelListener implements ChatModelListener {


  @Override
  public void onRequest(ChatModelRequestContext requestContext) {
    ChatModelRequest request = requestContext.request();
    Map<Object, Object> attributes = requestContext.attributes();
    log.info("请求参数:{}", requestContext);
   }


  @Override
  public void onResponse(ChatModelResponseContext responseContext) {
    ChatModelResponse response = responseContext.response();
    ChatModelRequest request = responseContext.request();
    Map<Object, Object> attributes = responseContext.attributes();
    log.info("返回结果:{}", attributes);
   }




  @Override
  public void onError(ChatModelErrorContext errorContext) {
    Throwable error = errorContext.error();
    ChatModelRequest request = errorContext.request();
    ChatModelResponse partialResponse = errorContext.partialResponse();
    Map<Object, Object> attributes = errorContext.attributes();
    // 记录错误
    log.error("请求异常:{}", errorContext);
   }
}

重试机制 (Retry Configuration)

LangChain4j 支持重试配置,可用于处理失败的请求。可以通过 maxRetries 来配置重试逻辑,指定重试次数和延迟等参数:

ChatLanguageModel model = OpenAiChatModel.builder()

.maxRetries(5) // 设置重试策略

.build();

超时配置 (Timeout Configuration)

对于超时配置,可以通过 timeout 设置请求的超时时间:

ChatLanguageModel model = OpenAiChatModel.builder()

.timeout(Duration.ofSeconds(10)) // 设置10秒超时

.build();

最终配置

java 复制代码
package com.itbaizhan.config;


import com.itbaizhan.service.ChatAssistant;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.time.Duration;
import java.util.List;


/**
 * 大模型配置
 */
@Configuration(proxyBeanMethods = false)
public class LLMConfig
{


  @Bean
  public ChatLanguageModel chatLanguageModel() {
    return OpenAiChatModel.builder()
         .apiKey("sk-46aeef92a70d4a86bc04e6c9d04d9db1")
         .logRequests(true)
         .logResponses(true)
        // 设置重试策略
         .maxRetries(1)
        //设置10秒超时
         .timeout(Duration.ofSeconds(100))
         .listeners(List.of(new TestChatModelListener()))
         .modelName("qwen-plus")
         .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
         .build();
   }




  @Bean
  public ChatAssistant chatAssistant() {
    return AiServices.builder(ChatAssistant.class)
         .chatLanguageModel(chatLanguageModel())
         .build();
   }


}

Java AI 开发工具_流式输出

介绍

LLM 每次生成一个标记,因此许多 LLM 提供商都提供逐个标记流式传输响应的方法,而不是等待生成整个文本。这显著改善了用户体验,因为用户无需等待未知的时间,几乎可以立即开始阅读响应。

流式响应处理

StreamingResponseHandler 接口流式响应的关键接口是 StreamingResponseHandler。它允许开发者定义在响应生成过程中的各个事件的处理逻辑。

Maven 依赖配置

XML 复制代码
<dependencies>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j</artifactId>
    </dependency>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai</artifactId>
    </dependency>


    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>


    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>


    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-reactor</artifactId>
      <version>0.35.0</version>
    </dependency>
  </dependencies>

编写配置文件

流式要使用到:StreamingChatLanguageModel和OpenAiStreamingChatModel

java 复制代码
package com.itbaizhan.config;


import com.itbaizhan.service.ChatAssistant;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.service.AiServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.time.Duration;


/**
 * 大模型配置
 */
@Configuration(proxyBeanMethods = false)
public class LLMConfig
{


  @Bean
  public ChatLanguageModel chatLanguageModel() {
    return OpenAiChatModel.builder()
         .apiKey("sk-xxxxxx")
         .modelName("qwen-plus")
         .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
         .build();
   }


  /**
   * 流返回
   * @return
   */
  @Bean
  public StreamingChatLanguageModel streamingChatLanguageModel(){
    return OpenAiStreamingChatModel.builder()
         .apiKey("sk-xxxxxx")
         .modelName("qwen-plus")
         .timeout(Duration.ofSeconds(10))
         .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
         .build();
   }






  @Bean
  public ChatAssistant chatAssistant(StreamingChatLanguageModel streamingChatLanguageModel){
    return AiServices.create(ChatAssistant.class, streamingChatLanguageModel);
   }


}

定义AI Service(返回值要使用Flux<>)

java 复制代码
/**
 * @author itbaizhan
 */
public interface ChatAssistant {


  /**
   * 聊天
   *
   * @param message 消息
   * @return {@link Flux }<{@link String }>
   */
  Flux<String> chat(String message);
}

编写控制层代码

java 复制代码
@RestController
public class ChatController {


  @Autowired
  private ChatAssistant chatAssistant;


  /**
   * 聊天
   * @param message 内容
   * @return
   */
  @GetMapping("/ai/generate")
  public Flux<String> chat(@RequestParam("message") String message) {
    return chatAssistant.chat(message);
   }
}

Java AI 开发工具_视觉理解

创建子模块

langchain-4j_image

Maven依赖

XML 复制代码
<dependencies>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j</artifactId>
    </dependency>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai</artifactId>
    </dependency>


    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>


  </dependencies>

构建大模型客户端

java 复制代码
@Bean
public ChatLanguageModel chatLanguageModel() {
return OpenAiChatModel.builder()
     .apiKey(System.getenv("DASHSCOPE_KEY"))
     .modelName("qwen-vl-max") // 设置使用的模型名称
     .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
     .build();
}

构建 ImageController

java 复制代码
/**
 * 视觉理解示例 - 通过Dashscope进行图像分析
 */
@RestController
public class ImageController {


  @Autowired
  private ChatLanguageModel chatLanguageModel;




  /**
   * 视觉理解
   * @param msg
   * @param file
   * @return
   * @throws IOException
   */
  @PostMapping("/identify")
  public String chatLanguageModel(String msg,MultipartFile file) throws IOException {
    InputStream inputStream = file.getInputStream();//得到输入流
    byte[] byteArray = inputStream.readAllBytes();//转为byte数组
    String encodeToString = Base64.getEncoder().encodeToString(byteArray);//再转为Base64                             //也可以传入其他的
    UserMessage userMessage = UserMessage.from(
        TextContent.from(msg),
        ImageContent.from(encodeToString, "https://www.itbaizhan.com/wiki/image/png")
     );//使用UserMessage来传入参数
    Response<AiMessage> response = chatLanguageModel.generate(userMessage);
    return response.content().text();
   }
}

编写配置application

设置文件上传最大值

java 复制代码
spring:
  servlet:
   multipart:
    max-file-size: 5MB
    max-request-size: 5MB

测试

Java AI 开发工具_文生图

创建子模块

langchain4j-05-generateimage

智谱生成apikey

官网 https://open.bigmodel.cn/

然后使用的是ImageModel来使用的

Java AI 开发工具_ChatMemory聊天记忆

为什么需要ChatMemory

实现聊天记忆实现起来非常简单,就是把用户所有的提问、大模型回答/产生的内容,放在一个List<ChatMessage>中,随着用户提问将List一并发送给大模型,让大模型具备了聊天记忆功能。

问题:

  • 随着提问不断增多,上下文会变的很长,很快超出大模型的上下文token限制。
  • 如果多人同时使用大模型,如何隔离不同用户的上下文信息。

手动维护和管理 ChatMessage 很麻烦。因此,LangChain4j 提供了一个 ChatMemory 抽象以及多个开箱即用的实现。ChatMemory 可以用作独立的低级组件,也可以用作高级组件(如 AI Services)的一部分。

ChatMemory实现什么能力

  • 容器管理机制,充当ChatMessage容器,对ChatMessage进行管理。
  • 淘汰机制(Eviction policy),为保证ChatMessage不会过多。
  • 持久化机制(Persistence),防止聊天上下文丢失的问题。
  • 消息特殊处理机制 SystemMessage特殊处理。 函数调用返回消息特殊处理。

淘汰机制(Eviction policy)

  1. 适应 LLM的上下文窗口: 一次LLM可以处理的token数量是有上限的。
  2. 控制成本: 每个token都有成本,这使得每次调用LLM越来越昂贵。逐出不必要的token可降低成本。
  3. 控制延迟: 发送到 LLM的token越多,处理它们所需的时间就越多。

实现流程

流程:

  1. 用户发起提示词 prompt 提问;
  2. 根据chatMemoryId 查询历史回话,并返回;
  3. 通过提示词模板将 prompt 和 history messages 组合成一个提示词发送给大模型;
  4. 大模型根据提示词进行回答,将prompt + AiMessages同时放入到ChatMemory中;
  5. 最后将大模型生成的结果返回给用户

Java AI 开发工具_ChatMemory聊天记忆实现

创建子模块

创建子模块langchain4j-chatmemory

Maven依赖

XML 复制代码
<dependencies>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j</artifactId>
    </dependency>


    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai</artifactId>
    </dependency>


    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>


    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>

Ai Services 定义

java 复制代码
public interface ChatAssistant {

  /**
   * 聊天
   *
   * @param userId  用户 ID  (根据ID隔离记忆)
   * @param message 消息
   * @return {@link String }
   * 前面参数前的注解也是必须要加上的
   */
  String chat(@MemoryId Long userId, @UserMessage String message);
}

编写配置文件生成元数据信息

java 复制代码
@Configuration(proxyBeanMethods = false)
public class LLMConfig {


  @Bean
  public ChatLanguageModel chatLanguageModel() {
    return OpenAiChatModel.builder()
         .apiKey(System.getenv("DASHSCOPE_KEY"))
         .modelName("qwen-long") // 设置使用的模型名称
         .logRequests(true)
         .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
         .build();
   }


  @Bean
  public AiAssistant aiAssistant(ChatLanguageModel chatLanguageModel) {
    return AiServices.builder(AiAssistant.class)
         .chatLanguageModel(chatLanguageModel)
//这里是使用了chatMemory的生产者去使用一个类似于滑动窗口的 也就是使用最近的10条消息
         .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
         .build()
         ;
   }


}

编写控制层

java 复制代码
@RestController
public class ChatMemoryController {


  @Autowired
  private AiAssistant aiAssistant;


  /**
   * 聊天记忆练习
   * @return
   */
  @GetMapping("/chat")
  public String chat(){
    aiAssistant.chat(1L, "你好!我的名字是小王");
    aiAssistant.chat(2L, "你好!我的名字是小刘");
    String chat = aiAssistant.chat(2L, "我的名字是什么");
    return chat;
   }
}

Java AI 开发工具_ChatMemory聊天记忆自定义持久化-MapDB嵌入数据库

MapDB简介

MapDB是一个轻量级的Java嵌入式数据库引擎,它支持在JVM中直接运行,无需外部服务器。MapDB提供了基于磁盘或堆外存储的并发的Maps、Sets、Lists、Queues等数据结构,使得开发者可以像使用Java集合一样轻松地使用MapDB。此外,MapDB还支持ACID事务、MVCC(多版本并发控制)等特性,确保数据的完整性和一致性。

MapDB的特点

  • 高性能:MapDB经过优化和重写,性能出色,可以在多核环境中实现线性扩展。
  • 轻量级:MapDB的jar包体积较小,且没有其他依赖项,非常适合嵌入式系统或内存数据库的应用场景。
  • 易用性:MapDB提供了基于Java集合的API,使得开发者可以轻松地进行数据存储和检索操作。
  • ACID事务支持:MapDB支持ACID事务,确保数据的一致性和隔离性。
  • 模块化设计:MapDB采用模块化的架构设计,易于扩展和定制。

如何引入 MapDB

要开始使用 MapDB,首先需要将其添加到你的项目中。如果你使用的是 Maven,可以在项目的 pom.xml 文件中添加以下依赖:

XML 复制代码
<dependency>
  <groupId>org.mapdb</groupId>
  <artifactId>mapdb</artifactId>
  <version>3.0.10</version>
</dependency>

MapDB 使用示例

1、简单的键值存储与检索

MapDB 提供了简单的键值存储机制,类似于 Java 的 HashMap。下面是一个基本的示例,展示如何创建一个数据库,添加、检索和删除记录。

java 复制代码
import org.mapdb.*;


public class MapDBExample {
  public static void main(String[] args) {
    // 创建或打开一个DB文件
    File dbFile = new File("mydb");
    DB db = DBMaker.newFileDB(dbFile)
         .make();


    // 创建一个HashMap并设置名称
    ConcurrentHashMap<String, String> map = db.getHashMap("myMap");


    // 在Map中存储数据
    map.put("key1", "value1");
    map.put("key2", "value2");


    // 提交事务以确保数据被持久化到磁盘
    db.commit();


    // 关闭数据库连接
    db.close();


    // 重新打开数据库以检索数据
    db = DBMaker.newFileDB(dbFile)
         .make();


    // 从Map中检索数据
    String value1 = map.get("key1");
    String value2 = map.get("key2");


    System.out.println("Value for key1: " + value1);
    System.out.println("Value for key2: " + value2);


    // 关闭数据库连接
    db.close();
   }
}

Java AI 开发工具_ChatMemory聊天记忆自定义持久化实现

自定义持久化

java 复制代码
/**
 * 自定义的持久化聊天存储器
 */
public class PersistentChatMemoryStore implements ChatMemoryStore {


  private final DB db = DBMaker.fileDB("./chat-memory1.db").transactionEnable().make();
  private final Map<Integer, String> map = db.hashMap("messages", INTEGER, STRING).createOrOpen();


  @Override
  public List<ChatMessage> getMessages(Object memoryId) {
    String json = map.get((int) memoryId);
    return messagesFromJson(json);
   }


  @Override
  public void updateMessages(Object memoryId, List<ChatMessage> messages) {
    String json = messagesToJson(messages);
    map.put((int) memoryId, json);
    db.commit();
   }


  @Override
  public void deleteMessages(Object memoryId) {
    map.remove((int) memoryId);
    db.commit();
   }
}

配置元信息

java 复制代码
/**
 * ai 配置
 */
@Configuration
public class ChatConfig {


  /**
   * 流返回
   * @return
   */
  @Bean
  public StreamingChatLanguageModel streamingChatLanguageModel(){
    return OpenAiStreamingChatModel.builder()
         .apiKey("sk-46aeef92a70d4a86bc04e6c9d04d9db1")
         .modelName("qwen-max")
         .timeout(Duration.ofSeconds(10))
         .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
         .build();
   }


  @Bean
  public ChatMemoryProvider chatMemoryProvider() {
    return memoryId -> MessageWindowChatMemory.builder()
        // 设置消息窗口 ID
         .id(memoryId)
        // 设置消息最大条数,默认为 10
         .maxMessages(10)
         .chatMemoryStore(chatMemoryStore())
         .build();
   }






  @Bean
  public ChatMemoryStore chatMemoryStore() {
    return new PersistentChatMemoryStore();
   }




  @Bean
  public Assistant chatAssistant(StreamingChatLanguageModel streamingChatLanguageModel){
    return AiServices.builder(Assistant.class)
         .streamingChatLanguageModel( streamingChatLanguageModel )
         .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
         .build();
   }




}

Java AI 开发工具_prompt提示词工程重要性

什么是提示词

当我们想用大语言模型开发具有独特功能的产品时,通常需要通过提示词模板让大语言模型显示出独特的技能。

创作提示词的万能模板

掌握提示词,是用好AI的关键!

复制代码
- Role:分析用户的Prompt,思考最适合扮演的1个或多个角色,该角色是这个领域最资深的专家,也最适合解决问题。
- Background:分析用户的Prompt,思考用户为什么会提出这个问题,陈述用户提出这个问题的原因、背景、上下文。
- Profile:基于这个新提示词应扮演的角色,描述该角色,以及该角色的特征和属性。
- Skills:考虑到这个提示词中应扮演的角色,思考完成任务所需的关键能力。
- Goals:分析这个新提示词角色应当扮演的部分,考虑用户希望通过这个新提示词实现的目标任务。思考哪些任务列表,如果被完成,就能够针对性地解决用户面临的问题。
- Constrains:若适用,基于此prompt扮演的角色,思考该角色应该遵守的规则,确保角色能够出色的完成任务。
- OutputFormat:若适用,预想生成的内容形式,考虑输出应采取何种格式。
-Workflow:若适用,基于此扮演的角色,拆解该角色执行任务时的工作流,生成不低于3个步骤
-Examples:若适用,给出几个例子作为few-shots
-Initalization:基于此扮演的角色,给出一个初始化的欢迎语和使用引导

问题

相信很多自媒体创作者都有个头疼的问题,就是觉得自己的文章明明内容做的很好,为什么浏览量和传播量这么低呢?

如果你去看那些10W+的文章,内容好是一部分,但是人家的标题也起得是真好啊!有种看见了不点进去心里就吃亏的感觉!所以,这里确定的需求就是为文章取爆款标题。

创作爆款标题Prompt

这里有个小技巧,就是我们需要让AI 把我们的需求用提示词模板的框架表述出来,所以在这里刚开始的时候,需要为AI赋予一个角色,那就是提示词工程师,让它知道自己的任务是什么。

所以,我设计的提示词如下:

复制代码
你是一位提示词工程师,你需要根据我提供的内容1,按照提示词模板,为我生成可重复使用的“文章爆款标题大师”结构化提示词。


这是内容1:
---
你是一位公众号爆款标题创作大师,你创作了无数吸引眼球的爆款标题,用户一旦看见你的标题一定会阅读文章。
---


这是提示词模板:
---
#Role:[请填写你想定义的角色名称]


##Profile:
-Author:itbaizhan
-Version:0.1
-Language:中文
- Description:[你是一名[角色名称],具有[核心能力]。擅长[核心方法],能够帮助用户[用户需求]。在[专业细节]方面有深入的了解,能够[具体细节],尽量50字以内]


##Background:
[请描述角色的背景信息,例如其历史、来源或特定的知识背景]


##Preferences:
[请描述角色的偏好或特定风格,例如对某种设计或文化的偏好]


##Goals:
[请列出该角色的主要目标1]
[请列出该角色的主要目标2]
...


##Constrains:
[请列出该角色在互动中必须遵循的限制条件1]
[请列出该角色在互动中必须遵循的限制条件2]
...


##Skills:
[为了在限制条件下实现目标,该角色需要拥有的技能1]
[为了在限制条件下实现目标,该角色需要拥有的技能2]
...


##Examples:
[提供一个输出示例1,展示角色的可能回答或行为]
[提供一个输出示例2]
...


##OutputFormat:
[请描述该角色的工作流程的第一步]
[请描述该角色的工作流程的第二步]
...


## Initialization :作为[角色名称], 拥有[技能], 严格遵守[限制条件], 使用[选择语言]与用户对话,友好的欢迎用户,并提示用户输入。
---

测试:

这里打开ChatGPT进行测试,当然,这样生成的提示词只是初稿,我们还需要进行优化。AI可以完成80%的工作,剩下的20%需要我们自己完成,毕竟AI只是辅助,我们才是最终决策者。

复制代码
通过你给出的提示词,我发现了以下问题:
---
一.在Examples里,示例标题太过简短,且没有说明为什么好的原因,所以我提供了一些标题,供你参考,在下次迭代提示词时加入。
1、制造反差。
人类的大脑对于反差的信息会更加关注。
范例:我被裁员了,但我更快乐了。


2、巧用数字。
数字标题给人清晰、具体、易操作的感觉,能快速吸引读者的注意力
范例:父母做到这3点,孩子更自信。


3、制造悬念。
就像没有人不爱看悬疑小说一样,悬念能够很好的激发好奇心。
范例:看了这本书以后,90后的我彻底不想奋斗了


4、名人效应。
名人之所以是名人,就是因为他们自带流量,适当蹭一蹭,可以提升你的打开率。
范例:马云,刘强东都在用的时间管理方法!


5、提出痛点问题。
范例:那些喜欢熬夜的人,多久会死?
---
二、在Outputformat里,只需要第一步引导输入主题或者关键词即可,然后第二步输出10个符合要求的爆款标题
---
三、在Initialization里,只需要说“作为[Role],仅输出“你好,我是:公众号爆款标题创作大师,请告诉我文章主题或者关键词,我将为你提供10个引人注目的爆款标题”
---
请按照以上问题优化提示词

请按照以上问题优化提示词

然后,拿到这版提示词之后,我们一定要打开一个新窗口进行测试,看看效果如何。

是不是一下子我们的选择就变多了呢,你若想达到更好的效果,对于其他部分,我们也可以返回到最初页面进行优化,当然这个问题因人而异,能达到自己的目标就行。

Java AI 开发工具_prompt提示词工程实现

角色设定

角色设定是指导大语言模型(LLM)行为的重要手段。通过明确定义AI助手的身份和能力范围,我们可以使其更专注于特定领域的任务。

在LangChain4j中,我们主要利用SystemMessage来实现这一点。

SystemMessage具有高优先级,能有效地指导模型的整体行为。

@SystemMessage("你好,我是:公众号爆款标题创作大师,请告诉我文章主题或者关键词,我将为你提供10个引人注目的爆款标题。")

提示词模板:精确控制输入输出

LangChain4j提供了多种方式来使用提示词模板,让我们能够灵活地构造输入并控制输出。以下是几种常用的方法:

1. 使用 @UserMessage@V 注解:
java 复制代码
public interface AiAssistant {
  @SystemMessage("你好,我是:公众号爆款标题创作大师,请告诉我文章主题或者关键词,我将为你提供10个引人注目的爆款标题。")
  @UserMessage("请回答以下问题:{{question}}")
  String answerLegalQuestion(@V("question") String question);
}
2. 使用 PromptTemplate 渲染:
java 复制代码
@GetMapping("/prompt1")
  public String prompt1(){
    String chat = legalAssistant.chat("资深java程序员不知道的6个小技巧?");
    return chat;
   }

Java AI 开发工具_JSON 结构化输出

大模型精准化输出

在利用大模型构建自己的应用时,需要每次调用大模型都能稳定的返回固定的字段,如果输出结果不是指定JSON格式,不一定能做到。

使用JSON结构化输出的优势

  1. 精确控制大模型输出字段 使大模型每次都精确稳定的返回指定的输出字段;
  2. 易于大模型对输出格式的理解;
  3. JSON格式方便应用端解析;
  4. JSON格式方便应用端对数据的利用:应用端可以根据自身需求对各字段的UI展示。

示例

下面是一个要求大模型设计语文阅读题并设计相应的选择题的例子,原来的提示词如下:

"""

假设你是一个中国大陆的初中生老师,你擅长设计初中语文的阅读题。 请以"聚会和休闲活动(亲朋好友聚会、看电影、去公园、参加音乐会等)"为主题,设计一篇250字左右的汉语阅读内容,然后根据阅读内容,出三个单选选择题,每个选择题包含四个选项,并给出每个选择题的正确答案。要求这个阅读题的难度是中等, 阅读题的段落过度要自然、逻辑清晰,不要使用"首先、其次、再次、然后、最后"这些副词和过渡词。

输出的内容包括:

  1. 设计的阅读题内容。

  2. 阅读题的主题。

  3. 阅读题对应的三个单选选择题。

  4. 每个题目的四个选项(A、B、C、D)。

  5. 每个题目的正确答案(A、B、C、D中的一个),必须避免三个选择题的答案都是相同(即不要都是同一个字母)。

  6. 每个题目的正确答案的解释(为什么是这个选项)。

  7. 该阅读理解的难度。

"""

大模型返回的结果如下:

阅读题内容:

在一个阳光明媚的周末,小明一家决定去郊外的公园享受休闲时光。他们早早地起床,准备了野餐篮,里面装满了小明最爱的三明治和水果。到达公园后,他们选择了一片树荫下的草地,铺开了野餐垫。孩子们在草地上追逐嬉戏,而大人们则坐在垫子上,享受着美食和阳光。午后,他们决定去附近的电影院看一场期待已久的电影。电影院里,灯光昏暗,气氛温馨,大家都沉浸在电影的情节中。傍晚时分,一家人又去了一个小型音乐会,现场的音乐让人心旷神怡。这一天,小明一家在聚会和休闲活动中度过了一个愉快的周末。

阅读题的主题:

聚会和休闲活动

单选选择题:

  1. 小明一家选择在哪个地方野餐?
  • A. 电影院

  • B. 公园的树荫下

  • C. 小型音乐会现场

  • D. 家中

  1. 他们野餐时,孩子们在做什么?
  • A. 看电影

  • B. 听音乐会

  • C. 追逐嬉戏

  • D. 准备食物

  1. 小明一家在音乐会上的感受是什么?
  • A. 紧张刺激

  • B. 心旷神怡

  • C. 疲惫不堪

  • D. 兴奋不已

正确答案:

  1. B

  2. C

  3. B
    上面的输出结果有几个问题:

  4. 解析不方便;

  5. 应用使用数据不方便:比如应用要展示某个选择题的某个选项,需要做多次的解析;

  6. 非结构化的输出,模型不一定能保证每次都输出相同的稳定的字段。

如何实现JSON结构化输出

下面的提示词将前面的例子要求转为结构化输出:

假设你是一个中国大陆的初中生老师,你擅长设计初中语文的阅读题。 请以"聚会和休闲活动(亲朋好友聚会、看电影、去公园、参加音乐会等)"为主题,设计一篇250字左右的汉语阅读内容,然后根据阅读内容,出三个单选选择题,每个选择题包含四个选项,并给出每个选择题的正确答案。要求这个阅读题的难度是中等, 阅读题的段落过度要自然、逻辑清晰,不要使用"首先、其次、再次、然后、最后"这些副词和过渡词。

输出的格式要求如下:

The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":

```json

{

"content": "设计的阅读题内容", //使用汉语,控制在250个汉字左右

"theme": "",

"choices": [{ //出的3选择题内容

"question": "题目内容" //根据阅读题内容出的单选题, 使用汉字,控制在100个汉字以内

"options": [

"A_option": "A选项内容", //使用汉语,控制在20个汉字以内

"B_option": "B选项内容" //使用汉语,控制在20个汉字以内

"C_option": "C选项内容" //使用汉语,控制在20个汉字以内

"D_option": "D选项内容" //使用汉语,控制在20个汉字以内

"correct_option": "该题目的答案选项" //该题目的正确选项,内容为'A','B','C','D'中的一个

"correct_option_reason": "解释答案的原因" //使用汉语,控制在100个汉字以内

]

}],

"difficulty": "设计的阅读理解的难度" //分"容易"、"中等"、"难"

}

大模型返回结果如下:

{

"content": "周末的午后,阳光明媚,小明和朋友们约定在公园里举行野餐。他们带来了各种美食,有香甜的蛋糕、新鲜的水果和美味的三明治。在树荫下,大家围坐在一起,边品尝美食边聊天,享受着轻松愉快的时光。随后,他们决定去划船,湖面上波光粼粼,船桨激起层层涟漪。傍晚时分,他们又一起去了电影院,观看了一部期待已久的电影。这一天,小明和朋友们的聚会充满了欢声笑语,留下了美好的回忆。",

"theme": "聚会和休闲活动",

"choices": [

{

"question": "小明和朋友们在哪里举行了野餐活动?",

"options": {

"A_option": "电影院",

"B_option": "公园",

"C_option": "湖边",

"D_option": "家里",

"correct_option": "B",

"correct_option_reason": "根据阅读内容,小明和朋友们是在公园里举行野餐。"

}

},

{

"question": "他们野餐时享受了哪些活动?",

"options": {

"A_option": "划船",

"B_option": "看电影",

"C_option": "品尝美食和聊天",

"D_option": "参加音乐会",

"correct_option": "C",

"correct_option_reason": "阅读内容提到他们在野餐时品尝美食并聊天。"

}

},

{

"question": "小明和朋友们的聚会在一天中的哪个时间段结束?",

"options": {

"A_option": "中午",

"B_option": "傍晚",

"C_option": "晚上",

"D_option": "早晨",

"correct_option": "B",

"correct_option_reason": "根据阅读内容,他们傍晚时分去电影院观看电影,说明聚会在傍晚结束。"

}

}

],

"difficulty": "中等"

}

Java AI 开发工具_结构化输出

如果要从 LLM接收结构化输出,可以将 AI Service 方法的返回类型更改为 String 或其他。

支持类型

  • 字符串 String。
  • 基本类型 boolean/byte/short/int/long/float/double。
  • 对象类型 Boolean/Byte/Short/Integer/Long/Float/Double/BigDecimal。
  • 时间类型 Date/LocalDate/LocalTime/LocalDateTime。
  • 集合类型 List/Set。
  • 枚举类型 Enum。
  • 自定义 POJO。
  • 自定义 Result 。
  • 大模型回复消息 AiMessage。

创建子模块

结构化输出示例

数字类型
java 复制代码
public interface SentimentAnalyzer {
  
  @UserMessage("Does {{it}} have positive sentiment?")
  boolean isPositive(String text);


  @UserMessage("Analyze sentiment of {{it}}")
  Sentiment analyzeSentimentOf(String text);


  enum Sentiment {
    POSITIVE, NEGATIVE, NEUTRAL
   }
}

配置元数据

java 复制代码
@Bean
public SentimentAnalyzer personExtractor(ChatLanguageModel chatLanguageModel) {
    return AiServices.create(SentimentAnalyzer.class, chatLanguageModel);
}

配置控制器

java 复制代码
@RestController
public class ChatController {
  
  @Autowired
  private SentimentAnalyzer personExtractor;


  /**
   * 聊天
   * @param message
   * @return
   */
  @GetMapping("/chat")
  public boolean chat(String message){
    return personExtractor.isPositive(message);
   }
  
}
数字类型
java 复制代码
@AiService
public interface NumberExtractor {
  
  @UserMessage("从{{it}}中提取一个数字")
  int extractInt(String text);


  @UserMessage("从{{it}}中提取一个长数字")
  long extractLong(String text);


  @UserMessage("从{{it}}中提取一个大整数")
  BigInteger extractBigInteger(String text);


  @UserMessage("从{{it}}中提取浮点数")
  float extractFloat(String text);


  @UserMessage("从{{it}}中提取一个双精度数")
  double extractDouble(String text);


  @UserMessage("从{{it}}中提取一个大小数")
  BigDecimal extractBigDecimal(String text);
  
}

Bean POJO

java 复制代码
package org.ivy.chatmemory.service;


import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;


import java.time.LocalDate;


@AiService
public interface PojoExtractor {


  @UserMessage("从{{it}}中提取有关某人的信息")
  Person extractPerson(String text);




  @Data
  @ToString
  class Person{
    // 名字
    private String name;
    // 年龄
    private int age;
    // 出生日期
    private LocalDate birthDate;
   }
  
}

Java AI 开发工具_funcation函数调用!!

在人工智能的世界里,大语言模型(LLMs)不仅仅是文本生成的能手,它们还能触发实际的操作。这种能力,我们称之为函数调用或函数调用。

案列

有无工具时的效果

Request:

  • messages:

  • UserMessage:

  • text: 475695037565的平方根是多少?

Response:

  • AiMessage:

  • text: 475695037565的平方根约为689710。

使用一下工具的消息

public class NumberHandler {

/**

* 返回给定数字的平方根

* @param number

* @return

*/

@Tool("返回给定数字的平方根")

public double square(double number) {

return Math.sqrt(number);

}

}

函数调用的应用场景

  1. 触发外部操作:如发送邮件、控制智能家居设备等。
  2. 实时数据获取:解决 LLM 知识更新滞后的问题,如进行实时搜索或数据库查询。
  3. 复杂逻辑处理:处理 LLM 难以直接计算的复杂数据运算问题。

经验法则

为了增加LLM调用正确工具和参数的几率,我们应该提供清晰且明确的:

  • 工具名称
  • 工具的功能描述以及何时使用
  • 每个工具参数的描述

一个好的经验法则是:

如果人类能理解工具的用途和如何使用,那么LLM也能理解。

注意:

工具/函数调用与JSON模式不同。

Java AI 开发工具_动态函数调用

引言

在现代软件开发中,代码执行引擎的应用场景日益广泛。LangChain4j框架通过集成多种代码执行引擎,为开发者提供了强大的工具支持。

执行流程

在大模型执行function calling的流程中:

  1. 大模型首先返回可直接运行的脚本语言代码
  2. LangChain4j接收到这段可运行代码后,调用CodeExecutionEngine执行
  3. 执行结果返回给大模型

LangChain4j支持的执行引擎

LangChain4j目前支持两种主要的代码执行引擎:

  1. GraalVM

    • Polyglot: 允许在同一应用中无缝使用多种编程语言
    • Truffle: 用于构建语言引擎的框架,支持轻松添加新语言
  2. Judge0

    • 开源代码执行引擎,支持多种编程语言(C, C++, Java, Python, Ruby等)
    • 被誉为"世界上最先进的开源在线代码执行系统"

执行引擎测试

<dependency>

<groupId>dev.langchain4j</groupId>

<artifactId>langchain4j-code-execution-engine-graalvm-polyglot</artifactId>

</dependency>

调用 js 版本斐波那契数列
java 复制代码
CodeExecutionEngine engine = new GraalVmJavaScriptExecutionEngine();


String code = """
    function fibonacci(n) {
      if (n <= 1) return n;
      return fibonacci(n - 1) + fibonacci(n - 2);
     }
            
    fibonacci(10)
    """;


String result = engine.execute(code);
动态函数示例
1. 配置类
复制代码
ChatAssistant assistant = AiServices.builder(ChatAssistant.class)
     .chatLanguageModel(chatLanguageModel)
     .tools(new GraalVmJavaScriptExecutionTool())
     .build();
2. AI Service 定义
复制代码
 

public interface Assistant {

String chat(String message);

}

3. 测试

String chat = chatAssistant.chat("What is the square root of 485906798473894056 in scientific notation?");

System.out.println(chat);

Java AI 开发工具_函数增强搜索

网址:https://www.perplexity.ai/search/jin-tian-shang-zheng-zhi-shu-s-kvEtItD9TvaTH1rzDD_CFA

Web Search API 是一种接口,允许开发者通过程序化的方式实时搜索互联网,并从搜索引擎中提取结构化数据,可用于大模型、AI应用进行后续的处理与分析。

各类AI Native应用、RAG应用、AI Agent智能体在开发过程都会遇到联网获取互联网网页信息的需求,此时需要得到原始网页链接以及文本摘要,以用于给workflow中的大模型作为上下文总结使用。

Langchain4j 支持的搜索引擎

SearchApi 引擎 是否支持
Google Web Search
Google News
Bing
Bing News
Baidu

申请密钥

1、打开SearchAPI网站

https://www.searchapi.io/users/sign_up

2、获取 API KEY

Java AI 开发工具_函数增强搜索实现

在你的项目 pom.xml 中添加以下依赖:

<dependency>

<groupId>dev.langchain4j</groupId>

<artifactId>langchain4j-web-search-engine-searchapi</artifactId>

</dependency>

定义 Ai Service

java 复制代码
public interface ChatAssistant {


  @SystemMessage("""
           1.  搜索支持:你的职责是为用户提供基于网络搜索的支持。
           2.  事件验证:如果用户提到的事件尚未发生或信息不明确,你需要通过网络搜索确认或查找相关信息。
           3.  网络搜索请求:使用用户的查询创建网络搜索请求,并通过网络搜索工具进行实际查询。
           4.  引用来源:在最终回应中,必须包括搜索到的来源链接,以确保信息的准确性和可验证性。
      """)
  String chat(String message);
}

测试

LangChain4j_向量数据库介绍

什么是向量数据库?

向量数据库,顾名思义,它以高维向量的形式存储数据。这些向量是一串数字,代表了某个对象的特征或属性。每一个向量都对应着一个独一无二的实体,比如一段文字、一张图片或一段视频。

为什么选择向量呢?

向量的魅力在于它们能够精准捕捉到数据的语义含义和相似度。

向量数据库核心!!!

向量数据库的核心在于相似性搜索(Similarity Search)。将文本转换成向量,然后将向量存储在数据库中,当用户输入问题时,将问题转换成向量,然后在数据库中搜索最相似的向量和上下文,最后将文本返回给用户。

我们先思考一个问题?为什么我们在生活中区分不同的物品和事物?

然而单靠一个体型大小的特征并不够,像照片中哈士奇、金毛和拉布拉多的体型就非常接近,我们无法区分。所以我们会继续观察其它的特征,例如毛发的长短。

为何向量数据库受到青睐?

近年来,随着机器学习和人工智能领域的迅速发展,向量数据库的需求日益增加。AI 和 ML 模型需要处理的非结构化数据量巨大,这就需要一种有效的存储、检索和搜索方法。

重点:

采用了专门的搜索和索引算法,能够迅速地在数十亿条数据中找到相似的向量。

向量数据库的应用场景

向量数据库的出现极大地扩展了 AI 和 ML 应用的可能性。

一些典型的应用场景包括:

  • RAG 系统:将向量数据库与大型语言模型结合,可构建出基于知识的语言 AI 应用。
  • 推荐系统:利用向量数据库构建个性化推荐引擎,通过向量来表示用户偏好和商品特性。
  • 基于内容的检索:向量数据库能够搜索视觉上相似的图像或视频,彻底改变了内容检索方式。
  • 自然语言处理:通过将文本转换为向量,向量数据库支持语义搜索、主题建模和文档分类。
  • 欺诈检测:向量数据库能够帮助识别金融交易中的异常模式和趋势。

LangChain4j_Qdrant向量数据库

目前常见的向量数据库有 Qdrant, Milvus, Faiss 等等。

什么是Qdrant

"Qdrant "是一个向量相似性搜索引擎,提供生产就绪的服务,并配有方便的 API,用于存储、搜索和管理点(即向量)以及附加的有效负载。" 你可以将有效负载视为额外的信息片段,这些信息可以帮助你优化搜索,并向用户提供有用的信息。

由 Rust 编写的向量数据库, 在性能上自然是第一梯队的。

LangChain4j支持的向量数据库

LangChain支持多种向量数据库,每种数据库具有不同的特性。以下是部分支持的向量数据库及其功能:

向量存储 存储元数据 按元数据过滤 移除向量
内存存储
Astra DB
Azure AI Search
Azure CosmosDB Mongo vCore
Azure CosmosDB NoSQL
Cassandra
Chroma
Couchbase
Elasticsearch
Infinispan
Milvus
MongoDB Atlas 仅支持原生过滤
Neo4j
OpenSearch
Oracle
PGVector
Pinecone
Qdrant
Redis
Tablestore
Vearch
Vespa
Weaviate

Qdrant 目前实现了 4 种距离算法

余弦相似度:适用于比较向量的方向,而不考虑向量的大小. 比如文本相似度, 信息检索等.

欧氏距离:适用于度量两点之间的直线距离,考虑向量的大小和方向. 用于几何计算, 图像处理等.

点积:适用于度量向量的相对位置和方向. 常用于线性代数和信号处理等离散数据计算.

曼哈顿距离:适用于度量两点之间的网格距离,适合网格状或离散空间. 用于路径规划, 特征工程等.

Qdrant 架构概览

概念:

  • 集合 (collections): 可以类比为 MySQL 中的表, 里边存储了一条条的记录
  • Points: 这个结构类似 MySQL 中的一条记录, 这是一个实体, 由三部分组成
  • • 唯一 ID
  • • vector: 固定长度的向量, 在创建集合的时候, 就已经确定好的
  • • payload: 记录里携带的 json 对象, 我们也是我们要利用的核心数据
  • Storage: 向量的存储方式, 向量和 payload 会分开存储, 通过 payload 索引进行关联, 为了保证数据完整,

LangChain4j_Qdrant向量库安装

Qdrant是一个高性能的向量数据库,用于存储嵌入并进行快速的向量搜索。

配置镜像加速器

您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'

{

"registry-mirrors": ["https://dockerhub.xianfish.site","https://docker.m.daocloud.io"]

}

EOF

sudo systemctl daemon-reload

sudo systemctl restart docker

安装Qdrant

使用Docker安装Qdrant:

docker run --name myqdrant -d -p 6333:6333 -p 6334:6334 qdrant/qdrant
参数说明:

  • 端口6333:用于HTTP API
  • 端口6334:用于gRPC API

访问

http://192.168.47.120:6333/dashboard#/welcome

192这个要换成自己的

LangChain4j_集成LangChain4j与Qdrant

添加Maven依赖

<dependency>

<groupId>dev.langchain4j</groupId>

<artifactId>langchain4j-qdrant</artifactId>

</dependency>

<dependency>

<groupId>dev.langchain4j</groupId>

<artifactId>langchain4j-zhipu-ai</artifactId>

<version>0.35.0</version>

</dependency>

创建Qdrant客户端

@Bean

public QdrantClient qdrantClient() {

QdrantGrpcClient.Builder grpcClientBuilder = QdrantGrpcClient.newBuilder("192.168.66.120", 6334, false);

return new QdrantClient(grpcClientBuilder.build());

}

创建索引

var vectorParams = Collections.VectorParams.newBuilder()

.setDistance(Collections.Distance.Cosine)

.setSize(1024)

.build();

qdrantClient.createCollectionAsync("testv", vectorParams);

配置Qdrant Embedding Store

/**

* 存储向量地方

* @return

*/

@Bean

public EmbeddingStore<TextSegment> embeddingStore(){

return QdrantEmbeddingStore.builder()

.host("192.168.47.120")

.port(6334)

.collectionName("itbaizhan")

.build();

}

配置向量模型

java 复制代码
/**
   * Embedding Model 向量模型,机器学习模型,核心功能 将高维数据映射到低维空间的技术。
   * 离散的,稀疏的数据转换连续的、密集的向量表示
   *       Duration callTimeout,
   *       Duration connectTimeout,
   *       Duration readTimeout,
   *       Duration writeTimeout
   * @return
   */
  @Bean
  public EmbeddingModel embeddingModel(){
    return ZhipuAiEmbeddingModel.builder()
         .apiKey("842df645f867724dddfbdd1145162a03.VlzbHzSVUg5y0Q9r")
         .callTimeout(Duration.ofSeconds(1000))
         .connectTimeout(Duration.ofSeconds(1000))
         .readTimeout(Duration.ofSeconds(1000))
         .writeTimeout(Duration.ofSeconds(1000))
         .build();
   }

文本生成与存储

java 复制代码
 /**
   * 存储文本到向量数据库
   */
  @Test
  public void saveText(){
    TextSegment from1 = TextSegment.from("客服的电话是400-3464563");
    TextSegment from2 = TextSegment.from("客服工作时间是周一到周五");
    TextSegment from3 = TextSegment.from("客服的投诉电话是400-123456");
    TextSegment from4 = TextSegment.from("客服的人数是245");
    // 转换向量
    Embedding content1 = embeddingModel.embed(from1).content();
    Embedding content2 = embeddingModel.embed(from2).content();
    Embedding content3 = embeddingModel.embed(from3).content();
    Embedding content4 = embeddingModel.embed(from4).content();
    // 存储入向量数据库
    embeddingStore.add(content1,from1);
    embeddingStore.add(content2,from2);
    embeddingStore.add(content3,from3);
    embeddingStore.add(content4,from4);
   }

向量查询与过滤

  1. 基本向量查询:
java 复制代码
/**
   * 向量查询与过滤
   */
  @Test
  public void search(){
    // 问题
    String msg = "你们公司客服的人数是多少";
    // 问题向量
    Embedding embedding = embeddingModel.embed(msg).content();
    // 搜索
    EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
         .maxResults(1)
         .queryEmbedding(embedding)
         .build();
    EmbeddingSearchResult search = embeddingStore.search(request);
    System.out.println(search.matches().get(0));
   }


  /**
   * 向量查询与过滤 元数据
   */
  @Test
  public void datameate(){
    TextSegment from1 = TextSegment.from("客服的女生人数是67人");
    from1.metadata().put("author","lisi");
    // 转换向量
    Embedding content1 = embeddingModel.embed(from1).content();
    // 存储入向量数据库
    embeddingStore.add(content1,from1);
    // 问题
    String msg = "你们公司客服有多少女生";
    // 问题向量
    Embedding embedding = embeddingModel.embed(msg).content();
    // 搜索
    EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
         .maxResults(1)
        // 过滤
         .filter(metadataKey("author").isEqualTo("lisi"))
         .queryEmbedding(embedding)
         .build();
    EmbeddingSearchResult search = embeddingStore.search(request);
    if (!CollectionUtils.isEmpty(search.matches())){
      List matches = search.matches();
      for (Object match : matches) {
        System.out.println(match);
       }
     }
   }

常用过滤器:

Filter名称 功能 使用示例
And 同时满足多个条件 Filter.and(condition1, condition2)
Or 满足其中任意一个条件 Filter.or(condition1, condition2)
Not 不满足条件 Filter.not(condition)
IsEqualTo 等于 new IsEqualTo("field", "value")
IsGreaterThan 大于 new IsGreaterThan("field", value)
IsLessThan 小于 new IsLessThan("field", value)
IsIn 在列表内 new IsIn("field", listOfValues)

LangChain4j_内容审查助手

敏感词过滤的应用场景

  • 社交网络:实时监控聊天记录,防止不当言论传播。
  • 在线评论系统:过滤用户评论中的敏感词,保护品牌声誉。
  • 用户注册:验证用户名和简介,确保符合社区准则。
  • 邮件系统:检测垃圾邮件,保障用户信息安全。

Sensitive-Word 简介

sensitive-word 是一个 Java 编写的敏感词过滤工具包,可以用于对文本中的敏感词进行过滤。该工具包提供了多种敏感词匹配算法,并支持自定义敏感词库和替换策略。使用该工具包可以有效地保护用户隐私,防止不良信息的传播。

主要功能和特点
  1. 高性能:能够处理大量关键词集,并在极短的时间内完成文本扫描。
  2. 灵活配置:支持多种配置方式,包括动态加载敏感词字典。
  3. 易于扩展:提供插件架构,方便添加新的过滤规则和替换策略。
  4. 全面文档:拥有详细的使用文档和示例代码,帮助开发者快速上手。
1. 通过Maven引入依赖

<dependency>

<groupId>com.github.houbb</groupId>

<artifactId>sensitive-word</artifactId>

<version>0.21.0</version>

</dependency>

2. 基本使用示例
java 复制代码
@Test
void testWord() {
 String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
//输出是否包含敏感词
 System.out.println(SensitiveWordHelper.contains(text));

//默认替换为*
 System.out.println(SensitiveWordHelper.replace(text));
 System.out.println(SensitiveWordHelper.replace(text, '0'));

//查找出第一个敏感词
 System.out.println(SensitiveWordHelper.findFirst(text));
 System.out.println(SensitiveWordHelper.findFirst(text, WordResultHandlers.word()));
 System.out.println(SensitiveWordHelper.findFirst(text, WordResultHandlers.raw()));

//查找全部的敏感词
 System.out.println(SensitiveWordHelper.findAll(text));
 System.out.println(SensitiveWordHelper.findAll(text, WordResultHandlers.word()));
 System.out.println(SensitiveWordHelper.findAll(text, WordResultHandlers.raw()));


}
相关推荐
爬山算法1 天前
Hibernate(25)Hibernate的批量操作是什么?
java·后端·hibernate
2501_941875281 天前
从日志语义到可观测性的互联网工程表达升级与多语言实践分享随笔
java·前端·python
高山上有一只小老虎1 天前
小红的字符串
java·算法
vibag1 天前
LangGraph全家桶使用
python·语言模型·langchain·大模型·langgraph
星火开发设计1 天前
折半插入排序原理与C++实现详解
java·数据结构·c++·学习·算法·排序算法·知识
欧阳天羲1 天前
ML工程师学习大纲
学习·算法·决策树
柒.梧.1 天前
深度解析Spring Bean生命周期以及LomBok插件
java·后端·spring
Hcoco_me1 天前
大模型面试题43:从小白视角递进讲解大模型训练的梯度累加策略
人工智能·深度学习·学习·自然语言处理·transformer