当前位置: 首页 > news >正文

使用Java拓展本地开源大模型的网络搜索问答能力

在这里插入图片描述

背景

开源大模型通常不具备最新语料的问答能力。因此需要外部插件的拓展,目前主流的langChain框架已经集成了网络搜索的能力。但是作为一个倔强的Java程序员,还是想要用Java去实现。

注册SerpAPI

Serpapi 提供了多种搜索引擎的搜索API接口。
访问 Serpapi 官网上注册一个用户:

https://serpapi.com/

在这里插入图片描述

可以选择Free Plan,提供每月100次的免费使用。接下来就是使用自己的邮箱和手机号进行注册。
在这里插入图片描述
注册成功登录:
在这里插入图片描述

创建SerpApiHttp对象

public class SerpApiHttp {private int httpConnectionTimeout;private int httpReadTimeout;/*** 后端服务地址*/private static final String BACK_END = "https://serpapi.com";/*** 初始化Gson对象*/private static Gson gson = new Gson();/*** 当前后端HTTP路径*/public String path;/**** 构造函数* @param path HTTP url路径*/public SerpApiHttp(String path) {this.path = path;}/**** 建立Socket连接** @param path URL端点* @param parameter 客户端参数,如: { "q": "coffee", "location": "Austin, TX"}* @return HttpURLConnection 连接对象* @throws SerpApiException 包装错误信息*/protected HttpURLConnection connect(String path, Map<String, String> parameter) throws SerpApiException {HttpURLConnection con;try {//allowHTTPS(); // 允许HTTPS支持String query = ParameterStringBuilder.getParamsString(parameter);URL url = new URL(BACK_END + path + "?" + query);con = (HttpURLConnection) url.openConnection();con.setRequestMethod("GET");} catch (IOException e) {throw new SerpApiException(e);} catch (Exception e) {e.printStackTrace();throw new SerpApiException(e);}String outputFormat = parameter.get("output");if (outputFormat == null) {throw new SerpApiException("output format must be defined: " + path);} else if (outputFormat.startsWith("json")) {con.setRequestProperty("Content-Type", "application/json");}con.setConnectTimeout(getHttpConnectionTimeout());con.setReadTimeout(getHttpReadTimeout());con.setDoOutput(true);return con;}/**** 返回HTTP响应内容的原始字符串** @param parameter 用户客户端参数* @return HTTP响应体* @throws SerpApiException 包装错误信息*/public String get(Map<String, String> parameter) throws SerpApiException {HttpURLConnection con = connect(this.path, parameter);// 获取HTTP状态码int statusCode = -1;// 保存响应流InputStream is = null;// 读取缓冲区BufferedReader in = null;try {statusCode = con.getResponseCode();if (statusCode == 200) {is = con.getInputStream();} else {is = con.getErrorStream();}Reader reader = new InputStreamReader(is);in = new BufferedReader(reader);} catch (IOException e) {throw new SerpApiException(e);}String inputLine;StringBuilder content = new StringBuilder();try {while ((inputLine = in.readLine()) != null) {content.append(inputLine);}in.close();} catch (IOException e) {throw new SerpApiException(e);}// 断开连接con.disconnect();if (statusCode != 200) {triggerSerpApiException(content.toString());}return content.toString();}/*** 在错误情况下触发异常** @param content 从serpapi.com返回的原始JSON响应* @throws SerpApiException 包装错误信息*/protected void triggerSerpApiException(String content) throws SerpApiException {String errorMessage;try {JsonObject element = gson.fromJson(content, JsonObject.class);errorMessage = element.get("error").getAsString();} catch (Exception e) {throw new AssertionError("invalid response format: " + content);}throw new SerpApiException(errorMessage);}/*** @return 当前HTTP连接超时时间*/public int getHttpConnectionTimeout() {return httpConnectionTimeout;}/*** @param httpConnectionTimeout 设置HTTP连接超时时间*/public void setHttpConnectionTimeout(int httpConnectionTimeout) {this.httpConnectionTimeout = httpConnectionTimeout;}/*** @return 当前HTTP读取超时时间*/public int getHttpReadTimeout() {return httpReadTimeout;}/*** @param httpReadTimeout 设置HTTP读取超时时间*/public void setHttpReadTimeout(int httpReadTimeout) {this.httpReadTimeout = httpReadTimeout;}
}

创建SerpApi对象

public class SerpApi extends Exception {/*** 客户端参数*/private final Map<String, String> parameter;/*** 初始化 gson*/private static final Gson gson = new Gson();/*** Java 7+ 的 https 客户端实现*/private final SerpApiHttp client;/*** 默认 HTTP 客户端超时时间*/private static final Integer TIME_OUT = 60000;/*** 搜索路径*/private static final String SEARCH_PATH = "/search";/**** 构造函数** @param parameter 默认搜索参数,应包括 {"api_key": "secret_api_key", "engine": "google" }*/public SerpApi(Map<String, String> parameter) {this.parameter = parameter;this.client = new SerpApiHttp(SEARCH_PATH);this.client.setHttpConnectionTimeout(TIME_OUT);}/**** 返回原始HTML搜索结果** @param parameter HTML搜索参数* @return 从客户端引擎获取的原始HTML响应,用于自定义解析* @throws SerpApiException 封装后端错误消息*/public String html(Map<String, String> parameter) throws SerpApiException {return get("/client", "html", parameter);}/**** 返回JSON格式的搜索结果** @param parameter 自定义搜索参数,可覆盖构造函数中提供的默认参数* @return JSON对象,包含搜索结果的顶层节点* @throws SerpApiException 封装后端错误消息*/public JsonObject search(Map<String, String> parameter) throws SerpApiException {return json(SEARCH_PATH, parameter);}/**** 使用Location API返回位置信息** @param parameter 必须包括 {q: "city", limit: 3}* @return JSON数组,使用Location API返回的位置信息* @throws SerpApiException 封装后端错误消息*/public JsonArray location(Map<String, String> parameter) throws SerpApiException {String content = get("/locations.json", "json", parameter);JsonElement element = gson.fromJson(content, JsonElement.class);return element.getAsJsonArray();}/**** 通过Search Archive API检索搜索结果** @param id 搜索的唯一标识符* @return 客户端结果的JSON对象* @throws SerpApiException 封装后端错误消息*/public JsonObject searchArchive(String id) throws SerpApiException {return json("/searches/" + id + ".json", null);}/**** 使用Account API获取账户信息** @param parameter 包含api_key的Map,如果未在默认客户端参数中设置* @return JSON对象,账户信息* @throws SerpApiException 封装后端错误消息*/public JsonObject account(Map<String, String> parameter) throws SerpApiException {return json("/account.json", parameter);}/**** 使用Account API获取账户信息** @return JSON对象,账户信息* @throws SerpApiException 封装后端错误消息*/public JsonObject account() throws SerpApiException {return json("/account.json", null);}/**** 将HTTP内容转换为JsonValue** @param endpoint 原始JSON HTTP响应* @return 通过gson解析器创建的JSON对象*/private JsonObject json(String endpoint, Map<String, String> parameter) throws SerpApiException {String content = get(endpoint, "json", parameter);JsonElement element = gson.fromJson(content, JsonElement.class);return element.getAsJsonObject();}/**** 获取HTTP客户端** @return 客户端实例*/public SerpApiHttp getClient() {return this.client;}/**** 扩展现有参数构建Serp API查询** @param path 后端HTTP路径* @param output 输出类型(json, html, json_with_images)* @param parameter 自定义搜索参数,可覆盖默认参数* @return 格式化参数HashMap* @throws SerpApiException 封装后端错误消息*/public String get(String path, String output, Map<String, String> parameter) throws SerpApiException {// 更新客户端路径this.client.path = path;// 创建HTTP查询Map<String, String> query = new HashMap(16);if (path.startsWith("/searches")) {// 仅保留API_KEYquery.put("api_key", this.parameter.get("api_key"));} else {// 合并默认参数query.putAll(this.parameter);}// 用自定义参数覆盖默认参数if (parameter != null) {query.putAll(parameter);}// 设置当前编程语言query.put("source", "java");// 设置输出格式query.put("output", output);return this.client.get(query);}
}

构建WebSearchChain

public class WebSearchChain {/*** apiKey*/private String apiKey;/*** 构造函数* @param apiKey*/public WebSearchChain(String apiKey){this.apiKey = apiKey;}/*** 初始化* @param apiKey* @return*/public static WebSearchChain fromLlm(String apiKey){return new WebSearchChain(apiKey);}/*** 搜索* @param question* @return*/public String search(String question){Map<String, String> parameter = new HashMap<>();parameter.put("api_key", apiKey);parameter.put("q", question);parameter.put("hl", "zh-cn");parameter.put("gl", "cn");parameter.put("google_domain", "google.com");parameter.put("safe", "active");parameter.put("start", "10");parameter.put("num", "10");parameter.put("device", "desktop");SerpApi serpapi = new SerpApi(parameter);JsonObject results = null;StringBuilder stringBuilder = new StringBuilder();try {results = serpapi.search(parameter);results.getAsJsonArray("organic_results").forEach(organicResult->{JsonObject result = organicResult.getAsJsonObject();String title = result.getAsJsonPrimitive("title").getAsString();String snippet = result.getAsJsonPrimitive("snippet").getAsString();stringBuilder.append(title).append("。").append(snippet).append("。");});} catch (SerpApiException e) {e.printStackTrace();}return stringBuilder.toString();}
}

使用

博主之前借鉴langChain的思路封装一个Java版的框架,可参考:https://blog.csdn.net/weixin_44455388/article/details/137098743?spm=1001.2014.3001.5501

因此,直接调用即可:

public static void test7() {String prompt = "吴亦凡犯了什么事";OpenAIChat openAIChat = OpenAIChat.builder().endpointUrl("http://192.168.0.84:9997/v1").model("Qwen1.5-14B-Chat").build().init();WebSearchChain webSearchChain = WebSearchChain.fromLlm("48d1bd8f7419xxxxxxxxxxxxxxxxxxxxxxxxxxxx");String searchResult = webSearchChain.search(prompt);Flux<String> stringFlux = openAIChat.streamChatWithChain("112233", "你是一个AI助手", searchResult, prompt);stringFlux.subscribe();
}

在这里插入图片描述

相关文章:

使用Java拓展本地开源大模型的网络搜索问答能力

背景 开源大模型通常不具备最新语料的问答能力。因此需要外部插件的拓展&#xff0c;目前主流的langChain框架已经集成了网络搜索的能力。但是作为一个倔强的Java程序员&#xff0c;还是想要用Java去实现。 注册SerpAPI Serpapi 提供了多种搜索引擎的搜索API接口。 访问 Ser…...

Mybatis——一对多关联映射

一对多关联映射 一对多关联映射有两种方式&#xff0c;都用到了collection元素 以购物网站中用户和订单之间的一对多关系为例 collection集合的嵌套结果映射 创建两个实体类和映射接口 package org.example.demo;import lombok.Data;import java.util.List;Data public cla…...

Pytorch实用教程:TensorDataset和DataLoader的介绍及用法示例

TensorDataset TensorDataset是PyTorch中torch.utils.data模块的一部分&#xff0c;它包装张量到一个数据集中&#xff0c;并允许对这些张量进行索引&#xff0c;以便能够以批量的方式加载它们。 当你有多个数据源&#xff08;如特征和标签&#xff09;时&#xff0c;TensorD…...

uni-app如何实现高性能

这篇文章主要讲解uni-app如何实现高性能的问题&#xff1f; 什么是uni-app&#xff1f; 简单说一下什么是uni-app&#xff0c;uni-app是继承自vue.js&#xff0c;对vue做了轻度定制&#xff0c;并且实现了完整的组件化开发&#xff0c;并且支持多端发布的一种架构&#xff0c…...

docker 应用部署

参考:docker 构建nginx服务 环境 Redhat 9 步骤&#xff1a; 1、docker部署MySQL 安装yum 工具包 [rootadmin ~]# yum -y install yum-utils.noarch 正在更新 Subscription Management 软件仓库。 无法读取客户身份本系统尚未在权利服务器中注册。可使用 subscription-…...

java.awt.FontFormatException: java.nio.BufferUnderflowException

Font awardFont Font.createFont(Font.TRUETYPE_FONT, awardFontFile).deriveFont(120f).deriveFont(Font.BOLD);使用如上语句创建字体时出现问题。java.awt.FontFormatException: java.nio.BufferUnderflowException异常表明在处理字体数据时出现了缓冲区下溢&#xff08;Buf…...

C++ 枚举类型 ← 关键字 enum

【知识点&#xff1a;枚举类型】● 枚举类型&#xff08;enumeration&#xff09;是 C 中的一种派生数据类型&#xff0c;它是由用户定义的若干枚举常量的集合。 ● 枚举元素作为常量&#xff0c;它们是有值的。C 编译时&#xff0c;依序对枚举元素赋整型值 0,1,2,3,…。 下面代…...

MySQL故障排查与优化

一、MySQL故障排查 1.1 故障现象与解决方法 1.1.1 故障1 1.1.2 故障2 1.1.3 故障3 1.1.4 故障4 1.1.5 故障5 1.1.6 故障6 1.1.7 故障7​ 1.1.8 故障8 1.1.9 MySQL 主从故障排查 二、MySQL优化 2.1 硬件方面 2.2 查询优化 一、MySQL故障排查 1.1 故障现象与解决方…...

如何做一个知识博主? 善用互联网检索

Google 使用引号: 使用双引号将要搜索的短语括起来,以便搜索结果中只包含该短语。例如,搜索 "人工智能" 将只返回包含该短语的页面。 排除词汇: 在搜索中使用减号 "-" 可以排除特定词汇。例如,搜索 "苹果 -手机" 将返回关于苹果公司的结果,但…...

《QT实用小工具·十》本地存储空间大小控件

1、概述 源码放在文章末尾 本地存储空间大小控件&#xff0c;反应电脑存储情况&#xff1a; 可自动加载本地存储设备的总容量/已用容量。进度条显示已用容量。支持所有操作系统。增加U盘或者SD卡到达信号。 下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #if…...

作为一个初学者该如何学习kali linux?

首先你要明白你学KALI的目的是什么&#xff0c;其次你要了解什么是kali&#xff0c;其实你并不是想要学会kali你只是想当一个hacker kali是什么&#xff1a; 只是一个集成了多种渗透工具的linux操作系统而已&#xff0c;抛开这些工具&#xff0c;他跟常规的linux没有太大区别。…...

多线程学习-线程池

目录 1.线程池的作用 2.线程池的实现 3.自定义创建线程池 1.线程池的作用 当我们使用Thread的实现类来创建线程并调用start运行线程时&#xff0c;这个线程只会使用一次并且执行的任务是固定的&#xff0c;等run方法中的代码执行完之后这个线程就会变成垃圾等待被回收掉。如…...

Linux第4课 Linux的基本操作

文章目录 Linux第4课 Linux的基本操作一、图形界面介绍二、终端界面介绍 Linux第4课 Linux的基本操作 一、图形界面介绍 本节以Ubuntu系统的GUI为例进行说明&#xff0c;Linux其他版本可自行网搜。 图形系统进入后&#xff0c;左侧黄框内为菜单栏&#xff0c;右侧为桌面&…...

堆排序解读

在算法世界中&#xff0c;排序算法一直是一个热门话题。推排序&#xff08;Heap Sort&#xff09;作为一种基于堆这种数据结构的有效排序方法&#xff0c;因其时间复杂度稳定且空间复杂度低而备受青睐。本文将深入探讨推排序的原理、实现方式&#xff0c;以及它在实际应用中的价…...

docker + miniconda + python 环境安装与迁移(详细版)

本文主要列出从安装dockerpython环境到迁移环境的整体步骤。windows与linux之间进行测试。 简化版可以参考&#xff1a;docker miniconda python 环境安装与迁移&#xff08;简化版&#xff09;-CSDN博客 目录 一、docker 安装和测试 二、docker中拉取miniconda&#xff…...

蓝桥杯刷题第八天(dp专题)

这道题有点像小学奥数题&#xff0c;解题的关键主要是&#xff1a; 有2种走法固走到第i级阶梯&#xff0c;可以通过计算走到第i-1级和第i-2级的走法和&#xff0c;可以初始化走到第1级楼梯和走到第2级楼梯。分别为f[1]1;f[2]1(11)1(2)2.然后就可以循环遍历到后面的状态。 f[i…...

【WEEK6】 【DAY1】DQL查询数据-第一部分【中文版】

2024.4.1 Monday 目录 4.DQL查询数据&#xff08;重点&#xff01;&#xff09;4.1.Data Query Language查询数据语言4.2.SELECT4.2.1.语法4.2.2.实践4.2.2.1.查询字段 SELECT 字段/* FROM 表查询全部的某某查询指定字段 4.2.2.2.给查询结果或者查询的这个表起别名&#xff08…...

Linux:权限篇

文章目录 前言1.用户2.文件的权限管理2.1 修改文件的权限2.2 修改文件的拥有者2.3 修改文件的所属组 3.file指令4.umask指令4.目录的权限管理总结 前言 Linux权限在两个地方有所体现&#xff0c;一种是使用用户&#xff1a;分为root超级用户员与普通用户。另一个是体现在文件的…...

Lua热更新(xlua)

发现错误时检查是否:冒号调用 只需要导入asset文件夹下的Plugins和Xlua这两个文件即可,别的不用导入 生成代码 和清空代码 C#调用lua using Xlua; 需要引入命名空间 解析器里面执行lua语法 lua解析器 LuaEnv 单引号是为了避免引号冲突 第二个参数是报错时显示什么提示…...

并查集(基础+带权以及可撤销并查集后期更新)

并查集 并查集是一种图形数据结构&#xff0c;用于存储图中结点的连通关系。 每个结点有一个父亲&#xff0c;可以理解为“一只伸出去的手”&#xff0c;会指向另一个点&#xff0c;初始时指向自己。一个点的根节点是该点的父亲的父亲的..的父亲&#xff0c;直到某个点的父亲…...

DeepSeek-R1补全能力封测倒计时(仅剩72小时开放API灰度权限):这份内部测试SOP已被3家头部科技公司紧急采购

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek-R1代码补全能力封测全景概览 DeepSeek-R1 是深度求索&#xff08;DeepSeek&#xff09;推出的高性能开源推理模型&#xff0c;在代码补全场景中展现出显著的上下文理解力与多语言泛化能力。本…...

如何快速解锁中兴光猫权限:zteOnu工具完整使用指南

如何快速解锁中兴光猫权限&#xff1a;zteOnu工具完整使用指南 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 中兴光猫作为家庭网络的核心设备&#xff0c;其强大的硬件性能常常被默认…...

OmenSuperHub:基于WMI BIOS控制的高性能笔记本硬件管理方案

OmenSuperHub&#xff1a;基于WMI BIOS控制的高性能笔记本硬件管理方案 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 在惠…...

总线式智能提示灯系统设计:从恒流驱动到模块化架构

1. 项目概述&#xff1a;从传统到智能的剧场提示灯系统革新在剧场、演播室或者大型活动现场的后台&#xff0c;如果你待过&#xff0c;一定对那套“红灯停&#xff0c;绿灯行”的提示灯系统不陌生。导演或舞台监督通过对讲机喊“Standby”&#xff08;准备&#xff09;&#xf…...

在Node.js服务中集成Taotoken实现稳定的大模型能力调用

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 在Node.js服务中集成Taotoken实现稳定的大模型能力调用 对于需要在后端服务中集成AI功能的Node.js开发者而言&#xff0c;直接对接…...

ComfyUI-Manager完全指南:掌握AI工作流管理的核心技术

ComfyUI-Manager完全指南&#xff1a;掌握AI工作流管理的核心技术 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various custo…...

为什么你明明很努力,领导却总看不到?问题出在这

许多测试同行在深夜加班排查Bug时&#xff0c;在凌晨赶写自动化脚本时&#xff0c;在对着海量数据做性能分析时&#xff0c;内心都会浮现一个共同的困惑&#xff1a;我明明已经这么拼了&#xff0c;为什么在领导眼里&#xff0c;我依然是个“找茬的”&#xff0c;而不是“创造价…...

从B站缓存困境到MP4自由:m4s-converter完整解决方案

从B站缓存困境到MP4自由&#xff1a;m4s-converter完整解决方案 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 当B站视频突然下架&#xff0c;那…...

一、[特殊字符]️ 误拦噩梦:护栏上线后的真实反弹

一、&#x1f6e1;️ 误拦噩梦&#xff1a;护栏上线后的真实反弹 不少团队在 LLM 推理服务中部署输入护栏后&#xff0c;遇到的第一个生产事故不是攻击漏过&#xff0c;而是正常请求被大规模误拦。某医疗平台上线正则输入过滤后&#xff0c;用户咨询“心绞痛的症状”被拦截&…...

小学阶段物理学习书籍推荐

结合小学阶段认知特点&#xff0c;推荐以下几本兼具趣味性和实用性的物理启蒙书籍&#xff0c;适配不同年级孩子的学习需求&#xff1a; 一、低龄&#xff08;1-2年级/6-8岁&#xff09;&#xff1a;趣味感知&#xff0c;激发好奇 1、漫画物理全套6册 用孩子最喜欢的漫画形式拆…...