找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1844

积分

0

好友

250

主题
发表于 7 小时前 | 查看: 2| 回复: 0

概述

还在为外部嵌入API的延迟和费用烦恼吗?或者觉得为向量搜索单独维护一个数据库服务过于臃肿?如果你是一名 PHP 开发者,并且你的 AI 应用对延迟和成本极其敏感,那么 MemVector 或许就是你正在寻找的答案。

MemVector 是一个专为 PHP 设计的高性能扩展,它将 AI 基础设施直接搬进了你的 PHP 进程。它本质上是一个本地的向量数据库和嵌入引擎,所有操作——包括文本向量化、存储、相似性搜索乃至交叉编码器重排序——都在进程内完成,完全跳过了网络往返。它使用 C++17 构建,并集成了 AVX2 SIMD 指令进行加速,旨在为 AI 工作负载提供极致的性能。

它特别适合与小型本地 GGUF 模型(嵌入和重排序模型,大小在24MB到636MB之间)以及长生命周期的 PHP 运行时(如 OpenSwoole、ReactPHP、RoadRunner 或 FrankenPHP)配合使用。在这些运行时中,工作进程是持久化的,可以一次性加载模型,之后每个请求都能在毫秒级延迟内完成完整的检索增强生成(RAG)流水线,且没有任何外部依赖。

快速开始

让我们通过几段代码,快速感受一下 MemVector 的能力。

首先是一个完整的语义搜索示例,这需要你在编译时启用 --with-llama 选项以集成本地模型支持:

// 使用本地嵌入模型进行语义搜索(需 --with-llama)
$emb = new MemVectorEmbedding('/models/all-MiniLM-L6-v2.Q8_0.gguf');
$store = new MemVectorStore(null, ['dimensions' => $emb->dimensions()]);

$store->set('php',     $emb->embed('PHP is a server-side scripting language'),     'lang');
$store->set('python',  $emb->embed('Python is used for machine learning'),         'lang');
$store->set('gravity', $emb->embed('Gravity pulls objects toward the earth'),      'science');
$store->set('dna',     $emb->embed('DNA encodes genetic information'),             'science');

$results = $store->search($emb->embed('programming languages'), 2);
// [['key' => 'php', 'score' => 0.82, 'metadata' => 'lang'],
//  ['key' => 'python', 'score' => 0.79, 'metadata' => 'lang']]

如果你想获得更精准的搜索结果,可以采用两阶段检索策略:先用向量搜索快速召回一批候选文档,再用交叉编码器进行精细的重排序:

// 二阶段检索:向量搜索 + 交叉编码器重排序(需 --with-llama)
$rr = new MemVectorReranker('/models/bge-reranker-v2-m3-Q8_0.gguf');
$candidates = $store->search($emb->embed('programming languages'), 50);
$results = $rr->rerank('programming languages', $candidates, 5);

当然,MemVector 也可以完全独立于本地模型工作。你可以使用来自 OpenAI 或其他任何来源的向量,它就是一个纯粹的、高性能的本地向量数据库:

// 或使用自定义向量(无需 llama.cpp)
$store = new MemVectorStore('/data/vectors', ['dimensions' => 1536]);
$store->set('doc_1', $openai_embedding, '{"title": "Introduction"}');
$results = $store->search($query_embedding, 10);

特性

MemVector 的设计目标是在提供丰富功能的同时,确保极致的性能和易用性。其主要特性包括:

  • 键值 API:提供 set(key, vector)get(key)delete(key) 等直观操作,batchSet() 支持批量 upsert。
  • 文本嵌入:可选集成 llama.cpp,支持直接在 PHP 中运行 GGUF 格式的嵌入模型进行推理。
  • 交叉编码器重排序:支持完整的二阶段检索流水线——先快速向量搜索,再高精度重排序,显著提升结果相关性。
  • 三种存储模式:灵活适应不同场景。
    • 内存:临时存储,速度最快。
    • 磁盘 (mmap):持久化存储,数据保存在文件中。
    • 共享内存 (shm):支持跨 PHP 进程共享数据,适合常驻内存的PHP应用。
  • HNSW 索引:搜索时自动构建业界流行的 HNSW (Hierarchical Navigable Small World) 图索引,支持高效的近似最近邻搜索。
  • 向量量化:支持多种量化方式以减少内存占用,包括 F16、Int8(标量)、二值化以及乘积量化 (PQ)。
  • 四种距离度量:支持余弦相似度、点积、欧氏距离和曼哈顿距离,满足不同算法需求。
  • 无锁并发:通过 std::atomic 实现读写操作,在高并发场景下也能保持良好性能。
  • AVX2 SIMD 加速:利用现代 CPU 的 SIMD 指令集,大幅加速余弦和点积距离的计算。
  • 多段架构:采用固定容量的段式结构,可自动增长,管理海量向量时更高效。
  • JSONL 导入导出:提供 dump()load() 方法,方便数据的备份、迁移和与其他系统交互。
  • 内存限制:可以设定 mmap 总内存使用量的上限,防止内存溢出。

性能

MemVector 的核心优势就在于其进程内的架构,消除了所有网络调用、序列化以及外部服务的开销。这意味着没有延迟,也没有额外成本。

嵌入生成

让我们对比一下生成文本嵌入的几种方式:

方法 单次延迟 成本
OpenAI API (text-embedding-3-small) 50-200 ms(网络往返) $0.02 / 1M tokens
Cohere API (embed-english-v3.0) 50-200 ms(网络往返) $0.10 / 1M tokens
MemVector + 本地 GGUF 模型 5-15 ms(进程内) 免费

本地嵌入比调用远程 API 快 10 到 40 倍,并且完全不存在按 token 计费的问题。模型通过 llama.cpp 在 PHP 进程内直接运行,没有 HTTP 开销、不需要 API 密钥,也不受速率限制。

向量搜索

在搜索环节,进程内向量数据库的优势更为明显:

方法 查询延迟 说明
Pinecone / Qdrant / Weaviate(云) 10-50 ms(网络) 托管服务,按向量计费
Pinecone / Qdrant / Weaviate(自托管) 5-20 ms(网络) 独立进程,仍有 TCP/gRPC 开销
PostgreSQL + pgvector 5-50 ms(查询 + 网络) 共享数据库,有连接池开销
MemVector(进程内) 0.1-5 ms 无网络、无序列化

MemVector 直接在 PHP 进程的内存(或 mmap 的文件)中搜索向量,省去了序列化、套接字通信和协议解析的步骤。结合 HNSW 索引和 AVX2 SIMD 加速,在百万级向量的规模下,大多数搜索都能在 1 毫秒内完成。

完整 RAG 流水线(嵌入 + 搜索 + 重排序)

对于一个完整的检索流程,将所有步骤放在进程内带来的收益是叠加的:

方法 总延迟 组件
OpenAI 嵌入 + Pinecone 搜索 100-400 ms 2 次网络往返
OpenAI 嵌入 + Pinecone 搜索 + Cohere 重排序 200-600 ms 3 次网络往返
MemVector(全进程内) 10-30 ms 0 次网络往返

一个完整的两阶段RAG检索流水线,在单个 PHP 进程中即可闭环,没有任何外部依赖。

内存占用

MemVector 在内存使用上也做了大量优化,特别是模型的共享机制:

组件 RSS
MemVector 扩展(无模型) ~1 MB
+ 嵌入模型 (all-MiniLM-L6-v2, 24 MB GGUF) ~33 MB
+ 重排序模型 (bge-reranker-v2-m3, 636 MB GGUF) ~200 MB
+ 10 万向量 (384 维, f32) ~150 MB
+ 10 万向量 (384 维, int8 量化) ~40 MB

模型权重通过 mmap() 加载,并且可以跨多个 php-fpm 或 OpenSwoole 工作进程,通过操作系统的页面缓存进行共享,避免了重复加载的内存浪费。

要求

要使用 MemVector,你的环境需要满足以下条件:

  • PHP 8.1+
  • C++17 编译器(GCC 7+ 或 Clang 5+)
  • (可选)llama.cpp,用于文本嵌入和交叉编码器重排序功能

构建

标准的 PHP 扩展构建流程:

phpize
./configure --enable-memvector
make
make test

安装 llama.cpp(可选,用于嵌入和重排序)

如果你需要文本嵌入和重排序功能,则需要先安装 llama.cpp。

macOS (Homebrew):

brew install llama.cpp

Linux(从源码构建):

git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
cmake -B build -DBUILD_SHARED_LIBS=ON -DGGML_CUDA=OFF
cmake --build build --config Release -j$(nproc)
sudo cmake --install build --prefix /usr/local
sudo ldconfig  # 刷新共享库缓存

如果需要 GPU 加速,可以将 -DGGML_CUDA=OFF 替换为 -DGGML_CUDA=ON(前提是已安装 CUDA 工具包)。

构建支持 llama.cpp(嵌入和重排序)

在构建 MemVector 时,通过 --with-llama 参数指向你的 llama.cpp 安装路径:

phpize
./configure --enable-memvector --with-llama=/usr/local
make
make test

如果 llama.cpp 安装在其他目录,使用 --with-llama=DIR 指定即可。

下载模型

你需要下载 GGUF 格式的模型文件。以下是一些推荐模型:

嵌入模型(推荐 24 MB,384 维的 all-MiniLM-L6-v2):

curl -L -o all-MiniLM-L6-v2-Q8_0.gguf \
  https://huggingface.co/leliuga/all-MiniLM-L6-v2-GGUF/resolve/main/all-MiniLM-L6-v2.Q8_0.gguf
模型 维度 大小 下载
all-MiniLM-L6-v2 (Q8) 384 24 MB HuggingFace
nomic-embed-text-v1.5 (Q8) 768 138 MB HuggingFace
bge-small-en-v1.5 (F16) 384 67 MB HuggingFace

重排序模型(GGUF 格式的交叉编码器):

curl -L -o bge-reranker-v2-m3-Q8_0.gguf \
  https://huggingface.co/gpustack/bge-reranker-v2-m3-GGUF/resolve/main/bge-reranker-v2-m3-Q8_0.gguf
模型 大小 下载
bge-reranker-v2-m3 (Q8) 636 MB HuggingFace
bge-reranker-v2-m3 (Q2) 366 MB HuggingFace

配置选项

./configure 阶段,你可以使用以下标志:

标志 描述
--enable-memvector 启用扩展(必需)
--enable-memvector-avx2 强制启用 AVX2 SIMD(默认会自动检测)
--with-llama[=DIR] 启用 llama.cpp 支持(用于嵌入和重排序)

功能检测

你可以在运行时通过检查是否定义了相关常量,来判断当前扩展支持哪些功能:

if (defined('MEMVECTOR_SHM')) {
    // 共享内存模式可用
    $store = new MemVectorStore('mystore', ['storage' => 'shm', 'dimensions' => 128]);
}

if (defined('MEMVECTOR_LLAMA')) {
    // 编译时包含 llama.cpp 支持
    $emb = new MemVectorEmbedding('/path/to/embedding-model.gguf');
    $rr  = new MemVectorReranker('/path/to/reranker-model.gguf');
}

PHP API

类:MemVectorStore

__construct(?string $dir = null, ?array $options = null)

创建或打开一个向量存储。

// 内存模式(临时存储,仅限单进程)
$store = new MemVectorStore();
$store = new MemVectorStore(null, ['dimensions' => 128]);

// 磁盘模式(持久化存储,基于 mmap 的文件)
$store = new MemVectorStore('/path/to/dir', ['dimensions' => 128]);

// 共享内存模式(持久化,支持跨进程访问)
$store = new MemVectorStore('mystore', ['storage' => 'shm', 'dimensions' => 128]);

选项(字符串值不区分大小写):

类型 默认值 描述
storage string auto 'disk'、'memory' 或 'shm'
dimensions int 1536 向量维度(范围 1-4096)
distance string 'cosine' 'cosine'、'dot'、'euclidean'、'manhattan'
quantization string 'none' 'none'、'f16'、'int8'、'binary'、'pq'
segment_size int 10M(磁盘/shm)、4096(内存) 每个段的最大记录数量
writable bool true 是否为只读模式(主要用于 shm 模式)
memory_limit int / string 0 mmap 总内存使用限制,0 表示无限制

set(string $key, array $vector, ?string $metadata = null): bool

按键插入或替换向量(upsert 语义)。如果键已存在,则更新对应的向量和元数据。

$store->set('doc_42', $vector);
$store->set('doc_42', $new_vector, '{"category": "science"}'); // 替换前一个向量
  • $key:唯一的字符串键,最大长度 63 个字符。
  • $vector:浮点数数组,必须与存储初始化时设定的维度相匹配。
  • $metadata:可选的元数据字符串,最大长度 4096 字节,通常用于存储 JSON。

batchSet(array $batch): int

一次性插入或替换多个向量。返回成功插入(或更新)的项目数量。这对于数据初始化或批量更新非常高效。

$count = $store->batchSet([
    ['key' => 'doc_1', 'vector' => $vec1],
    ['key' => 'doc_2', 'vector' => $vec2, 'metadata' => '{"tag": "a"}']
]);

总的来说,MemVector 为 PHP 生态带来了一个前所未有的高性能、低成本、零依赖的本地 AI 基础设施解决方案。它尤其适合那些对延迟有严苛要求、希望简化架构、或需要在受限环境中部署 RAG 应用的场景。如果你正在为 PHP 项目寻找 AI 能力的内化方案,不妨到云栈社区的技术论坛深入探讨,或在我们的资源库中寻找更多相关的工具和灵感。




上一篇:《生化危机9》游戏资讯:MOD争议、玩家热议及卡普空新动向
下一篇:逻辑斯谛方程原理详解:从数学推导到生态学与机器学习应用
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-5 19:13 , Processed in 0.391504 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表