知识图谱的权限逻辑和知识库的权限逻辑保持一致

This commit is contained in:
silk 2026-06-02 21:51:15 +08:00
parent 07b24c1f31
commit 9c056ab391
5 changed files with 46 additions and 13 deletions

View File

@ -632,6 +632,29 @@ async def chat_completion(
)
def _wrap_mcp_tool_safe(tool):
"""
包装 MCP 工具确保第三方服务异常网络不可达超时等被捕获并以
错误字符串返回而非向上抛出
这样 LangChain Agent 在工具调用失败时仍能写入对应的 ToolMessage
保持 checkpoint 中消息历史的完整性避免下次对话因 tool_calls 缺少
配对回复而触发 LLM 400 BadRequest 错误
"""
original_arun = tool._arun
async def safe_arun(*args, **kwargs):
try:
return await original_arun(*args, **kwargs)
except Exception as exc:
error_msg = f"工具 [{tool.name}] 调用失败: {exc}"
logger.warning(f"MCP 工具异常已捕获,返回错误字符串以维持对话完整性: {error_msg}")
return error_msg
tool._arun = safe_arun
return tool
async def _create_agent_for_request(
request: ChatRequest,
current_user: User,
@ -699,6 +722,7 @@ async def _create_agent_for_request(
# 普通聊天模式
mcp_client = await get_mcp_client()
mcp_tools = await mcp_client.get_tools()
# mcp_tools = [_wrap_mcp_tool_safe(t) for t in mcp_tools]
logger.info(f"成功加载 {len(mcp_tools)} 个 MCP 工具")
# 查询用户设置(深度思考是否与模型侧一致取决于 user_list.is_reasoner

View File

@ -277,7 +277,7 @@ async def _fetch_graph_or_404(conn: asyncpg.Connection, graph_pk: int, user: Use
creator_id=raw.get("creator_id"),
visibility=raw.get("visibility") or "private",
)
if not can_view_graph(user, gr):
if not await can_view_graph(conn, user, gr):
raise HTTPException(status_code=404, detail="图谱不存在或无权访问")
return raw

View File

@ -159,16 +159,18 @@ async def can_upload_to_kb(conn: asyncpg.Connection, user: User, kb: KnowledgeBa
# ──────────────────────────────────────────────
# 知识图谱级权限(保持不变
# 知识图谱级权限(与知识库规则完全一致
# ──────────────────────────────────────────────
def can_view_graph(user: User, g: GraphRecord) -> bool:
"""判断用户是否可查看该知识图谱规则与知识库一致)。"""
async def can_view_graph(conn: asyncpg.Connection, user: User, g: GraphRecord) -> bool:
"""判断用户是否可查看该知识图谱。leader 权限覆盖本部门及所有子孙部门(与知识库一致)。"""
if user.role == "admin":
return True
if g.creator_id is not None and user.id == g.creator_id:
return True
if user.role == "leader" and user.department_id is not None and g.department_id == user.department_id:
if user.role == "leader" and user.department_id is not None and g.department_id is not None:
managed = await get_managed_dept_ids(conn, user)
if g.department_id in managed:
return True
vis = g.visibility or "private"
if vis == "private":

View File

@ -601,7 +601,7 @@ async def check_knowledge_graph_has_rag(knowledge_graph_id: int, user: User) ->
creator_id=raw.get("creator_id"),
visibility=raw.get("visibility") or "private",
)
if not can_view_graph(user, gr):
if not await can_view_graph(conn, user, gr):
return False
return (
raw.get("build_status") == "completed"
@ -633,7 +633,7 @@ async def get_knowledge_graph_tool_flags(user: User, graph_id: int) -> Dict[str,
creator_id=raw.get("creator_id"),
visibility=raw.get("visibility") or "private",
)
if not can_view_graph(user, gr):
if not await can_view_graph(conn, user, gr):
return out
if raw.get("build_status") != "completed":
return out

View File

@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional, Tuple
import asyncpg
from core.graph_metadata import graph_table_sql
from core.permissions import can_manage_graph, can_view_graph
from core.permissions import can_manage_graph, can_view_graph, get_managed_dept_ids
from models.graph_metadata import GraphRecord
from models.user import User
from logger.logging import get_logger
@ -95,13 +95,18 @@ class KnowledgeGraphService:
dept_id = user.department_id
uid = user.id
# leader 需要获取本部门及所有子孙部门 ID与知识库列表保持一致
managed_dept_ids: List[int] = []
if role == "leader" and dept_id is not None:
managed_dept_ids = await get_managed_dept_ids(conn, user)
where_sql = """
g.enterprise_id = $1
AND (
$2::text = 'admin'
OR g.creator_id = $3
OR ($2::text = 'leader' AND g.department_id IS NOT NULL AND g.department_id = $4)
OR (g.visibility = 'department' AND g.department_id IS NOT NULL AND g.department_id = $4)
OR ($2::text = 'leader' AND g.department_id IS NOT NULL AND g.department_id = ANY($4::int[]))
OR (g.visibility = 'department' AND g.department_id IS NOT NULL AND g.department_id = $5)
OR (g.visibility = 'enterprise')
)
"""
@ -114,6 +119,7 @@ class KnowledgeGraphService:
enterprise_id,
role,
uid,
managed_dept_ids,
dept_id,
)
@ -131,11 +137,12 @@ class KnowledgeGraphService:
LEFT JOIN department d ON d.id = g.department_id
WHERE {where_sql}
ORDER BY g.created_at DESC
LIMIT $5 OFFSET $6
LIMIT $6 OFFSET $7
""",
enterprise_id,
role,
uid,
managed_dept_ids,
dept_id,
page_size,
offset,
@ -182,6 +189,6 @@ class KnowledgeGraphService:
gr = KnowledgeGraphService._row_to_graph_record(raw)
except Exception:
return None
if not can_view_graph(user, gr):
if not await can_view_graph(conn, user, gr):
return None
return await KnowledgeGraphService.enrich_graph_for_response(conn, raw, user)