fix(chat): 修复知识库权限过滤逻辑

TODO: 前端还未完成过滤
This commit is contained in:
Wenjie Zhang 2026-01-22 11:16:15 +08:00
parent 5f90385ad0
commit 5cb6e4402f
5 changed files with 35 additions and 39 deletions

View File

@ -48,7 +48,7 @@ class BaseContext:
metadata={"name": "部门ID", "configurable": False, "description": "用来唯一标识一个部门"}, metadata={"name": "部门ID", "configurable": False, "description": "用来唯一标识一个部门"},
) )
system_prompt: str = field( system_prompt: Annotated[str, {"__template_metadata__": {"kind": "prompt"}}] = field(
default="You are a helpful assistant.", default="You are a helpful assistant.",
metadata={"name": "系统提示词", "description": "用来描述智能体的角色和行为"}, metadata={"name": "系统提示词", "description": "用来描述智能体的角色和行为"},
) )
@ -71,7 +71,7 @@ class BaseContext:
}, },
) )
knowledges: list[str] = field( knowledges: Annotated[list[str], {"__template_metadata__": {"kind": "knowledges"}}] = field(
default_factory=list, default_factory=list,
metadata={ metadata={
"name": "知识库", "name": "知识库",
@ -81,7 +81,7 @@ class BaseContext:
}, },
) )
mcps: list[str] = field( mcps: Annotated[list[str], {"__template_metadata__": {"kind": "mcps"}}] = field(
default_factory=list, default_factory=list,
metadata={ metadata={
"name": "MCP服务器", "name": "MCP服务器",

View File

@ -7,7 +7,7 @@ from collections.abc import AsyncIterator
from langchain.messages import AIMessage, AIMessageChunk, HumanMessage from langchain.messages import AIMessage, AIMessageChunk, HumanMessage
from langgraph.types import Command from langgraph.types import Command
from src import config as conf from src import config as conf, knowledge_base
from src.agents import agent_manager from src.agents import agent_manager
from src.plugins.guard import content_guard from src.plugins.guard import content_guard
from src.repositories.agent_config_repository import AgentConfigRepository from src.repositories.agent_config_repository import AgentConfigRepository
@ -294,19 +294,19 @@ async def stream_agent_chat(
) )
agent_config_id = config_item.id agent_config_id = config_item.id
thread_id = config.get("thread_id") if not (thread_id := config.get("thread_id")):
thread_id = str(uuid.uuid4())
logger.warning(f"No thread_id provided, generated new thread_id: {thread_id}")
agent_config = (config_item.config_json or {}).get("context", {})
input_context = { input_context = {
"user_id": user_id, "user_id": user_id,
"thread_id": thread_id, "thread_id": thread_id,
"department_id": department_id, "department_id": department_id,
"agent_config_id": agent_config_id, "agent_config_id": agent_config_id,
"agent_config": (config_item.config_json or {}).get("context", config_item.config_json or {}), "agent_config": agent_config,
} }
if not thread_id:
thread_id = str(uuid.uuid4())
logger.warning(f"No thread_id provided, generated new thread_id: {thread_id}")
input_context["thread_id"] = thread_id
try: try:
conv_repo = ConversationRepository(db) conv_repo = ConversationRepository(db)
@ -332,7 +332,8 @@ async def stream_agent_chat(
input_context["attachments"] = [] input_context["attachments"] = []
# 根据用户权限过滤知识库 # 根据用户权限过滤知识库
requested_knowledge_names = input_context.get("knowledges") requested_knowledge_names = input_context["agent_config"].get("knowledges")
logger.info(f"Requesting knowledges: {requested_knowledge_names}")
if requested_knowledge_names and isinstance(requested_knowledge_names, list) and requested_knowledge_names: if requested_knowledge_names and isinstance(requested_knowledge_names, list) and requested_knowledge_names:
user_info = {"role": "user", "department_id": department_id} user_info = {"role": "user", "department_id": department_id}
accessible_databases = await knowledge_base.get_databases_by_user(user_info) accessible_databases = await knowledge_base.get_databases_by_user(user_info)
@ -341,13 +342,15 @@ async def stream_agent_chat(
for db in accessible_databases.get("databases", []) for db in accessible_databases.get("databases", [])
if isinstance(db, dict) and db.get("name") if isinstance(db, dict) and db.get("name")
} }
logger.info(f"Accessible knowledges: {accessible_kb_names}")
filtered_knowledge_names = [kb for kb in requested_knowledge_names if kb in accessible_kb_names] filtered_knowledge_names = [kb for kb in requested_knowledge_names if kb in accessible_kb_names]
blocked_knowledge_names = [kb for kb in requested_knowledge_names if kb not in accessible_kb_names] blocked_knowledge_names = [kb for kb in requested_knowledge_names if kb not in accessible_kb_names]
if blocked_knowledge_names: if blocked_knowledge_names:
logger.warning( logger.warning(
f"用户 {user_id} 无权访问知识库: {blocked_knowledge_names}, 已自动过滤" f"用户 {user_id} 无权访问知识库: {blocked_knowledge_names}, 已自动过滤"
) )
input_context["knowledges"] = filtered_knowledge_names input_context["agent_config"]["knowledges"] = filtered_knowledge_names
full_msg = None full_msg = None
accumulated_content = [] accumulated_content = []

View File

@ -1373,7 +1373,7 @@ watch(
height: 32px; height: 32px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-radius: 8px; border-radius: 6px;
color: var(--gray-900); color: var(--gray-900);
cursor: pointer; cursor: pointer;
width: auto; width: auto;

View File

@ -57,7 +57,7 @@
</div> </div>
<!-- 系统提示词 --> <!-- 系统提示词 -->
<div v-else-if="key === 'system_prompt'" class="system-prompt-container"> <div v-else-if="value.template_metadata.kind === 'prompt'" class="system-prompt-container">
<!-- 编辑模式 --> <!-- 编辑模式 -->
<a-textarea <a-textarea
v-if="systemPromptEditMode" v-if="systemPromptEditMode"
@ -82,7 +82,7 @@
</div> </div>
<!-- 工具选择 --> <!-- 工具选择 -->
<div v-else-if="value.template_metadata.kind === 'tools'" class="tools-selector"> <!-- <div v-else-if="value.template_metadata.kind === 'tools'" class="tools-selector">
<div class="tools-summary"> <div class="tools-summary">
<div class="tools-summary-info"> <div class="tools-summary-info">
<span class="tools-count">已选择 {{ getSelectedCount(key) }} 个工具</span> <span class="tools-count">已选择 {{ getSelectedCount(key) }} 个工具</span>
@ -116,7 +116,7 @@
{{ getToolNameById(toolId) }} {{ getToolNameById(toolId) }}
</a-tag> </a-tag>
</div> </div>
</div> </div> -->
<!-- 布尔类型 --> <!-- 布尔类型 -->
<a-switch <a-switch
@ -368,14 +368,12 @@ const isDeletingConfig = ref(false)
const hasOtherConfigs = computed(() => { const hasOtherConfigs = computed(() => {
if (isEmptyConfig.value) return false if (isEmptyConfig.value) return false
return Object.entries(configurableItems.value).some(([key, value]) => { return Object.entries(configurableItems.value).some(([key, value]) => {
// basic (System Prompt, LLM) const isBasic = value.template_metadata?.kind === 'prompt' || value.template_metadata?.kind === 'llm'
const isBasic = key === 'system_prompt' || value.template_metadata?.kind === 'llm'
// tools (mcps, knowledges, tools)
const isTools = const isTools =
key === 'mcps' || value.template_metadata?.kind === 'mcps' ||
key === 'knowledges' || value.template_metadata?.kind === 'knowledges' ||
value.template_metadata?.kind === 'tools' || value.template_metadata?.kind === 'tools'
key === 'tools'
return !isBasic && !isTools return !isBasic && !isTools
}) })
}) })
@ -408,25 +406,20 @@ const filteredTools = computed(() => {
// //
const shouldShowConfig = (key, value) => { const shouldShowConfig = (key, value) => {
const isBasic = value.template_metadata?.kind === 'prompt' || value.template_metadata?.kind === 'llm'
const isTools =
value.template_metadata?.kind === 'mcps' ||
value.template_metadata?.kind === 'knowledges' ||
value.template_metadata?.kind === 'tools'
if (activeTab.value === 'basic') { if (activeTab.value === 'basic') {
// System Prompt, LLM Model // System Prompt, LLM Model
return key === 'system_prompt' || value.template_metadata?.kind === 'llm' return isBasic
} else if (activeTab.value === 'tools') { } else if (activeTab.value === 'tools') {
// Tools, MCPs, Knowledges // Tools, MCPs, Knowledges
return ( return isTools
key === 'mcps' ||
key === 'knowledges' ||
value.template_metadata?.kind === 'tools' ||
key === 'tools'
)
} else { } else {
// //
const isBasic = key === 'system_prompt' || value.template_metadata?.kind === 'llm'
const isTools =
key === 'mcps' ||
key === 'knowledges' ||
value.template_metadata?.kind === 'tools' ||
key === 'tools'
return !isBasic && !isTools return !isBasic && !isTools
} }
} }

View File

@ -343,11 +343,11 @@ onMounted(async () => {
<style lang="less"> <style lang="less">
.agent-nav-btn { .agent-nav-btn {
display: flex; display: flex;
gap: 10px; gap: 6px;
padding: 6px 14px; padding: 6px 8px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-radius: 12px; border-radius: 6px;
color: var(--gray-900); color: var(--gray-900);
cursor: pointer; cursor: pointer;
width: auto; width: auto;