- 后端 API(Flask + Gunicorn) - RAG 引擎(混合检索 + 云端 Reranker + 引用溯源) - 文档解析(MinerU + 多格式支持) - Docker 生产部署配置 - 排除前端项目、敏感配置、模型文件
134 lines
5.9 KiB
Python
134 lines
5.9 KiB
Python
"""
|
|
Agentic RAG - 元问题处理 Mixin
|
|
|
|
包含元问题判断和知识库元数据回答方法
|
|
"""
|
|
|
|
import logging
|
|
|
|
from .agentic_base import logger
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MetaQuestionMixin:
|
|
"""元问题处理方法"""
|
|
|
|
def _is_meta_question(self, query: str) -> bool:
|
|
"""判断是否为元问题(关于知识库本身的问题)"""
|
|
meta_patterns = [
|
|
"有哪些文件", "什么文件", "哪些文件", "文件列表", "文件目录",
|
|
"可以查看", "能查看", "有权限查看", "权限查看",
|
|
"能访问", "可以访问", "有权限访问",
|
|
"我的权限", "用户权限", "查看权限", "访问权限",
|
|
"权限能", "权限可以", "有什么权限", "有哪些权限",
|
|
"我能看", "我可以看", "我能查", "我可以查",
|
|
"能看到什么", "能查到什么", "可以看什么", "可以查什么",
|
|
"知识库有哪些", "库里有", "文档有哪些", "有哪些文档",
|
|
"有什么文档", "有什么文件", "包含什么", "包含哪些",
|
|
"你知道什么", "你都知道", "你能回答什么",
|
|
"系统里有什么", "库里有什么",
|
|
"public_kb", "dept_tech", "dept_hr", "dept_finance", "dept_operation",
|
|
"kb里", "向量库", "有哪些库", "库列表", "kb有哪些"
|
|
]
|
|
query_lower = query.lower()
|
|
return any(kw in query_lower for kw in meta_patterns)
|
|
|
|
def _answer_meta_question(self, query: str, allowed_levels: list = None,
|
|
role: str = None, department: str = None) -> str:
|
|
"""回答元问题(关于知识库本身的问题)"""
|
|
try:
|
|
source_map = {}
|
|
|
|
try:
|
|
from knowledge.manager import get_kb_manager
|
|
from auth.gateway import get_accessible_collections as _get_accessible
|
|
|
|
kb_mgr = get_kb_manager()
|
|
accessible = _get_accessible(role or 'user', department or '', 'read')
|
|
|
|
for kb_name in accessible:
|
|
coll = kb_mgr.get_collection(kb_name)
|
|
if not coll:
|
|
continue
|
|
try:
|
|
result = coll.get(include=['metadatas'])
|
|
except Exception as e:
|
|
logger.debug(f"获取{kb_name}元数据失败: {e}")
|
|
continue
|
|
|
|
for meta in result.get('metadatas', []):
|
|
source = meta.get('source', '未知')
|
|
level = meta.get('security_level', 'public')
|
|
page = meta.get('page')
|
|
|
|
if source not in source_map:
|
|
source_map[source] = {
|
|
'count': 0, 'levels': set(),
|
|
'pages': set(), 'collections': set()
|
|
}
|
|
|
|
source_map[source]['count'] += 1
|
|
source_map[source]['levels'].add(level)
|
|
source_map[source]['collections'].add(kb_name)
|
|
if page:
|
|
source_map[source]['pages'].add(page)
|
|
|
|
except ImportError:
|
|
from core.engine import get_engine
|
|
all_docs = get_engine().collection.get(include=['metadatas'])
|
|
for meta in all_docs.get('metadatas', []):
|
|
source = meta.get('source', '未知')
|
|
level = meta.get('security_level', 'public')
|
|
page = meta.get('page')
|
|
|
|
if source not in source_map:
|
|
source_map[source] = {
|
|
'count': 0, 'levels': set(),
|
|
'pages': set(), 'collections': set()
|
|
}
|
|
|
|
source_map[source]['count'] += 1
|
|
source_map[source]['levels'].add(level)
|
|
if page:
|
|
source_map[source]['pages'].add(page)
|
|
|
|
# 根据安全级别过滤
|
|
if allowed_levels:
|
|
allowed_set = set(allowed_levels)
|
|
filtered_sources = {}
|
|
for source, info in source_map.items():
|
|
if info['levels'] & allowed_set:
|
|
filtered_sources[source] = info
|
|
source_map = filtered_sources
|
|
|
|
if not source_map:
|
|
return "抱歉,您当前没有权限查看任何文档,或者知识库为空。"
|
|
|
|
sorted_sources = sorted(source_map.items(), key=lambda x: x[1]['count'], reverse=True)
|
|
|
|
answer_parts = [f"📚 **知识库文档列表**(共 {len(sorted_sources)} 个文档)\n"]
|
|
|
|
for i, (source, info) in enumerate(sorted_sources, 1):
|
|
colls = info.get('collections', set())
|
|
coll_str = f",所属: {', '.join(sorted(colls))}" if colls else ""
|
|
pages_str = ''
|
|
if info['pages']:
|
|
pages_list = sorted(info['pages'])
|
|
if len(pages_list) <= 5:
|
|
pages_str = f",页码: {', '.join(map(str, pages_list))}"
|
|
else:
|
|
pages_str = f",共 {len(info['pages'])} 页"
|
|
|
|
answer_parts.append(f"{i}. **{source}** ({info['count']} 条片段{coll_str}{pages_str})")
|
|
|
|
answer_parts.append(f"\n**总计**: {sum(s[1]['count'] for s in sorted_sources)} 条知识片段")
|
|
answer_parts.append(f"\n**您的权限级别**: {', '.join(allowed_levels) if allowed_levels else '全部'}")
|
|
|
|
answer_parts.append("\n\n💡 **提示**: 您可以直接提问关于这些文档内容的问题。")
|
|
|
|
return '\n'.join(answer_parts)
|
|
|
|
except Exception as e:
|
|
return f"获取文档列表时出错: {str(e)}\n\n您可以直接提问,我会尝试从知识库中检索相关信息。"
|