spring-ai整合PGVector實現RAG

背景

最近公司的產品和業務線,要求往ai方向靠攏,在研發各種智能體,整理下最近學習的過程,將一部分內容整理出來,分享給需要的同學。

這篇文章將會提供詳細的例子以及踩坑說明。主要內容是整合spring-ai,同時本地借助ollama平臺部署本地模型,并基于PostgreSQL實現向量的存儲,實現最基本的RAG能力。

準備工作

安裝ollama部署本地大模型

首先,我們進入ollama官網Ollama,下載ollama安裝包,具體不贅述。

本地安裝完之后,打開命令行工具:
輸入命令:ollama -h獲取相關的提示

C:\Users\Administrator>ollama -h
Large language model runnerUsage:ollama [flags]ollama [command]Available Commands:serve       Start ollamacreate      Create a model from a Modelfileshow        Show information for a modelrun         Run a modelstop        Stop a running modelpull        Pull a model from a registrypush        Push a model to a registrylist        List modelsps          List running modelscp          Copy a modelrm          Remove a modelhelp        Help about any commandFlags:-h, --help      help for ollama-v, --version   Show version informationUse "ollama [command] --help" for more information about a command.

然后基于ollama pull命令下載大模型到本地(具體哪些模型,可以去ollama官網搜索):

C:\Users\Administrator>ollama list
NAME                              ID              SIZE      MODIFIED
shaw/dmeta-embedding-zh:latest    41783961c26d    408 MB    13 hours ago
llama3:latest                     365c0bd3c000    4.7 GB    37 hours agoC:\Users\Administrator>

示例中,我們下載了2個模型:

shaw/dmeta-embedding-zh:是嵌入式模型(Embedding model),僅用于內容將文本轉化為向量,無法用于內容生成,如對話等。我們后面的示例中會使用這個嵌入模型做向量化處理。

llama3:生成式模型,可以用于文本內容生成,如對話等

ollama run 命令詳解

1. 作用與功能

  • 核心功能:啟動交互式對話會話

  • 工作流程

    1. 檢查模型是否在本地

    2. 若不存在則自動下載 (ollama pull)

    3. 加載模型到內存

    4. 啟動 REPL(讀取-求值-打印循環)環境

    5. 等待用戶輸入并生成響應

2. 使用限制

  • 僅支持對話模型:如 Llama 3、Mistral 等生成式模型

  • 不支持嵌入模型:如?dmeta-embedding-zh?等向量模型

安裝PostgreSQL及Vector擴展

PostgreSQL主要用于向量數據的存儲,因為其天生的特性優勢,以及自帶的擴展插件等,可以用于向量數據的存儲。

首先在官網PostgreSQL: The world's most advanced open source database下載安裝包,選擇自己合適的版本。

我們選擇16.9版本,下載并安裝。安裝過程不再贅述。安裝完成后,基于PG-admin4管理工具可以看到安裝好的PostgreSQL.

接下來安裝vector插件:https://github.com/pgvector/pgvector/tags

網上沒找到預編譯的版本,要基于源碼自己編譯打包才行:

源碼下載到本地解壓:

安裝visual studio 2022版本,利用VS的編譯工具。

打開命令行工具,執行命令:

call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
cd D:\software\pgvector-0.7.3
set "PGROOT=D:\software\postgre16"
nmake /F Makefile.win
nmake /F Makefile.win install

如果執行時,報錯nmake命令找不到,則說明是visual studio安裝的不對缺少必要插件。解決方式如下:

步驟 1:安裝缺失的 C++ 組件

  1. 打開?Visual Studio Installer

  2. 找到已安裝的 Visual Studio Community 2022

  3. 點擊?"修改"

  4. 在?"工作負載"?選項卡中:

    • 勾選?"使用 C++ 的桌面開發"

    • 在右側?"安裝詳細信息"?中確保選中:

      • MSVC v143 - VS 2022 C++ x64/x86 生成工具

      • Windows 10 SDK(或 Windows 11 SDK)

      • C++ CMake 工具

  5. 點擊?"修改"?按鈕開始安裝

步驟 2:驗證安裝

安裝完成后,檢查以下路徑:

# 默認路徑
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat# 備選路徑
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_x86.bat
C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat

然后重新執行前面的編譯工作即可,此時就會把vector擴展安裝到postgre本地的安裝目錄下。

插件安裝完之后,進入PGAdmin4工具,創建擴展及表結構:

CREATE?EXTENSION IF?NOT?EXISTS?vector;
CREATE?EXTENSION IF?NOT?EXISTS?hstore;
CREATE?EXTENSION IF?NOT?EXISTS?"uuid-ossp";
CREATE?TABLE?IF?NOT?EXISTS?vector_store (id uuid?DEFAULT?uuid_generate_v4()?PRIMARY?KEY,content text,metadata json,embedding vector(1536)?//?1536?is?the?default?embedding dimension
);

搭建工程

引入依賴

廢話不多說,直接提供maven依賴的配置信息:
?

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.4</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.zxm</groupId><artifactId>spring-ai-agent</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-ai-agent</name><description>Demo project for Spring Boot</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version><spring-ai.version>1.0.1</spring-ai.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency>--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-advisors-vector-store</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client-webflux</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-ollama</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-pgvector</artifactId></dependency><dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></path></annotationProcessorPaths></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

application.yaml配置

server:port: 8090
spring:application:name: spring-ai-agentai:ollama:base-url: http://localhost:11434embedding:options:#model: llama3:latestmodel: shaw/dmeta-embedding-zh:latestmodel:embedding: ollamadatasource:url: jdbc:postgresql://localhost:5432/ai-vectorusername: rootpassword: rootdriver-class-name: org.postgresql.Driverhikari:connection-timeout: 30000maximum-pool-size: 5

編寫邏輯

首先定義PGVectorStore的配置類:

package com.zxm.spring.ai.agent.config;import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;import javax.sql.DataSource;import static org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgDistanceType.COSINE_DISTANCE;
import static org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType.HNSW;@Configuration
public class PgVectorVectorStoreConfig {@Beanpublic VectorStore pgVectorVectorStore(@Qualifier("vectorJdbcTemplate") JdbcTemplate jdbcTemplate,EmbeddingModel embeddingModel) {return PgVectorStore.builder(jdbcTemplate, embeddingModel).dimensions(768)  // 與嵌入模型維度對齊.distanceType(COSINE_DISTANCE)  // 余弦相似度計算.indexType(HNSW)  // 高效近似最近鄰搜索.initializeSchema(false)  // 自動初始化表結構.build();}@Bean("vectorJdbcTemplate")public JdbcTemplate jdbcTemplate(DataSource dataSource) {return new JdbcTemplate(dataSource);}
}

這里有個插曲,最開始選擇的模型是llama3,當時參考的示例中配置的向量的默認維度的1536,后來運行程序時報錯:

org.postgresql.util.PSQLException: 錯誤: expected 1536 dimensions, not 4096

經過排查后發現,llama3的維度是4096,嵌入模型的維度與vector存儲的dimensions必須保持一致,使用hnsw索引,在修改表的維度時,報錯: column cannot have more than 2000 dimensions for hnsw index,因此需要更換嵌入模型,使用:

shaw/dmeta-embedding-zh

編寫一個Controller,實現向量轉換以及存儲的邏輯:

package com.zxm.spring.ai.agent.controller;import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;import java.util.Arrays;
import java.util.List;/*** @Author* @Description* @Date Create in 下午 2:30 2018/12/21 0021*/
@RestController
@RequestMapping("/embeding")
public class EmbeddingController {@Resourceprivate EmbeddingModel embeddingModel;// 加載指定的資源文件@Value("classpath:document/醫院.txt")private org.springframework.core.io.Resource resource;@Resourceprivate VectorStore vectorStore;@GetMapping("/embed")public Object embed() {// 返回響應對象EmbeddingResponse embeddingResponse = embeddingModel.embedForResponse(List.of("今天天氣不錯"));// Map<String, EmbeddingResponse> embedding = Map.of("embedding", embeddingResponse);System.out.println(Arrays.toString(embeddingResponse.getResult().getOutput()));// 直接返回向量化后的數據float[] embed = embeddingModel.embed("挺風和日麗的");System.out.println(Arrays.toString(embed));return embed;}@GetMapping("/embed2")public String embed2() {// 讀取文本文件TextReader textReader = new TextReader(this.resource);// 元數據中增加文件名textReader.getCustomMetadata().put("filename", "醫院.txt");// 獲取Document對象List<Document> docList = textReader.read();// 向量化處理float[] embed = embeddingModel.embed(docList.get(0));// 打印向量化后的數據System.out.println(Arrays.toString(embed));// 打印Document中的原始文本數據System.out.println(docList.get(0).getText());return "success";}@GetMapping("/embed3")public String embed3() {// 讀取文本文件TextReader textReader = new TextReader(this.resource);// 元數據中增加文件名textReader.getCustomMetadata().put("filename", "醫院.txt");// 獲取Document對象List<Document> docList = textReader.read();// 文檔分割TokenTextSplitter splitter = new TokenTextSplitter();List<Document> splitDocuments = splitter.apply(docList);// 向量化處理float[] embed = embeddingModel.embed(splitDocuments.get(0));// 打印向量化后的數據System.out.println(Arrays.toString(embed));// 打印Document中的原始文本數據System.out.println(splitDocuments.get(0).getText());vectorStore.add(splitDocuments);return "success";}
}

本地預先準備文件用于生成向量:

大連市第三人民醫院
大醫二院
中心醫院
大連市第七人民醫院
大醫一院
鐵路醫院
小區門口的社區醫院
甘井子社區醫院

測試結果

瀏覽器執行:http://localhost:8090/embeding/embed3

數據已經向量化,且存儲到PostgreSQL中:

執行查詢:http://localhost:8090/search?query=醫院

返回結果:

[{"id": "357b9b35-7862-40d3-a062-38c394a10c7b","text": "大連市第三人民醫院\r\n大醫二院\r\n中心醫院\r\n大連市第七人民醫院\r\n大醫一院\r\n鐵路醫院\r\n宏都熙景小區門口的社區醫院\r\n甘井子社區醫院","media": null,"metadata": {"charset": "UTF-8","source": "醫院.txt","filename": "醫院.txt","distance": 0.40404886},"score": 0.5959511399269104
}]

實現簡單的RAG能力

我們的目標是根據輸入的提示,先轉換成向量,然后在向量數據庫中檢索,然后轉化成提示詞的上下文信息,輸入給大模型,大模型基于提示詞的增強,給出準確的反饋。

編寫實現的邏輯,先配置WebClient:

@Configuration
public class WebClientConfig {@Beanpublic WebClient ollamaWebClient() {return WebClient.builder().baseUrl("http://localhost:11434") // Ollama 服務地址.defaultHeader("Content-Type", "application/json").build();}
}

編寫核心實現邏輯:

import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
public class RAGController {@Autowiredprivate VectorStore vectorStore;@Autowiredprivate WebClient ollamaClient;@GetMapping("/ask")public Mono<String> askQuestion(@RequestParam String question) {// 步驟1: 向量檢索相關文檔List<Document> contextDocs = retrieveRelevantDocuments(question);// 步驟2: 構建LLM提示String prompt = buildPrompt(question, contextDocs);// 步驟3: 調用Llama3生成答案return generateAnswer(prompt);}// 檢索相關文檔private List<Document> retrieveRelevantDocuments(String query) {SearchRequest request = SearchRequest.builder().query(query).topK(3)  // 獲取最相關的3個文檔.build();return vectorStore.similaritySearch(request);}// 構建提示模板private String buildPrompt(String question, List<Document> contextDocs) {StringBuilder contextBuilder = new StringBuilder();contextBuilder.append("請基于以下上下文回答問題:\n\n");// 添加上下文文檔for (int i = 0; i < contextDocs.size(); i++) {contextBuilder.append("【上下文片段 ").append(i + 1).append("】:\n").append(contextDocs.get(i).getText()).append("\n\n");}// 添加問題contextBuilder.append("問題:").append(question).append("\n\n");contextBuilder.append("答案:");return contextBuilder.toString();}// 調用Llama3生成答案private Mono<String> generateAnswer(String prompt) {Map<String, Object> requestBody = new HashMap<>();requestBody.put("model", "llama3");requestBody.put("prompt", prompt);requestBody.put("stream", false);return ollamaClient.post().uri("/api/generate").bodyValue(requestBody).retrieve().bodyToMono(OllamaResponse.class).map(OllamaResponse::getResponse);}private static class OllamaResponse {private String response;public String getResponse() {return response;}public void setResponse(String response) {this.response = response;}}
}

然后,啟動ollama的生成式大模型:

瀏覽器調用請求:http://localhost:8090/ask?question=在宏都熙景附近去哪里看病方便?

響應結果:

至此一個最簡單的檢索增強生成的案例實現完成。

總結

今天的示例先分享到這里,學習的道路是漫長曲折的,后面有機會再分享更多的內容。希望大家一起多交流,互相成長。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92864.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92864.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92864.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Git 亂碼文件處理全流程指南

一、問題背景與核心目標 1.1 問題描述 在 Git 倉庫中發現了一個異常亂碼文件&#xff1a; "\001\342\240\025\250\325\3738\f\036\035\006\004\240\002\240\002\b\003\004\340\002\340\002\340\002\034\034\001\001\004:\016\020\001\005\016\016\016\211\266\257\211\266…

JavaScript垃圾回收機制

1.垃圾回收的概念 1.1 什么是垃圾回收機制&#xff1a; GC 即 Garbage Collection &#xff0c;程序工作過程中會產生很多"垃圾"&#xff0c;這些垃圾是程序不用的內存或者是之前用過了&#xff0c;以后不會再用的內存空間&#xff0c;而 GC 就是負責回收垃圾的&…

工業相機選擇規則

一、相機分辨率選擇相機分辨率指的是相機傳感器捕捉圖像細節的能力&#xff0c;具體來說就是傳感器上有效像素的總數量。可以把它理解為構成數字圖像的“小方塊”&#xff08;像素&#xff09;有多少個。工業領域內相機的分辨率的選擇根據更具產品需要的精度要求和產品大小來確…

【Web安全】csrf、ssrf和xxe的區別

CSRF、SSRF 和 XXE 是三種不同類型的網絡安全漏洞&#xff0c;它們的原理、攻擊目標、利用方式和危害場景均有顯著區別。以下從核心定義、原理、場景等維度詳細對比三者的差異。一、核心定義與原理對比漏洞類型全稱核心定義核心原理CSRF跨站請求偽造攻擊者誘導用戶在已登錄的情…

【Lua】XLua一鍵構建工具

將以下代碼放入Editor文件夾&#xff0c;點擊菜單欄的XLua/一鍵生成代碼和熱補丁 即可。using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine;/// <summary> /// XLua自動化構建工具 //…

20250808:EasyGBS 對接大華 ICC 平臺問題處理

最近有個現場在對接大華 ICC 平臺時&#xff0c;客戶反饋&#xff1a;EasyGBS 級聯成功&#xff0c;但 ICC 顯示下級離線。EasyGBS 成功對接過很多家國標平臺&#xff0c;但這種情況確實少見。我們遠程過去確認配置無誤后&#xff0c;就進行了抓包&#xff0c;拿到包我就納悶了…

js使用webscoket時使用自定義二進制包協議時并發問題處理

this.server new WebSocket.Server({ port: this.port });this.server.on(connection, (ws, req) > {const uniqueId dataUtil.uuid();ws.id uniqueId;global.serverSession.set(uniqueId, ws);logger.debug({ message: 客戶端已連接, traceId: ws.id, address: req.sock…

元數據管理與數據治理平臺:Apache Atlas 分類傳播 Classification Propagation

文中內容僅限技術學習與代碼實踐參考&#xff0c;市場存在不確定性&#xff0c;技術分析需謹慎驗證&#xff0c;不構成任何投資建議。Apache Atlas 框架是一套可擴展的核心基礎治理服務&#xff0c;使企業能夠有效、高效地滿足 Hadoop 中的合規性要求&#xff0c;并支持與整個企…

TSF應用開發與運維部署

架構演進歷程&#xff1a;單體架構-->SOA架構-->微服務架構-->Service Mesh騰訊微服務平臺TSF (Tencent Service Framework) 是一個圍繞應用和微服務的 PaaS 平臺。提供服務全生命周期管理能力和數據化運營支持。提供多維度應用、服務、機器的監控數據&#xff0c;助力…

linux開發之mmap內存映射

mmap概念 mmp是 將文件或設備直接映射到進程的虛擬內存空間 的一種機制&#xff0c;可實現程序像訪問內存一樣訪問文件&#xff0c;而不需要傳統的 read()/write()系統調用 文件內容被映射到進程的地址空間&#xff0c;讀寫文件就像操作內存一樣&#xff0c;操作系統負責自動同…

CPP繼承

繼承 一、繼承概述 1、為什么需要繼承 如下示例&#xff0c;Person 類、Student 類、Teacher 類有大量重復的代碼&#xff0c;造成代碼冗余&#xff0c;降低開發效率。我們可以通過繼承來解決這一問題。在面向對象的編程語言中&#xff0c;繼承是一個核心概念。主要作用將重復的…

模塊 PCB 技術在未來通信領域的創新突破方向

未來通信領域對數據傳輸速率、信號穩定性及設備集成度的要求持續攀升&#xff0c;模塊 PCB 作為通信設備的關鍵組件&#xff0c;其技術創新成為推動行業發展的核心動力。獵板 PCB 憑借深厚的技術積累與持續的研發投入&#xff0c;在模塊 PCB 技術創新方面取得諸多突破&#xff…

mysql的InnoDB索引總結

MySQL InnoDB索引知識點總結 1. 索引類型 1.1 聚簇索引&#xff08;Clustered Index&#xff09; 定義與特性 定義&#xff1a;聚簇索引是InnoDB的默認存儲方式&#xff0c;數據行按照主鍵的順序物理存儲在磁盤上特性&#xff1a; 每個InnoDB表只能有一個聚簇索引數據頁中的記錄…

C++模板的補充

類模板(上一篇沒講到類模板C/C內存管理&函數模板-CSDN博客&#xff09; 類模板的定義&#xff1a; template<class T1, class T2, ..., class Tn> class 類模板名 {// 類內成員定義 }; 用一個簡單的棧例子講類模板 #define _CRT_SECURE_NO_WARNINGS #include &l…

用JOIN替代子查詢的查詢性能優化

一、子查詢的性能瓶頸分析?重復執行成本?關聯子查詢會導致外層每行數據觸發一次子查詢&#xff0c;時間復雜度為O(M*N)sql-- 典型低效案例 SELECT e.employee_id, (SELECT d.department_name FROM departments d WHERE d.department_id e.department_id) FROM employees e; …

【設計模式】訪問者模式模式

訪問者模式&#xff08;Visitor Pattern&#xff09;詳解一、訪問者模式簡介 訪問者模式&#xff08;Visitor Pattern&#xff09; 是一種 行為型設計模式&#xff08;對象行為型模式&#xff09;&#xff0c;它允許你在不修改對象結構的前提下&#xff0c;為對象結構中的元素添…

比特幣現貨和比特幣合約的區別與聯系

一、基本定義項目現貨&#xff08;Spot&#xff09;合約&#xff08;Futures / Perpetual&#xff09;本質直接買賣比特幣本身買賣比特幣價格的衍生品合約所得資產真實的 BTC合約頭寸&#xff08;沒有直接持有 BTC&#xff09;結算方式交割比特幣現金結算&#xff08;多數平臺&…

Qt/C++開發監控GB28181系統/實時監測設備在線離線/視頻預覽自動重連/重新點播取流/低延遲

一、前言說明 一個好的視頻監控系統&#xff0c;設備掉線后能夠自動重連&#xff0c;也是一個重要的功能指標&#xff0c;如果監控系統只是個rtsp流地址&#xff0c;那非常好辦&#xff0c;只需要重新打開流地址即可&#xff0c;而gb28181中就變得復雜了很多&#xff0c;需要多…

此芯p1開發板使用OpenHarmony時llama.cpp不同優化速度對比(GPU vs CPU)

硬件環境 Cix P1 SoC 瑞莎星睿 O6 開發板 rx580顯卡 產品介紹&#xff1a; https://docs.radxa.com/orion/o6/getting-started/introduction OpenHarmony 5.0.0 使用vulkan后端的llama.cpp &#xff08;GPU&#xff09; # ./llama-bench -m /data/qwen1_5-0_5b-chat-q2_k.…

Android 四大布局:使用方式與性能優化原理

一、四大布局基本用法與特點1. LinearLayout&#xff08;線性布局&#xff09;使用方式&#xff1a;<LinearLayoutandroid:orientation"vertical" <!-- 排列方向&#xff1a;vertical/horizontal -->android:layout_width"match_parent"android:…