前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >基于🦜☕️ LangChain4j 实现问答机器人

基于🦜☕️ LangChain4j 实现问答机器人

原创
作者头像
花花Binki
发布2024-11-12 23:31:26
发布2024-11-12 23:31:26
9280
举报
封面
封面

2022 年 11 月 30 日,OpenAI 发布了基于 GPT-3.5 模型调优的新一代对话式AI模型 ChatGPT。随后的一段时间,国内外各大厂商都纷纷跟进,以至于在 2023 年间出现了“百模大战”这一历史节点。

如今的大语言模型(Large Language Model,简称LLM),无论是在底层的基座,还是下游的应用都取得了很大的成功。其中,在2022年同期发布的 LangChain 框架作为LLM应用层开发框架,备受追捧。不过,最开始的时候,并没有 Java 语言的实现。

“一个访问HTTPS的接口的轮子罢了,有什么困难?”

是的,所以23年末,就出现了 LangChain4J 这款产品。Spring 家族也在 24 年中旬发布了Spring AI的 M1 (Milestone 1)版本。

让主 Java 语言的开发者喊出那句话:"Make Java Great Again!"。

目录

关于这只“鹦鹉” 快速演示 机器人实战

关于这只“鹦鹉”

在官方的GitHub下面,有人提问(issues/8673):

LangChain 的 logo 有什么含义?

只有一个非官方的回答:

AI 大型语言模型经常被比作或称为“随机鹦鹉”,这是一种花哨的说法,即它们可以生成模仿人类输出的文本,但它们对生成的内容没有任何真正的“理解”。这个库的作用是将这些 “鹦鹉” 链接在一起,以获得更有意义和有用的输出。

其实这也隐喻着 LLM 的一个本质:模仿🦜与思维链🔗

LangChain4j并没有像原框架那么完善的体系,不过对于简化 Java 在 LLMs 的开发已经非常足够。

功能介绍
功能介绍

快速上手

如果只想快速体验一下 AI 应用开发,只需要一个简易的 Maven 即可。

配置

只需要官方的 OpenAI 包即可使用。这里的 LLM 的选择并不强制绑定国外,国内对于 API 的兼容性还是比较好的。

代码语言:xml
复制
    <dependency>
	    <groupId>dev.langchain4j</groupId>
	    <artifactId>langchain4j-open-ai</artifactId>
	</dependency>

key的选择

对于 API Key,官方提供了一个演示的“后门”,只需要把 Key 的值设置为 Demo 即可。当然,这是一个限量的,并且依赖比较自由的网络。

对于大多数而言,选择一个国内的大模型更为便捷。以下使用腾讯的hunyuan-lite作为演示。

大模型控制台
大模型控制台

将 key 放环境变量(可选),放在代码中也是可以的

环境变量的设置
环境变量的设置

编码

由于太过简化,直接上代码演示:

#main 中的逻辑,省去了非核心代码。

代码语言:java
复制
// 从系统变量中取得key
String apiKey = System.getenv("hunyuan_key");
// 配置基础模型,此处使用了builder设计模式,链式调用。
OpenAiChatModel model = OpenAiChatModel.builder()
  .apiKey(apiKey)
  .modelName("hunyuan-lite")
  .baseUrl("https://api.hunyuan.cloud.tencent.com/v1")
  .build();
// 发送请求,并将答案赋给answer
String answer = model.generate("如何高效学习");
// 引入log是为了方便后续调试。使用System.out.println输出也是没有问题的!
log.info(answer);

hunyuan-lite是免费模型,在功能和速度上有一点限制。再加上是直接输出,可能需要等待一点时间:

稍后可在控制台看到类似的以下输出:

基础输出
基础输出

流式回答

在与 ChatGPT 进行对话时,可以观察到它是一个字一个字的“敲”出来。避开 LLM 的原理不谈,Java 该如何实现呢?

框架已经想好了这一部分,详细说明查看 dev.langchain4j.model.StreamingResponseHandler

代码语言:java
复制
public interface StreamingResponseHandler<T> {
  // 拿到响应时的处理
  void onNext(String token);
  // 响应结束时的处理
  default void onComplete(Response<T> response) {}
  // 出现异常的处理
  void onError(Throwable error);
}

对于这样的接口实现,可以选择实现类-> 匿名实现类->lambda表达式->方法引用。

最后得到如下代码:

代码语言:java
复制
String apiKey = System.getenv("hunyuan_key");
OpenAiStreamingChatModel openAiStreamingChatModel = OpenAiStreamingChatModel.builder()
  .apiKey(apiKey)
  .modelName("hunyuan-lite")
  .baseUrl("https://api.hunyuan.cloud.tencent.com/v1")
  .build();

openAiStreamingChatModel.generate("如何高效学习", onNext(System.out::print));

效果演示

流式输出
流式输出

机器人实战

接下来进入机器人搭建的实战

初始化

虽说不强制绑定Spring,但就目前环境来说,开发一个应用还是离不开他。为了能够让前端能更好的呈现效果,还需要引入Flux相关依赖:

代码语言:xml
复制
		<dependency>
		    <groupId>dev.langchain4j</groupId>
		    <artifactId>langchain4j-reactor</artifactId>
		    <version>0.35.0</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

AI 服务

在boot项目中,如果想全局任意位置调用一个服务,需要使用@Bean注解。AI 也可以如此。

代码语言:java
复制
@Configuration
public class HunyuanStreamModelConfig {

    @Bean
    OpenAiStreamingChatModel getHunyuanAI() {
        String apiKey = System.getenv("hunyuan_key");
        OpenAiStreamingChatModel openAiStreamingChatModel = OpenAiStreamingChatModel.builder()
                .apiKey(apiKey)
                .modelName("hunyuan-lite")
                .baseUrl("https://api.hunyuan.cloud.tencent.com/v1")
                .build();
        return openAiStreamingChatModel;
    }
}
...
// 使用
@Resource
private OpenAiStreamingChatModel model;

而现实情况是,有时需要记忆功能,有时需要嵌入功能。一个固定了的模型对象有点捉襟见肘,以上这种不是很推荐。

对于LangChain4j 来说,他们提供的AI Service 是一个简单模板接口。通过注解加入出参,完成了提示词模板,格式化输出等操作。

代码语言:java
复制
public interface Assistant {

	@UserMessage("下面的描述正确吗?{{message}}")
	boolean isRight(String message);

流式输出以及接收

本篇主题不为前端,但简单介绍一下如何对流式问题做出响应。

前端处理

代码语言:js
复制
const response = await fetch('/ai-answer?question=如何进行高效的学习');
if (!response.ok) {
  throw new Error('网络请求错误');
}
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let result = '';
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  result += decoder.decode(value, { stream: true });
  // 动态更新页面内容
  document.getElementById('answer').innerHTML += decoder.decode(value, { stream: true }).replaceAll("data:","");
}

后端的接口为“/ai-answer”,所以在第一行使用fetch发出请求。8-9 行为正式处理流。

后端Controller

代码语言:java
复制
@GetMapping(value = "/ai-answer", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamAnswers(String question) {
    return getStreamingAnswer(question);
}

Flux<String> getStreamingAnswer(String question) {
    String apiKey = System.getenv("hunyuan_key");
    OpenAiStreamingChatModel openAiStreamingChatModel = OpenAiStreamingChatModel.builder()
            .apiKey(apiKey)
            .modelName("hunyuan-lite")
            .baseUrl("https://api.hunyuan.cloud.tencent.com/v1")
            .build();
    Assistant assistant = AiServices.create(Assistant.class, openAiStreamingChatModel);

    return assistant.chat(question);
}

演示效果

展示
展示

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 关于这只“鹦鹉”
  • 快速上手
    • 配置
      • key的选择
    • 编码
    • 流式回答
  • 机器人实战
    • 初始化
    • AI 服务
    • 流式输出以及接收
      • 前端处理
      • 后端Controller
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档