""" 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您可以直接提问,我会尝试从知识库中检索相关信息。"