DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

FAISS 文件加载成功,LlamaIndex 还报 No index in storage context

恢复 FAISS 向量文件不等于恢复 LlamaIndex 的完整索引。核对 persist_dir、index_store、文档存储与索引 ID,再用独立进程检查已知节点能否读取。

FAISS 文件加载成功,LlamaIndex 还报 No index in storage context

faiss.read_index() 没有报错,向量数也大于零,接着调用 load_index_from_storage() 却失败:

No index in storage context, check if you specified the right persist_dir.

优先检查 StorageContext 是怎样创建的。把 FAISS 文件恢复成 vector_store,只恢复了向量那一部分。LlamaIndex 加载索引还需要 index_store 中的索引结构;FAISS 本身也不会替你保存每个节点的原文。

最容易漏掉的是下面这个参数差别:恢复时写了 StorageContext.from_defaults(vector_store=vector_store),却没有传原来完整持久化目录的 persist_dir。新建出来的上下文自然可能没有索引结构。

历史 issue #3511 的环境是 llama-index 0.6.8、faiss-cpu 1.7.4、Python 3.10。下方使用当前拆包后的 core 与 FAISS 集成接口,加载逻辑同时对照源码快照 6dd2f3cd。

用独立目录验证保存和恢复这两半

需要 llama-index-core、llama-index-vector-stores-faiss、faiss-cpu。保存为 storage_probe.py,先运行 python storage_probe.py build,再运行 python storage_probe.py load。脚本在当前目录创建专用测试目录,不操作线上数据。

import sys
from pathlib import Path
import faiss
from llama_index.core import Document, StorageContext, VectorStoreIndex, load_index_from_storage
from llama_index.core.embeddings import MockEmbedding
from llama_index.core.node_parser import SentenceSplitter
from llama_index.vector_stores.faiss import FaissVectorStore

root = Path("./faiss_storage_probe").resolve()
# 只测试持久化连线;固定向量无法验证真实检索语义。
embed = MockEmbedding(embed_dim=8)
mode = sys.argv[1]
if mode == "build":
    if root.exists():
        raise FileExistsError(f"Use a fresh probe directory: {root}")
    store = FaissVectorStore(faiss_index=faiss.IndexFlatL2(8))
    context = StorageContext.from_defaults(vector_store=store)
    index = VectorStoreIndex.from_documents(
        [Document(text="storage probe unique marker 4107")],
        storage_context=context,
        embed_model=embed,
        transformations=[SentenceSplitter(tokenizer=list)],
    )
    index.set_index_id("probe")
    index.storage_context.persist(persist_dir=str(root))
elif mode == "load":
    store = FaissVectorStore.from_persist_dir(str(root))
    context = StorageContext.from_defaults(persist_dir=str(root), vector_store=store)
    assert len(context.index_store.index_structs()) == 1
    index = load_index_from_storage(context, index_id="probe", embed_model=embed)
    hits = index.as_retriever(similarity_top_k=1).retrieve("probe")
    assert hits and "4107" in hits[0].node.get_content()
    print("index structure and node text restored")
else:
    raise ValueError("expected build or load")

两个命令应在两个进程执行,避免内存中的对象掩盖磁盘缺失。验收不只看向量条数,还要看索引 ID 和节点文本是否能恢复。示例只有一条固定向量,故意不把这次测试当成召回准确率测试。

原来的目录怎么查

先保留现有文件,确认建库和加载使用的是同一个绝对目录。容器工作目录、挂载卷、启动脚本改变后,相对路径很容易指到另一个同名空目录。然后检查 index_store 能枚举出哪些索引结构,再核对指定的 index_id。

有多个索引时,load_index_from_storage 还会报“需要指定 index_id”一类错误。这表示它找到了多个结构,和一个都没有是不同情况,不能通过随意删文件解决。

如果最后只剩裸 FAISS 文件,没有文档存储、索引结构或可重建的原始资料,这段加载代码无法把它们凭空恢复出来。需要从备份补回配套数据,或从原始文档重新构建。恢复过程中保留原 embedding 模型、维度及相关预处理配置,避免存储修好以后又引入向量不兼容。

官方依据:历史问题 #3511、索引加载逻辑、FAISS 持久化实现。