From 9bc5b086f9b2b62e5faf250d05cb182f20f34d8c Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Fri, 27 Jun 2025 01:52:59 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E7=A7=BB=E9=99=A4=20Chat=20=E3=80=81R?= =?UTF-8?q?etriever=20=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E7=9F=A5=E8=AF=86=E5=BA=93=E4=B8=8E=E7=9F=A5=E8=AF=86=E5=9B=BE?= =?UTF-8?q?=E8=B0=B1=E9=BB=98=E8=AE=A4=E5=BC=80=E5=90=AF=E4=B8=94=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 retriever.py 文件,移除不再使用的检索器逻辑。 - 更新 base_router.py,简化重启逻辑,移除 retriever.restart() 调用。 - 修改 config.py,移除知识库和知识图谱的配置项。 - 更新前端组件,调整与知识库相关的显示逻辑,确保界面一致性。 - 修改路由配置,移除与聊天相关的路由,优化用户导航体验。 --- server/routers/base_router.py | 1 - server/routers/chat_router.py | 78 +------- src/__init__.py | 3 - src/config/__init__.py | 4 +- src/core/graphbase.py | 9 +- src/core/retriever.py | 182 ----------------- src/models/embedding.py | 3 - web/src/components/ChatComponent.vue | 3 +- web/src/layouts/AppLayout.vue | 34 +++- web/src/router/index.js | 13 -- web/src/views/ChatView.vue | 288 --------------------------- web/src/views/HomeView.vue | 2 +- web/src/views/LoginView.vue | 2 +- web/src/views/SettingView.vue | 29 --- 14 files changed, 30 insertions(+), 621 deletions(-) delete mode 100644 src/core/retriever.py delete mode 100644 web/src/views/ChatView.vue diff --git a/server/routers/base_router.py b/server/routers/base_router.py index 5fc81ae1..b3c746a9 100644 --- a/server/routers/base_router.py +++ b/server/routers/base_router.py @@ -93,7 +93,6 @@ async def update_config_item( async def restart(current_user: User = Depends(get_superadmin_user)): knowledge_base.restart() graph_base.start() - retriever.restart() return {"message": "Restarted!"} @base.get("/log") diff --git a/server/routers/chat_router.py b/server/routers/chat_router.py index ad1e83ca..86626f98 100644 --- a/server/routers/chat_router.py +++ b/server/routers/chat_router.py @@ -10,7 +10,7 @@ from langchain_core.messages import AIMessageChunk, HumanMessage from sqlalchemy.orm import Session from pydantic import BaseModel -from src import executor, config, retriever +from src import executor, config from src.core import HistoryManager from src.agents import agent_manager from src.models import select_model @@ -67,82 +67,6 @@ async def chat_get(current_user: User = Depends(get_required_user)): """聊天服务健康检查(需要登录)""" return "Chat Get!" -@chat.post("/") -async def chat_post( - query: str = Body(...), - meta: dict = Body(None), - history: list[dict] | None = Body(None), - thread_id: str | None = Body(None), - current_user: User = Depends(get_required_user)): - """处理聊天请求的主要端点(需要登录)""" - - model = select_model() - meta["server_model_name"] = model.model_name - history_manager = HistoryManager(history, system_prompt=meta.get("system_prompt")) - logger.debug(f"Received query: {query} with meta: {meta}") - - def make_chunk(content=None, **kwargs): - return json.dumps({ - "response": content, - "meta": meta, - **kwargs - }, ensure_ascii=False).encode('utf-8') + b"\n" - - def need_retrieve(meta): - return meta.get("use_web") or meta.get("use_graph") or meta.get("db_id") - - def generate_response(): - modified_query = query - refs = None - - # 处理知识库检索 - if meta and need_retrieve(meta): - chunk = make_chunk(status="searching") - yield chunk - - try: - modified_query, refs = retriever(modified_query, history_manager.messages, meta) - except Exception as e: - logger.error(f"Retriever error: {e}, {traceback.format_exc()}") - yield make_chunk(message=f"Retriever error: {e}", status="error") - return - - yield make_chunk(status="generating") - - messages = history_manager.get_history_with_msg(modified_query, max_rounds=meta.get('history_round')) - history_manager.add_user(query) # 注意这里使用原始查询 - - content = "" - reasoning_content = "" - try: - for delta in model.predict(messages, stream=True): - if not delta.content and hasattr(delta, 'reasoning_content'): - reasoning_content += delta.reasoning_content or "" - chunk = make_chunk(reasoning_content=reasoning_content, status="reasoning") - yield chunk - continue - - # 文心一言 - if hasattr(delta, 'is_full') and delta.is_full: - content = delta.content - else: - content += delta.content or "" - - chunk = make_chunk(content=delta.content, status="loading") - yield chunk - - logger.debug(f"Final response: {content}") - logger.debug(f"Final reasoning response: {reasoning_content}") - yield make_chunk(status="finished", - history=history_manager.update_ai(content), - refs=refs) - except Exception as e: - logger.error(f"Model error: {e}, {traceback.format_exc()}") - yield make_chunk(message=f"Model error: {e}", status="error") - return - - return StreamingResponse(generate_response(), media_type='application/json') - @chat.post("/call") async def call(query: str = Body(...), meta: dict = Body(None), current_user: User = Depends(get_required_user)): """调用模型进行简单问答(需要登录)""" diff --git a/src/__init__.py b/src/__init__.py index ea1782fc..06abbc9c 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -13,6 +13,3 @@ knowledge_base = KnowledgeBase() from src.core import GraphDatabase # noqa: E402 graph_base = GraphDatabase() - -from src.core.retriever import Retriever # noqa: E402 -retriever = Retriever() diff --git a/src/config/__init__.py b/src/config/__init__.py index 37cc762d..c9efd1f6 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -48,8 +48,6 @@ class Config(SimpleConfig): ### >>> 默认配置 # 功能选项 self.add_item("enable_reranker", default=False, des="是否开启重排序") - self.add_item("enable_knowledge_base", default=False, des="是否开启知识库") - self.add_item("enable_knowledge_graph", default=False, des="是否开启知识图谱") self.add_item("enable_web_search", default=False, des="是否开启网页搜索(注:现阶段会根据 TAVILY_API_KEY 自动开启,无法手动配置,将会在下个版本移除此配置项)") # noqa: E501 # 默认智能体配置 self.add_item("default_agent_id", default="", des="默认智能体ID") @@ -57,7 +55,7 @@ class Config(SimpleConfig): ## 注意这里是模型名,而不是具体的模型路径,默认使用 HuggingFace 的路径 ## 如果需要自定义本地模型路径,则在 src/.env 中配置 MODEL_DIR self.add_item("model_provider", default="siliconflow", des="模型提供商", choices=list(self.model_names.keys())) - self.add_item("model_name", default="Qwen/Qwen2.5-7B-Instruct", des="模型名称") + self.add_item("model_name", default="Qwen/Qwen3-32B", des="模型名称") self.add_item("embed_model", default="siliconflow/BAAI/bge-m3", des="Embedding 模型", choices=list(self.embed_model_names.keys())) self.add_item("reranker", default="siliconflow/BAAI/bge-reranker-v2-m3", des="Re-Ranker 模型", choices=list(self.reranker_names.keys())) # noqa: E501 diff --git a/src/core/graphbase.py b/src/core/graphbase.py index 9f923aed..f45dd446 100644 --- a/src/core/graphbase.py +++ b/src/core/graphbase.py @@ -31,9 +31,6 @@ class GraphDatabase: self.start() def start(self): - if not config.enable_knowledge_graph or not config.enable_knowledge_base: - return - uri = os.environ.get("NEO4J_URI", "bolt://localhost:7687") username = os.environ.get("NEO4J_USERNAME", "neo4j") password = os.environ.get("NEO4J_PASSWORD", "0123456789") @@ -46,7 +43,6 @@ class GraphDatabase: self.save_graph_info(self.kgdb_name) except Exception as e: logger.error(f"Failed to connect to Neo4j: {e}, {uri}, {self.kgdb_name}, {username}, {password}") - self.config.enable_knowledge_graph = False def close(self): """关闭数据库连接""" @@ -54,10 +50,7 @@ class GraphDatabase: def is_running(self): """检查图数据库是否正在运行""" - if not config.enable_knowledge_graph or not config.enable_knowledge_base: - return False - else: - return self.status == "open" + return self.status == "open" def get_sample_nodes(self, kgdb_name='neo4j', num=50): """获取指定数据库的 num 个节点信息""" diff --git a/src/core/retriever.py b/src/core/retriever.py deleted file mode 100644 index a74c772b..00000000 --- a/src/core/retriever.py +++ /dev/null @@ -1,182 +0,0 @@ -import traceback - -from src import config, knowledge_base, graph_base -from src.models.rerank_model import get_reranker -from src.utils.logging_config import logger -from src.models import select_model -from src.core.operators import HyDEOperator - -class Retriever: - - def __init__(self): - self._load_models() - - def _load_models(self): - if config.enable_reranker: - self.reranker = get_reranker() - - if config.enable_web_search: - from src.utils.web_search import WebSearcher - self.web_searcher = WebSearcher() - - def retrieval(self, query, history, meta): - refs = {"query": query, "history": history, "meta": meta} - refs["model_name"] = config.model_name - refs["entities"] = self.reco_entities(query, history, refs) - refs["knowledge_base"] = self.query_knowledgebase(query, history, refs) - refs["graph_base"] = self.query_graph(query, history, refs) - refs["web_search"] = self.query_web(query, history, refs) - - return refs - - def restart(self): - """所有需要重启的模型""" - self._load_models() - - def construct_query(self, query, refs, meta): - logger.debug(f"{refs=}") - if not refs or len(refs) == 0: - return query - - external_parts = [] - - # 解析知识库的结果 - kb_res = refs.get("knowledge_base", {}).get("results", []) - if kb_res: - kb_text = "\n".join(f"{r['id']}: {r['entity']['text']}" for r in kb_res) - external_parts.extend(["知识库信息:", kb_text]) - - # 解析图数据库的结果 - db_res = refs.get("graph_base", {}).get("results", {}) - if db_res.get("nodes") and len(db_res["nodes"]) > 0: - db_text = "\n".join( - [f"{edge['source_name']}和{edge['target_name']}的关系是{edge['type']}" for edge in db_res.get("edges", [])] - ) - external_parts.extend(["图数据库信息:", db_text]) - - # 解析网络搜索的结果 - web_res = refs.get("web_search", {}).get("results", []) - if web_res: - web_text = "\n".join(f"{r['title']}: {r['content']}" for r in web_res) - external_parts.extend(["网络搜索信息:", web_text]) - - # 构造查询 - from src.utils.prompts import knowbase_qa_template - if external_parts and len(external_parts) > 0: - external = "\n\n".join(external_parts) - query = knowbase_qa_template.format(external=external, query=query) - - return query - - def query_classification(self, query): - """判断是否需要查询 - - 对于完全基于用户给定信息的任务,称之为"足够""sufficient",不需要检索; - - 否则,称之为"不足""insufficient",可能需要检索, - """ - raise NotImplementedError - - def query_graph(self, query, history, refs): - results = [] - if refs["meta"].get("use_graph") and config.enable_knowledge_base: - for entity in refs["entities"]: - if entity == "": - continue - result = graph_base.query_node(entity) - if result != []: - results.extend(result) - return {"results": graph_base.format_query_result_to_graph(results)} - - - def query_knowledgebase(self, query, history, refs): - """查询知识库""" - - response = { - "results": [], - "all_results": [], - "rw_query": query, - "message": "", - } - - meta = refs["meta"] - - db_id = meta.get("db_id") - if not db_id or not config.enable_knowledge_base: - response["message"] = "知识库未启用、或未指定知识库、或知识库不存在" - return response - - rw_query = self.rewrite_query(query, history, refs) - - logger.debug(f"{meta=}") - query_result = knowledge_base.query(query_text=rw_query, - db_id=db_id, - distance_threshold=meta.get("distanceThreshold", 0.5), - rerank_threshold=meta.get("rerankThreshold", 0.1), - max_query_count=meta.get("maxQueryCount", 20), - top_k=meta.get("topK", 10)) - - response["results"] = query_result["results"] - response["all_results"] = query_result["all_results"] - response["rw_query"] = rw_query - - return response - - def query_web(self, query, history, refs): - """查询网络""" - - if not (refs["meta"].get("use_web") or not config.enable_web_search): - return {"results": [], "message": "Web search is disabled"} - - try: - search_results = self.web_searcher.search(query, max_results=5) - except Exception as e: - logger.error(f"Web search error: {str(e)}") - return {"results": [], "message": "Web search error"} - - return {"results": search_results} - - def rewrite_query(self, query, history, refs): - """重写查询""" - model_provider = config.model_provider - model_name = config.model_name - model = select_model(model_provider=model_provider, model_name=model_name) - if refs["meta"].get("mode") == "search": # 如果是搜索模式,就使用 meta 的配置,否则就使用全局的配置 - rewrite_query_span = refs["meta"].get("use_rewrite_query", "off") - else: - rewrite_query_span = config.use_rewrite_query - - if rewrite_query_span == "off": - return query - - from src.utils.prompts import rewritten_query_prompt_template2 as rw_template - history_query = [entry["content"] for entry in history if entry["role"] == "user"] if history else "" - rewritten_query_prompt = rw_template.format(history=history_query, query=query) - rewritten_query = model.predict(rewritten_query_prompt).content - - if rewrite_query_span == "hyde": - res = HyDEOperator.call(model_callable=model.predict, query=query, context_str=history_query) - rewritten_query = res.content - - return rewritten_query - - def reco_entities(self, query, history, refs): - """识别句子中的实体""" - query = refs.get("rewritten_query", query) - model_provider = config.model_provider - model_name = config.model_name - model = select_model(model_provider=model_provider, model_name=model_name) - - entities = [] - if refs["meta"].get("use_graph"): - from src.utils.prompts import entity_extraction_prompt_template as entity_template - # from src.utils.prompts import keywords_prompt_template as entity_templat|e - - entity_extraction_prompt = entity_template.format(text=query) - entities = model.predict(entity_extraction_prompt).content.split("<->") - # entities = [entity for entity in entities if all(char.isalnum() or char in "汉字" for char in entity)] - - return entities - - def __call__(self, query, history, meta): - refs = self.retrieval(query, history, meta) - query = self.construct_query(query, refs, meta) - return query, refs diff --git a/src/models/embedding.py b/src/models/embedding.py index 6718c887..e40d9fff 100644 --- a/src/models/embedding.py +++ b/src/models/embedding.py @@ -182,9 +182,6 @@ class OtherEmbedding(BaseEmbeddingModel): } def get_embedding_model(): - if not config.enable_knowledge_base: - return None - provider, model_name = config.embed_model.split('/', 1) support_embed_models = config.embed_model_names.keys() assert config.embed_model in support_embed_models, f"Unsupported embed model: {config.embed_model}, only support {support_embed_models}" diff --git a/web/src/components/ChatComponent.vue b/web/src/components/ChatComponent.vue index 123d2d5c..1f4510b8 100644 --- a/web/src/components/ChatComponent.vue +++ b/web/src/components/ChatComponent.vue @@ -98,14 +98,13 @@
知识图谱
diff --git a/web/src/layouts/AppLayout.vue b/web/src/layouts/AppLayout.vue index 34023249..21b8f52e 100644 --- a/web/src/layouts/AppLayout.vue +++ b/web/src/layouts/AppLayout.vue @@ -27,14 +27,35 @@ const layoutSettings = reactive({ const githubStars = ref(0) const isLoadingStars = ref(false) +// Add state for debug modal +const showDebugModal = ref(false) +const htmlRefHook = useTemplateRef('htmlRefHook') + +// Setup long press for debug modal +onLongPress( + htmlRefHook, + () => { + console.log('long press') + showDebugModal.value = true + }, + { + delay: 1000, // 1秒长按 + modifiers: { + prevent: true + } + } +) + +// Handle debug modal close +const handleDebugModalClose = () => { + showDebugModal.value = false +} + const getRemoteConfig = () => { configStore.refreshConfig() } const getRemoteDatabase = () => { - if (!configStore.config.enable_knowledge_base) { - return - } databaseStore.refreshDatabase() } @@ -68,11 +89,6 @@ console.log(route) // 下面是导航菜单部分,添加智能体项 const mainList = [{ - name: '对话', - path: '/chat', - icon: MessageSquareMore, - activeIcon: MessageSquareMore, - }, { name: '智能体', path: '/agent', icon: Bot, @@ -82,13 +98,11 @@ const mainList = [{ path: '/graph', icon: Waypoints, activeIcon: Waypoints, - // hidden: !configStore.config.enable_knowledge_graph, }, { name: '知识库', path: '/database', icon: LibraryBig, activeIcon: LibraryBig, - // hidden: !configStore.config.enable_knowledge_base, } ] diff --git a/web/src/router/index.js b/web/src/router/index.js index 5c095dd5..8e2ab8d7 100644 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -25,19 +25,6 @@ const router = createRouter({ component: () => import('../views/LoginView.vue'), meta: { requiresAuth: false } }, - { - path: '/chat', - name: 'chat', - component: AppLayout, - children: [ - { - path: '', - name: 'ChatComp', - component: () => import('../views/ChatView.vue'), - meta: { keepAlive: true, requiresAuth: true, requiresAdmin: true } - } - ] - }, { path: '/agent', name: 'AgentMain', diff --git a/web/src/views/ChatView.vue b/web/src/views/ChatView.vue deleted file mode 100644 index 5d2d1bf5..00000000 --- a/web/src/views/ChatView.vue +++ /dev/null @@ -1,288 +0,0 @@ - - - - - diff --git a/web/src/views/HomeView.vue b/web/src/views/HomeView.vue index 53e3ded8..1e2b25d3 100644 --- a/web/src/views/HomeView.vue +++ b/web/src/views/HomeView.vue @@ -71,7 +71,7 @@ const goToChat = async () => { // 根据用户角色进行跳转 if (userStore.isAdmin) { // 管理员用户跳转到聊天页面 - router.push('/chat'); + router.push('/agent'); return; } diff --git a/web/src/views/LoginView.vue b/web/src/views/LoginView.vue index d5599568..846a4113 100644 --- a/web/src/views/LoginView.vue +++ b/web/src/views/LoginView.vue @@ -221,7 +221,7 @@ const handleLogin = async () => { if (redirectPath === '/') { // 如果是管理员,直接跳转到/chat页面 if (userStore.isAdmin) { - router.push('/chat'); + router.push('/agent'); return; } diff --git a/web/src/views/SettingView.vue b/web/src/views/SettingView.vue index 07aaff47..e6fae9b0 100644 --- a/web/src/views/SettingView.vue +++ b/web/src/views/SettingView.vue @@ -13,7 +13,6 @@
基本设置 模型配置 - 路径配置 用户管理
@@ -72,23 +71,6 @@
-

功能配置

-
-
- {{ items?.enable_knowledge_base.des }} - -
-
- {{ items?.enable_knowledge_graph.des }} - -
-

模型配置

@@ -138,19 +120,8 @@ const handleModelLocalPathsUpdate = (config) => { } const preHandleChange = (key, e) => { - if (key == 'enable_knowledge_graph' && e && !configStore.config.enable_knowledge_base) { - message.error('启动知识图谱必须请先启用知识库功能') - return - } - - if (key == 'enable_knowledge_base' && !e && configStore.config.enable_knowledge_graph) { - message.error('关闭知识库功能必须请先关闭知识图谱功能') - return - } if (key == 'enable_reranker' - || key == 'enable_knowledge_graph' - || key == 'enable_knowledge_base' || key == 'embed_model' || key == 'reranker' || key == 'model_local_paths') {