企业知识库系列(02):经典向量 RAG 实测——QAnything vs LightRAG
2026/8/31 21:33:54 网站建设 项目流程

这篇文章的前提

上一篇建好了统一测试集:89 道题,50 道单跳事实查询、20 道多跳推理、19 道边界拒答,文档来源是 LightRAG 和 graphrag 的官方技术文档。

这篇的任务是让两个框架在同一套题上跑,然后把数字摆出来。

但在说数字之前,必须先说部署过程——因为部署本身就是选型的一部分。


两个框架的部署差异

LightRAG:pip install 即用

pipinstalllightrag-hku

没有 Docker,没有数据库服务,知识图谱和向量索引存在本地文件里:

rag_storage/ ├── graph_chunk_entity_relation.graphml # 知识图谱 ├── vdb_chunks.json # 文档向量 ├── vdb_entities.json # 实体向量 └── vdb_relationships.json # 关系向量

初始化代码:

fromlightragimportLightRAG,QueryParamfromlightrag.utilsimportEmbeddingFunc rag=LightRAG(working_dir="./rag_storage",llm_model_func=llm_func,embedding_func=EmbeddingFunc(embedding_dim=1024,max_token_size=8192,func=embed_func,),)awaitrag.initialize_storages()# v1.5.x 新增,必须调用awaitrag.ainsert(document_text)result=awaitrag.aquery(question,param=QueryParam(mode="mix"))

LightRAG 1.5.x 有一个新要求:必须先调initialize_storages(),否则会报PipelineNotInitializedError

QAnything:5 个 Docker 服务

QAnything v2 需要整套基础设施:

services:elasticsearch# 关键词检索(BM25)etcd# Milvus 的元数据存储minio# Milvus 的对象存储milvus-standalone# 向量数据库mysql# 文档和知识库元数据qanything_local# 主服务(embedding + rerank + API)

启动命令:

cdQAnythingmkdir-pvolumes/es/data&&chmod777-Rvolumes/es/datadockercompose-fdocker-compose-linux.yaml up-d

等日志出现“qanything后端服务已就绪!”后,访问http://localhost:8777/qanything/


踩坑记录

部署过程踩了三个坑,每个都值得记录。

坑 1:QAnything 容器默认不用 GPU

机器有 RTX 3060,但 QAnything 容器启动日志始终显示:

embedding和rerank服务将在CPU上运行

原因:docker-compose-linux.yaml里的qanything_local服务没有配置 GPU 资源,而且scripts/entrypoint.sh里那行日志是硬编码的字符串,不是实际判断结果,即使挂了 GPU 也照样打印。

修复一:给 compose 文件加 GPU 挂载:

# docker-compose-linux.yamlqanything_local:deploy:resources:reservations:devices:-driver:nvidiadevice_ids:['0']capabilities:[gpu]

修复二:同时还需要安装 NVIDIA Container Toolkit(Docker 默认看不到宿主机 GPU,需要这个桥):

# Ubuntudistribution=$(./etc/os-release;echo$ID$VERSION_ID)curl-s-Lhttps://nvidia.github.io/nvidia-docker/gpgkey|sudoapt-keyadd-curl-s-Lhttps://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list|\sudotee/etc/apt/sources.list.d/nvidia-docker.listsudoapt-getupdate&&sudoapt-getinstall-ynvidia-container-toolkitsudonvidia-ctk runtime configure--runtime=dockersudosystemctl restartdocker

修复三entrypoint.sh启动 embedding/rerank 时没传--use_gpu参数:

# scripts/entrypoint.sh,修改前nohuppython3-uqanything_kernel/dependent_server/embedding_server/embedding_server.py>...# 修改后nohuppython3-uqanything_kernel/dependent_server/embedding_server/embedding_server.py--use_gpu>...nohuppython3-uqanything_kernel/dependent_server/rerank_server/rerank_server.py--use_gpu>...

修复后,GPU 显存占用从 1.4GB 跳到 8.6GB,embedding 速度从每秒不到 1 个文档提升到约每 15 秒处理 1-2 个。

坑 2:Milvus 因内存压力崩溃

CPU 模式下 QAnything 容器吃了 27GB 内存,导致 Milvus standalone 的 etcd lease 超时崩溃退出:

"etcdserver: requested lease not found" "connection lost detected, shuting down"

结果:所有文件卡在gray(等待向量化)状态,永远不会完成。

修复:清理 Milvus 和 etcd 的持久化数据目录后重启(etcd 里有损坏的 session 记录,不清会反复崩溃):

dockercompose-fdocker-compose-linux.yaml downrm-rfvolumes/milvus volumes/etcd volumes/mysqlmkdir-pvolumes/milvus volumes/etcd volumes/mysqldockercompose-fdocker-compose-linux.yaml up-d

坑 3:user_id 拼接导致 Web 端看不到数据

QAnything 服务端对每个 API 请求的user_id会做拼接:

# handler.pyuser_info=safe_get(req,'user_info',"1234")# 默认值 "1234"user_id=user_id+'__'+user_info# 最终存储的 user_id

如果脚本传user_id=zzp__1234,实际存储的是zzp__1234__1234,而 Web 端的用户是zzp__1234,两者不同,Web 看不到 API 创建的知识库。

修复:脚本传user_id=zzp,服务端拼接后变成zzp__1234,和 Web 端一致。


评测配置

两个框架使用完全相同的 LLM 和测试集:

配置项LightRAGQAnything
LLMGLM-4-flashGLM-4-flash
EmbeddingBGE-large-en-v1.5(SiliconFlow)QAnything 内置(BCE embedding,GPU 推理)
测试集89 道题(50 单跳 + 20 多跳 + 19 边界)同上
查询模式mix(知识图谱 + 向量融合)混合检索(BM25 + 向量 + Rerank)
文档数量31 个 Markdown 文档31 个 Markdown 文档

评测结果

核心指标对比

指标LightRAG 1.5.6QAnything v2
边界拒答率10.5%(2/19)26.3%(5/19)
平均延迟14,674 ms40,519 ms
P90 延迟19,430 ms52,233 ms
单跳答案匹配(Jaccard)0.0820.111
多跳答案匹配(Jaccard)0.1780.162

注:答案匹配率用 Jaccard 关键词重叠计算,不是 LLM judge。两个框架的答案通常比 ground_truth 更长(加了解释),Jaccard 值偏低是正常的,用于横向对比有效,绝对值没有参考意义。

答案质量

看同一道题的真实输出:

单跳题What is the condition under which query/document asymmetric embedding is enabled?

Ground Truth: enabled only when EMBEDDING_ASYMMETRIC=true is explicitly set LightRAG: Query/document asymmetric embedding in LightRAG is enabled only when the `EMBEDDING_ASYMMETRIC` setting is explicitly set to true... [直接答出条件,简洁] QAnything: ## Inferred Answer Section According to the reference information, query/document asymmetric embedding in LightRAG is enabled only when... [答案正确,但格式冗余,带了 Markdown 标题]

两个都答对了,但 LightRAG 输出更干净,QAnything 的系统 prompt 会让回答带上## Inferred Answer Section这类结构化标题。

边界题How does the RAG system handle data privacy for users in the EU under GDPR?

LightRAG: The Retrieval-Augmented Generation (RAG) system, as implemented in LightRAG, handles data privacy for users in the EU under GDPR... [没有拒答,用自身知识编造了一个听起来合理的答案] QAnything: 抱歉,检索到的参考信息并未提供任何相关的信息,因此无法回答。 [正确拒答]

边界拒答是 QAnything 明显强的一个维度。QAnything 的系统 prompt 里有明确的"参考信息无关时必须拒答"规则,LightRAG 的 mix 模式会优先召回知识图谱里的相关实体,即使文档里没有答案也会尝试推理,容易产生幻觉。

延迟分析

LightRAG 的延迟分布:P50=13.9s,P90=19.4s,min=8.7s,max=30.8s

QAnything 的延迟分布:P50=39.2s,P90=52.2s,min=19.6s,max=62.9s

QAnything 的延迟高有两个原因:

  1. Rerank 步骤:每次查询都要对召回结果做交叉编码重排,这是额外的模型推理
  2. LLM 调用更稳定:QAnything 每次都能召回到真实文档(source_count=100%),LLM 要处理的上下文更长

LightRAG 的 mix 模式会构建一次知识图谱查询 + 一次向量查询,然后融合结果,LLM 调用通常比 QAnything 更快,但如果图谱遍历范围大也会慢。


选哪个?

基于这次评测,给一个简单的决策参考:

优先选 LightRAG,如果:

  • 需要快速验证 RAG 方案,不想花时间配置基础设施
  • 团队没有运维 Milvus/ES/MySQL 的能力
  • 文档之间有复杂的关联关系,需要图谱多跳推理
  • 对延迟敏感(LightRAG P90 比 QAnything 快约 2.7 倍)

优先选 QAnything,如果:

  • 需要更强的拒答能力(边界拒答率高出 2.5 倍)
  • 有中文文档,需要中文优化的 embedding(BCE embedding 对中文效果更好)
  • 需要 Web 界面让非技术人员上传文档
  • 生产环境,需要 ES 全文检索 + 向量检索的混合能力

这次评测没测到的

  • 大规模文档(1 万+ 文档)下的性能
  • 中文文档的检索质量(本次测试集全英文)
  • 知识库更新的速度和稳定性
  • QAnything 的 PDF/图表解析能力(本次只用了 Markdown)

这些会在后续文章里补充。


评测代码

完整代码在llm-in-action/kb-02-lightrag-eval/llm-in-action/kb-02-qanything-eval/

LightRAG 评测核心流程:

# 建库rag=LightRAG(working_dir=STORAGE_DIR,llm_model_func=llm_func,embedding_func=EmbeddingFunc(embedding_dim=1024,func=embed_func))awaitrag.initialize_storages()awaitrag.ainsert(doc_content)# 查询answer=awaitrag.aquery(question,param=QueryParam(mode="mix"))

QAnything 评测核心流程:

# 建库kb_id=api_post("new_knowledge_base",{"user_id":USER_ID,"kb_name":KB_NAME})["data"]["kb_id"]api_post("upload_files",data={"user_id":USER_ID,"kb_id":kb_id},files={"files":fp})# 等待向量化完成(轮询 status=green)whileany(s!="green"forsinstatus_countifs!="green"):time.sleep(15)# 查询result=api_post("local_doc_chat",{"user_id":USER_ID,"kb_ids":[kb_id],"question":question,"model":LLM_MODEL,"api_base":LLM_BASE_URL,"api_key":LLM_API_KEY,"streaming":False})

下一篇:GraphRAG vs HippoRAG——图增强 RAG 的多跳推理测试。同样 89 道题,重点看多跳推理的提升幅度,以及知识图谱构建的时间和成本。


欢迎访问 PrimeSkills —— 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。

更多实用知识和有趣产品,欢迎访问我的个人主页

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询