LightRAG 自定义 LLM / Embedding 接入常见问题总结

LightRAG 自定义 LLM / Embedding 接入常见问题总结

环境

  • LightRAG 版本 : 当前仓库 HKUDS/LightRAG
  • LLM : DeepSeek (deepseek-chat, API: https://api.deepseek.com/v1)
  • Embedding : 硅基流动 (Qwen/Qwen3-VL-Embedding-8B, API: https://api.siliconflow.cn/v1)
  • 运行平台: Windows 11

问题 1: ImportError --- wrap_llm_func_with_attrs 不存在

错误信息

复制代码
ImportError: cannot import name 'wrap_llm_func_with_attrs' from 'lightrag.utils'

根因

lightrag.utils根本没有 wrap_llm_func_with_attrs 这个函数。只有 wrap_embedding_func_with_attrs

修复

删除该导入,LLM 函数不需要专用包装器,只需手动补充属性:

python 复制代码
from lightrag.utils import wrap_embedding_func_with_attrs  # 只保留这一个

问题 2: LLM 函数不是 async

错误信息

运行异常,LLM 函数被同步调用导致阻塞。

根因

LightRAG 是全异步 框架,llm_model_func 的预期签名是 async def。使用同步 def + requests 会破坏事件循环。

修复

python 复制代码
# ❌ 错误
def deepseek_llm_func(prompt, ...):
    response = requests.post(...)
    ...

# ✅ 正确
async def deepseek_llm_func(prompt, ...):
    async with aiohttp.ClientSession() as session:
        async with session.post(...) as resp:
            ...

问题 3: 'function' object has no attribute 'func'

错误信息

复制代码
AttributeError: 'function' object has no attribute 'func'

根因

LightRAG 内部代码会访问 llm_model_func.func(参见 lightrag/utils.py EmbeddingFunc.__post_init__ 中的 unwrap 逻辑),自定义 LLM 函数没有这个属性。

修复

手动给函数附加 funcmodel_name 属性:

python 复制代码
deepseek_llm_func.func = deepseek_llm_func
deepseek_llm_func.model_name = "deepseek-chat"

问题 4: wrap_embedding_func_with_attrs 用法错误

错误信息

不确定的行为 / 装饰器未生效。

根因

wrap_embedding_func_with_attrs 是一个返回装饰器的函数 ,必须用作 @ 装饰器,不能当成普通函数调用。

修复

python 复制代码
# ❌ 错误 --- 当普通函数传参调用
silicon_embedding_wrapped = wrap_embedding_func_with_attrs(
    embedding_func=silicon_qwen_embedding_func,
    model_name=EMBED_MODEL_NAME
)

# ✅ 正确 --- 作为装饰器使用
@wrap_embedding_func_with_attrs(
    embedding_dim=4096,
    max_token_size=8192,
    model_name=EMBED_MODEL_NAME
)
async def silicon_qwen_embedding_func(texts):
    ...

问题 5: 'list' object has no attribute 'size' ⭐ 核心问题

错误信息

复制代码
ERROR: Pipeline halted on internal storage error
  (Cancelled by internal error: NanoVectorDBStorage[entities]:
  'list' object has no attribute 'size')

WARNING: Failed to batch pre-compute embeddings:
  'list' object has no attribute 'size'

ERROR: Query failed: 'list' object has no attribute 'size'

根因

EmbeddingFunc.__call__lightrag/utils.py:614)会在返回值上调用 .size

python 复制代码
# lightrag/utils.py 第 614 行
total_elements = result.size  # 要求 np.ndarray,Python list 没有此属性

返回 List[np.ndarray](Python list 包装的 numpy 数组)是错误的------list 没有 .size 属性。

修复

返回二维 np.ndarray,形状为 (N, embedding_dim)

python 复制代码
# ❌ 错误
embedding_list = [np.array(item["embedding"], dtype=np.float32) for item in data["data"]]
return embedding_list  # 返回的是 list

# ✅ 正确
return np.array([np.array(item["embedding"], dtype=np.float32) for item in data["data"]])
# 返回 shape=(len(texts), 4096) 的二维 numpy 数组

同时修正类型注解:

python 复制代码
async def silicon_qwen_embedding_func(texts: List[str]) -> np.ndarray:

问题 6: 缺少存储初始化

错误信息

复制代码
AttributeError: __aenter__
# 或
KeyError: 'history_messages'

根因

LightRAG 构造函数只创建对象,不会自动初始化底层存储后端。官方文档(AGENTS.md)明确将此列为"最常见错误"。

修复

python 复制代码
rag = LightRAG(...)

await rag.initialize_storages()  # 必须手动调用

try:
    await rag.ainsert(...)
    await rag.aquery(...)
finally:
    await rag.finalize_storages()

问题 7: 旧数据污染

错误信息

修复代码后仍然报 'list' object has no attribute 'size'

根因

之前错误运行时,embedding 返回了 list 而非 ndarray,向量数据库(NanoVectorDB)写入了损坏数据。修复代码后,旧数据没有被清理,继续触发错误。

修复

python 复制代码
import shutil
if os.path.exists(WORKING_DIR):
    shutil.rmtree(WORKING_DIR)
    print("已清理旧损坏数据库目录")

完整正确代码模板

python 复制代码
import os
import asyncio
import aiohttp
import numpy as np
from typing import List
from lightrag.utils import wrap_embedding_func_with_attrs

# ---------- 配置 ----------
DEEPSEEK_API_KEY = "your-key"
DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1"
DEEPSEEK_MODEL_NAME = "deepseek-chat"

SILICONFLOW_API_KEY = "your-key"
SILICONFLOW_BASE_URL = "https://api.siliconflow.cn/v1"
EMBED_MODEL_NAME = "Qwen/Qwen3-VL-Embedding-8B"
EMBED_DIM = 4096
MAX_TOKEN = 8192

WORKING_DIR = "./lightrag_db"

# ---------- LLM 函数 (async) ----------
async def deepseek_llm_func(prompt, system_prompt=None, history_messages=None, **kwargs):
    headers = {"Authorization": f"Bearer {DEEPSEEK_API_KEY}", "Content-Type": "application/json"}
    messages = []
    if system_prompt:
        messages.append({"role": "system", "content": system_prompt})
    if history_messages:
        messages.extend(history_messages)
    messages.append({"role": "user", "content": prompt})
    payload = {"model": DEEPSEEK_MODEL_NAME, "messages": messages, "temperature": 0.1, "max_tokens": 2048}
    async with aiohttp.ClientSession() as session:
        async with session.post(f"{DEEPSEEK_BASE_URL}/chat/completions", headers=headers, json=payload,
                                timeout=aiohttp.ClientTimeout(total=90)) as resp:
            resp.raise_for_status()
            data = await resp.json()
    return data["choices"][0]["message"]["content"]

deepseek_llm_func.func = deepseek_llm_func
deepseek_llm_func.model_name = DEEPSEEK_MODEL_NAME

# ---------- Embedding 函数 (async + 装饰器 + 返回 np.ndarray) ----------
@wrap_embedding_func_with_attrs(
    embedding_dim=EMBED_DIM, max_token_size=MAX_TOKEN, model_name=EMBED_MODEL_NAME
)
async def silicon_qwen_embedding_func(texts: List[str]) -> np.ndarray:
    headers = {"Authorization": f"Bearer {SILICONFLOW_API_KEY}", "Content-Type": "application/json"}
    payload = {"model": EMBED_MODEL_NAME, "input": texts}
    async with aiohttp.ClientSession() as session:
        async with session.post(f"{SILICONFLOW_BASE_URL}/embeddings", headers=headers, json=payload,
                                timeout=aiohttp.ClientTimeout(total=90)) as resp:
            resp.raise_for_status()
            data = await resp.json()
    # 关键: 返回二维 np.ndarray 而不是 list
    return np.array([np.array(item["embedding"], dtype=np.float32) for item in data["data"]])

# ---------- 主流程 ----------
from lightrag.lightrag import LightRAG

async def main():
    import shutil
    if os.path.exists(WORKING_DIR):
        shutil.rmtree(WORKING_DIR)

    rag = LightRAG(
        working_dir=WORKING_DIR,
        llm_model_func=deepseek_llm_func,
        embedding_func=silicon_qwen_embedding_func,
    )

    await rag.initialize_storages()  # 必须
    try:
        await rag.ainsert("你的文档内容...")
        result = await rag.aquery("你的问题?")
        print(result)
    finally:
        await rag.finalize_storages()

if __name__ == "__main__":
    asyncio.run(main())

关键要点速查

类别 要求
LLM 函数 async def, 手动加 .func / .model_name 属性
Embedding 函数 async def, @wrap_embedding_func_with_attrs(...) 装饰器
Embedding 返回值 二维 np.ndarray 形状 (N, dim), 不能返回 list
存储初始化 await rag.initialize_storages() 必须手动调用
数据清理 切换 embedding 模型/修复代码后删除 working_dir