使用 Spring AI Aliabab Module RAG 构建 Web Search 应用

使用 Spring AI Alibaba 构建大模型联网搜索应用

Spring AI 实现了模块化 RAG 架构,架构的灵感来自于论文“模块化 RAG:将 RAG 系统转变为类似乐高的可重构框架”中详述的模块化概念。

Spring AI 模块化 RAG 体系

在这里插入图片描述

总体上分为以下几个步骤:

Pre-Retrieval

增强和转换用户输入,使其更有效地执行检索任务,解决格式不正确的查询、query 语义不清晰、或不受支持的语言等。

  1. QueryAugmenter 查询增强:使用附加的上下文数据信息增强用户 query,提供大模型回答问题时的必要上下文信息;
  2. QueryTransformer 查询改写:因为用户的输入通常是片面的,关键信息较少,不便于大模型理解和回答问题。因此需要使用 prompt 调优手段或者大模型改写用户 query;
  3. QueryExpander 查询扩展:将用户 query 扩展为多个语义不同的变体以获得不同视角,有助于检索额外的上下文信息并增加找到相关结果的机会。

Retrieval

负责查询向量存储等数据系统并检索和用户 query 相关性最高的 Document。

  1. DocumentRetriever:检索器,根据 QueryExpander 使用不同的数据源进行检索,例如 搜索引擎、向量存储、数据库或知识图等;
  2. DocumentJoiner:将从多个 query 和从多个数据源检索到的 Document 合并为一个 Document 集合;

Post-Retrieval

负责处理检索到的 Document 以获得最佳的输出结果,解决模型中的中间丢失和上下文长度限制等。

  1. DocumentRanker:根据 Document 和用户 query 的相关性对 Document 进行排序和排名;
  2. DocumentSelector:用于从检索到的 Document 列表中删除不相关或冗余文档;
  3. DocumentCompressor:用于压缩每个 Document,减少检索到的信息中的噪音和冗余。

生成

生成用户 Query 对应的大模型输出。

Web Search 实践

接下来,将演示如何使用 Spring AI Alibaba 和阿里云 IQS 服务搭建联网搜索 RAG 的实现。

资源准备

DashScope apiKey:https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key

阿里云 IQS 服务 apiKey:https://help.aliyun.com/product/2837261.html

Pre-Retrieval

将用户 Query 使用 qwen-plus 大模型进行增强改写。

CustomContextQueryAugmenter.java

public class CustomContextQueryAugmenter implements QueryAugmenter {// 定义 prompt tmpl。private static final PromptTemplate DEFAULT_PROMPT_TEMPLATE = new PromptTemplate(// ......);private static final PromptTemplate DEFAULT_EMPTY_PROMPT_TEMPLATE = new PromptTemplate(// ...);@NotNull@Overridepublic Query augment(@Nullable Query query,@Nullable List<Document> documents) {// 1. collect content from documents.AtomicInteger idCounter = new AtomicInteger(1);String documentContext = documents.stream().map(document -> {String text = document.getText();return "[[" + (idCounter.getAndIncrement()) + "]]" + text;}).collect(Collectors.joining("\n-----------------------------------------------\n"));// 2. Define prompt parameters.Map<String, Object> promptParameters = Map.of("query", query.text(),"context", documentContext);// 3. Augment user prompt with document context.return new Query(this.promptTemplate.render(promptParameters));}// 当上下文为空时,返回 DEFAULT_EMPTY_PROMPT_TEMPLATEprivate Query augmentQueryWhenEmptyContext(Query query) {if (this.allowEmptyContext) {logger.debug("Empty context is allowed. Returning the original query.");return query;}logger.debug("Empty context is not allowed. Returning a specific query for empty context.");return new Query(this.emptyPromptTemplate.render());}public static final class Builder {// ......}
}

QueryTransformer 配置 bean,用于 rewrite 用户 query:

@Bean
public QueryTransformer queryTransformer(ChatClient.Builder chatClientBuilder,@Qualifier("transformerPromptTemplate") PromptTemplate transformerPromptTemplate
) {ChatClient chatClient = chatClientBuilder.defaultOptions(DashScopeChatOptions.builder().withModel("qwen-plus").build()).build();return RewriteQueryTransformer.builder().chatClientBuilder(chatClient.mutate()).promptTemplate(transformerPromptTemplate).targetSearchSystem("联网搜索").build();
}

QueryExpander.java 查询变体

public class MultiQueryExpander implements QueryExpander {private static final Logger logger = LoggerFactory.getLogger(MultiQueryExpander.class);private static final PromptTemplate DEFAULT_PROMPT_TEMPLATE = new PromptTemplate(// ...);@NotNull@Overridepublic List<Query> expand(@Nullable Query query) {// ...String resp = this.chatClient.prompt().user(user -> user.text(this.promptTemplate.getTemplate()).param("number", this.numberOfQueries).param("query", query.text())).call().content();// ...List<String> queryVariants = Arrays.stream(resp.split("\n")).filter(StringUtils::hasText).toList();if (CollectionUtils.isEmpty(queryVariants) || this.numberOfQueries != queryVariants.size()) {return List.of(query);}List<Query> queries = queryVariants.stream().filter(StringUtils::hasText).map(queryText -> query.mutate().text(queryText).build()).collect(Collectors.toList());// 是否引入原查询if (this.includeOriginal) {logger.debug("Including original query in the expanded queries for query: {}", query.text());queries.add(0, query);}return queries;}public static final class Builder {// ......}}

Retrieval

从不同数据源查询和用户 query 相似度最高的数据。(这里使用 Web Search)

WebSearchRetriever.java

public class WebSearchRetriever implements DocumentRetriever {// 注入 IQS 搜索引擎private final IQSSearchEngine searchEngine;@NotNull@Overridepublic List<Document> retrieve(@Nullable Query query) {// 搜索GenericSearchResult searchResp = searchEngine.search(query.text());// 清洗数据,将数据转换为 Spring AI 的 Document 对象List<Document> cleanerData = dataCleaner.getData(searchResp);logger.debug("cleaner data: {}", cleanerData);// 返回结果List<Document> documents = dataCleaner.limitResults(cleanerData, maxResults);logger.debug("WebSearchRetriever#retrieve() document size: {}, raw documents: {}",documents.size(),documents.stream().map(Document::getId).toArray());return enableRanker ? ranking(query, documents) : documents;}private List<Document> ranking(Query query, List<Document> documents) {if (documents.size() == 1) {// 只有一个时,不需要 rankreturn documents;}try {List<Document> rankedDocuments = documentRanker.rank(query, documents);logger.debug("WebSearchRetriever#ranking() Ranked documents: {}", rankedDocuments.stream().map(Document::getId).toArray());return rankedDocuments;} catch (Exception e) {// 降级返回原始结果logger.error("ranking error", e);return documents;}}public static final class Builder {// ...}
}

DocumentJoiner.java 合并 Document

public class ConcatenationDocumentJoiner implements DocumentJoiner {@NotNull@Overridepublic List<Document> join(@Nullable Map<Query, List<List<Document>>> documentsForQuery) {// ...Map<Query, List<List<Document>>> selectDocuments = selectDocuments(documentsForQuery, 10);Set<String> seen = new HashSet<>();return selectDocuments.values().stream()// Flatten List<List<Documents>> to Stream<List<Documents>..flatMap(List::stream)// Flatten Stream<List<Documents> to Stream<Documents>..flatMap(List::stream).filter(doc -> {List<String> keys = extractKeys(doc);for (String key : keys) {if (!seen.add(key)) {logger.info("Duplicate document metadata: {}",doc.getMetadata());// Duplicate keys found.return false;}}// All keys are unique.return true;}).collect(Collectors.toList());}private Map<Query, List<List<Document>>> selectDocuments(Map<Query, List<List<Document>>> documentsForQuery,int totalDocuments) {Map<Query, List<List<Document>>> selectDocumentsForQuery = new HashMap<>();int numberOfQueries = documentsForQuery.size();if (Objects.equals(0, numberOfQueries)) {return selectDocumentsForQuery;}int baseCount = totalDocuments / numberOfQueries;int remainder = totalDocuments % numberOfQueries;// To ensure consistent distribution. sort the keys (optional)List<Query> sortedQueries = new ArrayList<>(documentsForQuery.keySet());// Other sort// sortedQueries.sort(Comparator.comparing(Query::getSomeProperty));Iterator<Query> iterator = sortedQueries.iterator();for (int i = 0; i < numberOfQueries; i ++) {Query query = sortedQueries.get(i);int documentToSelect = baseCount + (i < remainder ? 1 : 0);List<List<Document>> originalDocuments = documentsForQuery.get(query);List<List<Document>> selectedNestLists = new ArrayList<>();int remainingDocuments = documentToSelect;for (List<Document> documentList : originalDocuments) {if (remainingDocuments <= 0) {break;}List<Document> selectSubList = new ArrayList<>();for (Document docs : documentList) {if (remainingDocuments <= 0) {break;}selectSubList.add(docs);remainingDocuments --;}if (!selectSubList.isEmpty()) {selectedNestLists.add(selectSubList);}}selectDocumentsForQuery.put(query, selectedNestLists);}return selectDocumentsForQuery;}private List<String> extractKeys(Document document) {// 提取 keyreturn keys;}
}

Post-Retrieval

处理从联网搜索种获得的 Document,以获得最佳输出。

DashScopeDocumentRanker.java

public class DashScopeDocumentRanker implements DocumentRanker {// ...@NotNull@Overridepublic List<Document> rank(@Nullable Query query,@Nullable List<Document> documents) {// ...try {List<Document> reorderDocs = new ArrayList<>();// 由调用者控制文档数DashScopeRerankOptions rerankOptions = DashScopeRerankOptions.builder().withTopN(documents.size()).build();if (Objects.nonNull(query) && StringUtils.hasText(query.text())) {// 组装参数调用 rankModelRerankRequest rerankRequest = new RerankRequest(query.text(),documents,rerankOptions);RerankResponse rerankResp = rerankModel.call(rerankRequest);rerankResp.getResults().forEach(res -> {Document outputDocs = res.getOutput();// 查找并添加到新的 list 中Optional<Document> foundDocsOptional = documents.stream().filter(doc ->{// debug rerank output.logger.debug("DashScopeDocumentRanker#rank() doc id: {}, outputDocs id: {}", doc.getId(), outputDocs.getId());return Objects.equals(doc.getId(), outputDocs.getId());}).findFirst();foundDocsOptional.ifPresent(reorderDocs::add);});}return reorderDocs;}catch (Exception e) {// 根据异常类型做进一步处理throw new SAAAppException(e.getMessage());}}
}

大模型输出

WebSearchService.java

@Service
public class SAAWebSearchService {// ...private static final String DEFAULT_WEB_SEARCH_MODEL = "deepseek-r1";public SAAWebSearchService(ChatClient.Builder chatClientBuilder,QueryTransformer queryTransformer,QueryExpander queryExpander,IQSSearchEngine searchEngine,DataClean dataCleaner,DocumentRanker documentRanker,@Qualifier("queryArgumentPromptTemplate") PromptTemplate queryArgumentPromptTemplate) {this.queryTransformer = queryTransformer;this.queryExpander = queryExpander;this.queryArgumentPromptTemplate = queryArgumentPromptTemplate;// 用于 DeepSeek-r1 的 reasoning content 整合到输出中this.reasoningContentAdvisor = new ReasoningContentAdvisor(1);// 构建 chatClientthis.chatClient = chatClientBuilder.defaultOptions(DashScopeChatOptions.builder().withModel(DEFAULT_WEB_SEARCH_MODEL)// stream 模式下是否开启增量输出.withIncrementalOutput(true).build()).build();// 日志this.simpleLoggerAdvisor = new SimpleLoggerAdvisor(100);this.webSearchRetriever = WebSearchRetriever.builder().searchEngine(searchEngine).dataCleaner(dataCleaner).maxResults(2).enableRanker(true).documentRanker(documentRanker).build();}// 处理用户输入public Flux<String> chat(String prompt) {return chatClient.prompt().advisors(createRetrievalAugmentationAdvisor(),// 整合到 reasoning content 输出中reasoningContentAdvisor,simpleLoggerAdvisor).user(prompt).stream().content();}// 创建 advisorprivate RetrievalAugmentationAdvisor createRetrievalAugmentationAdvisor() {return RetrievalAugmentationAdvisor.builder().documentRetriever(webSearchRetriever).queryTransformers(queryTransformer).queryAugmenter(new CustomContextQueryAugmenter(queryArgumentPromptTemplate,null,true)).queryExpander(queryExpander).documentJoiner(new ConcatenationDocumentJoiner()).build();}}

演示

使用问题 杭州有什么推荐旅游的地方吗 为例。

普通输出
### 必游景点  
1. **西湖**  - **核心特色**:杭州的标志性景点,包含“西湖十景”(如苏堤春晓、断桥残雪、三潭印月等),可泛舟湖上或沿湖骑行。  - **推荐活动**:夜游西湖灯光秀、漫步白堤/苏堤。  2. **灵隐寺与飞来峰**  - **文化价值**:千年古刹灵隐寺被誉为“东南佛国”,飞来峰的摩崖石刻为宋代佛教艺术瑰宝。  ---### 自然与生态  
1. **西溪国家湿地公园**  - **亮点**:国内首个国家湿地公园,可乘摇橹船游览,春秋季观芦苇、赏梅花。  2. **九溪十八涧**  - **特色**:茶园、溪流、古树构成的徒步路线,适合夏季避暑。  ---### 文化体验  
1. **宋城景区**  - **必看演出**:《宋城千古情》通过歌舞演绎杭州历史,沉浸式体验南宋文化。  2. **中国茶叶博物馆(龙井馆)**  - **体验**:了解龙井茶文化,参与采茶、制茶活动,品鉴正宗西湖龙井。  ---### 美食街区  
1. **河坊街**  - **推荐小吃**:葱包桧、定胜糕、西湖醋鱼、东坡肉。  2. **武林夜市**  - **特色**:本地人常去的夜宵聚集地,汇聚浙江风味与网红美食。  ---### 温馨提示  
- **最佳季节**:春季(3-5月)赏桃柳,秋季(9-11月)观桂花。  
- **交通建议**:西湖周边景点集中,建议骑行或步行;地铁1号线覆盖主城区。  如需更详细的行程规划,可补充具体需求(如亲子游、摄影主题等)。
联网搜索输出
### 杭州旅游推荐#### 1. 西湖风景区  
杭州的核心景点,包含断桥残雪、苏堤春晓等经典景观,四季景色各异,适合漫步或乘船游览。清晨和傍晚的光线最佳,湖光山色与人文遗迹交融,是摄影和休闲的首选 [2][3][6]。  #### 2. 灵隐寺  
千年古刹隐于山林,古木参天,佛教氛围浓厚。寺内素斋体验和祈福活动值得尝试,适合寻求宁静的游客 [2][5][6]。  #### 3. 西溪国家湿地公园  
城市内的生态绿肺,河道纵横,可乘船观赏湿地风光,偶遇白鹭等水鸟。春季踏青、秋季赏芦的绝佳地 [2][3][6]。  #### 4. 天竺三寺  
位于西湖区灵隐寺附近,由三座历史悠久的寺庙组成,建筑风格独特,环境清幽,适合文化探访和秋日游览 [1]。  #### 5. 杭州宋城  
以宋代风貌为主题的景区,可换古装沉浸式体验市井生活,大型演出《宋城千古情》融合历史与艺术,视觉震撼 [2][5]。  #### 6. 河坊街  
古色古香的商业街,聚集传统小吃、手工艺品店,可品尝葱包桧、定胜糕等美食,适合拍摄人文题材照片 [2][3][5]。  #### 7. 千岛湖风景区  
以1078座岛屿闻名,梅峰岛观景台可俯瞰全景,湖光山色如画卷。适合自驾游和山水摄影 [3][6]。  #### 8. 茅家埠景区  
西湖边的隐逸之地,春季樱花与湖柳相映,秋季芦苇摇曳,人少景美,适合徒步和自然摄影 [1][3]。  #### 9. 九溪烟树(九溪十八涧)  
山涧、茶园与枫叶交织的徒步路线,秋季红叶似火,溪水潺潺,充满诗意 [2][6]。  #### 10. 太子湾公园  
春季郁金香、樱花盛开,色彩斑斓,是热门打卡地。适合家庭游和花卉摄影 [2][3]。  ---**其他推荐**  
- **浙西大龙湾**:自然峡谷与瀑布群,夏季漂流项目刺激 [1]。  
- **中国印学博物馆**:展示印章文化与历史,适合文化爱好者 [1]。  
- **塘栖古镇**:运河畔的江南水乡,保留明清建筑与民俗风情 [3][6]。  **旅行提示**  
- 西湖、灵隐寺等热门景点建议提前预约门票 [5]。  
- 春季多雨,需携带雨具;秋季适合户外活动 [2][5]。  (参考文档:[1][2][3][5][6])

参考文档

  1. Spring AI RAG:https://docs.spring.io/spring-ai/reference/api/retrieval-augmented-generation.html
  2. 阿里云 IQS:https://help.aliyun.com/product/2837261.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/74016.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一些练习 C 语言的小游戏

一些练习 C 语言的小游戏 — 1. 猜数字游戏 描述&#xff1a;程序随机生成一个数字&#xff0c;玩家需要猜测这个数字&#xff0c;并根据提示&#xff08;太高或太低&#xff09;调整猜测&#xff0c;直到猜中为止。 功能点&#xff1a; 随机数生成 (rand() 函数)。循环和…

关于中文编程的一些思考

随着信息化与数字化的发展&#xff0c;工业4.0时代亦将徐徐到来。当计算机的普及程度越来越高&#xff0c;数据的产生、传输、处理等变得越来越快、越来越大量的时候&#xff0c;人们想要自动化办公的愿望也越来越强烈&#xff0c;希望能将自身从耗费脑力但是重复繁琐的工作中解…

golang 日志log与logrus

目录 一、Go 标准库 log 详解 1. 功能特点 2. 常用函数 3. 示例代码 4. 优势和局限 二、第三方库 logrus 详解 1. 功能特点 2. 核心功能 3. 示例代码 4. 优势和扩展性 三、总结 1. 何时选择 log&#xff1f; 2. 何时选择 logrus&#xff1f; 3. 对比总结 一、Go 标…

消费品行业创新创业中品类创新与数字化工具的融合:以开源 AI 智能客服、AI 智能名片及 S2B2C 商城小程序为例

摘要&#xff1a; 本文聚焦于消费品行业的创新与创业&#xff0c;深入探讨“选择大于努力”这一观点&#xff0c;强调品类选择在品牌发展中的关键作用。同时&#xff0c;详细分析了品类创新对于新消费品牌崛起以及传统品牌转型的重要意义。在此基础上&#xff0c;引入开源 AI 智…

Razer macOS v0.4.10快速安装

链接点这里下载最新的 .dmg 文件。将下载的 .dmg 映像文件拖入 应用程序 文件夹中。若首次打开时出现安全警告【什么扔到废纸篓】&#xff0c;这时候点击 Mac 的“系统偏好设置”-> “安全性与隐私”-> “通用”&#xff0c;然后点击底部的 “打开”。【或者仍然打开】 对…

Flask项目部署:Flask + uWSGI + Nginx

目录 1,网络架构 2,环境安装 2.1,安装yum:Shell软件包管理器 2.2 安装python 2.3 安装uWSGI 2.4 安装Flask 3,上传工程包到服务器,打包Flask项目 4,创建和配置 uwsgi 配置文件 uwsgi.ini 4.1配置文件 4.2配置文件注释详解 5,启动服务 6,安装nginx 7,nginx配置 8,…

[FPGA基础学习]实现流水灯与按键暂停

FPGA实现LED流水灯 1.vscode的安装和使用 vscode下载 Visual Studio Code - Code Editing. Redefined vscode插件&#xff08;Verilog-HDL/SystemVerilog&#xff09;下载 quartus绑定vscode 2.用6个LED完成周期为1秒的跑马灯效果 流水灯模块设计 时钟输入 DE2-115开发板…

【TensorRT】TensorRT从安装到推理——Python 环境下 MobileNetV4 三分类任务

我想开发一个基于深度学习的分类小软件&#xff0c;逐渐了解到了TensorRT在模型推理速度上的优势&#xff0c;经过一下午资料的查找实现了将onnx模型转为TensorRT格式模型的推理及测试过程。将实现过程记录下来方便日后查看。 本文实验设备是MX350显卡 2G显存 一 、安装Tenso…

1.两数之和(Java)

1. 题目描述 LeetCode 1. 两数之和&#xff08;Two Sum&#xff09; 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那两个整数&#xff0c;并返回它们的索引。 示例 1&#xff1a; 输入&#xff1a;nums [2,7,11,15], target 9 …

《深入探索 Python 数据分析:用 Pandas 高效处理与可视化大型数据集》

《深入探索 Python 数据分析:用 Pandas 高效处理与可视化大型数据集》 引言:从零到分析高手 数据是当代社会最宝贵的资源,而数据分析技能是现代职业人不可或缺的一部分。在数据科学的领域中,Python 已成为当之无愧的“首选语言”,其强大的生态系统和简洁的语法让人如虎添…

将树莓派5当做Ollama服务器,C#调用generate的API的示例

其实完全没这个必要&#xff0c;性能用脚后跟想都会很差。但基于上一篇文章的成果&#xff0c;来都来了就先简单试试吧。 先来看看这个拼夕夕上五百多块钱能达到的效果&#xff1a; 只要对速度没要求&#xff0c;那感觉就还行。 Ollama默认只在本地回环&#xff08;127.0.0…

python基础学习二(列表及字典的使用)

文章目录 列表列表的创建获取列表中的多个元素判断列表中元素是否存在列表元素的添加操作列表元素的删除操作列表元素的修改列表的排序列表生成式 字典字典的创建字典的常规操作字典的常用操作字典的视图操作字典元素的遍历字典的特点字典的生成式 列表 一个对象由id&#xff0…

Android设计模式之代理模式

一、定义&#xff1a; 为其他对象提供一种代理以控制对这个对象的访问。 二、角色组成&#xff1a; Subject抽象主题&#xff1a;声明真是主题与代理的共同接口方法&#xff0c;可以是一个抽象类或接口。 RealSubject真实主题&#xff1a;定义了代理表示的真实对象&#xff0c…

国外计算机证书推荐(考证)(6 Sigma、AWS、APICS、IIA、Microsoft、Oracle、PMI、Red Hat)

文章目录 证书推荐1. 六西格玛 (6 Sigma)2. 亚马逊网络服务 (AWS)3. 美国生产与库存控制学会 (APICS)4. 内部审计师协会 (IIA)5. 微软 (Microsoft)6. 甲骨文 (Oracle)7. 项目管理协会 (PMI)8. 红帽 (Red Hat) 证书推荐 1. 六西格玛 (6 Sigma) 介绍&#xff1a;六西格玛是一种…

用mkdocs写文档#自动更新github-page

https://wuyisheng.github.io/blog 背景是上一篇博客 使用mkdocs&#xff0c;最后提及可以部署github page。这里说明下怎么自动部署。 当然&#xff0c;这篇博客主要的目的还是提供下github page的链接 &#xff1a;&#xff09; 我是这样做的&#xff1a; step 1: pip3 i…

QT五 文件系统,QFile,QfileInfo

总览 QIODevice&#xff1a;所有 I/O 设备类的父类&#xff0c;提供了字节块读写的通用操作以及基本接口&#xff1b;QFileDevice&#xff1a;Qt5新增加的类&#xff0c;提供了有关文件操作的通用实现。QFlie&#xff1a;访问本地文件或者嵌入资源&#xff1b;QTemporaryFile&a…

EF Core表达式树

文章目录 前言一、表达式树与委托的区别二、动态构建表达式树示例1示例2示例3高级技巧&#xff1a;表达式合并 三、ExpressionTreeToString安装方法基本用法支持的格式化风格 四、注意事项总结 前言 在 Entity Framework Core 中&#xff0c;表达式树&#xff08;Expression T…

NVM安装速通使用手册(Windows版)NVM管理node版本命令手册 NVM使用手册

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的命令行工具。通过nvm&#xff0c;你可以在同一台机器上安装和切换多个Node.js版本&#xff0c;非常适合开发和测试在不同Node.js版本上运行的应用程序 一、安装地址 1. 官方下载&#xff1a; &…

vLLM命令行使用方法详解

vLLM 是一个针对大语言模型(LLMs)优化的高效推理和服务库。以下是 vLLM 命令行工具的详细使用方法解析,涵盖常见场景和参数配置: 一、核心命令行工具 vLLM 提供两个主要的命令行入口: 启动 API 服务器 用于部署 HTTP/OpenAI 兼容的 API 服务: python -m vllm.entrypoint…

# 基于 OpenCV 的选择题自动批改系统实现

在教育领域&#xff0c;选择题的批改工作通常较为繁琐且重复性高。为了提高批改效率&#xff0c;我们可以利用计算机视觉技术&#xff0c;通过 OpenCV 实现选择题的自动批改。本文将详细介绍如何使用 Python 和 OpenCV 实现一个简单的选择题自动批改系统。 1. 项目背景 选择题…