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

从RestTemplate到RestClient:Spring HTTP客户端的现代化演进

1. 老朋友RestTemplate曾经的功臣与如今的困境如果你用Spring做过项目特别是几年前的项目大概率会碰到RestTemplate。它就像是Spring生态里一个任劳任怨的老伙计帮你处理各种HTTP请求调用外部API简单直接。我刚开始用的时候也觉得挺方便getForObject、postForEntity方法名一看就懂配个RestTemplate的Bean就能开干。在单体应用或者并发不高的场景下它确实够用也陪伴了无数项目从零到一。但技术这玩意儿发展得太快了。随着微服务架构成为主流一个服务动不动就要调用几十个其他服务的接口这时候RestTemplate的一些“老毛病”就开始暴露出来了。最核心的问题就是它的阻塞式同步模型。什么叫阻塞式简单说就是当你用RestTemplate发起一个请求时执行这行代码的线程会一直“傻等”在那里直到收到远端的响应或者超时。想象一下你的服务线程池里一共就50个线程如果同时有50个请求都在调用一个响应慢的外部服务那么这50个线程就全被“卡住”了。这时候再来第51个请求对不起没线程可用了只能排队或者直接失败。这就是在高并发下可能导致线程池耗尽的典型场景系统的吞吐量一下子就到了天花板。另一个让我头疼的问题是它的API设计。RestTemplate是在Spring 3时代诞生的那时候的设计理念和现在不太一样。它提供了海量的重载方法光是一个getForObject就有好几种变体。刚接触时你可能觉得“哇功能真全”但用久了维护起来就痛苦了。代码里到处是restTemplate.exchange(uri, HttpMethod.GET, requestEntity, responseType)这种冗长的调用可读性一般。而且它完全跟不上反应式编程的浪潮。现在很多新项目都在用WebFlux做响应式架构追求更高的资源利用率和更低的延迟但RestTemplate是同步阻塞的跟反应式那套非阻塞、背压的模型格格不入你想把它集成到反应式调用链里会非常别扭。所以尽管RestTemplate功不可没但Spring官方在文档里也明确表示它已经进入了维护模式不再推荐在新的项目中使用。这就像是你家里有一台老式的显像管电视机还能看但体积大、耗电高、功能少是时候考虑换一台更轻薄、更智能的液晶电视了。2. 新星RestClient为何它是现代化的选择那么谁来接RestTemplate的班呢答案就是RestClient。从Spring Framework 6.1和Spring Boot 3.2开始它正式登场目标就是成为一个更现代、更友好、能力更强的HTTP客户端。我把它看作是RestTemplate的“精神续作”继承了其同步调用的直观性但内核和API设计都全面升级了。首先最直观的感受就是API变得无比流畅。RestClient采用了建造者Builder模式和流式FluentAPI设计写出来的代码读起来就像是在说英语句子。比如你想发起一个GET请求代码会是restClient.get().uri(/users).retrieve().body(User.class)一气呵成意图非常清晰。这种设计大大减少了样板代码也降低了记忆负担你不再需要去翻文档查某个重载方法到底该传哪些参数了。其次RestClient在可测试性上做了精心设计。做过单元测试的朋友都知道模拟HTTP调用是个麻烦事。RestClient通过MockRestServiceServer可以非常方便地进行测试。你可以在测试中精确地模拟服务端返回什么状态码、什么响应体然后验证你的客户端代码逻辑是否正确。这种“开箱即用”的测试支持对于保证代码质量至关重要也是现代框架必备的素质。还有一个杀手级特性就是对服务发现和负载均衡的原生支持。如果你在用Spring Cloud那么从某个版本开始RestClient可以直接和负载均衡器如Spring Cloud LoadBalancer集成。这意味着你不再需要手动拼接服务实例的URL而是直接使用服务名比如http://user-serviceRestClient会自动帮你从注册中心发现可用的实例并做负载均衡。这对于构建微服务来说简直是如虎添翼简化了配置也提升了系统的弹性。最后对比另一个现代化客户端WebClientRestClient还有一个优势轻量无需额外依赖。WebClient是反应式非阻塞的功能强大但它需要引入spring-boot-starter-webflux这个依赖。如果你的项目本身不是反应式架构引入它可能有点“杀鸡用牛刀”。而RestClient就简单多了它在Spring Boot的Web模块spring-boot-starter-web中就直接提供了开箱即用没有额外的学习成本和依赖负担。3. 深入对比设计理念与性能差异光说优点可能有点抽象我们不妨把RestTemplate和RestClient拉出来从几个关键维度做个实实在在的对比这样你就能更清楚为什么后者是更好的选择。设计哲学对比RestTemplate的设计哲学是“功能完备的工具箱”。它把各种可能的HTTP操作GET、POST、PUT等和参数组合都封装成了一个个独立的方法。这就像给你一个装满各种型号螺丝刀和扳手的工具箱你需要什么就找什么。好处是直接缺点是工具太多容易挑花眼而且工具箱本身比较笨重API臃肿。RestClient的设计哲学则是“流畅的表达链”。它提供了一个统一的入口然后通过链式调用来组装你的请求。这就像乐高积木给你一些基础模块方法你可以按照自己的需求自由组合出想要的形态。这种方式更加灵活、表达力更强也符合现代API设计的潮流。性能考量虽然两者默认都是同步阻塞的但它们的底层实现和扩展性不同这间接影响了性能表现。RestTemplate默认使用JDK的HttpURLConnection或者Apache的HttpClient作为底层引擎。它的阻塞是“硬阻塞”线程在等待IO时完全被占用。在高并发下如前所述容易导致线程资源紧张。RestClient它是一个更高层次的抽象底层可以灵活适配不同的HTTP客户端库比如JDK 11自带的HttpClient、ApacheHttpComponents等。更重要的是这种设计为未来的优化留下了空间。虽然当前主要用作同步客户端但其底层基础设施与反应式栈是相通的未来如果需要向非阻塞模式迁移或集成会更平滑。为了更直观我们看一个简单的对比表格特性维度RestTemplateRestClient说明API风格传统、基于重载方法现代、流式FluentRestClient代码更简洁意图更清晰。阻塞模型同步阻塞同步阻塞当前两者当前都是同步的但RestClient底层更灵活。反应式支持不支持底层基础设施支持API暂为同步RestClient未来更容易与反应式编程集成。测试便利性支持但稍显繁琐优秀原生支持MockRestServiceServerRestClient的测试支持更友好、更强大。服务发现集成需通过LoadBalanced注解原生支持需Spring Cloud环境RestClient与Spring Cloud生态集成更紧密、更现代。依赖需求spring-boot-starter-webspring-boot-starter-web两者基础依赖相同RestClient无需额外引入反应式依赖。官方推荐度维护模式不推荐新项目使用推荐用于新的同步HTTP调用Spring官方明确建议新项目使用RestClient。从表格可以看出RestClient几乎在每一个方面都做了优化和增强特别是在API设计、可测试性和与现代云原生生态的集成上优势明显。4. 实战上手从零开始使用RestClient说了这么多不如动手写两行代码来得实在。下面我就带你一步步把RestClient用起来你会发现迁移成本其实非常低。第一步引入依赖如果你用的是Spring Boot 3.2或更高版本那么恭喜你RestClient已经包含在spring-boot-starter-web里了你什么都不用加。如果是旧项目升级确保你的Spring Boot版本至少是3.2并引入了web starter即可。dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency第二步创建RestClient实例和RestTemplate一样我们通常把它配置成一个Spring Bean。有两种常见方式简单创建如果你只需要一个基础的客户端用create()方法最快。Configuration public class RestClientConfig { Bean public RestClient restClient() { // 可以指定一个基础URL后续请求的uri会相对这个路径 return RestClient.create(https://api.example.com); } }自定义构建大部分时候我们可能需要设置连接超时、读写超时或者使用特定的HTTP客户端库如Apache HttpClient。这时就用builder()方法。Bean public RestClient customRestClient(RestTemplateBuilder builder) { // 利用Spring Boot自动配置的RestTemplateBuilder来构建它能自动应用配置文件中的属性 return builder .baseUrl(https://api.example.com) .defaultHeader(User-Agent, MyApp/1.0) .requestInterceptor((request, body, execution) - { // 可以添加统一的请求拦截器比如打印日志、添加认证头 System.out.println(Sending request to: request.getURI()); return execution.execute(request, body); }) .build(); }你也可以直接在application.yml中配置超时等属性Spring Boot会自动应用到通过RestTemplateBuilder创建的客户端上spring: rest: client: timeout: connect: 2s read: 5s第三步发起HTTP请求这是最核心的部分我们看看几种常见操作。GET请求 - 获取资源Service public class UserService { private final RestClient restClient; public UserService(RestClient restClient) { this.restClient restClient; } public User getUserById(Long id) { // 链式调用非常清晰获取 - 设置URI - 执行并获取响应 - 提取响应体 User user restClient.get() .uri(/users/{id}, id) // 支持URI模板变量 .header(Authorization, Bearer my-token) // 设置请求头 .accept(MediaType.APPLICATION_JSON) // 设置Accept头 .retrieve() // 执行请求并获取响应 .body(User.class); // 将响应体反序列化为Java对象 return user; } public ListUser getAllUsers() { // 响应体是数组或列表的情况 ListUser users restClient.get() .uri(/users) .retrieve() .body(new ParameterizedTypeReferenceListUser() {}); return users; } }retrieve()方法表示你只关心成功的响应体。如果服务端返回4xx或5xx错误它会抛出RestClientException的子类如HttpClientErrorException、HttpServerErrorException你可以通过ExceptionHandler或try-catch来处理。POST请求 - 创建资源public User createUser(User newUser) { User createdUser restClient.post() .uri(/users) .contentType(MediaType.APPLICATION_JSON) // 设置Content-Type .body(newUser) // 设置请求体会自动序列化为JSON .retrieve() .body(User.class); return createdUser; } // 如果不关心响应体只关心状态码 public void createUserWithoutResponse(User newUser) { restClient.post() .uri(/users) .contentType(MediaType.APPLICATION_JSON) .body(newUser) .retrieve() .toBodilessEntity(); // 适用于POST/PUT/DELETE等操作忽略响应体 }处理错误响应 有时候你可能想更精细地处理非2xx的响应而不是直接抛出异常。可以用onStatus方法。public User getUserSafe(Long id) { return restClient.get() .uri(/users/{id}, id) .retrieve() .onStatus(status - status.value() 404, (request, response) - { // 当状态码为404时抛出自定义异常 throw new UserNotFoundException(User with id id not found); }) .onStatus(status - status.value() 500, (request, response) - { // 当状态码为5xx时记录日志或进行其他处理 log.error(Server error while fetching user); }) .body(User.class); }第四步编写单元测试测试是RestClient的一大亮点。Spring提供了MockRestServiceServer来模拟后端服务。SpringBootTest public class UserServiceTest { Autowired private UserService userService; Autowired private RestClient restClient; // 注入被测试的RestClient private MockRestServiceServer mockServer; BeforeEach void setUp() { mockServer MockRestServiceServer.bindTo(restClient).build(); } Test void testGetUserById() { // 1. 定义当请求匹配某个条件时返回什么响应 mockServer.expect(requestTo(https://api.example.com/users/1)) .andRespond(withSuccess({\id\:1,\name\:\张三\}, MediaType.APPLICATION_JSON)); // 2. 执行被测试的方法 User user userService.getUserById(1L); // 3. 验证结果 assertThat(user.getId()).isEqualTo(1L); assertThat(user.getName()).isEqualTo(张三); // 4. 验证所有预期的请求都已被执行 mockServer.verify(); } }通过这种方式你可以完全隔离外部依赖快速、可靠地测试你的客户端逻辑。5. 迁移指南与最佳实践如果你手头有正在使用RestTemplate的老项目想要迁移到RestClient别担心这个过程通常是渐进且平滑的。我结合自己的迁移经验给你几点建议。渐进式迁移而非一刀切 不要试图在一个PR里替换掉项目中所有的RestTemplate。最好的方法是“新人新办法老人老办法”。对于新开发的模块或接口直接使用RestClient。对于已有的、稳定的代码可以先不动等到需要修改或重构时再顺便将其替换为RestClient。这样风险可控也不会给团队带来过大的负担。利用IDE的查找替换和包装模式RestTemplate的调用通常模式固定。你可以利用IDE的“查找引用”功能找到所有使用RestTemplate的地方。对于简单的getForObject、postForEntity调用可以手动或写个小脚本将其转换成RestClient的流式API。对于更复杂或分散的调用可以考虑先创建一个RestClient的包装类这个类内部使用RestClient但对外提供与原有RestTemplate类似的方法签名这样调用方的代码几乎不用改动只需替换注入的Bean类型即可。配置的统一管理 之前RestTemplate的超时、拦截器等配置可能散落在各个Bean定义方法里。迁移到RestClient时建议利用Spring Boot的自动配置特性将通用配置如基础URL、默认超时、公共请求头集中到application.yml或一个统一的配置类中。通过RestTemplateBuilder或自定义的RestClientBuilder来创建Bean能让配置更加清晰和可维护。关注异常处理的差异RestTemplate和RestClient在错误处理上略有不同。RestTemplate的一些方法如getForObject在遇到4xx/5xx时可能返回null或抛出异常行为取决于具体方法。而RestClient的retrieve()方法在遇到非2xx状态码时会统一抛出异常。这意味着你的全局异常处理器ControllerAdvice或现有的try-catch块可能需要调整以捕获HttpClientErrorException或HttpServerErrorException。充分利用新特性 迁移不仅仅是API的简单替换更是享受新特性红利的机会。比如尝试流式API用RestClient的链式调用重写旧代码你会发现代码行数减少了可读性提高了。引入更优雅的测试为新写的RestClient代码配套编写基于MockRestServiceServer的单元测试你会发现测试代码更简洁意图更明确。探索与Cloud集成如果你的项目是微服务架构并使用了Spring Cloud尝试配置RestClient与负载均衡器的集成体验直接使用服务名进行调用的便捷。从我实际迁移的几个项目来看虽然初期需要一些学习和适配但一旦熟悉了RestClient的套路开发效率和对代码的控制力都有明显的提升。特别是当项目需要与多个外部API交互时RestClient清晰的API和强大的自定义能力让代码维护起来轻松了不少。

相关文章:

从RestTemplate到RestClient:Spring HTTP客户端的现代化演进

1. 老朋友RestTemplate:曾经的功臣与如今的困境 如果你用Spring做过项目,特别是几年前的项目,大概率会碰到RestTemplate。它就像是Spring生态里一个任劳任怨的老伙计,帮你处理各种HTTP请求,调用外部API,简单…...

OpenClaw健康检查:Qwen3-32B服务可用性监控与告警配置

OpenClaw健康检查:Qwen3-32B服务可用性监控与告警配置 1. 为什么需要健康检查? 去年冬天的一个深夜,我正赶着处理一批自动化文档整理任务时,突然发现OpenClaw连续三次执行失败。检查日志才发现是Qwen3-32B服务响应超时——原来是…...

Clawdbot入门指南:Qwen3-32B代理网关CORS配置与前端跨域调用安全实践

Clawdbot入门指南:Qwen3-32B代理网关CORS配置与前端跨域调用安全实践 1. 引言:为什么需要关注CORS配置? 如果你正在使用Clawdbot这样的AI代理网关,并且在前端调用时遇到了跨域问题,那么这篇文章就是为你准备的。跨域…...

深度学习项目训练环境亲测:环境已预装,上传代码即可开始训练

深度学习项目训练环境亲测:环境已预装,上传代码即可开始训练 1. 镜像环境概览 这个深度学习训练环境镜像已经预装了完整的开发工具链,特别适合需要快速开展深度学习项目的研究人员和开发者。我亲自测试后发现,这个环境最大的优势…...

【ComfyUI】Qwen-Image-Edit-F2P 与Dify集成:打造无需代码的AI人脸生成应用工作流

ComfyUI Qwen-Image-Edit-F2P 与Dify集成:打造无需代码的AI人脸生成应用工作流 你有没有想过,让不懂编程的运营同事或者设计师,也能轻松点几下鼠标,就生成一张风格独特的AI人像?这听起来像是需要一支技术团队才能实现…...

FLUX.1-dev模型微调指南:基于LoRA的个性化风格训练

FLUX.1-dev模型微调指南:基于LoRA的个性化风格训练 想用FLUX.1-dev生成独一无二的专属风格图片吗?比如,把照片一键变成你最喜欢的插画师风格,或者让模型学会生成特定品牌的设计元素。今天,我们就来聊聊怎么用LoRA技术…...

开发者必备:Chandra调试技巧与常见问题解决

开发者必备:Chandra调试技巧与常见问题解决 1. 引言 调试是每个开发者都绕不开的必修课,尤其是在使用Chandra这样的AI工具时。你可能已经遇到过这样的情况:模型运行好好的突然就卡住了,或者生成的文本总是偏离预期,又…...

墨语灵犀本地知识库构建:基于开源模型的Agent智能体开发

墨语灵犀本地知识库构建:基于开源模型的Agent智能体开发 最近和几个做企业服务的朋友聊天,发现大家有个共同的痛点:公司内部有大量的产品文档、技术手册、客户案例,但新员工上手慢,老员工查资料也费劲。市面上那些通用…...

造相-Z-Image-Turbo 计算机网络基础:理解模型API的HTTP请求与响应

造相-Z-Image-Turbo 计算机网络基础:理解模型API的HTTP请求与响应 你是不是也遇到过这种情况?在网上看到一个很酷的AI画图模型,比如“造相-Z-Image-Turbo”,兴冲冲地找到它的API文档,结果满眼都是“HTTP POST”、“JS…...

AI普及74%,仍超6成团队陷延期?

大模型时代,项目管理该是什么新形态?AI工具的深度应用如何切实赋能岗位工作?项目交付延期的核心症结该如何破解?跨角色协作的效率瓶颈该如何突破……大家好!为更真实地了解当前IT行业项目管理的现状,我们面…...

基于动态分时电价的电动汽车有序充放电实时优化调度系统研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

UDOP-large完整指南:英文文档标题提取、摘要生成、布局分析全流程

UDOP-large完整指南:英文文档标题提取、摘要生成、布局分析全流程 你是不是经常需要处理一堆英文PDF文档,比如学术论文、报告或者发票?手动去翻找标题、总结内容、提取关键信息,不仅耗时耗力,还容易出错。今天&#x…...

两级式光伏并网逆变器低电压穿越LVRT仿真模型:改进MPPT、改进电流环、DSOGI锁相环与电流前馈控制(仿真+配套设计说明文档+参考文献)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

mPLUG视觉问答功能体验:支持多格式图片,分析结果秒级返回

mPLUG视觉问答功能体验:支持多格式图片,分析结果秒级返回 1. 视觉问答技术的新体验 当你面对一张复杂的照片时,是否曾希望有个助手能立即告诉你图片中的内容?mPLUG视觉问答工具让这个愿望成为现实。这个基于ModelScope官方模型的…...

MiniCPM-V-2_6跨模态对齐解析:图文匹配度评估与错误定位实战

MiniCPM-V-2_6跨模态对齐解析:图文匹配度评估与错误定位实战 1. 理解跨模态对齐的核心价值 跨模态对齐是多模态AI领域的核心技术,它让机器能够理解图像和文本之间的深层关联。想象一下,当你看到一张图片时,大脑会自动理解图片内…...

Swin2SR算力适配优化:24G显存下稳定输出4K画质

Swin2SR算力适配优化:24G显存下稳定输出4K画质 1. 引言:当AI显微镜遇上显存瓶颈 你有没有遇到过这种情况?在网上找到一张绝佳的参考图,但分辨率低得可怜,放大后全是马赛克;或者用AI生成了一张满意的概念图…...

Z-Image Turbo步数设置指南:4/8/12步生成效果对比与选型建议

Z-Image Turbo步数设置指南:4/8/12步生成效果对比与选型建议 1. 引言:为什么步数设置如此重要? 在使用Z-Image Turbo进行AI绘图时,步数(Steps)是最影响生成效果和速度的核心参数之一。很多用户都有这样的…...

Wan2.1-UMT5入门:C语言开发者也能懂的模型调用原理

Wan2.1-UMT5入门:C语言开发者也能懂的模型调用原理 如果你有C语言基础,习惯了和内存、指针、结构体打交道,第一次接触像Wan2.1-UMT5这样的大模型,可能会觉得它像个黑盒子,里面充满了“张量”、“注意力”、“前向传播…...

Phi-3-vision-128k-instruct 赋能JavaScript开发:浏览器端图片上传与AI分析

Phi-3-vision-128k-instruct 赋能JavaScript开发:浏览器端图片上传与AI分析 1. 场景价值与核心思路 想象这样一个场景:用户在你的电商网站上随手拍了一张商品照片,页面立即显示出该商品的详细参数和购买链接。这种"拍照识物"的体…...

树莓派Ubuntu开机卡在initramfs?3步搞定磁盘修复(附blkid和fsck详细用法)

树莓派Ubuntu开机卡在initramfs?3步搞定磁盘修复(附blkid和fsck详细用法) 当你满心期待地按下树莓派的电源键,准备继续昨天的项目时,屏幕上却突然跳出陌生的(initramfs)提示符——这种场景恐怕是每个嵌入式开发者的噩梦…...

手把手教你部署Qwen3-Embedding-4B:一键实现智能语义匹配

手把手教你部署Qwen3-Embedding-4B:一键实现智能语义匹配 1. 为什么选择Qwen3-Embedding-4B进行语义搜索? 传统关键词搜索就像拿着放大镜在图书馆里找书——只能看到书名里有没有你要的字,却不知道书里到底讲了什么。比如搜索"如何重启…...

FDTD Script实战:farfield3d命令参数详解与常见错误排查指南

FDTD Script实战:farfield3d命令参数详解与常见错误排查指南 在光学仿真领域,FDTD(时域有限差分)方法因其对复杂电磁场问题的精确模拟能力而广受青睐。而farfield3d命令作为FDTD Script中的关键功能,能够将近场数据转换…...

NSIS安装包必知必会:3个默认参数详解(附实际应用场景)

NSIS安装包必知必会:3个默认参数详解(附实际应用场景) 在软件分发和自动化部署领域,NSIS(Nullsoft Scriptable Install System)因其轻量级和高度可定制性成为众多开发者的首选安装包制作工具。对于需要频繁…...

避坑指南:CloudCompare点云显示六大常见误区与优化方案(2024版)

避坑指南:CloudCompare点云显示六大常见误区与优化方案(2024版) 第一次打开CloudCompare加载点云数据时,很多人会被默认的显示效果震惊——锯齿状的方形点、昏暗的渐变背景、生硬的渲染效果,让本应精美的三维点云看起…...

小白也能玩转大模型!Qwen2.5-7B-Instruct一键Docker部署实战

小白也能玩转大模型!Qwen2.5-7B-Instruct一键Docker部署实战 1. 前言:为什么选择Qwen2.5-7B-Instruct 大语言模型正在改变我们与技术交互的方式,而阿里通义千问的Qwen2.5系列无疑是当前最值得关注的模型之一。作为1.5B/3B轻量版的进阶旗舰款…...

高效媒体处理:LosslessCut实现零质量损失的视频剪辑解决方案

高效媒体处理:LosslessCut实现零质量损失的视频剪辑解决方案 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字内容创作领域,视频剪辑效率…...

5个专业级技巧:如何通过游戏外设调校实现射击精准控制

5个专业级技巧:如何通过游戏外设调校实现射击精准控制 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 在竞技射击游戏中,…...

深蓝词库转换:20+输入法格式互转的终极解决方案

深蓝词库转换:20输入法格式互转的终极解决方案 【免费下载链接】imewlconverter ”深蓝词库转换“ 一款开源免费的输入法词库转换程序 项目地址: https://gitcode.com/gh_mirrors/im/imewlconverter 在数字时代,输入法词库已成为用户个性化体验的…...

罗技鼠标宏压枪脚本:精准射击算法的工程化实现方案

罗技鼠标宏压枪脚本:精准射击算法的工程化实现方案 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 在竞技射击游戏中,后坐…...

lychee-rerank-mm与LangChain集成指南:构建智能文档检索系统

lychee-rerank-mm与LangChain集成指南:构建智能文档检索系统 用最简单的方式,让AI看懂你的图片和文字 1. 开篇:为什么需要多模态检索? 你有没有遇到过这样的情况:想找一张去年会议的合影,但只记得当时讨论…...