📑 目录
1. 需求背景
1.1 业务需求
用户需要能够:
- 创建多个独立的智能体(Agent),每个智能体拥有独立的知识库
- 上传文档到指定智能体,实现数据隔离
- 选择不同智能体进行对话,查询结果仅来自该智能体的知识库
- 删除智能体及其所有数据,包括文档、向量、图数据
- 删除空智能体(无任何文档的智能体)
1.2 核心目标
- ✅ 数据严格隔离:不同智能体的数据互不干扰
- ✅ 用户体验友好:简单的创建/切换/删除操作
- ✅ 向后兼容:不影响现有单workspace使用场景
- ✅ 性能可控:多智能体不会导致内存/连接爆炸
2. 现有架构分析
2.1 LightRAG已有的Workspace机制
2.1.1 核心发现:Workspace已是多租户基础
通过源码分析,LightRAG已经具备完整的workspace数据隔离能力:
证据1:所有存储层都支持workspace参数
python
# lightrag/lightrag.py:157
workspace: str = field(default_factory=lambda: os.getenv("WORKSPACE", ""))
# lightrag/lightrag.py:576-641 - 每个存储实例都传入workspace
self.llm_response_cache: BaseKVStorage = self.key_string_value_json_storage_cls(
namespace=NameSpace.KV_STORE_LLM_RESPONSE_CACHE,
workspace=self.workspace, # ✅ workspace隔离
global_config=global_config,
embedding_func=self.embedding_func,
)
证据2:JSON存储实现了workspace目录隔离
python
# lightrag/kg/json_kv_impl.py:30-38
if self.workspace:
# Include workspace in the file path for data isolation
workspace_dir = os.path.join(working_dir, self.workspace)
else:
workspace_dir = working_dir
self.workspace = ""
os.makedirs(workspace_dir, exist_ok=True)
self._file_name = os.path.join(workspace_dir, f"kv_store_{self.namespace}.json")
证据3:PostgreSQL/MongoDB/Redis等存储也支持workspace过滤
python
# lightrag/kg/postgres_impl.py:1883-1895
# Implement workspace priority: self.workspace > PostgreSQLDB.workspace > "default"
if hasattr(self, "workspace") and self.workspace:
pass # Use storage class's workspace (highest priority)
# lightrag/kg/mongo_impl.py:749-758
mongodb_workspace = os.environ.get("MONGODB_WORKSPACE")
if mongodb_workspace and mongodb_workspace.strip():
effective_workspace = mongodb_workspace.strip()
else:
effective_workspace = self.workspace
2.1.2 RagManager已支持多workspace实例管理
证据4:RagManager的多实例缓存机制
python
# lightrag/api/lightrag_server.py:388-414
class RagManager:
def __init__(self, args, rag_init_wrapper):
self.rag_instances: Dict[str, LightRAG] = {} # ✅ 按workspace缓存实例
self.doc_managers: Dict[str, DocumentManager] = {}
self.lock = asyncio.Lock()
async def get_rag_instance_async(self, workspace: str) -> LightRAG:
ws = workspace or self.args.workspace or ""
if ws not in self.rag_instances:
async with self.lock:
if ws not in self.rag_instances:
rag = self.rag_init_wrapper(ws) # ✅ 创建新实例
await rag.initialize_storages()
self.rag_instances[ws] = rag
return self.rag_instances[ws]
2.1.3 ContextVar实现请求级上下文传递
证据5:已有的上下文变量机制
python
# lightrag/api/lightrag_server.py:86
current_workspace_var: ContextVar[str] = ContextVar("current_workspace", default="")
# lightrag/api/lightrag_server.py:367-369
def _get_real_instance(self):
ws = current_workspace_var.get() # ✅ 从上下文获取workspace
return self._manager.get_rag_instance(ws)
2.2 现有架构的优势
| 优势 | 说明 | 改造影响 |
|---|---|---|
| 数据隔离已实现 | workspace参数已贯穿全栈 | ✅ 无需修改存储层 |
| 多实例管理已就绪 | RagManager支持动态创建 | ✅ 只需增强元数据管理 |
| 上下文传递机制完善 | ContextVar避免参数污染 | ✅ 复用现有机制 |
| 向后兼容性好 | 默认workspace=""不影响旧代码 | ✅ 零破坏性改动 |
2.3 现有架构的不足
| 不足 | 影响 | 改造方案 |
|---|---|---|
| 缺少Agent元数据存储 | 无法管理Agent名称、描述、创建时间 | ✅ 新增 agent_manager.py |
| 缺少Agent CRUD API | 前端无法创建/查询/删除Agent | ✅ 新增 agent_routes.py |
| 缺少workspace生命周期管理 | 删除workspace时数据残留风险 | ✅ 利用已有的 drop() 方法 |
| 前端无Agent选择界面 | 用户无法切换智能体 | ✅ 新增前端组件 |
3. 技术可行性论证
3.1 数据隔离可行性
3.1.1 存储层隔离验证
JSON存储实现物理隔离:
working_dir/
├── agent_001/ # workspace="agent_001"
│ ├── kv_store_full_docs.json
│ ├── vdb_entities.json
│ └── graph_chunk_entity_relation.graphml
├── agent_002/ # workspace="agent_002"
│ ├── kv_store_full_docs.json
│ ├── vdb_entities.json
│ └── graph_chunk_entity_relation.graphml
└── default/ # workspace=""
└── ...
PostgreSQL/MongoDB实现逻辑隔离:
sql
-- 所有查询都带workspace过滤条件
SELECT * FROM lightrag_full_docs WHERE workspace = 'agent_001' AND ...
SELECT * FROM lightrag_entities WHERE workspace = 'agent_002' AND ...
3.1.2 向量检索隔离验证
证据6:所有向量存储都支持workspace过滤
python
# lightrag/kg/postgres_impl.py:3012-3016
params = {
"workspace": self.workspace, # ✅ workspace作为查询条件
"closer_than_threshold": 1 - self.cosine_better_than_threshold,
"top_k": top_k,
}
# lightrag/kg/qdrant_impl.py:580-582
query_filter=models.Filter(
must=[workspace_filter_condition(self.effective_workspace)] # ✅ workspace过滤
),
3.2 删除操作可行性
3.2.1 所有存储已实现drop()方法
证据7:StorageNameSpace抽象类定义了drop()接口
python
# lightrag/base.py:191-214
@abstractmethod
async def drop(self) -> dict[str, str]:
"""Drop all data from storage and clean up resources
Returns:
dict[str, str]: Operation status and message
- On success: return {"status": "success", "message": "data dropped"}
- On failure: return {"status": "error", "message": "<error details>"}
"""
证据8:所有存储实现都已支持drop()
python
# JSON存储
# lightrag/kg/json_kv_impl.py:395-407
async def drop(self) -> dict[str, str]:
try:
async with self._storage_lock:
self._data.clear() # ✅ 清空内存
await set_all_update_flags(self.namespace, workspace=self.workspace)
await self.index_done_callback() # ✅ 持久化
return {"status": "success", "message": "data dropped"}
# PostgreSQL存储
# lightrag/kg/postgres_impl.py - drop()实现已存在
# MongoDB存储
# lightrag/kg/mongo_impl.py:478-497 - drop()实现已存在
# Redis存储
# lightrag/kg/redis_impl.py:398-425 - drop()实现已存在
证据9:文档清空功能已使用drop()方法
python
# lightrag/api/routers/document_routes.py:2374-2398
# Use drop method to clear all data
storages = [
rag.text_chunks,
rag.full_docs,
rag.entities_vdb,
rag.relationships_vdb,
rag.chunks_vdb,
rag.chunk_entity_relation_graph,
rag.doc_status,
]
for storage in storages:
if storage is not None:
drop_tasks.append(storage.drop()) # ✅ 已在生产环境使用
3.2.2 文件删除可行性
证据10:DocumentManager已支持workspace目录管理
python
# lightrag/api/routers/document_routes.py:1857-1872
class DocumentManager:
def __init__(self, input_dir: Path, workspace: str = ""):
self.base_dir = Path(input_dir)
self.workspace = workspace
# Construct workspace-specific directory
if self.workspace:
self.input_dir = self.base_dir / self.workspace # ✅ workspace目录隔离
else:
self.input_dir = self.base_dir
删除Agent的完整流程:
python
async def delete_agent(agent_id: str):
# 1. 调用所有存储的drop()
rag = await rag_manager.get_rag_instance_async(agent_id)
await asyncio.gather(
rag.full_docs.drop(),
rag.entities_vdb.drop(),
rag.chunk_entity_relation_graph.drop(),
# ... 其他存储
)
# 2. 删除workspace文件目录
import shutil
workspace_dir = Path(working_dir) / agent_id
if workspace_dir.exists():
shutil.rmtree(workspace_dir) # ✅ 物理删除
# 3. 删除上传的文档目录
doc_dir = Path(input_dir) / agent_id
if doc_dir.exists():
shutil.rmtree(doc_dir)
# 4. 从RagManager移除实例
rag_manager.rag_instances.pop(agent_id, None)
rag_manager.doc_managers.pop(agent_id, None)
3.3 性能可行性
3.3.1 内存占用分析
单个LightRAG实例内存占用估算:
- Python对象本身:~50KB
- 12个Storage实例:~200KB(主要是对象引用)
- 共享的shared_storage缓存:所有实例共享,不重复计算
- 合计:~250KB/实例
100个Agent场景:
- 总内存:100 × 250KB = 25MB(可接受)
- 实际数据在数据库,内存只是管理对象
3.3.2 连接池管理
证据11:PostgreSQL/MongoDB使用单例连接池
python
# lightrag/kg/postgres_impl.py:1785-1853
class ClientManager:
"""Singleton client manager for PostgreSQL connections"""
_instance: PostgreSQLDB | None = None
_lock: asyncio.Lock = asyncio.Lock()
_ref_count: int = 0
@classmethod
async def get_client(cls) -> PostgreSQLDB:
# ✅ 所有workspace共享同一连接池
结论:多个workspace不会创建多个数据库连接池,只是逻辑隔离。
4. 详细设计方案
4.1 Agent元数据模型
4.1.1 数据结构设计
python
# lightrag/api/models/agent_model.py
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional
class Agent(BaseModel):
"""智能体元数据模型"""
id: str = Field(..., description="智能体唯一ID(等同于workspace)")
name: str = Field(..., min_length=1, max_length=100, description="智能体名称")
description: str = Field(default="", max_length=500, description="智能体描述")
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
doc_count: int = Field(default=0, description="文档数量(运行时计算)")
class Config:
json_schema_extra = {
"example": {
"id": "agent_legal_20250123_abc123",
"name": "法律助手",
"description": "专业法律咨询智能体",
"created_at": "2025-01-23T10:00:00Z",
"updated_at": "2025-01-23T10:00:00Z",
"doc_count": 5
}
}
4.1.2 存储方案
方案选择:JSON文件存储(与LightRAG风格一致)
json
// {working_dir}/agents_meta.json
{
"agent_legal_20250123_abc123": {
"id": "agent_legal_20250123_abc123",
"name": "法律助手",
"description": "专业法律咨询智能体",
"created_at": "2025-01-23T10:00:00Z",
"updated_at": "2025-01-23T10:00:00Z"
},
"agent_customer_service_xyz789": {
"id": "agent_customer_service_xyz789",
"name": "客服助手",
"description": "24小时在线客服",
"created_at": "2025-01-23T11:00:00Z",
"updated_at": "2025-01-23T11:00:00Z"
}
}
优势:
- ✅ 与LightRAG现有风格一致(如doc_status使用JSON)
- ✅ 无需额外数据库依赖
- ✅ 便于备份和迁移
- ✅ 支持多进程通过文件锁安全访问
4.2 AgentManager实现
4.2.1 核心类设计
python
# lightrag/api/agent_manager.py
import os
import json
import asyncio
from pathlib import Path
from datetime import datetime, timezone
from typing import Dict, Optional, List
from lightrag.utils import logger, compute_mdhash_id
class AgentManager:
"""智能体元数据管理器"""
def __init__(self, working_dir: str):
self.working_dir = Path(working_dir)
self.meta_file = self.working_dir / "agents_meta.json"
self.lock = asyncio.Lock()
async def initialize(self):
"""初始化元数据文件"""
if not self.meta_file.exists():
await self._save_meta({})
async def create_agent(self, name: str, description: str = "") -> Dict:
"""创建新智能体"""
async with self.lock:
meta = await self._load_meta()
# 生成唯一ID
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
unique_suffix = compute_mdhash_id(f"{name}_{timestamp}", prefix="")[:8]
agent_id = f"agent_{name}_{unique_suffix}"
# 检查名称重复
if any(a["name"] == name for a in meta.values()):
raise ValueError(f"智能体名称 '{name}' 已存在")
# 创建元数据
agent = {
"id": agent_id,
"name": name,
"description": description,
"created_at": datetime.now(timezone.utc).isoformat(),
"updated_at": datetime.now(timezone.utc).isoformat(),
}
meta[agent_id] = agent
await self._save_meta(meta)
logger.info(f"创建智能体成功: {agent_id} ({name})")
return agent
async def list_agents(self) -> List[Dict]:
"""列出所有智能体(包含doc_count)"""
meta = await self._load_meta()
# 动态计算文档数量
for agent_id, agent in meta.items():
agent["doc_count"] = await self._get_doc_count(agent_id)
return list(meta.values())
async def get_agent(self, agent_id: str) -> Optional[Dict]:
"""获取智能体详情"""
meta = await self._load_meta()
agent = meta.get(agent_id)
if agent:
agent["doc_count"] = await self._get_doc_count(agent_id)
return agent
async def delete_agent(self, agent_id: str) -> bool:
"""删除智能体元数据(不删除实际数据)"""
async with self.lock:
meta = await self._load_meta()
if agent_id not in meta:
return False
del meta[agent_id]
await self._save_meta(meta)
logger.info(f"删除智能体元数据成功: {agent_id}")
return True
async def _get_doc_count(self, agent_id: str) -> int:
"""获取智能体的文档数量"""
try:
# 通过读取doc_status获取文档数量
doc_status_file = self.working_dir / agent_id / "kv_store_doc_status.json"
if doc_status_file.exists():
with open(doc_status_file, "r", encoding="utf-8") as f:
data = json.load(f)
return len(data)
return 0
except Exception as e:
logger.warning(f"获取文档数量失败 {agent_id}: {e}")
return 0
async def _load_meta(self) -> Dict:
"""加载元数据"""
try:
if self.meta_file.exists():
with open(self.meta_file, "r", encoding="utf-8") as f:
return json.load(f)
return {}
except Exception as e:
logger.error(f"加载Agent元数据失败: {e}")
return {}
async def _save_meta(self, meta: Dict):
"""保存元数据"""
try:
with open(self.meta_file, "w", encoding="utf-8") as f:
json.dump(meta, f, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"保存Agent元数据失败: {e}")
raise
4.3 API路由设计
4.3.1 Agent管理路由
python
# lightrag/api/routers/agent_routes.py
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel, Field
from typing import List, Literal
import shutil
router = APIRouter(prefix="/agents", tags=["Agent Management"])
class CreateAgentRequest(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
description: str = Field(default="", max_length=500)
class AgentResponse(BaseModel):
id: str
name: str
description: str
created_at: str
updated_at: str
doc_count: int
class DeleteAgentResponse(BaseModel):
status: Literal["success", "error"]
message: str
deleted_doc_count: int = 0
def create_agent_routes(agent_manager, rag_manager, args, combined_auth):
@router.post("", response_model=AgentResponse)
async def create_agent(request: CreateAgentRequest):
"""创建新智能体"""
try:
agent = await agent_manager.create_agent(
name=request.name,
description=request.description
)
return {**agent, "doc_count": 0}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("", response_model=List[AgentResponse])
async def list_agents():
"""获取智能体列表"""
agents = await agent_manager.list_agents()
return agents
@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(agent_id: str):
"""获取智能体详情"""
agent = await agent_manager.get_agent(agent_id)
if not agent:
raise HTTPException(status_code=404, detail="智能体不存在")
return agent
@router.delete("/{agent_id}", response_model=DeleteAgentResponse)
async def delete_agent(agent_id: str):
"""删除智能体及其所有数据"""
try:
# 1. 检查智能体是否存在
agent = await agent_manager.get_agent(agent_id)
if not agent:
raise HTTPException(status_code=404, detail="智能体不存在")
doc_count = agent["doc_count"]
# 2. 获取RAG实例并调用drop()
try:
rag = await rag_manager.get_rag_instance_async(agent_id)
storages = [
rag.text_chunks,
rag.full_docs,
rag.full_entities,
rag.full_relations,
rag.entity_chunks,
rag.relation_chunks,
rag.entities_vdb,
rag.relationships_vdb,
rag.chunks_vdb,
rag.chunk_entity_relation_graph,
rag.doc_status,
]
drop_results = await asyncio.gather(
*[s.drop() for s in storages if s],
return_exceptions=True
)
# 检查是否有失败
failed = [r for r in drop_results if isinstance(r, Exception)]
if failed:
logger.warning(f"部分存储删除失败: {failed}")
except Exception as e:
logger.error(f"删除存储数据失败: {e}")
raise HTTPException(status_code=500, detail=f"删除数据失败: {str(e)}")
# 3. 删除workspace目录
workspace_dir = Path(args.working_dir) / agent_id
if workspace_dir.exists():
shutil.rmtree(workspace_dir)
# 4. 删除文档目录
doc_dir = Path(args.input_dir) / agent_id
if doc_dir.exists():
shutil.rmtree(doc_dir)
# 5. 从RagManager移除实例
rag_manager.rag_instances.pop(agent_id, None)
rag_manager.doc_managers.pop(agent_id, None)
# 6. 删除元数据
await agent_manager.delete_agent(agent_id)
return {
"status": "success",
"message": f"智能体 '{agent['name']}' 删除成功",
"deleted_doc_count": doc_count
}
except HTTPException:
raise
except Exception as e:
logger.error(f"删除智能体失败: {e}")
raise HTTPException(status_code=500, detail=str(e))
return router
4.4 中间件增强
4.4.1 Agent上下文中间件
python
# lightrag/api/lightrag_server.py 添加中间件
@app.middleware("http")
async def agent_context_middleware(request: Request, call_next):
"""从请求头提取Agent ID并设置上下文"""
agent_id = request.headers.get("X-Agent-ID", "")
# 设置到ContextVar
current_workspace_var.set(agent_id)
# 记录日志(调试用)
if agent_id:
logger.debug(f"请求使用Agent: {agent_id} - {request.url.path}")
response = await call_next(request)
return response
4.5 前端改造
4.5.1 Agent选择器组件
typescript
// lightrag_webui/src/components/agent/AgentSelector.tsx
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { useAgentStore } from '@/stores/agentStore'
export function AgentSelector() {
const { currentAgent, agents, setCurrentAgent, fetchAgents } = useAgentStore()
useEffect(() => {
fetchAgents()
}, [])
return (
<Select value={currentAgent?.id} onValueChange={(id) => {
const agent = agents.find(a => a.id === id)
if (agent) setCurrentAgent(agent)
}}>
<SelectTrigger className="w-[200px]">
<SelectValue placeholder="选择智能体" />
</SelectTrigger>
<SelectContent>
{agents.map(agent => (
<SelectItem key={agent.id} value={agent.id}>
{agent.name} ({agent.doc_count}篇)
</SelectItem>
))}
</SelectContent>
</Select>
)
}
4.5.2 Axios拦截器自动添加Agent头
typescript
// lightrag_webui/src/api/lightrag.ts
import axios from 'axios'
import { useAgentStore } from '@/stores/agentStore'
const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL
})
// 请求拦截器:自动添加X-Agent-ID
axiosInstance.interceptors.request.use((config) => {
const currentAgent = useAgentStore.getState().currentAgent
if (currentAgent) {
config.headers['X-Agent-ID'] = currentAgent.id
}
return config
})
export default axiosInstance
5. 风险评估与应对
5.1 技术风险
| 风险项 | 风险等级 | 影响 | 应对措施 |
|---|---|---|---|
| 删除操作不可逆 | 高 | 误删导致数据永久丢失 | 1. 删除前强制二次确认 2. 实施软删除(标记后延迟真删) 3. 提供备份导出功能 |
| 并发删除冲突 | 中 | 同时删除同一Agent导致异常 | 使用asyncio.Lock锁定删除操作 |
| 元数据与实际数据不一致 | 中 | 显示错误的文档数量 | doc_count实时计算,不存储缓存 |
| 大量Agent内存占用 | 低 | 超过100个Agent可能占用过多内存 | 实施LRU淘汰策略,仅保留活跃实例 |
5.2 用户体验风险
| 风险项 | 风险等级 | 影响 | 应对措施 |
|---|---|---|---|
| Agent名称冲突 | 中 | 用户困惑 | 创建时检查重名,提示用户 |
| 删除空Agent误操作 | 低 | 用户后悔 | 明确提示"该智能体无文档,确认删除?" |
| 切换Agent后忘记当前上下文 | 中 | 查询结果混淆 | 1. 顶部显著位置显示当前Agent 2. 对话记录自动清空 |
5.3 兼容性风险
| 风险项 | 风险等级 | 影响 | 应对措施 |
|---|---|---|---|
| 破坏现有单workspace用户 | 高 | 现有用户无法使用 | workspace=""作为默认值,完全向后兼容 |
| 多进程环境元数据冲突 | 中 | Gunicorn模式下数据异常 | 使用文件锁保护agents_meta.json |
6. 实施路线图
6.1 开发阶段划分
第一阶段:后端核心(3-4天)
Day 1:Agent元数据管理
- 实现
agent_manager.py - 单元测试:创建/查询/删除Agent
- 集成测试:与RagManager配合
Day 2:Agent API路由
- 实现
agent_routes.py - API测试:Postman/curl验证
- 压力测试:并发创建/删除
Day 3:数据删除功能
- 完整删除流程实现
- 测试各存储类型的drop()
- 验证文件目录删除
Day 4:中间件与集成
- 实现Agent上下文中间件
- 修改现有API支持X-Agent-ID
- 端到端测试
第二阶段:前端界面(2-3天)
Day 5:Agent管理界面
- Agent列表卡片
- 创建Agent对话框
- 删除确认对话框
Day 6:Agent选择器
- 顶部导航栏集成
- 切换Agent逻辑
- Axios拦截器
Day 7:联调与优化
- 前后端联调
- UI/UX优化
- 错误提示优化
第三阶段:测试与文档(1-2天)
Day 8:全面测试
- 功能测试矩阵
- 边界条件测试
- 性能测试
Day 9:文档与发布
- 用户使用文档
- API文档更新
- 部署指南
6.2 测试验收标准
功能验收
- 创建Agent成功,返回唯一ID
- Agent列表显示正确的文档数量
- 上传文档到Agent A,在Agent B中查询不到
- 删除Agent后,所有数据完全清除
- 删除空Agent无错误
- 切换Agent后对话上下文正确
性能验收
- 创建Agent响应时间 < 500ms
- 删除Agent响应时间 < 3s(含存储清理)
- 支持至少50个并发Agent
- 单个Agent最大支持10000篇文档
兼容性验收
- 现有无workspace用户不受影响
- PostgreSQL/MongoDB/Redis存储全部通过
- 多进程(Gunicorn)模式正常
7. 关键代码审查
7.1 需要修改的文件清单
新增文件(5个)
lightrag/api/agent_manager.py- Agent元数据管理器lightrag/api/models/agent_model.py- Agent数据模型lightrag/api/routers/agent_routes.py- Agent API路由lightrag_webui/src/stores/agentStore.ts- Agent状态管理lightrag_webui/src/components/agent/AgentSelector.tsx- Agent选择器
修改文件(2个)
lightrag/api/lightrag_server.py- 添加中间件、注册路由lightrag_webui/src/api/lightrag.ts- Axios拦截器
7.2 关键函数调用链
创建Agent流程
用户操作
↓
POST /agents {name, description}
↓
agent_routes.create_agent()
↓
agent_manager.create_agent()
├─ 生成唯一ID: agent_{name}_{hash}
├─ 检查名称重复
├─ 保存到 agents_meta.json
└─ 返回Agent对象
↓
前端agentStore.addAgent()
↓
更新UI列表
上传文档到Agent流程
用户选择Agent A + 上传文件
↓
前端发送请求:
POST /documents/upload
Headers: X-Agent-ID: agent_A
Body: FormData(file)
↓
中间件提取X-Agent-ID → current_workspace_var.set("agent_A")
↓
document_routes.upload_file()
├─ rag = await rag_manager.get_rag_instance_async()
│ └─ 从current_workspace_var.get() → "agent_A"
│ └─ 返回 rag_instances["agent_A"]
↓
rag.ainsert(file_content)
├─ self.workspace = "agent_A"
├─ 所有存储操作带workspace参数
│ ├─ text_chunks.upsert(..., workspace="agent_A")
│ ├─ entities_vdb.upsert(..., workspace="agent_A")
│ └─ chunk_entity_relation_graph.upsert(..., workspace="agent_A")
└─ 数据物理/逻辑隔离完成
删除Agent流程
用户确认删除Agent
↓
DELETE /agents/{agent_id}
↓
agent_routes.delete_agent()
├─ 1. 获取Agent元数据(含doc_count)
├─ 2. 获取RAG实例
│ rag = await rag_manager.get_rag_instance_async(agent_id)
├─ 3. 调用所有存储的drop()
│ await asyncio.gather(
│ rag.text_chunks.drop(),
│ rag.entities_vdb.drop(),
│ rag.chunk_entity_relation_graph.drop(),
│ ...
│ )
├─ 4. 删除文件目录
│ shutil.rmtree(working_dir / agent_id)
│ shutil.rmtree(input_dir / agent_id)
├─ 5. 移除内存实例
│ rag_manager.rag_instances.pop(agent_id)
└─ 6. 删除元数据
await agent_manager.delete_agent(agent_id)
7.3 核心代码依赖关系
┌─────────────────────────────────────┐
│ lightrag_server.py │
│ - 注册agent_routes │
│ - 添加agent_context_middleware │
│ - current_workspace_var (已有) │
└──────────┬──────────────────────────┘
│
├─────────────────────┐
↓ ↓
┌──────────────────┐ ┌────────────────────┐
│ agent_routes.py │ │ document_routes.py│
│ - create_agent │ │ - upload_file │
│ - list_agents │ │ (已有,无需修改) │
│ - delete_agent │ └────────────────────┘
└─────┬────────────┘
↓
┌──────────────────┐
│ agent_manager.py │
│ - 管理元数据 │
│ - 文件存储 │
└─────┬────────────┘
↓
┌──────────────────┐
│agents_meta.json │
│ { │
│ "agent_id": { │
│ "name": ... │
│ } │
│ } │
└──────────────────┘
8. 总结与建议
8.1 技术可行性结论
✅ 完全可行,理由如下:
-
LightRAG已有完整的workspace基础架构
- 所有存储层支持workspace参数
- RagManager支持多实例管理
- ContextVar实现上下文传递
-
数据隔离能力已验证
- JSON存储实现物理隔离(独立目录)
- PostgreSQL/MongoDB实现逻辑隔离(workspace字段过滤)
- 向量检索带workspace过滤条件
-
删除功能已就绪
- 所有存储实现了drop()抽象方法
- 文档清空功能已使用drop()并在生产环境验证
-
性能风险可控
- 单实例内存占用 ~250KB
- 数据库连接池共享,不会爆炸
- 支持100+并发Agent
8.2 改造风险评估
总体风险等级 :🟢 低风险
- 向后兼容性:✅ 完全兼容(workspace=""作为默认值)
- 代码侵入性:✅ 最小侵入(只增加,不修改核心逻辑)
- 测试覆盖率:✅ 可全面测试(功能点清晰)
- 回滚难度:✅ 容易回滚(新增文件可直接删除)
8.3 实施建议
立即开始的理由
- 架构基础已就绪:无需大规模重构
- 关键代码已验证:drop()方法已在生产使用
- 用户价值明确:多智能体是强需求
- 技术债务小:不会引入复杂依赖
推荐实施路径
第1周:后端核心
├─ Day 1-2: agent_manager + agent_routes
├─ Day 3-4: 删除功能 + 中间件
└─ Day 5: 单元测试 + 集成测试
第2周:前端界面
├─ Day 6-7: Agent管理界面
├─ Day 8: Agent选择器 + 拦截器
└─ Day 9-10: 联调 + 优化
第3周:测试与发布
├─ Day 11-12: 全面测试
└─ Day 13-14: 文档 + 上线
8.4 后续扩展方向
完成基础多租户后,可进一步扩展:
- 用户权限系统:User → Agent 多对多关系
- Agent共享:允许多个用户共享同一Agent
- Agent模板:预设领域专家Agent
- Agent导出/导入:备份与迁移
- Agent统计分析:查询次数、文档来源分析
9. 附录
9.1 关键类图
manages
creates/manages
collaborates
LightRAG
+str workspace
+BaseKVStorage text_chunks
+BaseVectorStorage entities_vdb
+BaseGraphStorage chunk_entity_relation_graph
+async initialize_storages()
+async finalize_storages()
RagManager
+Dict[str, LightRAG] rag_instances
+Dict[str, DocumentManager] doc_managers
+async get_rag_instance_async(workspace: str)
+async finalize_all()
AgentManager
+Path meta_file
+async create_agent(name, description)
+async list_agents()
+async delete_agent(agent_id)
-async _load_meta()
-async _save_meta(meta)
Agent
+str id
+str name
+str description
+datetime created_at
+int doc_count
9.2 序列图:创建Agent并上传文档
Storage LightRAG RagManager AgentManager API Frontend User Storage LightRAG RagManager AgentManager API Frontend User 点击"创建智能体" POST /agents {name: "法律助手"} create_agent("法律助手") 生成agent_id 保存到agents_meta.json 返回Agent对象 返回Agent JSON 更新Agent列表 选择"法律助手" + 上传文件 POST /documents/upload Header: X-Agent-ID=agent_legal_xxx Middleware提取X-Agent-ID get_rag_instance_async("agent_legal_xxx") new LightRAG(workspace="agent_legal_xxx") initialize storages with workspace 返回LightRAG实例 ainsert(file_content) upsert data with workspace="agent_legal_xxx" 存储成功 处理完成 上传成功
9.3 关键配置项
bash
# .env 配置示例
# Workspace配置(可选,为空表示默认workspace)
WORKSPACE=
# PostgreSQL配置(多workspace共享连接池)
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=lightrag
POSTGRES_PASSWORD=password
POSTGRES_DATABASE=lightrag
# 文档存储目录
INPUT_DIR=./input_files
# RAG存储目录
WORKING_DIR=./rag_storage
9.4 测试用例矩阵
| 测试场景 | 预期结果 | 验证方法 |
|---|---|---|
| 创建Agent A | 返回唯一agent_id | 检查agents_meta.json |
| 创建同名Agent | 返回400错误 | 断言HTTP状态码 |
| 上传文档到Agent A | 文档存储在agent_A目录 | 检查文件系统 |
| 在Agent A查询 | 只返回Agent A的文档 | 检查reference_id |
| 在Agent B查询 | 不返回Agent A的文档 | 检查结果为空 |
| 删除空Agent | 成功删除,doc_count=0 | 检查元数据移除 |
| 删除有文档的Agent | 所有数据清除 | 检查目录、数据库、VDB |
| 并发创建10个Agent | 全部成功 | 压力测试 |
| 并发删除同一Agent | 只有一个成功 | 锁机制测试 |
文档结束
下一步行动:
- 评审本文档,确认技术方案
- 开始实施"第一阶段Day 1"任务
- 建立代码审查流程
- 配置测试环境
联系方式:如有疑问,请参考本文档第7节"关键代码审查"