From ef5113bffb2e79fa19789de01e03699e2ba9eb80 Mon Sep 17 00:00:00 2001
From: root <953994191@qq.com>
Date: Wed, 29 Apr 2026 12:52:41 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E7=9B=AE?=
=?UTF-8?q?=E5=BD=95=E7=BB=93=E6=9E=84=20-=20=E7=AE=80=E5=8C=96=E5=B1=82?=
=?UTF-8?q?=E7=BA=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/app/__init__.py | 2 +-
backend/app/agent/hybrid_router.py | 242 ------
backend/app/agent/service.py | 4 +-
backend/app/agent_subgraphs/README.md | 744 ------------------
.../app/agent_subgraphs/common/__init__.py | 72 --
.../app/agent_subgraphs/research/README.md | 633 ---------------
backend/app/backend.py | 10 +-
backend/app/core/__init__.py | 1 +
.../common => core}/formatter.py | 0
.../common => core}/human_review.py | 0
.../common => core}/intent.py | 0
.../app/{agent => core}/intent_classifier.py | 0
.../common => core}/state_base.py | 0
backend/app/graph/__init__.py | 73 --
backend/app/main_graph/__init__.py | 1 +
.../{graph => main_graph}/graph_builder.py | 4 +-
backend/app/main_graph/nodes/__init__.py | 1 +
.../app/{ => main_graph}/nodes/finalize.py | 4 +-
.../app/{ => main_graph}/nodes/llm_call.py | 2 +-
.../{ => main_graph}/nodes/memory_trigger.py | 2 +-
.../{graph => main_graph/nodes}/rag_nodes.py | 2 +-
.../nodes}/react_nodes.py | 4 +-
.../nodes}/retrieve_memory.py | 0
backend/app/{ => main_graph}/nodes/router.py | 2 +-
.../app/{ => main_graph}/nodes/summarize.py | 2 +-
.../app/{ => main_graph}/nodes/tool_call.py | 4 +-
backend/app/{graph => main_graph}/state.py | 2 +-
backend/app/main_graph/tools/__init__.py | 1 +
.../tools}/graph_tools.py | 0
.../tools}/subgraph_tools.py | 12 +-
backend/app/main_graph/utils/__init__.py | 1 +
.../utils}/rag_initializer.py | 0
.../utils}/retry_utils.py | 0
.../utils}/subgraph_builder.py | 8 +-
.../utils}/visualize_graph.py | 2 +-
backend/app/nodes/__init__.py | 19 -
backend/app/subgraphs/__init__.py | 1 +
.../contact/README.md | 0
.../contact/__init__.py | 0
.../contact/api_client.py | 0
.../contact/graph.py | 2 +-
.../contact/nodes.py | 0
.../contact/state.py | 0
.../dictionary/README.md | 0
.../dictionary/__init__.py | 0
.../dictionary/api_client.py | 0
.../dictionary/graph.py | 2 +-
.../dictionary/nodes.py | 0
.../dictionary/state.py | 0
.../news_analysis/__init__.py | 0
.../news_analysis/api_client.py | 0
.../news_analysis/graph.py | 2 +-
.../news_analysis/nodes.py | 0
.../news_analysis/state.py | 0
54 files changed, 42 insertions(+), 1819 deletions(-)
delete mode 100644 backend/app/agent/hybrid_router.py
delete mode 100644 backend/app/agent_subgraphs/README.md
delete mode 100644 backend/app/agent_subgraphs/common/__init__.py
delete mode 100644 backend/app/agent_subgraphs/research/README.md
create mode 100644 backend/app/core/__init__.py
rename backend/app/{agent_subgraphs/common => core}/formatter.py (100%)
rename backend/app/{agent_subgraphs/common => core}/human_review.py (100%)
rename backend/app/{agent_subgraphs/common => core}/intent.py (100%)
rename backend/app/{agent => core}/intent_classifier.py (100%)
rename backend/app/{agent_subgraphs/common => core}/state_base.py (100%)
delete mode 100644 backend/app/graph/__init__.py
create mode 100644 backend/app/main_graph/__init__.py
rename backend/app/{graph => main_graph}/graph_builder.py (94%)
create mode 100644 backend/app/main_graph/nodes/__init__.py
rename backend/app/{ => main_graph}/nodes/finalize.py (92%)
rename backend/app/{ => main_graph}/nodes/llm_call.py (99%)
rename backend/app/{ => main_graph}/nodes/memory_trigger.py (96%)
rename backend/app/{graph => main_graph/nodes}/rag_nodes.py (99%)
rename backend/app/{graph => main_graph/nodes}/react_nodes.py (98%)
rename backend/app/{graph => main_graph/nodes}/retrieve_memory.py (100%)
rename backend/app/{ => main_graph}/nodes/router.py (97%)
rename backend/app/{ => main_graph}/nodes/summarize.py (98%)
rename backend/app/{ => main_graph}/nodes/tool_call.py (97%)
rename backend/app/{graph => main_graph}/state.py (98%)
create mode 100644 backend/app/main_graph/tools/__init__.py
rename backend/app/{graph => main_graph/tools}/graph_tools.py (100%)
rename backend/app/{graph => main_graph/tools}/subgraph_tools.py (94%)
create mode 100644 backend/app/main_graph/utils/__init__.py
rename backend/app/{agent => main_graph/utils}/rag_initializer.py (100%)
rename backend/app/{graph => main_graph/utils}/retry_utils.py (100%)
rename backend/app/{graph => main_graph/utils}/subgraph_builder.py (95%)
rename backend/app/{graph => main_graph/utils}/visualize_graph.py (97%)
delete mode 100644 backend/app/nodes/__init__.py
create mode 100644 backend/app/subgraphs/__init__.py
rename backend/app/{agent_subgraphs => subgraphs}/contact/README.md (100%)
rename backend/app/{agent_subgraphs => subgraphs}/contact/__init__.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/contact/api_client.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/contact/graph.py (98%)
rename backend/app/{agent_subgraphs => subgraphs}/contact/nodes.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/contact/state.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/dictionary/README.md (100%)
rename backend/app/{agent_subgraphs => subgraphs}/dictionary/__init__.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/dictionary/api_client.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/dictionary/graph.py (97%)
rename backend/app/{agent_subgraphs => subgraphs}/dictionary/nodes.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/dictionary/state.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/news_analysis/__init__.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/news_analysis/api_client.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/news_analysis/graph.py (96%)
rename backend/app/{agent_subgraphs => subgraphs}/news_analysis/nodes.py (100%)
rename backend/app/{agent_subgraphs => subgraphs}/news_analysis/state.py (100%)
diff --git a/backend/app/__init__.py b/backend/app/__init__.py
index 2bd75d5..529cfa2 100644
--- a/backend/app/__init__.py
+++ b/backend/app/__init__.py
@@ -3,6 +3,6 @@ AI Agent 应用模块
"""
from .agent.service import AIAgentService
-from .graph.graph_tools import AVAILABLE_TOOLS, TOOLS_BY_NAME
+from app.main_graph.graph_tools import AVAILABLE_TOOLS, TOOLS_BY_NAME
__all__ = ["AIAgentService", "AVAILABLE_TOOLS", "TOOLS_BY_NAME"]
diff --git a/backend/app/agent/hybrid_router.py b/backend/app/agent/hybrid_router.py
deleted file mode 100644
index 633cc83..0000000
--- a/backend/app/agent/hybrid_router.py
+++ /dev/null
@@ -1,242 +0,0 @@
-# backend/app/agent/hybrid_router.py
-
-from enum import Enum
-from typing import Optional, List, Dict, Any
-from dataclasses import dataclass
-import sys
-import os
-
-# 添加项目路径
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
-
-from app.agent.intent_classifier import IntentClassifier, IntentType, get_intent_classifier
-
-
-class RouterAction(Enum):
- """路由动作"""
- FAST_RAG = "fast_rag" # 快速 RAG 路径
- FAST_TOOL = "fast_tool" # 快速工具路径
- REACT_LOOP = "react_loop" # React 循环路径
- DIRECT_ANSWER = "direct_answer" # 直接回答
- CLARIFY = "clarify" # 澄清反问
-
-
-@dataclass
-class RouterDecision:
- """路由决策结果"""
- action: RouterAction
- intent: IntentType
- confidence: float
- reasoning: str
- metadata: Dict[str, Any] = None
-
-
-class HybridRouter:
- """混合路由决策器"""
-
- def __init__(
- self,
- intent_classifier: IntentClassifier,
- rag_pipeline = None,
- tool_registry: Dict[str, Any] = None,
- react_graph = None
- ):
- self.classifier = intent_classifier
- self.rag = rag_pipeline
- self.tools = tool_registry or {}
- self.react_graph = react_graph
-
- async def route(self, user_input: str, context: Optional[str] = None) -> RouterDecision:
- """
- 路由决策
-
- Args:
- user_input: 用户输入
- context: 对话上下文
-
- Returns:
- RouterDecision
- """
- # 1. 意图分类
- intent_result = await self.classifier.classify(user_input, context)
-
- # 2. 根据意图路由
- decision = self._make_decision(intent_result, user_input)
-
- return decision
-
- def _make_decision(self, intent_result: IntentResult, user_input: str) -> RouterDecision:
- """根据意图做出路由决策"""
- intent = intent_result.intent_type
- confidence = intent_result.confidence
-
- # 低置信度 → 走 React 循环(更安全)
- if confidence < 0.6:
- return RouterDecision(
- action=RouterAction.REACT_LOOP,
- intent=intent,
- confidence=confidence,
- reasoning=f"置信度 {confidence:.2f} 较低,走 React 循环"
- )
-
- # 根据意图路由
- routing_map = {
- IntentType.KNOWLEDGE: RouterAction.FAST_RAG,
- IntentType.REALTIME: RouterAction.FAST_TOOL,
- IntentType.ACTION: RouterAction.FAST_TOOL,
- IntentType.CHITCHAT: RouterAction.DIRECT_ANSWER,
- IntentType.CLARIFY: RouterAction.CLARIFY,
- IntentType.MIXED: RouterAction.REACT_LOOP,
- IntentType.UNKNOWN: RouterAction.REACT_LOOP,
- }
-
- action = routing_map.get(intent, RouterAction.REACT_LOOP)
-
- return RouterDecision(
- action=action,
- intent=intent,
- confidence=confidence,
- reasoning=intent_result.reasoning
- )
-
- async def execute(self, decision: RouterDecision, user_input: str, thread_id: str) -> str:
- """
- 根据决策执行对应路径
-
- Args:
- decision: 路由决策
- user_input: 用户输入
- thread_id: 线程 ID
-
- Returns:
- 最终答案
- """
- if decision.action == RouterAction.FAST_RAG:
- return await self._execute_fast_rag(user_input)
- elif decision.action == RouterAction.FAST_TOOL:
- return await self._execute_fast_tool(user_input)
- elif decision.action == RouterAction.DIRECT_ANSWER:
- return await self._execute_direct_answer(user_input)
- elif decision.action == RouterAction.CLARIFY:
- return await self._execute_clarify(user_input)
- elif decision.action == RouterAction.REACT_LOOP:
- return await self._execute_react_loop(user_input, thread_id)
- else:
- return await self._execute_react_loop(user_input, thread_id)
-
- async def _execute_fast_rag(self, user_input: str) -> str:
- """快速 RAG 路径"""
- print("🚀 执行快速 RAG 路径")
-
- # 1. 检索文档(如果 RAG 可用)
- docs = []
- if self.rag and hasattr(self.rag, 'aretrieve'):
- docs = await self.rag.aretrieve(user_input)
-
- # 2. 格式化上下文
- context = ""
- if self.rag and hasattr(self.rag, 'format_context'):
- context = self.rag.format_context(docs)
-
- # 3. 生成回答
- prompt = f"""
- 请根据以下文档回答用户问题。
-
- 参考文档:
- {context or "(无文档)"}
-
- 用户问题: {user_input}
- """
-
- response = await self.classifier.llm.ainvoke(prompt)
- return response.content
-
- async def _execute_fast_tool(self, user_input: str) -> str:
- """快速工具路径"""
- print("🚀 执行快速工具路径")
-
- # 这里简化处理,实际项目中:
- # 1. 解析需要调用的工具
- # 2. 生成工具参数
- # 3. 执行工具
- # 4. 生成回答
-
- return "快速工具路径:功能开发中..."
-
- async def _execute_direct_answer(self, user_input: str) -> str:
- """直接回答路径"""
- print("💬 执行直接回答路径")
-
- prompt = f"""
- 用户说: {user_input}
-
- 请友好回应。
- """
-
- response = await self.classifier.llm.ainvoke(prompt)
- return response.content
-
- async def _execute_clarify(self, user_input: str) -> str:
- """澄清反问路径"""
- print("❓ 执行澄清反问路径")
-
- prompt = f"""
- 用户说: {user_input}
-
- 用户的问题不太明确,请礼貌地询问更多细节。
- """
-
- response = await self.classifier.llm.ainvoke(prompt)
- return response.content
-
- async def _execute_react_loop(self, user_input: str, thread_id: str) -> str:
- """React 循环路径"""
- print("🔄 执行 React 循环路径")
-
- # 这里调用现有的完整 LangGraph 流程
- # 具体实现根据您的项目结构
- return "React 循环路径:调用现有 LangGraph..."
-
-
-# 便捷函数
-async def hybrid_agent_route(
- user_input: str,
- thread_id: str,
- context: Optional[str] = None
-) -> str:
- """
- 混合 Agent 路由入口函数
-
- Args:
- user_input: 用户输入
- thread_id: 线程 ID
- context: 对话上下文
-
- Returns:
- 最终答案
- """
- # 获取依赖(实际项目应该用依赖注入)
- classifier = get_intent_classifier()
- # rag = get_rag_pipeline()
- # tools = get_tool_registry()
- # graph = get_react_graph()
-
- # 创建路由器
- router = HybridRouter(
- intent_classifier=classifier,
- rag_pipeline=None, # 实际项目中传入
- tool_registry={}, # 实际项目中传入
- react_graph=None # 实际项目中传入
- )
-
- # 路由决策
- decision = await router.route(user_input, context)
- print(f"🧭 路由决策: {decision.action} (意图: {decision.intent}, 置信度: {decision.confidence:.2f})")
- print(f"📝 推理: {decision.reasoning}")
-
- # 执行
- # result = await router.execute(decision, user_input, thread_id)
- # return result
-
- # 临时返回
- return f"路由决策: {decision.action}"
\ No newline at end of file
diff --git a/backend/app/agent/service.py b/backend/app/agent/service.py
index 51a3091..affa401 100644
--- a/backend/app/agent/service.py
+++ b/backend/app/agent/service.py
@@ -7,8 +7,8 @@ import json
import asyncio
# 本地模块
-from ..graph.graph_builder import GraphBuilder, GraphContext
-from ..graph.graph_tools import AVAILABLE_TOOLS, TOOLS_BY_NAME
+from app.main_graph.graph_builder import GraphBuilder, GraphContext
+from app.main_graph.graph_tools import AVAILABLE_TOOLS, TOOLS_BY_NAME
from ..model_services.chat_services import get_all_chat_services, LocalVLLMChatProvider
from .rag_initializer import init_rag_tool
from .intent_classifier import get_intent_classifier
diff --git a/backend/app/agent_subgraphs/README.md b/backend/app/agent_subgraphs/README.md
deleted file mode 100644
index cb6d6e0..0000000
--- a/backend/app/agent_subgraphs/README.md
+++ /dev/null
@@ -1,744 +0,0 @@
-# LangGraph Agent - 全能个人助手系统
-
-该模块负责将个人助手从"查询型"升级为"全能执行型",通过 LangGraph 子图架构实现通讯录管理、智能词典、增强研究分析等核心功能。
-
----
-
-## 🔧 公共工具与共享组件
-
-三个子图共享一套统一的基础设施和通用工具,避免重复实现,确保架构一致。
-
-### 公共工具架构
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ 公共工具层 (Shared Tools) │
-├─────────────────────────────────────────────────────────────────┤
-│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
-│ │意图理解工具 │ │人工审核工具 │ │格式化输出 │ │状态管理│ │
-│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │
-│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
-│ │检查点持久化 │ │条件路由 │ │LLM 调用 │ │数据库 │ │
-│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ 子图层 (Subgraphs) │
-├─────────────────────────────────────────────────────────────────┤
-│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
-│ │ 通讯录子图 │ │ 智能词典子图│ │ 研究分析子图│ │
-│ └──────────────┘ └──────────────┘ └──────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-### 公共工具详解
-
-#### 1. 意图理解工具 (Intent Understanding Tool)
-
-**技术栈**:LangChain LLM + 少样本提示词 + 结构化输出
-
-**使用方法**:
-```python
-from agent_subgraphs.common.intent import parse_intent
-
-result = parse_intent(
- user_input="添加张三电话13800138000",
- intent_categories=["contact", "dictionary", "research", "chat"]
-)
-# 返回: {
-# "intent_type": "contact",
-# "sub_intent": "add",
-# "extracted_info": {"name": "张三", "phone": "13800138000"}
-# }
-```
-
-**实现逻辑**:
-- 使用 LLM 进行意图分类,输出结构化 JSON
-- 关键词匹配兜底(如"保存"、"添加" → contact)
-- 自动提取关键信息(实体、参数)
-- 支持自定义意图分类器
-
-**所有子图共用**:在 `agent_subgraphs/common/intent.py`
-
----
-
-#### 2. 人工审核工具 (Human-in-the-loop Tool)
-
-**技术栈**:LangGraph `interrupt()` + 状态持久化
-
-**使用方法**:
-```python
-from agent_subgraphs.common.human_loop import human_approval_node
-
-def email_send_workflow(state: dict) -> dict:
- # 生成邮件草稿...
- state["pending_action"] = {"type": "email_send", "draft": draft}
- return human_approval_node(state) # 挂起等待用户确认
-```
-
-**实现逻辑**:
-- 使用 `interrupt()` 触发挂起
-- 支持三种操作:确认、修改、取消
-- 超时自动取消(可配置超时时间)
-- 用户反馈结构化存储
-- 支持断点续作
-
-**共享位置**:`agent_subgraphs/common/human_loop.py`
-
-**应用场景**:
-- 通讯录:邮件发送、联系人删除
-- 研究分析:信息源确认、报告结构调整
-- 智能词典:批量删除确认
-
----
-
-#### 3. 格式化输出工具 (Formatting Tool)
-
-**技术栈**:Jinja2 模板 + Markdown 生成
-
-**使用方法**:
-```python
-from agent_subgraphs.common.format import format_output
-
-result = format_output(
- template="contact_result",
- data={"contact": contact_data, "action": "added"}
-)
-```
-
-**实现逻辑**:
-- 预定义输出模板库
-- 支持 Markdown、HTML、纯文本三种格式
-- 自动处理列表、表格等复杂结构
-- 支持用户自定义模板
-
-**共享位置**:`agent_subgraphs/common/format.py`
-
----
-
-#### 4. 检查点持久化工具 (Checkpoint Tool)
-
-**技术栈**:LangGraph CheckpointSaver + SQLite / PostgreSQL
-
-**使用方法**:
-```python
-from agent_subgraphs.common.checkpoint import get_checkpointer
-
-checkpointer = get_checkpointer(db_url="sqlite:///checkpoints.db")
-
-# 在图编译时传入
-graph = workflow.compile(checkpointer=checkpointer)
-```
-
-**实现逻辑**:
-- 自动在每个节点执行后保存检查点
-- 支持断点续作
-- 状态版本管理
-- 支持查询历史状态
-
-**共享位置**:`agent_subgraphs/common/checkpoint.py`
-
----
-
-#### 5. 条件路由工具 (Conditional Routing Tool)
-
-**技术栈**:LangGraph 条件边 + 路由函数
-
-**使用方法**:
-```python
-from agent_subgraphs.common.routing import route_by_intent
-
-def my_router(state: dict) -> str:
- return route_by_intent(
- state,
- {
- "translate": "translate_node",
- "lookup": "lookup_node",
- }
- )
-```
-
-**实现逻辑**:
-- 标准化的意图路由
-- 支持复杂条件判断
-- 路由函数可组合
-- 自动处理默认分支
-
-**共享位置**:`agent_subgraphs/common/routing.py`
-
----
-
-#### 6. LLM 调用工具 (LLM Invocation Tool)
-
-**技术栈**:LangChain ChatOpenAI + 重试 + 流式输出
-
-**使用方法**:
-```python
-from agent_subgraphs.common.llm import call_llm, call_llm_stream
-
-# 同步调用
-result = call_llm(prompt="翻译这句话", system_prompt="你是翻译官")
-
-# 流式调用
-async for chunk in call_llm_stream(prompt="写一篇文章"):
- print(chunk.content, end="")
-```
-
-**实现逻辑**:
-- 统一的 LLM 调用接口
-- 自动重试(指数退避)
-- 支持流式和非流式
-- Token 计数和监控
-- 模型 fallback 机制
-
-**共享位置**:`agent_subgraphs/common/llm.py`
-
----
-
-#### 7. 数据库工具 (Database Tool)
-
-**技术栈**:SQLAlchemy + PostgreSQL / SQLite
-
-**使用方法**:
-```python
-from agent_subgraphs.common.db import get_db, add_record, query_records
-
-# 获取 session
-with get_db() as db:
- # 添加记录
- add_record(db, Contact, {"name": "张三", "phone": "13800138000"})
- # 查询记录
- contacts = query_records(db, Contact, filters={"name": "张三"})
-```
-
-**实现逻辑**:
-- 统一的 ORM 会话管理
-- 标准 CRUD 操作封装
-- 支持事务
-- 自动错误处理
-
-**共享位置**:`agent_subgraphs/common/db.py`
-
----
-
-#### 8. 状态基类工具 (State Base Classes)
-
-**技术栈**:TypedDict + 类型注解
-
-**使用方法**:
-```python
-from agent_subgraphs.common.state import BaseSubgraphState
-
-class ContactState(BaseSubgraphState):
- # 继承基础字段
- contact_data: Optional[dict]
- # 自定义字段...
-```
-
-**实现逻辑**:
-- 预定义基础状态字段
-- 类型安全
-- 状态验证
-- 状态合并辅助函数
-
-**共享位置**:`agent_subgraphs/common/state.py`
-
----
-
-### 公共工具目录结构
-
-```
-agent_subgraphs/
-├── common/ # 公共工具层
-│ ├── __init__.py
-│ ├── intent.py # 意图理解工具
-│ ├── human_loop.py # 人工审核工具
-│ ├── format.py # 格式化输出工具
-│ ├── checkpoint.py # 检查点持久化工具
-│ ├── routing.py # 条件路由工具
-│ ├── llm.py # LLM 调用工具
-│ ├── db.py # 数据库工具
-│ ├── state.py # 状态基类
-│ └── prompts/ # 公共提示词模板
-│ ├── intent.j2
-│ └── format.j2
-├── contact/ # 通讯录子图(简化版,使用公共工具)
-├── dictionary/ # 智能词典子图(简化版,使用公共工具)
-└── research/ # 研究分析子图(简化版,使用公共工具)
-```
-
----
-
-### 公共配置项
-
-所有子图共享的配置项(在 `.env` 中配置):
-
-```env
-# LLM 配置
-LLM_PROVIDER=deepseek
-LLM_MODEL=deepseek-chat
-LLM_API_KEY=***
-LLM_TEMPERATURE=0.7
-LLM_MAX_TOKENS=2000
-
-# 数据库配置
-DB_URL=postgresql://user:pass@localhost/agent_db
-
-# 检查点配置
-CHECKPOINT_DB_URL=sqlite:///checkpoints.db
-
-# 人工审核配置
-HUMAN_LOOP_TIMEOUT=3600
-
-# 格式化配置
-DEFAULT_OUTPUT_FORMAT=markdown
-```
-
----
-
-### 使用公共工具开发新子图
-
-创建新子图的步骤:
-
-1. **继承状态基类**
-```python
-from agent_subgraphs.common.state import BaseSubgraphState
-
-class MySubgraphState(BaseSubgraphState):
- my_field: str
-```
-
-2. **使用公共意图理解**
-```python
-from agent_subgraphs.common.intent import parse_intent
-
-def intent_node(state: MySubgraphState) -> MySubgraphState:
- result = parse_intent(state["user_input"], ["my_intents])
- state.update(result)
- return state
-```
-
-3. **使用公共人工审核**
-```python
-from agent_subgraphs.common.human_loop import human_approval_node
-
-def my_workflow(state: MySubgraphState) -> MySubgraphState:
- return human_approval_node(state)
-```
-
-4. **使用公共格式化输出**
-```python
-from agent_subgraphs.common.format import format_output
-
-def format_node(state: MySubgraphState) -> MySubgraphState:
- state["final_result"] = format_output("my_template", state)
- return state
-```
-
----
-
-## 📑 目录导航
-
-- [核心功能](#-核心功能) - 三大子图功能和技术特性
-- [技术架构](#️-技术架构) - 技术栈、子图架构图、数据流
-- [子图设计](#-子图设计) - 三个核心子图的详细说明
-- [状态管理](#-状态管理) - 主状态和子状态定义
-- [安全与边界](#️-安全与边界) - 安全机制和边界控制
-- [快速开始](#-快速开始) - 开发环境搭建
-- [实现指南](#-实现指南) - 子图开发、工具集成
-- [未来规划](#-未来规划) - 多模态、流式输出等
-
----
-
-## 🎯 核心功能
-
-### 三大核心子图
-
-| 子图模块 | 功能概述 | 关键特性 |
-|---------|---------|---------|
-| **通讯录子图** | 联系人 CRUD、邮件读取与审核、外发邮件、智能嗅探 | 人工审核强制、敏感信息加密、IMAP 邮箱绑定 |
-| **智能词典子图** | 翻译、查词、每日一词、专业名词提炼、生词本管理 | 联想记忆法、艾宾浩斯遗忘曲线、Anki 导出 |
-| **研究分析子图** | 联网搜索、报告生成、引用溯源、可视化图表 | 人工干预点、可定制报告结构、引用验证 |
-
-### 通用机制
-
-- ✅ **人工审核(Human-in-the-loop)**:通用节点,用于邮件发送、重要操作前的确认
-- ✅ **自动联系人嗅探**:对话中出现"人名+联系方式"时,主动询问是否保存
-- ✅ **流式输出**:所有 LLM 生成内容均采用流式传输,提升交互体验
-- ✅ **长期记忆**:PostgreSQL + pgvector 实现持久化记忆和语义检索
-
----
-
-## 🏗️ 技术架构
-
-### 技术栈总览
-
-| 层级 | 组件 | 技术选型 | 版本 | 说明 |
-|------|------|---------|------|------|
-| **Agent 框架** | 工作流编排 | LangGraph + LangChain | latest | 子图架构,状态机驱动 |
-| **LLM 服务** | 模型调用 | 智谱 AI / DeepSeek / 本地模型 | latest | 多模型路由 |
-| **向量数据库** | 语义检索 | Qdrant / pgvector | v1.12+ | 对话记忆、联系人语义索引 |
-| **关系数据库** | 结构化存储 | PostgreSQL | v16 | 联系人、生词本、邮件配置 |
-| **邮件协议** | IMAP/SMTP | `imaplib` / `smtplib` | 内置 | 邮件读取和发送 |
-| **后端框架** | API 服务 | FastAPI + Uvicorn | v0.115+ | 子图执行、状态管理 |
-
-### 主图架构流程图
-
-```mermaid
-graph TB
- Start[START] --> Intent[意图分类节点]
-
- Intent -->|contact| ContactSubgraph[通讯录子图]
- Intent -->|dictionary| DictSubgraph[智能词典子图]
- Intent -->|research| ResearchSubgraph[研究分析子图]
- Intent -->|chat| ChatNode[普通对话节点]
-
- ContactSubgraph --> Final[最终响应]
- DictSubgraph --> Final
- ResearchSubgraph --> Final
- ChatNode --> Final
-
- Final --> End[END]
-
- style Start fill:#e1f5ff
- style Intent fill:#fff4e1
- style ContactSubgraph fill:#e8f5e9
- style DictSubgraph fill:#f3e5f5
- style ResearchSubgraph fill:#ffebee
- style Final fill:#fff9c4
-```
-
-### 子图架构总览
-
-```mermaid
-graph TB
- MainGraph[主图
MainState]
-
- MainGraph --> ContactSub[通讯录子图
ContactSubState]
- MainGraph --> DictSub[词典子图
DictSubState]
- MainGraph --> ResearchSub[研究子图
ResearchSubState]
-
- ContactSub --> ContactNodes[内部节点
parse_intent
add_contact
list_contacts
generate_draft
human_approval
send_email]
- DictSub --> DictNodes[内部节点
translate
lookup
extract_terms
daily_word]
- ResearchSub --> ResearchNodes[内部节点
decompose
web_search
extract_info
generate_report]
-
- ContactNodes --> PG[(PostgreSQL
联系人)]
- DictNodes --> PG2[(PostgreSQL
生词本)]
- ResearchNodes --> Qdrant[(Qdrant
向量检索)]
-
- style MainGraph fill:#e1f5ff
- style ContactSub fill:#e8f5e9
- style DictSub fill:#f3e5f5
- style ResearchSub fill:#ffebee
-```
-
-### 状态传递机制
-
-```
-主状态 (MainState)
- │
- ├─→ input: {user_input: messages[-1].content}
- │
- ▼
-子图状态 (SubState)
- │
- ├─→ 内部处理...
- │
- ▼
-output: {messages: [AIMessage(final_result)], last_action: sub_state}
- │
- ▼
-主状态更新
-```
-
----
-
-## 📂 项目结构
-
-```
-Agent1/
-├── agent_subgraphs/ # LangGraph 子图模块
-│ ├── __init__.py
-│ ├── contact/ # 通讯录子图
-│ │ ├── README.md
-│ │ ├── __init__.py
-│ │ ├── state.py # 子图状态定义
-│ │ ├── graph.py # 子图构建器
-│ │ ├── nodes.py # 子图节点实现
-│ │ ├── tools.py # 子图工具集
-│ │ └── prompts.py # 提示词模板
-│ ├── dictionary/ # 智能词典子图
-│ │ ├── README.md
-│ │ ├── __init__.py
-│ │ ├── state.py
-│ │ ├── graph.py
-│ │ ├── nodes.py
-│ │ ├── tools.py
-│ │ └── prompts.py
-│ └── research/ # 研究分析子图
-│ ├── README.md
-│ ├── __init__.py
-│ ├── state.py
-│ ├── graph.py
-│ ├── nodes.py
-│ ├── tools.py
-│ └── prompts.py
-├── backend/ # 现有后端模块
-│ └── app/
-│ ├── graph/ # 主图构建
-│ │ ├── graph_builder.py # 主图 + 子图集成
-│ │ └── state.py # 主状态定义
-│ └── ...
-└── ...
-```
-
----
-
-## 🎯 状态管理
-
-### 主状态定义 (MainState)
-
-```python
-from typing import TypedDict, List, Optional, Annotated
-from langchain_core.messages import BaseMessage
-from langgraph.graph import add_messages
-
-class MainState(TypedDict):
- messages: Annotated[List[BaseMessage], add_messages]
- intent: str # 顶层意图:contact / dictionary / research / chat
- sub_intent: str # 细分意图
-
- # 工具通用
- tool_call: Optional[dict] # 当前要执行的工具调用
- tool_result: str
-
- # 控制流
- next_node: str
- human_feedback: Optional[str] # 用于挂起重启
-
- # 子图结果
- last_contact_action: Optional[dict]
- last_dict_action: Optional[dict]
- last_research_action: Optional[dict]
-```
-
-### 状态映射函数
-
-```python
-# 通讯录子图输入映射
-def contact_input_mapper(state: MainState) -> dict:
- return {
- "user_input": state["messages"][-1].content,
- }
-
-# 通讯录子图输出映射
-def contact_output_mapper(sub_state: dict, original: MainState) -> dict:
- return {
- "messages": [AIMessage(content=sub_state["final_result"])],
- "last_contact_action": sub_state,
- }
-```
-
----
-
-## 🎯 主图实现
-
-### 主图构建器
-
-```python
-from langgraph.graph import StateGraph, START, END
-from agent_subgraphs.contact import build_contact_subgraph
-from agent_subgraphs.dictionary import build_dict_subgraph
-from agent_subgraphs.research import build_research_subgraph
-
-def build_main_graph() -> StateGraph:
- main_graph = StateGraph(MainState)
-
- # 添加子图节点
- main_graph.add_node(
- "contact_module",
- build_contact_subgraph(),
- input=contact_input_mapper,
- output=contact_output_mapper,
- )
- main_graph.add_node(
- "dict_module",
- build_dict_subgraph(),
- input=dict_input_mapper,
- output=dict_output_mapper,
- )
- main_graph.add_node(
- "research_module",
- build_research_subgraph(),
- input=research_input_mapper,
- output=research_output_mapper,
- )
- main_graph.add_node("chat_node", chat_node)
- main_graph.add_node("final_response", final_response_node)
-
- # 主图路由
- main_graph.add_conditional_edges(
- START,
- route_main_intent,
- {
- "contact": "contact_module",
- "dictionary": "dict_module",
- "research": "research_module",
- "chat": "chat_node",
- }
- )
-
- # 所有路径汇聚到最终响应
- main_graph.add_edge("contact_module", "final_response")
- main_graph.add_edge("dict_module", "final_response")
- main_graph.add_edge("research_module", "final_response")
- main_graph.add_edge("chat_node", "final_response")
- main_graph.add_edge("final_response", END)
-
- return main_graph.compile()
-
-def route_main_intent(state: MainState) -> str:
- """顶层意图分类"""
- user_input = state["messages"][-1].content
- # 使用 LLM 分类
- # 返回 contact / dictionary / research / chat
-```
-
----
-
-## 🔒 安全与边界
-
-### 安全机制
-
-| 风险点 | 对策 | 实现位置 |
-|--------|------|---------|
-| 邮箱密码泄露 | 使用环境变量存储,永不写入日志 | `agent_subgraphs/contact/tools.py` |
-| 恶意邮件发送 | 强制人工审核,单日发送数量限制 | 人工审核节点 |
-| 联系人隐私 | 向量检索结果脱敏展示,仅交互时完整显示 | 通讯录子图节点 |
-| 搜索内容安全 | 过滤成人内容,屏蔽高风险域名 | 研究子图搜索工具 |
-| 敏感词输出 | 流式输出后处理过滤 | 最终响应节点 |
-
-### 人工审核节点
-
-```python
-from langgraph.graph import interrupt
-
-def human_approval_node(state: dict) -> dict:
- """人工审核节点:挂起图,等待外部输入"""
- pending_action = state["pending_action"]
-
- # 触发中断,等待外部通过 update_state 传入 human_feedback
- return interrupt(
- {
- "type": "human_approval",
- "message": f"请确认操作:{pending_action}",
- "options": ["确认", "修改", "取消"],
- }
- )
-```
-
----
-
-## 🚀 快速开始
-
-### 环境配置
-
-```bash
-# 激活虚拟环境
-source venv/bin/activate
-
-# 安装依赖(新增)
-pip install langgraph langchain-experimental
-```
-
-### 配置文件
-
-在 `.env` 中新增:
-
-```env
-# 通讯录模块
-IMAP_SERVER=imap.qq.com
-IMAP_PORT=993
-SMTP_SERVER=smtp.qq.com
-SMTP_PORT=587
-EMAIL_USER=your_email@qq.com
-EMAIL_PASSWORD=your_auth_code
-
-# 词典模块
-DEEPL_API_KEY=your_deepl_key
-YOUDAO_API_KEY=your_youdao_key
-
-# 研究模块
-SEARCH_API_KEY=your_search_key
-```
-
-### 运行测试
-
-```python
-from backend.app.graph.graph_builder import build_main_graph
-
-# 编译主图
-graph = build_main_graph()
-
-# 调用子图
-result = graph.invoke({
- "messages": [HumanMessage(content="添加张三电话 13800138000")]
-})
-
-print(result["messages"][-1].content)
-```
-
----
-
-## 📖 实现指南
-
-### 添加新子图
-
-1. 在 `agent_subgraphs/` 下创建新文件夹
-2. 创建 `state.py` 定义子图状态
-3. 创建 `nodes.py` 实现子图节点
-4. 创建 `graph.py` 构建子图
-5. 在主图 `graph_builder.py` 中注册新子图
-
-### 子图开发最佳实践
-
-- ✅ 子图拥有独立的状态,避免与主状态命名冲突
-- ✅ 使用 `input`/`output` 映射函数进行状态转换
-- ✅ 子图内部节点之间直接连接,主图只负责路由到子图入口
-- ✅ 将工具封装在子图内部,通过节点调用
-- ✅ 提供子图级别的单元测试
-
----
-
-## 🎯 未来规划
-
-### Phase 1: 基础功能(当前)
-
-- [ ] 通讯录子图完整实现
-- [ ] 智能词典子图完整实现
-- [ ] 研究分析子图完整实现
-- [ ] 主图集成和状态管理
-
-### Phase 2: 增强功能
-
-- [ ] 流式输出改造(所有 LLM 调用)
-- [ ] 多模态语音输入(STT)
-- [ ] 可视化图表生成
-- [ ] Anki 生词本导出
-
-### Phase 3: 高级特性
-
-- [ ] 智能家居控制子图
-- [ ] 日程管理子图
-- [ ] 更多工具集成
-
----
-
-## 📚 相关文档
-
-- [通讯录子图 README](./contact/README.md) - 详细了解通讯录模块
-- [智能词典子图 README](./dictionary/README.md) - 详细了解词典模块
-- [研究分析子图 README](./research/README.md) - 详细了解研究模块
-- [主项目 README](../README.md) - 了解整体架构
-
diff --git a/backend/app/agent_subgraphs/common/__init__.py b/backend/app/agent_subgraphs/common/__init__.py
deleted file mode 100644
index c66cecd..0000000
--- a/backend/app/agent_subgraphs/common/__init__.py
+++ /dev/null
@@ -1,72 +0,0 @@
-"""
-公共工具模块
-提供可复用的基础组件
-
-导出:
-- formatter.py: 格式化输出工具
-- intent.py: 意图理解工具
-- human_review.py: 人工审核工具
-- state_base.py: 状态基类工具
-"""
-
-from .formatter import (
- MarkdownFormatter,
- TemplateManager,
- OutputRenderer,
- PresetTemplates
-)
-
-from .intent import (
- # React 模式 API
- ReasoningAction,
- RetrievalConfig,
- ReasoningResult,
- ReactIntentReasoner,
- react_reason,
- react_reason_async,
- get_route_by_reasoning
-)
-
-from .human_review import (
- ReviewStatus,
- HumanReview,
- HumanReviewStore,
- InMemoryReviewStore,
- HumanReviewNode,
- ReviewManager
-)
-
-from .state_base import (
- BaseState,
- Phase,
- TokenUsage,
- StateUtils
-)
-
-__all__ = [
- # formatter
- "MarkdownFormatter",
- "TemplateManager",
- "OutputRenderer",
- "PresetTemplates",
- # intent - React 模式
- "ReasoningAction",
- "RetrievalConfig",
- "ReasoningResult",
- "ReactIntentReasoner",
- "react_reason",
- "react_reason_async",
- "get_route_by_reasoning",
- # human_review
- "ReviewStatus",
- "HumanReview",
- "HumanReviewStore",
- "InMemoryReviewStore",
- "HumanReviewNode",
- "ReviewManager",
- # state_base
- "BaseState",
- "Phase",
- "TokenUsage",
- "StateUtils"
-]
diff --git a/backend/app/agent_subgraphs/research/README.md b/backend/app/agent_subgraphs/research/README.md
deleted file mode 100644
index 1a93ee5..0000000
--- a/backend/app/agent_subgraphs/research/README.md
+++ /dev/null
@@ -1,633 +0,0 @@
-# 研究分析子图 (Research Analysis Subgraph)
-
-该子图负责处理研究分析相关的请求,基于 LangGraph 状态机编排多阶段研究流水线,支持联网搜索、信息提取与验证、结构化报告生成等功能。子图设计遵循"可中断、可恢复、质量优先、透明可追溯"原则,通过内置人工干预点和多源交叉验证保障输出质量。
-
-> **使用公共工具**:意图理解、人工审核、格式化输出、检查点持久化、条件路由、LLM 调用、数据库工具、状态基类
-
----
-
-## 🎯 核心架构
-
-### 技术栈
-
-| 层级 | 组件 | 说明 |
-|:-----|:-----|:-----|
-| **编排框架** | LangGraph StateGraph | 状态机驱动的子图工作流编排,支持条件路由与中断恢复 |
-| **LLM 服务** | 智谱 AI / DeepSeek API | 意图理解、任务分解、信息提取、报告生成等认知任务(使用公共 LLM 工具) |
-| **向量检索** | Qdrant / pgvector | 历史研究结果语义检索,实现记忆增强研究 |
-| **关系存储** | PostgreSQL | 研究项目、报告版本、引用记录持久化(使用公共数据库工具) |
-| **搜索服务** | 多源搜索 API 网关 | 统一接入通用搜索、学术数据库、专业知识库等外部信息源 |
-| **图表生成** | 图表服务 | 趋势图、对比图、分布图等可视化图表自动生成 |
-
-### 子图分层架构
-
-子图采用分层设计,各层职责清晰、边界明确,便于独立测试与演化。
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ 主图 (Main Graph) │
-└──────────────────────────────┬──────────────────────────────────┘
- │ 状态映射 / 结果聚合
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ 研究分析子图接口层 │
-│ - 状态转换:主状态 ↔ 子图状态(使用公共状态基类) │
-│ - 错误传播与优雅降级 │
-└──────────────────────────────┬──────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ 工作流编排层 │
-│ - 节点调度与条件路由(使用公共路由工具) │
-│ - 人工干预点暂停/恢复管理(使用公共审核工具) │
-│ - 状态持久化与检查点(使用公共检查点工具) │
-└──────────────────────────────┬──────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ 节点层 │
-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
-│ │意图理解 │ │任务分解 │ │搜索执行 │ │信息提取 │ │报告生成│ │
-│ │(公共工具)│ │ │ │ │ │ │ │ │ │
-│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └────────┘ │
-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
-│ │信息源筛选│ │信息整合 │ │结构生成 │ │人工审核 │ │
-│ │ │ │ │ │ │ │(公共) │ │
-│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
-└──────────────────────────────┬──────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ 工具层 │
-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
-│ │搜索工具集│ │提取工具集│ │验证工具集│ │图表工具集│ │
-│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-### 数据流总览
-
-研究分析子图的数据流向遵循"输入 → 理解 → 检索 → 处理 → 整合 → 生成 → 审核 → 输出"的线性推进路径,每个阶段的状态变更均被完整记录,支持断点续作。
-
-```
-用户研究请求
- │
- ▼
-┌─────────────┐
-│ 意图理解 │ ← 使用公共意图理解工具
-└──────┬──────┘
- │
- └─────┐
- ▼
-┌─────────────┐
-│ 任务分解 │
-└──────┬──────┘
- │
- ▼
-┌─────────────┐ ┌─────────────┐
-│ 多源搜索 │────▶│ 信息源筛选 │
-└─────────────┘ └──────┬──────┘
- │
- ▼
-┌─────────────┐ ┌─────────────┐
-│ 报告生成 │◀────│ 报告结构确认│
-└──────┬──────┘ └─────────────┘
- │
- ▼
-┌─────────────┐
-│ 格式输出 │ ← 使用公共格式化工具
-└──────┬──────┘
- │
- ▼
- 返回主图
-```
-
----
-
-## 📂 模块与文件结构
-
-子图代码组织遵循 LangGraph 最佳实践,核心模块职责分明。
-
-```
-app/research/
-├── __init__.py
-├── graph.py # 子图构建入口,定义状态图与路由
-├── state.py # 子图状态定义(继承公共状态基类)
-├── nodes/ # 节点实现
-│ ├── __init__.py
-│ ├── decomposition.py # 任务分解节点
-│ ├── search.py # 搜索执行节点
-│ ├── extraction.py # 信息提取节点
-│ ├── integration.py # 信息整合与冲突检测节点
-│ ├── structure.py # 报告结构生成节点
-│ └── generation.py # 报告生成节点
-├── tools/ # 子图特有工具集
-│ ├── search/ # 搜索工具集
-│ ├── extract/ # 信息提取工具集
-│ ├── verify/ # 信息验证工具集
-│ └── chart/ # 图表生成工具集
-└── persistence/ # (使用公共检查点工具,无需单独实现)
-```
-
-> **注意**:以下模块使用公共工具,无需单独实现:
-> - 意图理解节点 → 使用 `agent_subgraphs.common.intent`
-> - 人工审核节点 → 使用 `agent_subgraphs.common.human_loop`
-> - 格式输出节点 → 使用 `agent_subgraphs.common.format`
-> - 检查点持久化 → 使用 `agent_subgraphs.common.checkpoint`
-> - 条件路由 → 使用 `agent_subgraphs.common.routing`
-> - LLM 调用 → 使用 `agent_subgraphs.common.llm`
-> - 数据库操作 → 使用 `agent_subgraphs.common.db`
-
----
-
-## 🎯 演进路线与核心机制
-
-研究分析子图的能力演进分为五个层级,每一层在上一层的基座上叠加更复杂的认知与决策能力。
-
-### Level 1:基础单轮研究流水线
-
-**核心机制**:单一意图理解 → 单次搜索 → 简单提取 → 直接报告生成。
-
-- 使用 LLM 解析用户请求,生成搜索关键词。
-- 调用通用搜索引擎获取原始结果。
-- 基于规则或轻量模型提取关键信息片段。
-- 按照预设模板生成 Markdown 格式报告。
-
-**适用场景**:快速知识查询、简单概念解释。
-
-**实现指引**:子图默认配置为完整流水线的最小化变体,通过路由条件识别“简单查询”后走该分支。
-
-### Level 2:多阶段搜索与信息验证
-
-**核心机制**:引入“广度→深度→验证”三轮搜索策略,叠加信息冲突检测与多源交叉验证。
-
-- **第一轮广度搜索**:使用主要关键词并行查询多个信息源,获取广泛上下文。
-- **第二轮深度搜索**:基于首轮结果识别出的关键话题,生成细化关键词进行深入检索。
-- **第三轮验证搜索**:针对关键事实(如时间、数据、人名)执行验证性搜索,对比多个独立来源。
-- **冲突检测**:自动识别不同来源对同一事实的冲突描述,按严重程度分级标记。
-- **交叉验证评分**:对每条关键信息计算多源一致性得分,低分项触发人工审核或补充搜索。
-
-**适用场景**:市场调研、事件分析、学术资料整理等对信息准确性要求较高的任务。
-
-**实现指引**:搜索执行节点内部维护搜索轮次状态,每一轮均可动态调整关键词;信息整合节点输出冲突报告。
-
-### Level 3:人工干预点与动态路由
-
-**核心机制**:在关键决策点(信息源确认、报告结构调整)插入人工审核节点,子图挂起等待用户反馈,并根据反馈动态调整后续路由。
-
-- **信息源筛选审核**:自动筛选后的信息源列表(含可信度、时效性评分)展示给用户,用户可增删或调整优先级。
-- **报告结构审核**:生成的报告大纲与可视化建议展示给用户,用户可调整章节顺序、增删模块。
-- **路由反馈闭环**:
- - 用户要求添加信息源 → 返回搜索执行节点补充检索。
- - 用户调整报告结构 → 重新进入结构生成节点。
- - 关键信息冲突且用户无法裁决 → 返回搜索执行节点补充验证来源。
-
-**适用场景**:专业研究报告、决策支持分析等需要人类专家介入的场景。
-
-**实现指引**:人工审核节点使用 LangGraph 的 `interrupt` 机制实现状态挂起;路由函数读取用户反馈字段决定下一节点。
-
-### Level 4:记忆增强研究
-
-**核心机制**:利用历史研究结果作为上下文,避免重复搜索,提升研究深度与连贯性。
-
-- **语义检索历史**:将当前研究主题与意图向量化,从向量库检索相关历史研究项目。
-- **上下文注入**:将匹配到的历史报告摘要、关键结论、已确认信息源作为先验知识注入意图理解与任务分解阶段。
-- **增量更新**:对于相似主题的后续研究,仅搜索新增或变化的信息,与历史结果融合生成更新报告。
-
-**适用场景**:周期性行业分析、追踪式课题研究、企业内部知识累积复用。
-
-**实现指引**:在意图理解节点前增加记忆检索步骤,检索结果存入子图状态的 `historical_context` 字段供下游节点消费。
-
-### Level 5:自主研究规划与多模态分析
-
-**核心机制**:子图具备初步的自主规划能力,能够分解开放式研究问题,并协调多模态搜索与分析工具。
-
-- **复杂任务自主分解**:LLM 根据高层研究目标生成多步骤研究计划,包括子任务依赖关系、预期信息源类型。
-- **多模态搜索与分析**:除文本外,支持图像、视频、表格数据的搜索与信息提取。
-- **质量自评估与迭代**:生成报告后,由 LLM 对报告完整性、一致性进行自评,识别信息缺口并自动触发补充搜索。
-- **插件化工具扩展**:第三方可通过标准接口注册自定义搜索源或分析工具。
-
-**适用场景**:综合性行业白皮书撰写、跨领域技术调研、深度竞品分析。
-
-**实现指引**:任务分解节点升级为规划节点,输出结构化的研究计划图;工具调用采用 OpenAI Function Calling 风格统一接口。
-
----
-
-## 🔧 核心组件详解
-
-### 1. 意图理解节点
-
-**职责**:接收用户原始请求,区分简单查询、深度研究、对比分析等意图类型,评估研究复杂度。
-
-**输入**:用户自然语言请求、历史记忆上下文(可选)。
-
-**输出**:
-- `intent_type`:意图类别枚举。
-- `complexity_level`:复杂度评分(影响流程分支选择)。
-- `clarified_query`:消歧后的核心研究问题。
-
-**实现要点**:
-- 使用 LLM 进行少样本分类,输出结构化 JSON。
-- 结合关键词匹配与规则兜底(如“对比”、“区别” → 对比分析)。
-- 复杂度评分综合考虑用户指定信息源数量、时间范围跨度、是否需要可视化等因素。
-
-### 2. 任务分解节点
-
-**职责**:将复杂研究任务拆解为原子子任务,生成搜索关键词列表,并设计初步报告结构。
-
-**输入**:澄清后的研究问题、意图类型、复杂度评分。
-
-**输出**:
-- `sub_tasks`:子任务列表,每个子任务包含描述与预期信息类型。
-- `search_keywords`:多组搜索关键词(支持广度/深度/验证轮次)。
-- `draft_outline`:初步报告章节大纲。
-
-**实现要点**:
-- 针对对比分析类意图,自动生成对比维度矩阵。
-- 关键词生成利用 LLM 同义词扩展与上下位词推理能力。
-- 初步大纲作为后续报告结构生成的基础框架。
-
-### 3. 搜索执行节点
-
-**职责**:根据搜索策略执行多轮搜索,收集原始信息并记录元数据。
-
-**输入**:搜索关键词组、搜索策略(广度/深度/验证)、信息源偏好。
-
-**输出**:
-- `raw_search_results`:原始搜索结果列表,每条包含标题、摘要、URL、来源域名、发布时间。
-- `search_metadata`:搜索执行记录(搜索词、时间戳、来源类型)。
-
-**实现要点**:
-- 内部调用统一搜索网关,屏蔽不同搜索源的 API 差异。
-- 支持并行请求多个搜索源,通过 `asyncio.gather` 提升效率。
-- 每条结果附带初始可信度评分(基于域名信誉库与来源类型)。
-
-### 4. 信息源筛选节点(人工干预点)
-
-**职责**:自动筛选低质量信息源,将候选列表提交用户确认,根据反馈决定后续流向。
-
-**输入**:原始搜索结果列表。
-
-**输出**:
-- `confirmed_sources`:用户确认使用的信息源列表。
-- `user_feedback`:用户添加/删除/优先级调整记录。
-
-**实现要点**:
-- 自动筛选规则:排除可信度评分低于阈值的来源、发布时间过旧的内容、已被屏蔽的域名。
-- 人工审核界面以简洁列表形式展示信息源,支持多选、拖拽排序。
-- 若用户选择“跳过审核”,则直接使用自动筛选后的结果进入下一阶段。
-
-### 5. 信息提取节点
-
-**职责**:从确认后的信息源中提取结构化关键信息,标注实体与术语。
-
-**输入**:确认后的信息源内容(网页全文或摘要)。
-
-**输出**:
-- `extracted_fragments`:信息片段列表,每条包含内容文本、提取类型(事实/观点/数据)、来源指针。
-- `entity_annotations`:实体识别结果(时间、地点、人物、组织、专业术语)。
-
-**实现要点**:
-- 使用 LLM 进行开放式信息抽取,遵循预定义的抽取模式(如“主体-关系-客体”)。
-- 对数值类信息(百分比、金额、增长率)进行归一化处理,便于后续对比。
-- 每条信息片段保留完整来源元数据,支持最终报告的引用溯源。
-
-### 6. 信息整合与冲突检测节点
-
-**职责**:融合多源信息片段,检测冲突并进行交叉验证,生成结构化信息视图。
-
-**输入**:提取的信息片段列表。
-
-**输出**:
-- `integrated_info`:按主题/时间线/对比维度组织的结构化信息。
-- `conflict_report`:冲突项列表,含冲突等级与各方陈述。
-- `verification_summary`:关键事实的多源验证结果。
-
-**实现要点**:
-- 采用聚类算法或 LLM 语义匹配将描述同一事实的片段聚合。
-- 冲突检测基于事实三元组比对(如“X 公司市场份额 20%” vs “X 公司市场份额 25%”)。
-- 高优先级冲突(如核心数据差异超过阈值)触发路由至人工审核或补充搜索。
-
-### 7. 报告结构生成节点(人工干预点)
-
-**职责**:基于整合后的信息生成详细报告结构,提交用户确认或调整。
-
-**输入**:结构化信息、初步大纲、用户偏好。
-
-**输出**:
-- `confirmed_outline`:确认后的报告结构(多级标题)。
-- `visualization_suggestions`:建议的图表类型与数据映射。
-
-**实现要点**:
-- 报告结构生成考虑信息量分布与逻辑叙事顺序。
-- 可视化建议基于数据特征(如时间序列 → 折线图,类别对比 → 柱状图)。
-- 用户反馈可触发结构调整或返回信息整合节点重新组织内容。
-
-### 8. 报告生成节点
-
-**职责**:按照确认的结构生成完整报告草稿,自动插入引用标记。
-
-**输入**:确认的报告结构、结构化信息、引用元数据。
-
-**输出**:
-- `draft_report`:包含章节内容与引用标记的完整报告文本。
-- `citation_map`:引用标记到来源 URL 的映射表。
-
-**实现要点**:
-- 使用 LLM 逐章节生成内容,确保风格统一与逻辑连贯。
-- 引用标记采用 `[^1]` 脚注风格,在报告末尾聚合展示来源链接。
-- 对于数据可视化部分,调用图表服务生成图片并嵌入 Markdown 引用。
-
-### 9. 人工审核节点
-
-**职责**:在特定检查点挂起子图执行,等待用户输入,将反馈存入状态供后续路由消费。
-
-**输入**:待审核内容(信息源列表、报告结构等)。
-
-**输出**:用户反馈(确认、修改指令、取消等)。
-
-**实现要点**:
-- 基于 LangGraph `interrupt` 函数实现状态持久化挂起。
-- 反馈数据结构化存储,包含操作类型(confirm/modify/cancel)与具体参数。
-- 支持超时自动确认(可配置)以保证流程不无限阻塞。
-
-### 10. 最终格式化节点
-
-**职责**:将报告草稿转换为用户指定输出格式,生成执行摘要,准备返回主图。
-
-**输入**:确认后的报告草稿、输出格式偏好。
-
-**输出**:
-- `final_report`:格式化后的报告内容。
-- `executive_summary`:执行摘要(可选)。
-- `suggestions`:后续研究建议(可选)。
-
-**实现要点**:
-- 支持 Markdown、HTML、纯文本三种输出格式。
-- 执行摘要通过 LLM 从完整报告中提炼核心观点与结论。
-- 最终输出聚合到子图状态 `output` 字段,由接口层转换回主状态。
-
----
-
-## 🔀 条件路由详解
-
-子图内部通过条件路由函数实现动态流程控制,主要路由点如下:
-
-### 入口路由:选择流程模式
-
-- **位置**:意图理解节点之后。
-- **条件**:
- - `complexity_level == "simple"` → 简化流程(跳过任务分解与多轮搜索)。
- - `complexity_level in ["moderate", "complex"]` → 完整流程。
-- **实现**:路由函数读取状态中的 `complexity_level` 字段返回下一节点名称。
-
-### 搜索策略路由
-
-- **位置**:任务分解节点之后。
-- **条件**:
- - 用户要求“快速概览” → 单轮搜索。
- - 用户要求“深度分析” → 多轮搜索(广度→深度→验证)。
- - 意图为“对比分析” → 按对比维度分别搜索后融合。
-- **实现**:根据 `intent_type` 与用户偏好字段决定搜索执行节点的内部模式。
-
-### 信息源确认路由
-
-- **位置**:信息源筛选节点(人工干预点)之后。
-- **条件**:
- - 用户点击“确认” → 进入信息提取节点。
- - 用户点击“添加信息源” → 返回搜索执行节点,携带补充关键词。
- - 用户点击“调整优先级” → 重新排序后再次进入审核(循环)。
-- **实现**:读取 `user_feedback.action` 字段进行路由。
-
-### 冲突处理路由
-
-- **位置**:信息整合节点之后。
-- **条件**:
- - 无冲突或仅有低优先级冲突 → 进入报告结构生成。
- - 存在高优先级冲突且用户未选择“忽略” → 进入人工审核节点。
- - 用户要求“补充验证” → 返回搜索执行节点进行第三轮验证搜索。
-- **实现**:评估 `conflict_report` 中的最高冲突等级与用户历史选择。
-
-### 报告结构确认路由
-
-- **位置**:报告结构生成节点(人工干预点)之后。
-- **条件**:
- - 用户确认 → 进入报告生成节点。
- - 用户要求修改结构 → 重新调用结构生成节点(带修改指令)。
- - 用户要求调整内容 → 返回信息整合节点调整结构化信息。
-- **实现**:读取 `user_feedback` 中的结构修改指令进行路由。
-
-### 输出格式路由
-
-- **位置**:最终格式化节点之前。
-- **条件**:
- - `output_format == "markdown"` → Markdown 格式化。
- - `output_format == "html"` → HTML 格式化。
- - `output_format == "text"` → 纯文本格式化。
-- **实现**:读取用户偏好或默认配置选择格式化器。
-
----
-
-## 📊 状态设计
-
-子图状态采用 TypedDict 定义,按研究阶段分层组织,完整记录中间产物以支持中断恢复与调试。
-
-### 状态结构概览
-
-| 分组 | 字段 | 类型 | 说明 |
-|:-----|:-----|:-----|:-----|
-| **输入** | `user_request` | `str` | 用户原始研究请求 |
-| | `preferences` | `dict` | 用户指定的信息源、输出格式等偏好 |
-| | `historical_context` | `list[dict]` | 记忆检索注入的历史研究摘要 |
-| **意图与任务** | `intent_type` | `str` | 意图类别 |
-| | `complexity_level` | `str` | 复杂度评级 |
-| | `clarified_query` | `str` | 澄清后的核心问题 |
-| | `sub_tasks` | `list[dict]` | 子任务列表 |
-| | `search_keywords` | `list[list[str]]` | 多轮搜索关键词组 |
-| | `draft_outline` | `list[str]` | 初步报告大纲 |
-| **搜索与收集** | `raw_search_results` | `list[dict]` | 原始搜索结果(含元数据) |
-| | `confirmed_sources` | `list[dict]` | 用户确认使用的信息源 |
-| | `user_source_feedback` | `dict` | 用户对信息源的调整记录 |
-| **提取与整合** | `extracted_fragments` | `list[dict]` | 结构化信息片段 |
-| | `integrated_info` | `dict` | 按主题/时间线组织的整合信息 |
-| | `conflict_report` | `list[dict]` | 冲突项列表 |
-| | `verification_summary` | `dict` | 关键事实验证结果 |
-| **报告生成** | `confirmed_outline` | `list[dict]` | 确认后的报告结构 |
-| | `visualization_suggestions` | `list[dict]` | 图表建议 |
-| | `draft_report` | `str` | 报告草稿(含引用标记) |
-| | `citation_map` | `dict` | 引用标记到来源映射 |
-| | `user_structure_feedback` | `dict` | 用户对报告结构的调整 |
-| **控制流** | `current_phase` | `str` | 当前执行阶段 |
-| | `next_node` | `str` | 下一节点名称 |
-| | `interrupt_point` | `str` | 中断点标识 |
-| | `error_info` | `dict` | 错误信息(如有) |
-| **输出** | `final_report` | `str` | 最终报告内容 |
-| | `output_format` | `str` | 输出格式 |
-| | `executive_summary` | `str` | 执行摘要 |
-
-### 状态更新原则
-
-- **增量写入**:每个节点只修改其职责范围内的字段,其他字段只读。
-- **原子提交**:节点执行成功后才将变更合并到全局状态。
-- **版本记录**:每次状态变更均记录前序版本,支持回滚(用于人工审核场景)。
-- **持久化友好**:所有字段均可 JSON 序列化,便于通过检查点器持久化。
-
----
-
-## 🔄 工作流程与中断恢复
-
-### 完整研究流程(四个阶段)
-
-| 阶段 | 步骤 | 节点 | 人工干预 |
-|:-----|:-----|:-----|:---------|
-| **理解与分解** | 1. 意图理解 | `intent_understanding` | 否 |
-| | 2. 任务分解 | `task_decomposition` | 否 |
-| **检索与收集** | 3. 多源搜索执行 | `search_execution` | 否 |
-| | 4. 信息源筛选与确认 | `source_filtering` | **是** |
-| **提取与整合** | 5. 关键信息提取 | `information_extraction` | 否 |
-| | 6. 信息整合与冲突检测 | `information_integration` | 否(可能触发审核) |
-| **生成与输出** | 7. 报告结构确认 | `structure_generation` | **是** |
-| | 8. 报告生成与格式化 | `report_generation` + `final_formatting` | 否 |
-
-### 简化流程(快速查询模式)
-
-当 `complexity_level == "simple"` 时,子图走精简路径:
-
-1. 意图理解(简化版,不拆解任务)。
-2. 单次搜索执行(仅广度搜索)。
-3. 快速信息提取(不进行深度整合)。
-4. 直接生成简短回答(跳过结构确认)。
-
-### 中断与恢复机制
-
-子图支持在以下位置中断并持久化状态:
-
-- 信息源筛选节点(人工干预点 1)
-- 报告结构生成节点(人工干预点 2)
-- 任意节点执行完成后的检查点(由检查点器自动保存)
-
-**恢复流程**:
-1. 主图传入相同的 `thread_id` 与中断前状态。
-2. 子图从检查点加载状态,定位 `interrupt_point`。
-3. 若中断点为人工审核节点,等待用户反馈后继续执行。
-4. 若为其他检查点,直接从下一节点开始执行。
-
----
-
-## 🔒 安全与边界控制
-
-### 安全机制
-
-| 类别 | 机制 | 实现位置 |
-|:-----|:-----|:---------|
-| **内容安全** | 搜索关键词过滤、结果内容审查、成人内容屏蔽 | 搜索工具网关 |
-| **数据安全** | 用户数据加密存储、传输层 TLS、敏感信息脱敏 | 持久化层与接口层 |
-| **访问控制** | 基于角色的功能权限(普通/高级/管理员) | 接口层中间件 |
-| **资源限制** | 单用户 QPS 限制、单次研究最大 Token 消耗、最大信息源数量 | 工作流编排层 |
-| **审计日志** | 记录所有搜索、提取、生成操作,包含操作者、时间戳、资源消耗 | 各节点内置日志 |
-
-### 人工审核触发边界
-
-以下情况强制进入人工审核节点:
-
-- 信息源可信度平均评分低于阈值。
-- 高优先级信息冲突且无法自动裁决。
-- 用户请求超出常规研究边界(如要求访问受限领域)。
-- 首次使用特定高风险搜索源。
-
-### 错误处理边界
-
-- **可恢复错误**(如单次搜索超时):自动重试或切换备选搜索源。
-- **不可恢复错误**(如 LLM 服务不可用):终止执行,向主图返回错误状态与友好提示。
-- **部分成功**:即使部分子任务失败,仍返回已完成的部分结果(如已提取的信息片段)。
-
----
-
-## 🛠️ 工具集成
-
-### 工具集概览
-
-| 工具集 | 功能 | 外部依赖 |
-|:-------|:-----|:---------|
-| **搜索工具集** | 通用网页搜索、学术论文检索、专业知识库查询、新闻资讯获取 | 搜索 API 网关 |
-| **信息提取工具集** | 实体识别、数据提取、术语标注、关系抽取、摘要生成 | LLM 服务 |
-| **信息验证工具集** | 多源交叉验证、可信度评分、时效性检查、一致性检查 | 域名信誉库、LLM |
-| **报告生成工具集** | 内容生成、引用插入、图表生成、格式转换 | LLM、图表服务 |
-| **记忆检索工具集** | 历史研究语义检索、项目检索、时间范围检索 | Qdrant / pgvector |
-
-### 工具调用规范
-
-所有工具遵循统一接口规范:
-
-- **输入**:标准字典参数。
-- **输出**:标准字典结果,包含 `status`、`data`、`error` 字段。
-- **元数据**:每次调用记录调用时间、耗时、资源标识。
-
-### 工具扩展方式
-
-新增工具仅需三步:
-
-1. 在对应工具集中实现标准接口的适配器。
-2. 在工具注册表中声明工具元数据(名称、描述、参数模式)。
-3. 在相关节点中通过工具名称调用,无需修改节点核心逻辑。
-
----
-
-## 📑 快速开始(概念级)
-
-研究分析子图作为主图的一个子图节点被调用,典型集成方式如下:
-
-1. **主图路由**:当主图识别到用户意图为“研究分析”时,路由至 `research_subgraph` 节点。
-2. **状态映射**:主状态中的 `user_input`、`user_id` 等字段映射到子图状态输入部分。
-3. **子图执行**:子图按照上述工作流自主执行,可能在人工干预点挂起。
-4. **结果回传**:子图执行完毕后,将 `final_report`、`executive_summary` 等字段回写到主状态。
-
-子图内部配置项(如默认搜索源、重试次数、审核超时)通过环境变量或配置文件管理。
-
----
-
-## ⚙️ 配置项参考
-
-| 配置项 | 说明 | 默认值 |
-|:-------|:-----|:-------|
-| `RESEARCH_LLM_MODEL` | 意图理解与生成使用的 LLM 模型 | `deepseek-chat` |
-| `SEARCH_API_GATEWAY_URL` | 统一搜索网关地址 | `http://localhost:8080` |
-| `SEARCH_DEFAULT_SOURCES` | 默认启用的搜索源列表 | `["web", "news"]` |
-| `MAX_SEARCH_ROUNDS` | 最大搜索轮次 | `3` |
-| `RERANK_TOP_N` | 信息源筛选保留数量 | `20` |
-| `CONFLICT_SEVERITY_THRESHOLD` | 触发人工审核的冲突等级 | `high` |
-| `HUMAN_LOOP_TIMEOUT_SEC` | 人工审核超时自动确认时间 | `3600` |
-| `VECTOR_DB_URL` | 记忆检索向量库地址 | `http://localhost:6333` |
-| `CHART_SERVICE_URL` | 图表生成服务地址 | `http://localhost:3000` |
-
----
-
-## 🤝 与主系统集成
-
-研究分析子图通过 LangGraph 子图机制与主系统解耦集成:
-
-- **状态隔离**:子图状态字段使用前缀 `research_` 避免与主状态冲突。
-- **错误传播**:子图内部异常捕获后转换为标准错误结构向上传递,主图可选择重试或降级。
-- **检查点共享**:子图与主图共用同一检查点器后端,确保整体流程的断点续作能力。
-
-子图对外暴露的唯一接口是编译后的 `StateGraph` 实例,主图通过 `builder.add_node("research", research_subgraph)` 将其作为一个节点加入。
-
----
-
-## 📈 性能考量
-
-- **并行搜索**:多源搜索与多关键词检索采用异步并行,典型场景下搜索阶段耗时控制在 3 秒内。
-- **流式报告生成**:报告生成节点支持流式输出,用户在报告结构确认后可实时看到内容逐段生成。
-- **结果缓存**:对于相同搜索词在短时间内的重复请求,搜索网关层提供 TTL 缓存。
-- **状态压缩**:持久化前对大型字段(如原始搜索结果全文)进行摘要化处理,减少存储开销。
-
----
-
-## 🔮 未来演进方向
-
-参见需求文档中的详细规划,技术实现层面重点关注:
-
-- **LLM 工具调用标准化**:向 OpenAI Function Calling 风格对齐。
-- **多模态管道**:集成图像描述生成与视觉问答模型。
-- **插件市场**:提供标准工具接口 SDK,支持第三方搜索源接入。
-- **协同研究**:支持多用户对同一研究项目的评论与版本分支管理。
\ No newline at end of file
diff --git a/backend/app/backend.py b/backend/app/backend.py
index 22431e2..1977f60 100644
--- a/backend/app/backend.py
+++ b/backend/app/backend.py
@@ -14,18 +14,18 @@ from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Depe
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
-from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
+from app.main_graph.checkpoint.postgres.aio import AsyncPostgresSaver
from .agent.service import AIAgentService
from .agent.history import ThreadHistoryService
-from .agent_subgraphs.common.human_review import (
+from app.core.human_review import (
ReviewManager,
InMemoryReviewStore,
ReviewStatus,
HumanReview
)
-from .agent_subgraphs.contact.api_client import ContactAPIClient
-from .agent_subgraphs.dictionary.api_client import DictionaryAPIClient
-from .agent_subgraphs.news_analysis.api_client import NewsAPIClient
+from app.subgraphs.contact.api_client import ContactAPIClient
+from app.subgraphs.dictionary.api_client import DictionaryAPIClient
+from app.subgraphs.news_analysis.api_client import NewsAPIClient
from .db.init_db import init_subgraph_tables
from .db.models import ContactRepository, DictionaryRepository, NewsRepository
from .logger import info, error
diff --git a/backend/app/core/__init__.py b/backend/app/core/__init__.py
new file mode 100644
index 0000000..b0f74e0
--- /dev/null
+++ b/backend/app/core/__init__.py
@@ -0,0 +1 @@
+"""核心模块 - 基类和通用工具"""
diff --git a/backend/app/agent_subgraphs/common/formatter.py b/backend/app/core/formatter.py
similarity index 100%
rename from backend/app/agent_subgraphs/common/formatter.py
rename to backend/app/core/formatter.py
diff --git a/backend/app/agent_subgraphs/common/human_review.py b/backend/app/core/human_review.py
similarity index 100%
rename from backend/app/agent_subgraphs/common/human_review.py
rename to backend/app/core/human_review.py
diff --git a/backend/app/agent_subgraphs/common/intent.py b/backend/app/core/intent.py
similarity index 100%
rename from backend/app/agent_subgraphs/common/intent.py
rename to backend/app/core/intent.py
diff --git a/backend/app/agent/intent_classifier.py b/backend/app/core/intent_classifier.py
similarity index 100%
rename from backend/app/agent/intent_classifier.py
rename to backend/app/core/intent_classifier.py
diff --git a/backend/app/agent_subgraphs/common/state_base.py b/backend/app/core/state_base.py
similarity index 100%
rename from backend/app/agent_subgraphs/common/state_base.py
rename to backend/app/core/state_base.py
diff --git a/backend/app/graph/__init__.py b/backend/app/graph/__init__.py
deleted file mode 100644
index 74c2c01..0000000
--- a/backend/app/graph/__init__.py
+++ /dev/null
@@ -1,73 +0,0 @@
-"""
-Graph 子模块 - React 模式增强版(带超时重试)
-"""
-
-from .graph_builder import GraphBuilder
-from .subgraph_builder import build_main_graph, build_react_main_graph
-from .react_nodes import (
- init_state_node,
- react_reason_node,
- error_handling_node,
- final_response_node,
- route_by_reasoning
-)
-from .rag_nodes import (
- rag_retrieve_node,
- rag_re_retrieve_node,
- inject_rag_tool_to_state,
- get_rag_tool_from_state
-)
-from .state import (
- MessagesState,
- GraphContext,
- MainGraphState,
- CurrentAction,
- ErrorRecord,
- ErrorSeverity
-)
-from .retry_utils import (
- RetryConfig,
- RetryResult,
- RetryStrategy,
- with_retry,
- with_async_retry,
- create_retry_wrapper_for_node,
- RAG_RETRY_CONFIG,
- SUBGRAPH_RETRY_CONFIG
-)
-
-__all__ = [
- # 旧版兼容性
- "GraphBuilder",
- "build_main_graph",
- "MessagesState",
- "GraphContext",
- "MainGraphState",
- "CurrentAction",
-
- # 新版 React 模式
- "build_react_main_graph",
- "init_state_node",
- "react_reason_node",
- "error_handling_node",
- "final_response_node",
- "route_by_reasoning",
- "ErrorRecord",
- "ErrorSeverity",
-
- # RAG 节点(独立模块)
- "rag_retrieve_node",
- "rag_re_retrieve_node",
- "inject_rag_tool_to_state",
- "get_rag_tool_from_state",
-
- # 超时和重试工具
- "RetryConfig",
- "RetryResult",
- "RetryStrategy",
- "with_retry",
- "with_async_retry",
- "create_retry_wrapper_for_node",
- "RAG_RETRY_CONFIG",
- "SUBGRAPH_RETRY_CONFIG"
-]
diff --git a/backend/app/main_graph/__init__.py b/backend/app/main_graph/__init__.py
new file mode 100644
index 0000000..baaf33c
--- /dev/null
+++ b/backend/app/main_graph/__init__.py
@@ -0,0 +1 @@
+"""主图模块 - LangGraph 主流程"""
diff --git a/backend/app/graph/graph_builder.py b/backend/app/main_graph/graph_builder.py
similarity index 94%
rename from backend/app/graph/graph_builder.py
rename to backend/app/main_graph/graph_builder.py
index 21abe76..18cb28a 100644
--- a/backend/app/graph/graph_builder.py
+++ b/backend/app/main_graph/graph_builder.py
@@ -4,7 +4,7 @@ LangGraph 状态图构建模块 - 精简版,仅负责组装图
"""
from langchain_core.language_models import BaseLLM
-from langgraph.graph import StateGraph, START, END
+from app.main_graph.graph import StateGraph, START, END
from .state import MessagesState, GraphContext
from ..nodes import (
should_continue,
@@ -14,7 +14,7 @@ from ..nodes import (
create_summarize_node,
finalize_node,
)
-from ..nodes.memory_trigger import memory_trigger_node, set_mem0_client
+from app.main_graph.nodes.memory_trigger import memory_trigger_node, set_mem0_client
from ..memory import Mem0Client
diff --git a/backend/app/main_graph/nodes/__init__.py b/backend/app/main_graph/nodes/__init__.py
new file mode 100644
index 0000000..ae9de0f
--- /dev/null
+++ b/backend/app/main_graph/nodes/__init__.py
@@ -0,0 +1 @@
+"""主图节点"""
diff --git a/backend/app/nodes/finalize.py b/backend/app/main_graph/nodes/finalize.py
similarity index 92%
rename from backend/app/nodes/finalize.py
rename to backend/app/main_graph/nodes/finalize.py
index 2203a0b..dd52a2c 100644
--- a/backend/app/nodes/finalize.py
+++ b/backend/app/main_graph/nodes/finalize.py
@@ -4,10 +4,10 @@
"""
from typing import Any, Dict
-from langgraph.config import get_stream_writer
+from app.main_graph.config import get_stream_writer
# 本地模块
-from ..graph.state import MessagesState
+from app.main_graph.state import MessagesState
from ..utils.logging import log_state_change
from ..logger import info, error
diff --git a/backend/app/nodes/llm_call.py b/backend/app/main_graph/nodes/llm_call.py
similarity index 99%
rename from backend/app/nodes/llm_call.py
rename to backend/app/main_graph/nodes/llm_call.py
index f413d85..207b64d 100644
--- a/backend/app/nodes/llm_call.py
+++ b/backend/app/main_graph/nodes/llm_call.py
@@ -9,7 +9,7 @@ from langchain_core.language_models import BaseLLM
from langchain_core.messages import AIMessage
# 本地模块
-from ..graph.state import MessagesState
+from app.main_graph.state import MessagesState
from ..agent.prompts import create_system_prompt
from ..utils.logging import log_state_change
from ..logger import debug, info, error
diff --git a/backend/app/nodes/memory_trigger.py b/backend/app/main_graph/nodes/memory_trigger.py
similarity index 96%
rename from backend/app/nodes/memory_trigger.py
rename to backend/app/main_graph/nodes/memory_trigger.py
index be5a65c..0784dd6 100644
--- a/backend/app/nodes/memory_trigger.py
+++ b/backend/app/main_graph/nodes/memory_trigger.py
@@ -1,6 +1,6 @@
from typing import Any, Dict
from langchain_core.runnables.config import RunnableConfig
-from ..graph.state import MessagesState
+from app.main_graph.state import MessagesState
from ..memory.mem0_client import Mem0Client
from ..logger import info
diff --git a/backend/app/graph/rag_nodes.py b/backend/app/main_graph/nodes/rag_nodes.py
similarity index 99%
rename from backend/app/graph/rag_nodes.py
rename to backend/app/main_graph/nodes/rag_nodes.py
index c1d0c98..4dd2bde 100644
--- a/backend/app/graph/rag_nodes.py
+++ b/backend/app/main_graph/nodes/rag_nodes.py
@@ -254,7 +254,7 @@ async def initialize_rag_from_initializer() -> None:
注意:这是示例代码,实际使用时需要提供 local_llm_creator
"""
try:
- from ..agent.rag_initializer import init_rag_tool
+ from app.main_graph.utils.rag_initializer import init_rag_tool
# 注意:这里需要传入 local_llm_creator
# 示例:
diff --git a/backend/app/graph/react_nodes.py b/backend/app/main_graph/nodes/react_nodes.py
similarity index 98%
rename from backend/app/graph/react_nodes.py
rename to backend/app/main_graph/nodes/react_nodes.py
index 386e10f..d2fecb1 100644
--- a/backend/app/graph/react_nodes.py
+++ b/backend/app/main_graph/nodes/react_nodes.py
@@ -15,13 +15,13 @@ from typing import Dict, Any, Optional
from datetime import datetime
# 导入我们的 intent.py
-from ..agent_subgraphs.common.intent import (
+from app.core.intent import (
react_reason,
get_route_by_reasoning,
ReasoningAction,
ReasoningResult
)
-from ..agent_subgraphs.common.state_base import StateUtils
+from app.core.state_base import StateUtils
from .state import MainGraphState, ErrorRecord, ErrorSeverity
from .retry_utils import (
RetryConfig,
diff --git a/backend/app/graph/retrieve_memory.py b/backend/app/main_graph/nodes/retrieve_memory.py
similarity index 100%
rename from backend/app/graph/retrieve_memory.py
rename to backend/app/main_graph/nodes/retrieve_memory.py
diff --git a/backend/app/nodes/router.py b/backend/app/main_graph/nodes/router.py
similarity index 97%
rename from backend/app/nodes/router.py
rename to backend/app/main_graph/nodes/router.py
index 6fab51a..b703adb 100644
--- a/backend/app/nodes/router.py
+++ b/backend/app/main_graph/nodes/router.py
@@ -8,7 +8,7 @@ from langchain_core.messages import AIMessage
# 本地模块
from ..config import ENABLE_GRAPH_TRACE, MEMORY_SUMMARIZE_INTERVAL
-from ..graph.state import MessagesState
+from app.main_graph.state import MessagesState
from ..logger import info
diff --git a/backend/app/nodes/summarize.py b/backend/app/main_graph/nodes/summarize.py
similarity index 98%
rename from backend/app/nodes/summarize.py
rename to backend/app/main_graph/nodes/summarize.py
index 2c9856b..a2c7f9e 100644
--- a/backend/app/nodes/summarize.py
+++ b/backend/app/main_graph/nodes/summarize.py
@@ -6,7 +6,7 @@
from typing import Any, Dict
# 本地模块
-from ..graph.state import MessagesState
+from app.main_graph.state import MessagesState
from ..memory.mem0_client import Mem0Client
from ..utils.logging import log_state_change
from ..logger import debug, info, error, warning
diff --git a/backend/app/nodes/tool_call.py b/backend/app/main_graph/nodes/tool_call.py
similarity index 97%
rename from backend/app/nodes/tool_call.py
rename to backend/app/main_graph/nodes/tool_call.py
index 69ad2e6..e23e3d6 100644
--- a/backend/app/nodes/tool_call.py
+++ b/backend/app/main_graph/nodes/tool_call.py
@@ -6,10 +6,10 @@
import asyncio
from typing import Any, Dict
from langchain_core.messages import AIMessage, ToolMessage
-from langgraph.config import get_stream_writer
+from app.main_graph.config import get_stream_writer
# 本地模块
-from ..graph.state import MessagesState
+from app.main_graph.state import MessagesState
from ..utils.logging import log_state_change
from ..logger import debug, info
diff --git a/backend/app/graph/state.py b/backend/app/main_graph/state.py
similarity index 98%
rename from backend/app/graph/state.py
rename to backend/app/main_graph/state.py
index d3a10fa..eee414e 100644
--- a/backend/app/graph/state.py
+++ b/backend/app/main_graph/state.py
@@ -6,7 +6,7 @@ Main Graph State Definition - React Mode Enhanced
from enum import Enum, auto
from typing import Optional, Dict, Any, Annotated, Sequence, TypedDict, List
from dataclasses import dataclass, field
-from langgraph.graph import add_messages
+from app.main_graph.graph import add_messages
from langchain_core.messages import BaseMessage
diff --git a/backend/app/main_graph/tools/__init__.py b/backend/app/main_graph/tools/__init__.py
new file mode 100644
index 0000000..72f9f49
--- /dev/null
+++ b/backend/app/main_graph/tools/__init__.py
@@ -0,0 +1 @@
+"""主图工具"""
diff --git a/backend/app/graph/graph_tools.py b/backend/app/main_graph/tools/graph_tools.py
similarity index 100%
rename from backend/app/graph/graph_tools.py
rename to backend/app/main_graph/tools/graph_tools.py
diff --git a/backend/app/graph/subgraph_tools.py b/backend/app/main_graph/tools/subgraph_tools.py
similarity index 94%
rename from backend/app/graph/subgraph_tools.py
rename to backend/app/main_graph/tools/subgraph_tools.py
index f675508..e29fbf8 100644
--- a/backend/app/graph/subgraph_tools.py
+++ b/backend/app/main_graph/tools/subgraph_tools.py
@@ -22,13 +22,13 @@ def dictionary_tool(query: str, action: Optional[str] = None) -> str:
格式化的结果文本
"""
try:
- from backend.app.agent_subgraphs.dictionary import (
+ from app.subgraphs.dictionary import (
DictionaryState,
DictionaryAction,
parse_intent,
format_result
)
- from backend.app.agent_subgraphs.dictionary.nodes import (
+ from app.subgraphs.dictionary.nodes import (
query_word, translate_text, extract_terms, get_daily_word
)
@@ -87,13 +87,13 @@ def news_analysis_tool(query: str, action: Optional[str] = None) -> str:
格式化的结果文本
"""
try:
- from backend.app.agent_subgraphs.news_analysis import (
+ from app.subgraphs.news_analysis import (
NewsAnalysisState,
NewsAction,
parse_intent,
format_result
)
- from backend.app.agent_subgraphs.news_analysis.nodes import (
+ from app.subgraphs.news_analysis.nodes import (
query_news, analyze_url, extract_keywords, generate_report
)
@@ -150,13 +150,13 @@ def contact_tool(query: str, action: Optional[str] = None) -> str:
格式化的结果文本
"""
try:
- from backend.app.agent_subgraphs.contact import (
+ from app.subgraphs.contact import (
ContactState,
ContactAction,
parse_intent,
format_result
)
- from backend.app.agent_subgraphs.contact.nodes import (
+ from app.subgraphs.contact.nodes import (
query_contact, add_contact, list_contacts
)
diff --git a/backend/app/main_graph/utils/__init__.py b/backend/app/main_graph/utils/__init__.py
new file mode 100644
index 0000000..a03be40
--- /dev/null
+++ b/backend/app/main_graph/utils/__init__.py
@@ -0,0 +1 @@
+"""主图工具函数"""
diff --git a/backend/app/agent/rag_initializer.py b/backend/app/main_graph/utils/rag_initializer.py
similarity index 100%
rename from backend/app/agent/rag_initializer.py
rename to backend/app/main_graph/utils/rag_initializer.py
diff --git a/backend/app/graph/retry_utils.py b/backend/app/main_graph/utils/retry_utils.py
similarity index 100%
rename from backend/app/graph/retry_utils.py
rename to backend/app/main_graph/utils/retry_utils.py
diff --git a/backend/app/graph/subgraph_builder.py b/backend/app/main_graph/utils/subgraph_builder.py
similarity index 95%
rename from backend/app/graph/subgraph_builder.py
rename to backend/app/main_graph/utils/subgraph_builder.py
index b3ebd7a..5199ec8 100644
--- a/backend/app/graph/subgraph_builder.py
+++ b/backend/app/main_graph/utils/subgraph_builder.py
@@ -3,7 +3,7 @@ React 模式主图构建器 - 完整循环推理版本
Main Graph Builder - Full React Mode with Loop Reasoning
"""
-from langgraph.graph import StateGraph, START, END
+from app.main_graph.graph import StateGraph, START, END
from typing import Dict, Any
from .state import MainGraphState, CurrentAction
@@ -15,9 +15,9 @@ from .react_nodes import (
route_by_reasoning
)
from .rag_nodes import rag_retrieve_node
-from ..agent_subgraphs.contact import build_contact_subgraph
-from ..agent_subgraphs.dictionary import build_dictionary_subgraph
-from ..agent_subgraphs.news_analysis import build_news_analysis_subgraph
+from app.subgraphs.contact import build_contact_subgraph
+from app.subgraphs.dictionary import build_dictionary_subgraph
+from app.subgraphs.news_analysis import build_news_analysis_subgraph
# ========== 子图包装器(处理子图错误传递) ==========
diff --git a/backend/app/graph/visualize_graph.py b/backend/app/main_graph/utils/visualize_graph.py
similarity index 97%
rename from backend/app/graph/visualize_graph.py
rename to backend/app/main_graph/utils/visualize_graph.py
index 9059ce8..c50e72e 100644
--- a/backend/app/graph/visualize_graph.py
+++ b/backend/app/main_graph/utils/visualize_graph.py
@@ -25,7 +25,7 @@ load_dotenv(PROJECT_ROOT / ".env")
from app.agent.service import AIAgentService
from app.config import DB_URI
-from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
+from app.main_graph.checkpoint.postgres.aio import AsyncPostgresSaver
import asyncio
diff --git a/backend/app/nodes/__init__.py b/backend/app/nodes/__init__.py
deleted file mode 100644
index 345883a..0000000
--- a/backend/app/nodes/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""
-节点模块 - 导出所有 LangGraph 节点函数
-"""
-
-from .router import should_continue
-from .llm_call import create_llm_call_node
-from .tool_call import create_tool_call_node
-from ..graph.retrieve_memory import create_retrieve_memory_node
-from .summarize import create_summarize_node
-from .finalize import finalize_node
-
-__all__ = [
- "should_continue",
- "create_llm_call_node",
- "create_tool_call_node",
- "create_retrieve_memory_node",
- "create_summarize_node",
- "finalize_node",
-]
diff --git a/backend/app/subgraphs/__init__.py b/backend/app/subgraphs/__init__.py
new file mode 100644
index 0000000..566a6b4
--- /dev/null
+++ b/backend/app/subgraphs/__init__.py
@@ -0,0 +1 @@
+"""子图模块"""
diff --git a/backend/app/agent_subgraphs/contact/README.md b/backend/app/subgraphs/contact/README.md
similarity index 100%
rename from backend/app/agent_subgraphs/contact/README.md
rename to backend/app/subgraphs/contact/README.md
diff --git a/backend/app/agent_subgraphs/contact/__init__.py b/backend/app/subgraphs/contact/__init__.py
similarity index 100%
rename from backend/app/agent_subgraphs/contact/__init__.py
rename to backend/app/subgraphs/contact/__init__.py
diff --git a/backend/app/agent_subgraphs/contact/api_client.py b/backend/app/subgraphs/contact/api_client.py
similarity index 100%
rename from backend/app/agent_subgraphs/contact/api_client.py
rename to backend/app/subgraphs/contact/api_client.py
diff --git a/backend/app/agent_subgraphs/contact/graph.py b/backend/app/subgraphs/contact/graph.py
similarity index 98%
rename from backend/app/agent_subgraphs/contact/graph.py
rename to backend/app/subgraphs/contact/graph.py
index 0c00360..4026179 100644
--- a/backend/app/agent_subgraphs/contact/graph.py
+++ b/backend/app/subgraphs/contact/graph.py
@@ -4,7 +4,7 @@ Contact Subgraph Builder
支持 API 注入的工厂模式
"""
-from langgraph.graph import StateGraph, START, END
+from app.main_graph.graph import StateGraph, START, END
from .state import ContactState
from .nodes import create_contact_nodes
diff --git a/backend/app/agent_subgraphs/contact/nodes.py b/backend/app/subgraphs/contact/nodes.py
similarity index 100%
rename from backend/app/agent_subgraphs/contact/nodes.py
rename to backend/app/subgraphs/contact/nodes.py
diff --git a/backend/app/agent_subgraphs/contact/state.py b/backend/app/subgraphs/contact/state.py
similarity index 100%
rename from backend/app/agent_subgraphs/contact/state.py
rename to backend/app/subgraphs/contact/state.py
diff --git a/backend/app/agent_subgraphs/dictionary/README.md b/backend/app/subgraphs/dictionary/README.md
similarity index 100%
rename from backend/app/agent_subgraphs/dictionary/README.md
rename to backend/app/subgraphs/dictionary/README.md
diff --git a/backend/app/agent_subgraphs/dictionary/__init__.py b/backend/app/subgraphs/dictionary/__init__.py
similarity index 100%
rename from backend/app/agent_subgraphs/dictionary/__init__.py
rename to backend/app/subgraphs/dictionary/__init__.py
diff --git a/backend/app/agent_subgraphs/dictionary/api_client.py b/backend/app/subgraphs/dictionary/api_client.py
similarity index 100%
rename from backend/app/agent_subgraphs/dictionary/api_client.py
rename to backend/app/subgraphs/dictionary/api_client.py
diff --git a/backend/app/agent_subgraphs/dictionary/graph.py b/backend/app/subgraphs/dictionary/graph.py
similarity index 97%
rename from backend/app/agent_subgraphs/dictionary/graph.py
rename to backend/app/subgraphs/dictionary/graph.py
index 6f3ce31..bc65340 100644
--- a/backend/app/agent_subgraphs/dictionary/graph.py
+++ b/backend/app/subgraphs/dictionary/graph.py
@@ -3,7 +3,7 @@
Dictionary Subgraph Builder - Complete
"""
-from langgraph.graph import StateGraph, START, END
+from app.main_graph.graph import StateGraph, START, END
from .state import DictionaryState
from .nodes import (
diff --git a/backend/app/agent_subgraphs/dictionary/nodes.py b/backend/app/subgraphs/dictionary/nodes.py
similarity index 100%
rename from backend/app/agent_subgraphs/dictionary/nodes.py
rename to backend/app/subgraphs/dictionary/nodes.py
diff --git a/backend/app/agent_subgraphs/dictionary/state.py b/backend/app/subgraphs/dictionary/state.py
similarity index 100%
rename from backend/app/agent_subgraphs/dictionary/state.py
rename to backend/app/subgraphs/dictionary/state.py
diff --git a/backend/app/agent_subgraphs/news_analysis/__init__.py b/backend/app/subgraphs/news_analysis/__init__.py
similarity index 100%
rename from backend/app/agent_subgraphs/news_analysis/__init__.py
rename to backend/app/subgraphs/news_analysis/__init__.py
diff --git a/backend/app/agent_subgraphs/news_analysis/api_client.py b/backend/app/subgraphs/news_analysis/api_client.py
similarity index 100%
rename from backend/app/agent_subgraphs/news_analysis/api_client.py
rename to backend/app/subgraphs/news_analysis/api_client.py
diff --git a/backend/app/agent_subgraphs/news_analysis/graph.py b/backend/app/subgraphs/news_analysis/graph.py
similarity index 96%
rename from backend/app/agent_subgraphs/news_analysis/graph.py
rename to backend/app/subgraphs/news_analysis/graph.py
index 9dfbf90..1aa07c8 100644
--- a/backend/app/agent_subgraphs/news_analysis/graph.py
+++ b/backend/app/subgraphs/news_analysis/graph.py
@@ -3,7 +3,7 @@
News Analysis Subgraph Builder
"""
-from langgraph.graph import StateGraph, START, END
+from app.main_graph.graph import StateGraph, START, END
from .state import NewsAnalysisState
from .nodes import (
diff --git a/backend/app/agent_subgraphs/news_analysis/nodes.py b/backend/app/subgraphs/news_analysis/nodes.py
similarity index 100%
rename from backend/app/agent_subgraphs/news_analysis/nodes.py
rename to backend/app/subgraphs/news_analysis/nodes.py
diff --git a/backend/app/agent_subgraphs/news_analysis/state.py b/backend/app/subgraphs/news_analysis/state.py
similarity index 100%
rename from backend/app/agent_subgraphs/news_analysis/state.py
rename to backend/app/subgraphs/news_analysis/state.py