news 2026/9/9 22:58:42

fastest-rag-milvus-groq 实战:Milvus 二值向量检索 + Groq 推理,构建毫秒级 RAG 应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
fastest-rag-milvus-groq 实战:Milvus 二值向量检索 + Groq 推理,构建毫秒级 RAG 应用

fastest-rag-milvus-groq 实战:Milvus 二值向量检索 + Groq 推理,构建毫秒级 RAG 应用

【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub

导读

本文基于 ai-engineering-hub 仓库中的 fastest-rag-milvus-groq 项目,完整拆解一条以“低检索时延”为核心目标的 RAG 技术栈:用 HuggingFace 模型产出稠密向量并做二值量化(Binary Quantization),存入 Milvus 向量库做二进制向量索引与 Hamming 距离检索,再由 Groq 作为推理引擎驱动 Kimi K2 模型生成答案,最后借助 Beam 完成 Serverless 部署。读完本文,你将掌握二值向量检索的原理与落地代码、MilvusBINARY_VECTOR集合的建库与索引配置、Groq LLM 的接入方式,以及一条从 PDF 上传到流式问答、并在本地/云端运行完整应用的实操路径。


一、系统全景:这条 RAG 技术栈为什么“快”

该项目在 README.md 中给出了明确的设计目标:构建检索时延 < 15ms的 RAG 应用。这一目标由四个核心组件协同实现:

组件在本项目中的角色代码位置
LlamaIndex编排 RAG 应用,提供文档加载、Embedding 与 LLM 封装rag.py
Milvus二进制向量(BINARY_VECTOR)的索引与存储rag.py
Groq推理引擎,运行 MoonshotAI 的 Kimi K2(moonshotai/kimi-k2-instructrag.py
Beam极速 Serverless 云端部署 Streamlit 应用start_server.py

速度来自两条主线(依据仓库源码 rag.py 实现推断):

  1. 检索侧:稠密向量被符号化压缩为每个维度仅 1 bit 的二进制向量,存储开销相对 float32 降至约 1/32;Milvus 通过BIN_FLAT索引 +HAMMING(汉明)距离直接按位计算相似度,无需浮点乘法。
  2. 生成侧:Groq 作为高吞吐推理引擎驱动 LLM,配合 LlamaIndex 的流式接口把首字延迟进一步摊薄。

需要说明:< 15ms是项目 README 给出的目标指标,实际数值与语料规模、索引类型(本项目BIN_FLAT属于精确扫描)、部署硬件(本地 CPU 还是 Beam GPU)强相关,应以你所在环境的实测为准——本项目的 app.py 内置了毫秒级检索计时器,可以直接量化验证。


二、核心原理:Embedding 的二值量化(Binary Quantization)

二值量化是本项目检索侧提速的关键。它把 float32 的稠密向量变成仅含 0/1 的比特串。仓库在EmbedData中给出了完整实现,模型默认为BAAI/bge-large-en-v1.5(rag.py):

class EmbedData: def __init__(self, embed_model_name="BAAI/bge-large-en-v1.5", batch_size=512): self.embed_model_name = embed_model_name self.embed_model = self._load_embed_model() # HuggingFaceEmbedding self.batch_size = batch_size def _binary_quantize(self, embeddings): """Convert float32 embeddings to binary vectors""" embeddings_array = np.array(embeddings) binary_embeddings = np.where(embeddings_array > 0, 1, 0).astype(np.uint8) # Pack bits into bytes (8 dimensions per byte) packed_embeddings = np.packbits(binary_embeddings, axis=1) return [vec.tobytes() for vec in packed_embeddings] def embed(self, contexts): for batch_context in batch_iterate(contexts, self.batch_size): batch_embeddings = self.generate_embedding(batch_context) # float32 self.embeddings.extend(batch_embeddings) binary_batch = self._binary_quantize(batch_embeddings) # 二值化 self.binary_embeddings.extend(binary_batch)

量化过程分两步:

  • 符号化(Sign 编码)np.where(x > 0, 1, 0)以 0 为阈值,向量各维大于 0 记 1、否则记 0;
  • 位打包np.packbits(binary_embeddings, axis=1)沿向量维度方向把 8 个 bit 打包成 1 个 byte,最终以bytes形式送入 Milvus,这正是 MilvusBINARY_VECTOR字段所需的数据形态。

代码中有两个值得注意的工程细节:

  1. 批处理batch_iteratebatch_size=512分批生成 Embedding 与二进制向量,避免一次处理整个语料造成内存压力;
  2. 模型缓存_load_embed_model()将模型缓存在./hf_cache目录(rag.py),首次运行需联网下载bge-large-en-v1.5,之后可离线加载。

值得一提的设计权衡:符号化只用“正/负”信息而丢弃幅值,因此对相似度精度是有损压缩。它换取的是 Milvus 端仅需按位比较的 Hamming 距离与约 32 倍的内存节省——这正是该项目换取检索速度的“代价”。对检索召回率要求极高的场景,可在此基础上用重排序(Re-ranking)阶段补偿(本项目未包含,属于可自行扩展方向)。


三、向量库设计:Milvus 二进制向量集合

3.1 客户端与本地库文件

项目使用MilvusClient(db_file)直接以本地文件的方式运行 Milvus Lite(rag.py),无需单独起 Milvus 服务,非常适合单机/开发期验证:

def define_client(self): try: self.client = MilvusClient(self.db_file) logger.info(f"Initialized Milvus Lite client with database: {self.db_file}") except Exception as e: raise e

在 app.py 中,每个浏览器会话会生成独立的库文件milvus_{session_id}.db放在系统临时目录,并在重新索引前先删除旧文件,保证多会话数据隔离。

3.2 集合 Schema 与索引参数

MilvusVDB_BQ.create_collection()定义了二进制向量集合的完整结构(rag.py):

schema = self.client.create_schema( auto_id=True, enable_dynamic_fields=True, ) schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True) schema.add_field(field_name="context", datatype=DataType.VARCHAR, max_length=65535) schema.add_field(field_name="binary_vector", datatype=DataType.BINARY_VECTOR, dim=self.vector_dim) index_params = self.client.prepare_index_params() index_params.add_index( field_name="binary_vector", index_name="binary_vector_index", index_type="BIN_FLAT", # Exact search for binary vectors metric_type="HAMMING" # Hamming distance for binary vectors ) self.client.create_collection( collection_name=self.collection_name, schema=schema, index_params=index_params )

关键参数逐项说明:

配置项取值含义与影响
auto_idTrue主键id由 Milvus 自动生成,插入时无需传 id
enable_dynamic_fieldsTrue允许后续插入未预定义的字段
contextVARCHAR(65535)存储原始文本片段,检索时随结果一起取出
binary_vectorBINARY_VECTOR二进制向量类型,维度dim必须与量化前的 Embedding 维度一致(8 的整数倍)
index_typeBIN_FLAT二进制向量的精确(暴力)扫描索引,代码注释明确标注 “Exact search”
metric_typeHAMMING相似度度量采用汉明距离,数值越小表示两个比特串差异越少

关于维度,rag.py 默认vector_dim=1024,而 app.py 采用更稳妥的做法:先对一条"test"文本取真实 Embedding 长度作为actual_dim,再传入建库函数,从根上避免维度不匹配的报错。

3.3 批量写入

ingest_data()将文本与二进制向量一一配对、逐批插入(rag.py):

for batch_context, batch_binary_embeddings in zip( batch_iterate(embeddata.contexts, self.batch_size), batch_iterate(embeddata.binary_embeddings, self.batch_size) ): data_batch = [ {"context": context, "binary_vector": binary_embedding} for context, binary_embedding in zip(batch_context, batch_binary_embeddings) ] self.client.insert(collection_name=self.collection_name, data=data_batch)

注意binary_vector字段写入的是打包后的bytes对象_binary_quantize的返回值),而非 0/1 矩阵或 float 数组,这是 MilvusBINARY_VECTOR的输入约定。


四、检索链路:查询二值化 → Hamming 距离 → 相似度换算

Retriever类负责把用户问题映射为同样的二进制空间再执行检索(rag.py):

def _binary_quantize_query(self, query_embedding): embedding_array = np.array([query_embedding]) binary_embedding = np.where(embedding_array > 0, 1, 0).astype(np.uint8) packed_embedding = np.packbits(binary_embedding, axis=1) return packed_embedding[0].tobytes() def search(self, query, top_k=None): if top_k is None: top_k = self.top_k # 默认 5 query_embedding = self.embeddata.embed_model.get_query_embedding(query) binary_query = self._binary_quantize_query(query_embedding) search_results = self.vector_db.client.search( collection_name=self.vector_db.collection_name, data=[binary_query], anns_field="binary_vector", search_params={"metric_type": "HAMMING", "params": {}}, limit=top_k, output_fields=["context"] ) formatted_results = [] for result in search_results[0]: formatted_results.append({ "id": result["id"], "score": 1.0 / (1.0 + result["distance"]), # 汉明距离 → 相似度 "payload": {"context": result["entity"]["context"]}, }) return formatted_results

四个要点值得展开:

  1. 查询也需同源量化get_query_embedding产生 float32 查询向量后,必须用与建库阶段完全一致的> 0 → 1阈值规则打包成 bytes,否则检索结果无意义;
  2. 索引字段对齐anns_field="binary_vector"指明在二进制向量字段上检索,search_params中的度量必须是建索引时注册的HAMMING
  3. 返回原文:通过output_fields=["context"]让 Milvus 直接带回命中的文本片段,省去二次查询;
  4. 相似度换算:Milvus 返回的是汉明距离(越小越相似),项目用1.0 / (1.0 + distance)将其转换成 “越大越相似” 的分数,方便下游或 UI 直接展示。

五、生成侧:LlamaIndex + Groq 驱动 Kimi K2

检索到的片段由RAG类交给 Groq 上的 LLM 完成生成(rag.py)。初始化核心参数如下:

class RAG: def __init__(self, retriever, llm_model="moonshotai/kimi-k2-instruct", groq_api_key=None): self.llm_model = llm_model self.groq_api_key = groq_api_key or os.getenv("GROQ_API_KEY") self.llm = self._setup_llm() self.retriever = retriever self.prompt_template = ( "CONTEXT: {context}\n" "---------------------\n" "Given the context information above I want you to think step by step to answer the user's query " "in a crisp and concise manner. In case you don't know the answer simply say 'I don't know!'. " "Don't try to make up an answer. Only answer based on facts and contextual information.\n" "QUERY: {query}\n" "ANSWER: " ) def _setup_llm(self): if not self.groq_api_key: raise ValueError("Groq API key is required...") return Groq( model=self.llm_model, api_key=self.groq_api_key, temperature=0.4, max_tokens=1000 )

需要特别说明的几处设计:

  • 模型选择moonshotai/kimi-k2-instruct走 Groq 的推理端点,API Key 通过GROQ_API_KEY环境变量或构造参数传入,缺省时会抛出明确错误提示;
  • 解码参数temperature=0.4(偏低、更保守稳定)与max_tokens=1000(单次回复上限),可结合自身场景调整;
  • 防幻觉提示词:Prompt 模板要求模型“基于事实与上下文回答、不知道就说 I don't know,绝不编造”,这是 RAG 落地中抑制幻觉的常见手段;
  • 双入口 APIquery()llm.stream_complete/llm.completechat_query()llm.stream_chat/llm.chat,UI 层选用stream_complete实现逐 token 流式输出。

generate_context()会把top_k(默认 5)条检索结果按\n\n---\n\n拼接成单一上下文块(rag.py),再填入上述模板——检索与生成的衔接就在这里完成。


六、前端交互:Streamlit 应用与毫秒级计时

app.py 用 Streamlit 把整套流程包装成可视化应用,交互设计可总结为四步:

  1. 侧边栏输入 Groq API Key(密码输入框,支持从环境变量预填);
  2. 上传 PDF:文件进入临时目录后由 LlamaIndex 的SimpleDirectoryReader(input_dir=..., required_exts=[".pdf"], recursive=True)抽取文本(app.py);
  3. 三步索引管线:生成 Embedding(进度 40%)→ 创建二进制向量集合并写入 Milvus Lite(60%)→ 构建RAG查询引擎(100%),全程用st.progress反馈进度;同一会话内已处理的文档存入st.session_state.file_cache,避免重复索引;
  4. 流式对话 + 计时:用户提问后走检索 → 组装提示词 →llm.stream_complete的流水线。

其中计时逻辑是验证“快不快”的关键(app.py):

# Measure retrieval time retrieval_start = time.perf_counter() context_text = query_engine.generate_context(query=prompt) retrieval_time = time.perf_counter() - retrieval_start # ... stream LLM tokens and render ... retrieval_ms = int(retrieval_time * 1000) st.caption(f"⏱️ Retrieval time: {retrieval_ms} ms")

这里测量的范围是generate_context()——即查询二值化 + Milvus Hamming 检索 + 上下文拼接的纯检索阶段(不含 LLM 生成),因此该数字能直接刻画向量检索环节的时延,用于验证 README 提出的毫秒级目标。

其余 UI 细节还包括:内置 PDF 的 base64 内联预览、每条会话独立的 Milvus 集合(docs_{uuid8})与“Clear ↺”按钮(重置对话并触发gc.collect()释放内存)。


七、环境准备与本地运行

7.1 安装 uv 与依赖

README 要求Python 3.11 及以上,并推荐用 uv 管理项目与虚拟环境。先安装 uv:

# MacOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

初始化项目并安装依赖:

# Create a new directory for our project uv init fastest-rag cd fastest-rag # Create virtual environment and activate it uv venv source .venv/bin/activate # MacOS/Linux .venv\Scripts\activate # Windows # Install dependencies uv add pymilvus llama-index llama-index-embeddings-huggingface llama-index-llms-groq streamlit beam-client

依赖清单与本仓库实际 import 一一对应:pymilvus(Milvus 客户端)、llama-index核心及其 HuggingFace Embedding / Groq LLM 扩展、streamlit(UI)、beam-client(云端部署)。若按仓库目录直接运行,还需python-dotenv以读取.env中的密钥。

7.2 配置 Groq API Key

在 Groq 控制台申请 API Key 后写入项目根目录的.env

GROQ_API_KEY=<YOUR_GROQ_API_KEY>

应用启动时通过load_dotenv()(app.py)自动读取;也可以在页面侧边栏手动填入,二者等价。

7.3 本地启动

streamlit run app.py

浏览器打开后上传一个 PDF(仓库fastest-rag-milvus-groq/docs/raft.pdf可作为测试样例),即可看到 “生成 Embeddings → 创建向量索引 → 存入向量库” 的进度条,随后进入流式问答界面,并实时显示每次提问的检索毫秒数。


八、一键上云:Beam Serverless 部署

为了让“毫秒级”在真实服务中可被体验,项目还提供了 Beam 部署脚本 start_server.py,把 Streamlit 应用直接发布到 Beam 云:

from beam import Image, Pod streamlit_server = Pod( image=Image().add_python_packages([ "streamlit", "pymilvus", "llama-index", "llama-index-embeddings-huggingface", "llama-index-llms-groq" ]), ports=[8501], # Default port for streamlit gpu="T4", memory="2Gi", entrypoint=["streamlit", "run", "app.py"], ) res = streamlit_server.create() print("✨ Streamlit server hosted at:", res.url)

脚本的资源配置要点如下,便于按需调整:

配置取值说明
ports[8501]Streamlit 默认监听端口
gpu"T4"指定 T4 GPU(当前被注释的cpu=4表明也可切换为纯 CPU 规格)
memory"2Gi"容器内存配额
entrypoint["streamlit", "run", "app.py"]容器启动命令
image.add_python_packages5 个 Python 包云端运行环境依赖

部署步骤(README 原文)依次是:

# 1. 注册 Beam:进入控制台,默认 token 会自动生成,然后在终端绑定 beam configure default --token <YOUR_BEAM_TOKEN> # 2. 执行部署脚本,等待 Pod 创建 python start_server.py

脚本执行成功后会在终端打印 Streamlit 服务的公网地址,把生成的链接粘贴到浏览器即可直接访问部署在 Beam 上的问答应用。


九、代码路径速览与进一步探索

围绕本主题,可以在仓库中继续阅读以下文件,从“会跑”进阶到“懂实现”:

  • fastest-rag-milvus-groq/README.md:项目目标、完整安装与部署命令;
  • fastest-rag-milvus-groq/rag.py:二值量化、Milvus 集合建库、检索器与 RAG 引擎的核心实现(重点看EmbedDataMilvusVDB_BQRetrieverRAG四个类);
  • fastest-rag-milvus-groq/app.py:Streamlit 交互、会话级集合隔离、检索计时与流式输出;
  • fastest-rag-milvus-groq/start_server.py:Beam Pod 的云部署声明;
  • fastest-rag-milvus-groq/docs/raft.pdf:仓库内置的可直接用于测试的示例 PDF。

值得自行验证与思考的边界

  • BIN_FLAT是精确扫描:源码注释明确其为 “Exact search for binary vectors”,检索耗时随库内向量数量线性增长。当语料达到较大规模时,可在 Milvus 二进制索引体系内进一步调研近似检索(ANN)索引方案来换取舍与速度的平衡;
  • 二值量化是有损压缩:阈值 0 的符号化丢弃了向量幅值信息,换取约 32 倍存储缩减与按位运算。对精度敏感的评测集,建议先用本项目内置的Retrieval time计时 + 人工问答验证召回质量;
  • 时延目标存在前提< 15ms是设计目标,实测值受硬件(Beam T4 / 本地 CPU)、语料量与文本长度影响,务必以应用内展示的毫秒数为准。

综上,这个项目提供了一条“Embedding 二值化 → Milvus 二进制索引 → Groq 快速生成”的低时延 RAG 参考实现。从本地 Streamlit 验证到 Beam 云上发布,链路完整、代码量小,是理解二进制向量检索落地与 LLM 快速推理协同的极佳起点。

【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 22:56:50

复现文本抑郁症检测项目全流程:从数据清洗到特征工程实践

简介&#xff1a;面向文本抑郁症检测方向&#xff0c;这份源代码是论文“基于文本的抑郁症检测”的配套实现&#xff0c;围绕文本特征提取、模型训练与结果分析搭建完整实验链路&#xff0c;适合自然语言处理研究者和对心理健康计算感兴趣的中高级开发者参考。压缩包共29个文件…

作者头像 李华
网站建设 2026/9/9 22:55:56

Audacity:从录音到混音,3 步掌握免费音频编辑

Audacity&#xff1a;从录音到混音&#xff0c;3 步掌握免费音频编辑 【免费下载链接】audacity Audio Editor 项目地址: https://gitcode.com/GitHub_Trending/au/audacity 你刚录完一段播客&#xff0c;背景里全是空调的嗡嗡声。Audacity 是一款免费开源的数字音频编…

作者头像 李华
网站建设 2026/9/9 22:53:19

ST7789V2驱动详解:从零点亮1.3寸IPS屏,字符图片显示全记录

简介&#xff1a;面向嵌入式开发者和电子制作爱好者&#xff0c;这份ST7789V2驱动示例代码展示了在SPI/I2C接口液晶屏上显示字符与图片的完整实现。压缩包一共包含2个文件&#xff0c;分别为C源文件与头文件&#xff0c;整体只有6KB&#xff0c;代码量非常精简。其中C源文件承担…

作者头像 李华
网站建设 2026/9/9 22:51:48

胡广书《数字信号处理》Matlab代码实战:FFT、滤波器与谱估计全解析

简介&#xff1a;配套胡广书《数字信号处理理论、算法与实现》的Matlab代码及参考文献合集&#xff0c;面向正在系统学习数字信号处理课程的高校学生与自学者。内容围绕经典数字信号处理与统计数字信号处理两大体系&#xff0c;覆盖离散时间信号与系统、Z变换、傅里叶变换、数字…

作者头像 李华
网站建设 2026/9/9 22:49:32

中大型企业全链路服务:2026主流智能客服系统盘点

中大型企业全链路服务&#xff1a;2026主流智能客服系统盘点 一、市场背景&#xff1a;全链路智能服务成为企业刚需 2026年&#xff0c;企业客户服务正经历从“成本中心”向“价值中心”的深刻转变。随着大模型技术的成熟与AI Agent&#xff08;智能体&#xff09;的落地&#…

作者头像 李华