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 函数没有这个属性。
修复
手动给函数附加 func 和 model_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 |