From a85cdb687d0d968f2c008d7a77def12f329cda69 Mon Sep 17 00:00:00 2001 From: lintsinghua Date: Sun, 14 Dec 2025 14:52:06 +0800 Subject: [PATCH] =?UTF-8?q?refactor(agent):=20=E9=87=8D=E6=9E=84Agent?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E5=B9=B6=E5=AE=9E=E7=8E=B0=E5=8A=A8=E6=80=81?= =?UTF-8?q?Agent=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat(sandbox): 增强沙箱工具的错误处理和日志记录 test(verification): 添加沙箱验证工具的独立测试脚本 docs: 删除过时的文档和测试文件 --- backend/README_UV.md | 93 ---- backend/UV_MIGRATION.md | 82 --- backend/app/services/agent/graph/runner.py | 25 +- .../app/services/agent/tools/sandbox_tool.py | 14 +- backend/app/services/llm/service.py | 49 +- backend/scripts/test_verification_sandbox.py | 179 ++++++ backend/test_logo.py | 32 -- backend/test_msg.md | 297 ---------- backend/test_msg_2.md | 259 --------- backend/架构升级方案.md | 527 ------------------ 10 files changed, 248 insertions(+), 1309 deletions(-) delete mode 100644 backend/README_UV.md delete mode 100644 backend/UV_MIGRATION.md create mode 100644 backend/scripts/test_verification_sandbox.py delete mode 100644 backend/test_logo.py delete mode 100644 backend/test_msg.md delete mode 100644 backend/test_msg_2.md delete mode 100644 backend/架构升级方案.md diff --git a/backend/README_UV.md b/backend/README_UV.md deleted file mode 100644 index 9acf9ad..0000000 --- a/backend/README_UV.md +++ /dev/null @@ -1,93 +0,0 @@ -# 使用 uv 管理 Python 依赖 - -本项目已迁移到使用 [uv](https://github.com/astral-sh/uv) 作为 Python 依赖管理器。 - -## 快速开始 - -### 安装 uv - -```bash -# macOS/Linux -curl -LsSf https://astral.sh/uv/install.sh | sh - -# 或使用 Homebrew -brew install uv -``` - -### 安装依赖 - -```bash -cd backend -uv sync -``` - -这会自动创建虚拟环境并安装所有依赖。 - -### 运行项目 - -```bash -# 激活虚拟环境(uv 会自动管理) -uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload - -# 或使用 uv 直接运行 -uv run python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload -``` - -### 数据库迁移 - -```bash -uv run alembic upgrade head -``` - -### 添加新依赖 - -```bash -# 添加依赖 -uv add package-name - -# 添加开发依赖 -uv add --dev package-name -``` - -### 更新依赖 - -```bash -uv sync --upgrade -``` - -### 其他常用命令 - -```bash -# 查看已安装的包 -uv pip list - -# 运行 Python 脚本 -uv run python script.py - -# 运行 Alembic 命令 -uv run alembic -``` - -## 从 pip/venv 迁移 - -如果你之前使用 pip 和 venv: - -1. 删除旧的虚拟环境(可选): - ```bash - rm -rf venv - ``` - -2. 使用 uv 同步依赖: - ```bash - uv sync - ``` - -3. 之后使用 `uv run` 运行命令,或激活 uv 创建的虚拟环境。 - -## 优势 - -- **速度快**:比 pip 快 10-100 倍 -- **可复现**:自动生成锁文件 -- **简单**:一个命令管理所有依赖 -- **兼容**:完全兼容 pip 和 requirements.txt - diff --git a/backend/UV_MIGRATION.md b/backend/UV_MIGRATION.md deleted file mode 100644 index 8852511..0000000 --- a/backend/UV_MIGRATION.md +++ /dev/null @@ -1,82 +0,0 @@ -# 迁移到 uv 依赖管理器 - -## ✅ 已完成的工作 - -1. **初始化 uv 项目** - - 创建了 `pyproject.toml` 配置文件 - - 所有依赖已迁移到 `pyproject.toml` - -2. **依赖管理** - - 使用 `uv sync` 安装所有依赖 - - 创建了 `.venv` 虚拟环境(uv 自动管理) - - 生成了 `requirements-lock.txt` 锁定文件 - -3. **工具和脚本** - - 创建了 `start.sh` 启动脚本 - - 创建了 `README_UV.md` 使用文档 - -## 📝 使用方式 - -### 启动服务 - -```bash -cd backend -./start.sh -``` - -或手动启动: - -```bash -cd backend -uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload -``` - -### 数据库迁移 - -```bash -cd backend -uv run alembic upgrade head -``` - -### 添加新依赖 - -```bash -cd backend -uv add package-name -``` - -## 🔄 从旧环境迁移 - -如果你之前使用 `venv` 和 `pip`: - -1. **删除旧虚拟环境**(可选): - ```bash - rm -rf venv - ``` - -2. **使用 uv 同步**: - ```bash - uv sync - ``` - -3. **之后使用 `uv run` 运行所有命令** - -## 📦 依赖文件说明 - -- `pyproject.toml` - 项目配置和依赖声明(主要文件) -- `requirements.txt` - 保留用于兼容性,但建议使用 `pyproject.toml` -- `requirements-lock.txt` - 自动生成的锁定文件(确保可复现) - -## ⚠️ 注意事项 - -- uv 创建的虚拟环境在 `.venv/` 目录(不是 `venv/`) -- 使用 `uv run` 运行命令会自动使用正确的虚拟环境 -- 也可以手动激活:`source .venv/bin/activate` - -## 🎯 优势 - -- ⚡ **速度快**:比 pip 快 10-100 倍 -- 🔒 **可复现**:自动生成锁定文件 -- 🎯 **简单**:一个命令管理所有依赖 -- 🔄 **兼容**:完全兼容 pip 和 requirements.txt - diff --git a/backend/app/services/agent/graph/runner.py b/backend/app/services/agent/graph/runner.py index 8f6c07c..69822d5 100644 --- a/backend/app/services/agent/graph/runner.py +++ b/backend/app/services/agent/graph/runner.py @@ -271,6 +271,7 @@ class AgentRunner: } # 沙箱工具(仅 Verification Agent 可用) + self.sandbox_manager = None try: from app.services.agent.tools.sandbox_tool import SandboxConfig sandbox_config = SandboxConfig( @@ -281,17 +282,27 @@ class AgentRunner: network_mode=settings.SANDBOX_NETWORK_MODE, ) self.sandbox_manager = SandboxManager(config=sandbox_config) + except Exception as e: + logger.warning(f"❌ Sandbox Manager initialization failed: {e}") + import traceback + logger.warning(f"Traceback: {traceback.format_exc()}") + # 尝试创建默认管理器作为后备 + try: + self.sandbox_manager = SandboxManager() + logger.info("⚠️ Created fallback SandboxManager (Docker might be unavailable)") + except Exception as e2: + logger.error(f"❌ Failed to create fallback SandboxManager: {e2}") + # 始终注册沙箱工具,即使 Docker 不可用(工具内部会检查) + if self.sandbox_manager: self.verification_tools["sandbox_exec"] = SandboxTool(self.sandbox_manager) self.verification_tools["sandbox_http"] = SandboxHttpTool(self.sandbox_manager) self.verification_tools["verify_vulnerability"] = VulnerabilityVerifyTool(self.sandbox_manager) - logger.info(f"✅ Sandbox tools initialized successfully: sandbox_exec, sandbox_http, verify_vulnerability") - logger.info(f"✅ Verification tools: {list(self.verification_tools.keys())}") - - except Exception as e: - logger.warning(f"❌ Sandbox initialization failed: {e}") - import traceback - logger.warning(f"Traceback: {traceback.format_exc()}") + logger.info(f"✅ Sandbox tools initialized (Docker available: {self.sandbox_manager.is_available})") + else: + logger.error("❌ Sandbox tools NOT initialized due to critical manager failure") + + logger.info(f"✅ Verification tools: {list(self.verification_tools.keys())}") # 统计总工具数 total_tools = len(set( diff --git a/backend/app/services/agent/tools/sandbox_tool.py b/backend/app/services/agent/tools/sandbox_tool.py index 03ff701..fcdc777 100644 --- a/backend/app/services/agent/tools/sandbox_tool.py +++ b/backend/app/services/agent/tools/sandbox_tool.py @@ -614,12 +614,15 @@ class SandboxHttpTool(AgentTool): **kwargs ) -> ToolResult: """执行 HTTP 请求""" - await self.sandbox_manager.initialize() + try: + await self.sandbox_manager.initialize() + except Exception as e: + logger.warning(f"Sandbox init failed during execution: {e}") if not self.sandbox_manager.is_available: return ToolResult( success=False, - error="沙箱环境不可用", + error="沙箱环境不可用 (Docker Unavailable)", ) result = await self.sandbox_manager.execute_http_request( @@ -716,12 +719,15 @@ class VulnerabilityVerifyTool(AgentTool): **kwargs ) -> ToolResult: """执行漏洞验证""" - await self.sandbox_manager.initialize() + try: + await self.sandbox_manager.initialize() + except Exception as e: + logger.warning(f"Sandbox init failed during execution: {e}") if not self.sandbox_manager.is_available: return ToolResult( success=False, - error="沙箱环境不可用", + error="沙箱环境不可用 (Docker Unavailable)", ) result = await self.sandbox_manager.verify_vulnerability( diff --git a/backend/app/services/llm/service.py b/backend/app/services/llm/service.py index dee4eec..8ef0c70 100644 --- a/backend/app/services/llm/service.py +++ b/backend/app/services/llm/service.py @@ -8,7 +8,7 @@ import re import logging from typing import Dict, Any, Optional, List from .types import LLMConfig, LLMProvider, LLMMessage, LLMRequest, DEFAULT_MODELS -from .factory import LLMFactory +from .factory import LLMFactory, NATIVE_ONLY_PROVIDERS from app.core.config import settings # json-repair 库用于修复损坏的 JSON @@ -460,8 +460,6 @@ Please analyze the following code: Yields: dict: {"type": "token", "content": str} 或 {"type": "done", ...} """ - from .adapters.litellm_adapter import LiteLLMAdapter - llm_messages = [ LLMMessage(role=msg["role"], content=msg["content"]) for msg in messages @@ -473,11 +471,46 @@ Please analyze the following code: max_tokens=max_tokens, ) - # 使用 LiteLLM adapter 进行流式调用 - adapter = LiteLLMAdapter(self.config) - - async for chunk in adapter.stream_complete(request): - yield chunk + if self.config.provider in NATIVE_ONLY_PROVIDERS: + adapter = LLMFactory.create_adapter(self.config) + response = await adapter.complete(request) + content = response.content or "" + usage = None + if response.usage: + usage = { + "prompt_tokens": response.usage.prompt_tokens or 0, + "completion_tokens": response.usage.completion_tokens or 0, + "total_tokens": response.usage.total_tokens or 0, + } + if not content: + yield { + "type": "done", + "content": "", + "usage": usage, + "finish_reason": response.finish_reason or "stop", + } + else: + accumulated = "" + chunk_size = 20 + for i in range(0, len(content), chunk_size): + part = content[i:i + chunk_size] + accumulated += part + yield { + "type": "token", + "content": part, + "accumulated": accumulated, + } + yield { + "type": "done", + "content": content, + "usage": usage, + "finish_reason": response.finish_reason or "stop", + } + else: + from .adapters.litellm_adapter import LiteLLMAdapter + adapter = LiteLLMAdapter(self.config) + async for chunk in adapter.stream_complete(request): + yield chunk def _parse_json(self, text: str) -> Dict[str, Any]: """从LLM响应中解析JSON(增强版)""" diff --git a/backend/scripts/test_verification_sandbox.py b/backend/scripts/test_verification_sandbox.py new file mode 100644 index 0000000..e788cc2 --- /dev/null +++ b/backend/scripts/test_verification_sandbox.py @@ -0,0 +1,179 @@ + +import asyncio +import os +import sys +import json +import logging +from typing import Dict, Any, List + +# Add backend to path +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from app.db.session import AsyncSessionLocal +from app.models.user_config import UserConfig +from app.services.llm.service import LLMService +from app.services.agent.agents.verification import VerificationAgent +from app.services.agent.tools.sandbox_tool import SandboxTool, SandboxHttpTool, VulnerabilityVerifyTool, SandboxManager, SandboxConfig +from app.services.agent.agents.base import AgentType +from app.services.agent.config import AgentConfig +from app.core.config import settings +from sqlalchemy import select + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +async def get_user_llm_config(): + """Fetch LLM configuration from the first user in the database""" + async with AsyncSessionLocal() as session: + result = await session.execute(select(UserConfig)) + user_config = result.scalars().first() + + if not user_config: + logger.error("❌ No user config found in database!") + return None + + logger.info(f"✅ Loaded config for user_id: {user_config.user_id}") + + import json + raw_config = user_config.llm_config + llm_data = json.loads(raw_config) if raw_config else {} + logger.info(f"📂 Loaded LLM config keys: {list(llm_data.keys())}") + + # Try to find keys regardless of naming convention (camelCase vs snake_case) + api_key = llm_data.get("api_key") or llm_data.get("llmApiKey") or llm_data.get("apiKey") + base_url = llm_data.get("base_url") or llm_data.get("llmBaseUrl") or llm_data.get("baseUrl") + model = llm_data.get("model") or llm_data.get("llmModel") + provider = llm_data.get("provider") or llm_data.get("llmProvider") + + return { + "api_key": api_key, + "base_url": base_url, + "model": model, + "provider": provider + } + +async def run_verification_test(): + print("\n🚀 Starting Verification Agent Sandbox Test (Standalone Mode)\n") + + llm_config = await get_user_llm_config() + if not llm_config: + return + + override_provider = os.getenv("TEST_LLM_PROVIDER") + override_api_key = os.getenv("TEST_LLM_API_KEY") + override_model = os.getenv("TEST_LLM_MODEL") + + if override_provider or override_api_key or override_model: + llm_config["provider"] = override_provider or llm_config.get("provider") + llm_config["api_key"] = override_api_key or llm_config.get("api_key") + llm_config["model"] = override_model or llm_config.get("model") + + # 2. Initialize LLM Service + # Transform simple config to the structure LLMService expects + service_user_config = { + "llmConfig": { + "llmProvider": llm_config.get("provider"), + "llmApiKey": llm_config.get("api_key"), + "llmModel": llm_config.get("model"), + "llmBaseUrl": llm_config.get("base_url") + } + } + llm_service = LLMService(user_config=service_user_config) + + # Also update settings just in case + if llm_config.get("api_key"): + settings.LLM_API_KEY = llm_config["api_key"] + + print(f"🔧 Configured LLM: {llm_config.get('provider')} / {llm_config.get('model')}") + + # 3. Initialize Sandbox Tools + print("📦 Initializing Sandbox Tools...") + try: + sandbox_config = SandboxConfig( + image=settings.SANDBOX_IMAGE, + memory_limit=settings.SANDBOX_MEMORY_LIMIT, + cpu_limit=settings.SANDBOX_CPU_LIMIT, + timeout=settings.SANDBOX_TIMEOUT, + network_mode=settings.SANDBOX_NETWORK_MODE, + ) + sandbox_manager = SandboxManager(config=sandbox_config) + # Pre-check docker + await sandbox_manager.initialize() + if sandbox_manager.is_available: + print("✅ Docker Sandbox is AVAILABLE") + else: + print("⚠️ Docker Sandbox is UNAVAILABLE (Tools will return error messages)") + + tools = { + "sandbox_exec": SandboxTool(sandbox_manager), + "sandbox_http": SandboxHttpTool(sandbox_manager), + "verify_vulnerability": VulnerabilityVerifyTool(sandbox_manager) + } + except Exception as e: + print(f"❌ Failed to init sandbox: {e}") + return + + # 4. Initialize Verification Agent + # VerificationAgent.__init__ does not take 'config' argument, it builds it internally. + agent = VerificationAgent( + llm_service=llm_service, + tools=tools + ) + + # 5. Create Mock Input (Simulating a Command Injection Finding) + mock_findings = [ + { + "id": "finding_123", + "type": "command_injection", + "file": "legacy/vuln.php", + "line": 42, + "code": "", + "confidence": "high", + "severity": "critical", + "description": "User input is directly passed to system() function.", + "context": "Legacy admin panel file." + } + ] + + input_data = { + "previous_results": { + "findings": mock_findings + }, + "task": "Verify this critical command injection vulnerability using sandbox tools.", + } + + print("\n🎯 Starting Verification Task...") + print(f"Input: {json.dumps(input_data, indent=2, ensure_ascii=False)}") + print("-" * 50) + + # 6. Run Agent + try: + result = await agent.run(input_data) + print("\n✅ Verification Completed!") + print("-" * 50) + if hasattr(result, "model_dump"): + print(json.dumps(result.model_dump(), indent=2, ensure_ascii=False)) + elif hasattr(result, "__dict__"): + print(json.dumps(result.__dict__, indent=2, ensure_ascii=False, default=str)) + else: + print(str(result)) + + stats = agent.get_stats() + print(f"\n📊 Stats: Tool Calls={stats['tool_calls']}, Tokens={stats['tokens_used']}") + if stats.get("tool_calls", 0) == 0: + print("\n⚠️ LLM 未调用任何工具,直接通过 VerificationAgent.execute_tool 测试 sandbox_exec...") + observation = await agent.execute_tool( + "sandbox_exec", + {"command": "echo sandbox_test", "timeout": 10} + ) + print("\n🔍 Direct sandbox_exec result:") + print(observation) + + except Exception as e: + print(f"\n❌ Execution Failed: {e}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + asyncio.run(run_verification_test()) diff --git a/backend/test_logo.py b/backend/test_logo.py deleted file mode 100644 index 2b1d388..0000000 --- a/backend/test_logo.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -import base64 - -def test_logo_read(): - try: - # 模拟 ReportGenerator 中的路径逻辑 - current_dir = os.getcwd() # 假设我们在 backend 目录下运行 - # 调整逻辑以匹配 ReportGenerator.__file__ 的行为 - # 假设脚本在 backend/app/services/test_logo.py - - # 直接使用绝对路径进行测试,排除相对路径计算干扰 - project_root = "/Users/lintsinghua/DeepAudit" - logo_path = os.path.join(project_root, 'frontend/public/logo_deepaudit.png') - - print(f"Looking for logo at: {logo_path}") - - if os.path.exists(logo_path): - print("File exists.") - with open(logo_path, "rb") as image_file: - data = image_file.read() - b64 = base64.b64encode(data).decode('utf-8') - print(f"Read {len(data)} bytes.") - print(f"Base64 length: {len(b64)}") - print(f"Base64 prefix: {b64[:50]}...") - else: - print("File does NOT exist.") - - except Exception as e: - print(f"Error: {e}") - -if __name__ == "__main__": - test_logo_read() diff --git a/backend/test_msg.md b/backend/test_msg.md deleted file mode 100644 index b93b71e..0000000 --- a/backend/test_msg.md +++ /dev/null @@ -1,297 +0,0 @@ -前端页面情况: - -16:18:28 -🔗 Connected to audit stream -16:18:43 -Orchestrator -Thought: 我需要首先了解这个项目的整体结构和功能,以便确定审计的重点。从目录结构来看,这是一个复杂的多模块系统,包含多个引擎(MediaEngine, MindSpider, QueryEngine等)和相关的报告系统。我应该先使用recon Agent来分析项目结构、技术栈和入口点,以便后续有针对性地进行安全审计。 -16:18:49 -📤 调度 recon Agent: 分析项目整体结构、技术栈、入口点和主要功能模块... -Orchestrator -16:18:57 -Recon -Thought: 用户指定了审计范围是1个目标文件:InsightEngine/llms/__init__.py。我需要直接读取和分析这个文件,不要浪费时间遍历其他目录。首先,我应该读取这个文件的内容来了解其结构和功能。 -16:19:00 -Completed: read_file -Recon -0ms -16:19:10 -Recon -Thought: 我已经读取了指定的文件 InsightEngine/llms/__init__.py。这是一个简单的Python模块初始化文件,它从.base模块导入了LLMClient类。为了更好地理解这个模块的上下文和依赖关系,我应该搜索项目中是否有其他相关的文件,特别是base.py文件,以及可能使用LLMClient的其他文件。 -16:19:13 -Completed: search_code -Recon -13ms -16:19:15 -Recon -Thought: 搜索结果显示LLMClient只在InsightEngine/llms/__init__.py文件中被引用。为了更全面地了解这个模块,我应该查找base.py文件,因为它是LLMClient的定义所在。同时,我也应该搜索项目中是否有其他使用这个LLMClient的文件,以了解它的使用场景。 -16:19:17 -Completed: search_code -Recon -6ms -16:19:19 -Recon -Thought: 搜索base.py没有找到结果。让我尝试搜索"from .base"或"import base"来找到base模块的定义位置。同时,我也应该搜索整个项目中是否有其他文件引用了InsightEngine.llms或LLMClient,以了解这个模块的使用范围。 -16:19:21 -Completed: search_code -Recon -6ms -16:19:23 -Recon -Thought: 看来base.py文件可能不在审计范围内,或者它可能是一个不存在的文件。让我尝试搜索"InsightEngine"来了解这个模块在整个项目中的使用情况,以及是否有其他相关的LLM或大语言模型相关的文件。 -16:19:25 -Completed: search_code -Recon -8ms -16:19:48 -Recon -Thought: 看起来搜索范围仅限于用户指定的单个文件。根据用户的要求,审计范围限定为1个目标文件:InsightEngine/llms/__init__.py。这意味着我只能分析这个文件,而不能访问项目中的其他文件。 - -让我总结一下从这个文件中收集到的信息: -1. 这是一个名为LLM的模块,为Insight Engine提供统一的OpenAI兼容客户端 -2. 它从.base模块导入了LLMClient类 -3. 它通过__all__列表暴露了LLMClient类 - -由于base.py文件不在审计范围内,我无法获取LLMClient的具体实现。但根据文件描述,这个模块似乎是一个大语言模型(LLM)客户端,可能与OpenAI API兼容。 -16:19:58 -Completed: reflect -Recon -0ms -16:19:59 -Recon -Thought: 我已经完成了对指定文件的分析。由于审计范围被限定为单个文件,我无法获取更多关于项目结构、技术栈、入口点等信息。我现在可以总结收集到的信息并输出最终结果。 - -Final Answer: -```json -{ - "project_structure": { - "directories": [], - "config_files": [], - "total_files": 1 - }, - "tech_stack": { - "languages": ["Python"], - "frameworks": [], - "databases": [] - }, - "entry_points": [ - {"type": "module_init", "file": "InsightEngine/llms/__init__.py", "line": 6} - ], - "high_risk_areas": [], - "dependencies": { - "internal": ["base.LLMClient"], - "external": [] - }, - "initial_findings": [] -} -``` -16:20:05 -✅ recon Agent 完成 -Orchestrator -16:20:07 -Orchestrator -Thought: Recon Agent的结果显示只分析了1个文件,这与项目目录结构中显示的多个目录和文件不符。这可能是因为Recon Agent没有正确扫描整个项目结构。我需要重新调度Recon Agent,或者直接转向Analysis Agent进行更深入的分析。考虑到项目结构复杂,包含多个引擎模块,我应该尝试让Analysis Agent直接对整个项目进行安全审计,重点关注用户指定的漏洞类型:SQL注入、XSS、命令注入、路径遍历和SSRF。 -16:20:15 -📤 调度 analysis Agent: 对整个项目进行安全审计,重点关注SQL注入、XSS、命令注入、路径遍历和SSRF漏洞... -Orchestrator -16:20:18 -Analysis -Thought: 我需要分析指定的文件 InsightEngine/llms/__init__.py。首先,我应该读取这个文件的内容,了解其结构和功能,然后根据代码内容选择合适的分析工具来检测潜在的安全漏洞。 -16:20:21 -Completed: read_file -Analysis -1ms -16:20:23 -Analysis -Thought: 这个文件是一个简单的Python模块初始化文件,它只导入了`LLMClient`类并定义了`__all__`列表。文件本身非常短,没有明显的安全漏洞。但是,为了全面分析,我需要查看被导入的`base.py`文件,因为实际的实现逻辑可能在那里。我应该继续读取`base.py`文件来进行更深入的安全分析。 -16:20:25 -Completed: read_file -Analysis -0ms -16:20:43 -Analysis -Thought: 我只能分析用户指定的文件,即 InsightEngine/llms/__init__.py。这个文件本身非常简单,只包含导入语句和模块定义,没有明显的安全漏洞。由于文件内容非常有限,我可以使用 pattern_match 工具来进一步确认是否存在任何潜在的安全模式,尽管从目前来看,这个文件几乎不可能包含安全漏洞。 -16:20:49 -Completed: pattern_match -Analysis -5ms -16:21:41 -Analysis -Thought: 我已经完成了对 InsightEngine/llms/__init__.py 文件的分析。这个文件是一个简单的Python模块初始化文件,只包含导入语句和模块定义,没有包含任何可能存在安全漏洞的代码。pattern_match 工具也没有检测到任何已知的危险模式。由于这个文件非常简单且只包含导入语句,它本身不会构成安全风险。我应该总结分析结果。 -16:21:48 -Completed: reflect -Analysis -0ms -16:21:50 -Analysis -Thought: 我已经完成了对 InsightEngine/llms/__init__.py 文件的全面安全分析。这个文件非常简单,只包含导入语句和模块定义,没有包含任何可能存在安全漏洞的代码。pattern_match 工具也没有检测到任何已知的危险模式。由于这个文件本身不包含任何业务逻辑或敏感操作,它不会构成安全风险。现在我可以提供最终的分析结果。 - -Final Answer: { - "findings": [], - "summary": "已完成对 InsightEngine/llms/__init__.py 文件的安全分析。该文件是一个简单的Python模块初始化文件,只包含导入语句和模块定义,没有包含任何可能存在安全漏洞的代码。pattern_match 工具也没有检测到任何已知的危险模式。由于这个文件本身不包含任何业务逻辑或敏感操作,它不会构成安全风险。" -} -16:22:00 -Analysis -```json -{ - "findings": [], - "summary": "已完成对 InsightEngine/llms/__init__.py 文件的安全分析。该文件是一个简单的Python模块初始化文件,只包含导入语句和模块定义,没有包含任何可能存在安全漏洞的代码。pattern_match 工具也没有检测到任何已知的危险模式。由于这个文件本身不包含任何业务逻辑或敏感操作,它不会构成安全风险。" -} -``` -16:22:04 -✅ analysis Agent 完成 -Orchestrator -16:22:05 -Orchestrator -Thought: Analysis Agent也没有发现任何漏洞,这很奇怪,因为项目结构复杂且包含多个模块。可能是因为Agent没有正确访问到所有文件。让我尝试直接查看一些关键文件,特别是入口点文件如app.py和report_engine_only.py,这些通常是用户交互的主要入口点,可能包含安全漏洞。 -16:22:11 -📤 调度 recon Agent: 重新分析项目,重点关注入口点文件和主要模块... -Orchestrator -16:22:18 -Recon -Thought: 我需要收集项目信息,但审计范围限定为1个目标文件:InsightEngine/llms/__init__.py。用户还提到之前的分析可能没有正确访问到所有文件,需要关注app.py、report_engine_only.py等入口点文件。我应该先读取指定的目标文件,然后探索项目结构以获取更全面的信息。 -16:22:22 -Completed: read_file -Recon -1ms -16:22:23 -Recon -Thought: 我已经读取了指定的目标文件 InsightEngine/llms/__init__.py,这是一个简单的模块初始化文件,它从 .base 导入了 LLMClient 类。现在我需要探索项目结构,了解整个项目的组织方式,特别是用户提到的 app.py、report_engine_only.py 等入口点文件。我将列出根目录的内容来获取项目结构。 -16:22:28 -Completed: list_files -Recon -18ms -16:23:05 -Recon -Thought: 系统显示审计范围限定为1个指定文件,但我注意到用户在任务上下文中特别提到了需要关注app.py、report_engine_only.py等入口点文件。我应该尝试搜索这些关键文件,看看它们是否存在于项目中。我将先搜索app.py文件。 -16:23:08 -Completed: search_code -Recon -17ms -16:23:11 -Recon -Thought: 没有找到app.py文件。让我尝试搜索report_engine_only.py文件,看看它是否存在。 -16:23:12 -Completed: search_code -Recon -9ms -16:23:43 -Recon -Thought: 看来系统中确实只有指定的1个文件。让我尝试搜索其他可能的入口点文件,比如main.py或index.py,看看是否有其他入口点。 -16:23:46 -Completed: search_code -Recon -19ms -16:23:47 -Recon -Thought: 系统中似乎只有指定的1个文件。让我尝试搜索Python文件中常见的入口点模式,比如"if __name__ == '__main__'",看看是否有其他入口点代码。 -16:23:50 -Completed: search_code -Recon -9ms -16:23:54 -Recon -Thought: 系统中确实只有指定的1个文件。让我尝试搜索其他可能的关键词,比如"Flask"、"Django"等框架相关的关键词,看看是否能推断出技术栈。 -16:23:57 -Completed: search_code -Recon -9ms -16:23:58 -Recon -Thought: 让我尝试搜索其他常见的技术栈关键词,比如"import"语句,看看能收集到什么信息。 -16:24:00 -Completed: search_code -Recon -9ms -16:24:01 -Recon -Thought: 我找到了一个import语句,它从.base模块导入了LLMClient。让我尝试搜索其他可能的技术栈关键词,比如"from"语句,看看是否有其他导入。 -16:24:03 -Completed: search_code -Recon -8ms -16:24:19 -Recon -Thought: 我已经收集了足够的信息。系统中只有指定的1个文件:InsightEngine/llms/__init__.py。这是一个简单的模块初始化文件,它从.base模块导入了LLMClient类。由于系统中只有这一个文件,我无法收集到更多的项目结构、技术栈、入口点等信息。现在我将整理收集到的信息并输出结果。 - -Final Answer: -```json -{ - "project_structure": { - "directories": ["InsightEngine/llms"], - "config_files": [], - "total_files": 1 - }, - "tech_stack": { - "languages": ["Python"], - "frameworks": [], - "databases": [] - }, - "entry_points": [ - {"type": "module_init", "file": "InsightEngine/llms/__init__.py", "line": 6} - ], - "high_risk_areas": [], - "dependencies": {}, - "initial_findings": [] -} -``` -16:24:52 -✅ recon Agent 完成 -Orchestrator -16:24:54 -Orchestrator -Thought: Recon Agent仍然只找到了1个文件,这与项目目录结构严重不符。看起来Agent可能无法正确访问项目中的所有文件。考虑到这种情况,我应该尝试直接查看一些关键文件的内容,特别是app.py和report_engine_only.py,这些是项目的主要入口点。我将尝试使用Verification Agent来直接检查这些文件。 -16:24:58 -📤 调度 verification Agent: 直接检查项目入口点文件app.py和report_engine_only.py的安全问题... -Orchestrator -16:24:58 -✅ verification Agent 完成 -Orchestrator -16:24:58 -Orchestrator -Thought: 所有Agent似乎都无法正确访问项目中的文件,这可能是由于项目访问权限或路径问题导致的。根据用户提供的信息,我们知道项目包含多个目录和文件,但所有Agent都只返回了很少的信息。在这种情况下,我应该基于用户提供的信息和目录结构进行推理分析,并尝试总结可能的安全风险点。 -16:25:11 -Orchestrator -Thought: 虽然所有Agent都无法直接访问项目文件进行详细分析,但我已经基于项目目录结构进行了推理分析。由于系统限制无法获取更多详细信息,我应该结束审计并总结我的发现和建议。 - - -后端日志: -lintsinghua@lintsinghuadeMacBook-Pro backend % uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload -INFO: Will watch for changes in these directories: ['/Users/lintsinghua/XCodeReviewer/backend'] -INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: Started reloader process [94873] using WatchFiles -INFO: Started server process [94875] -INFO: Waiting for application startup. -INFO:app.main:DeepAudit 后端服务启动中... -INFO:app.db.init_db:开始初始化数据库... -INFO:app.db.init_db:演示账户已存在: demo@example.com -INFO:app.db.init_db:演示数据已存在,跳过创建 -INFO:app.services.init_templates:开始初始化系统模板和规则... -INFO:app.services.init_templates:✓ 系统模板和规则初始化完成 -INFO:app.db.init_db:数据库初始化完成 -INFO:app.main:✓ 数据库初始化完成 -INFO:app.main:================================================== -INFO:app.main:DeepAudit 后端服务已启动 -INFO:app.main:API 文档: http://localhost:8000/docs -INFO:app.main:================================================== -INFO:app.main:演示账户: demo@example.com / demo123 -INFO:app.main:================================================== -INFO: Application startup complete. -[Branch] 项目: d, 类型: github, URL: https://github.com/666ghj/BettaFish -[Branch] GitHub Token: 未配置, GitLab Token: 未配置 -[Branch] 警告: GitHub Token 未配置,可能会遇到 API 限制 -INFO:httpx:HTTP Request: GET https://api.github.com/repos/666ghj/BettaFish/branches?per_page=100 "HTTP/1.1 200 OK" -[Branch] 成功获取 7 个分支 -INFO:httpx:HTTP Request: GET https://api.github.com/repos/666ghj/BettaFish/git/trees/main?recursive=1 "HTTP/1.1 200 OK" -INFO:app.api.v1.endpoints.agent_tasks:Created agent task 8717c2de-fedc-4d39-bb19-6b186da9e610 for project d -INFO:app.api.v1.endpoints.agent_tasks:✅ Cloned repository https://github.com/666ghj/BettaFish (branch: main) to /tmp/deepaudit/8717c2de-fedc-4d39-bb19-6b186da9e610 -INFO:app.api.v1.endpoints.agent_tasks:🚀 Task 8717c2de-fedc-4d39-bb19-6b186da9e610 started with Dynamic Agent Tree architecture -WARNING:app.services.agent.agents.recon:[Recon] Empty LLM response in iteration 1 -WARNING:app.services.agent.agents.analysis:[Analysis] Empty LLM response in iteration 4 -ERROR:app.api.v1.endpoints.agent_tasks:Task 8717c2de-fedc-4d39-bb19-6b186da9e610 failed: property 'progress_percentage' of 'AgentTask' object has no setter -Traceback (most recent call last): - File "/Users/lintsinghua/XCodeReviewer/backend/app/api/v1/endpoints/agent_tasks.py", line 392, in _execute_agent_task - task.progress_percentage = 100.0 - ^^^^^^^^^^^^^^^^^^^^^^^^ -AttributeError: property 'progress_percentage' of 'AgentTask' object has no setter -WARNING: WatchFiles detected changes in 'app/services/llm/adapters/litellm_adapter.py'. Reloading... diff --git a/backend/test_msg_2.md b/backend/test_msg_2.md deleted file mode 100644 index d2cf94e..0000000 --- a/backend/test_msg_2.md +++ /dev/null @@ -1,259 +0,0 @@ -前端页面输出: - -16:36:05 -🔗 Connected to audit stream -16:36:35 -Orchestrator -Thought: 我需要对这个PHP项目进行安全审计,但审计范围已经限定为单个文件(agent_t/1.php)。由于不需要分析整个项目结构,我可以直接调度analysis Agent对这个文件进行深度安全审计,重点关注用户指定的漏洞类型:SQL注入、XSS、命令注入、路径遍历和SSRF。 -16:36:44 -📤 调度 analysis Agent: 对agent_t/1.php文件进行深度安全审计,重点检查sql_injection、xss、command_injection、path_traversal、ssrf等漏洞类型... -Orchestrator -16:36:51 -Analysis -Thought: 我需要分析agent_t/1.php文件,重点关注SQL注入、XSS、命令注入、路径遍历和SSRF漏洞。首先,我应该读取文件内容,了解代码结构和逻辑,然后使用pattern_match工具进行初步扫描,检测常见的不安全模式。 -16:36:55 -Completed: read_file -Analysis -0ms -16:36:56 -Analysis -Thought: 我已经读取了agent_t/1.php文件的内容。这是一个明显包含多种安全漏洞的测试靶场代码。从代码注释可以看出,它故意包含了多种漏洞类型,包括SQL注入、XSS、命令注入、路径遍历、SSRF等。现在我需要使用pattern_match工具进行系统化的漏洞检测,确认这些漏洞并获取详细信息。 -16:37:45 -Completed: pattern_match -Analysis -3ms -16:37:46 -Analysis -Thought: pattern_match工具检测到了2个路径遍历漏洞,但我注意到代码中实际上包含更多类型的漏洞。让我使用semgrep_scan工具进行更全面的扫描,以检测所有目标漏洞类型,包括SQL注入、XSS、命令注入等。 -16:37:50 -Completed: semgrep_scan -Analysis -100318ms -16:39:31 -Analysis -Thought: semgrep工具不可用,我需要使用其他方法进行漏洞分析。我已经读取了文件内容,可以直接分析代码中的漏洞。从代码中我可以看到多种明显的漏洞,包括SQL注入、XSS、命令注入、路径遍历、SSRF等。让我使用dataflow_analysis工具来追踪一些关键的数据流,特别是用户输入如何流向危险函数。 -16:39:43 -Completed: dataflow_analysis -Analysis -79066ms -Input: -{ - "source_code": "$username = $_POST['username'];\n$password = $_POST['password'];\n$sql = \"SELECT * FROM users WHERE username = '$username' AND password = '$password'\";\n$result = mysql_query($sql);", - "sink_code": "mysql_query($sql);", - "variable_name": "username", - "file_path": "agent_t/1.php" -} - -Output: -null -16:41:04 -Analysis -我再尝试分析其他漏洞的数据流,特别是命令注入和XSS部分。 -16:41:08 -Completed: dataflow_analysis -Analysis -63459ms -16:42:14 -Analysis -让我尝试分析XSS漏洞的数据流: -16:42:18 -Completed: dataflow_analysis -Analysis -181539ms -Input: -{ - "source_code": "$query = $_GET['q'];\necho \"You searched for: \" . $query;", - "sink_code": "echo \"You searched for: \" . $query;", - "variable_name": "query", - "file_path": "agent_t/1.php" -} - -Output: -null -16:45:22 -Analysis -Thought: dataflow_analysis工具似乎没有返回有用的结果。不过,我已经通过读取文件内容获得了足够的信息来分析漏洞。现在我将总结在agent_t/1.php中发现的所有安全漏洞,并按照要求的格式提供最终报告。 - -从代码分析中,我发现了以下漏洞: -1. SQL注入(第34行) -2. XSS(第77行) -3. 命令注入(第50行) -4. 路径遍历(第58行) -5. SSRF(第66行) -6. 硬编码凭证(第18行) -7. 不安全的反序列化(第23行) -8. 弱加密算法(第39行) -9. 敏感信息泄露(第80行) -10. 任意文件上传(第86-87行) -11. 越权访问(第94行) -12. 不安全的随机数生成器(第98行) - -我将按照要求的格式提供最终报告。 - -Final Answer: ```json -{ - "findings": [ - { - "vulnerability_type": "sql_injection", - "severity": "high", - "title": "SQL 注入漏洞", - "description": "在登录功能中直接拼接用户输入到SQL查询语句中,没有任何过滤或参数化查询,导致SQL注入漏洞。", - "file_path": "agent_t/1.php", - "line_start": 34, - "code_snippet": "$sql = \"SELECT * FROM users WHERE username = '$username' AND password = '$password'\";", - "source": "用户输入 (POST username, password)", - "sink": "mysql_query() 函数", - "suggestion": "使用参数化查询或预处理语句,避免直接拼接SQL语句。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "xss", - "severity": "high", - "title": "跨站脚本攻击 (XSS)", - "description": "在搜索功能中直接输出用户输入,未进行HTML实体编码,导致反射型XSS漏洞。", - "file_path": "agent_t/1.php", - "line_start": 77, - "code_snippet": "echo \"You searched for: \" . $query;", - "source": "用户输入 (GET q)", - "sink": "echo 输出函数", - "suggestion": "对输出进行HTML实体编码,使用htmlspecialchars()函数。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "command_injection", - "severity": "high", - "title": "命令注入漏洞", - "description": "在ping功能中直接将用户输入传递给shell_exec函数,导致命令注入漏洞。", - "file_path": "agent_t/1.php", - "line_start": 50, - "code_snippet": "$cmd = shell_exec(\"ping -c 4 \" . $target);", - "source": "用户输入 (GET ip)", - "sink": "shell_exec() 函数", - "suggestion": "验证和过滤用户输入,使用白名单机制,避免直接执行用户提供的命令。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "path_traversal", - "severity": "high", - "title": "路径遍历漏洞", - "description": "在view功能中直接使用用户提供的文件名进行文件包含操作,允许读取服务器上的任意文件。", - "file_path": "agent_t/1.php", - "line_start": 58, - "code_snippet": "include($file);", - "source": "用户输入 (GET file)", - "sink": "include() 函数", - "suggestion": "验证和限制文件路径,使用白名单机制,避免路径遍历字符如../", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "ssrf", - "severity": "high", - "title": "服务端请求伪造 (SSRF)", - "description": "在proxy功能中直接使用用户提供的URL进行文件获取,同时禁用了SSL验证,导致SSRF漏洞。", - "file_path": "agent_t/1.php", - "line_start": 66, - "code_snippet": "$content = file_get_contents($url, false, stream_context_create([\"ssl\" => [\"verify_peer\"=>false, \"verify_peer_name\"=>false]]));", - "source": "用户输入 (GET url)", - "sink": "file_get_contents() 函数", - "suggestion": "验证和限制URL,只允许访问特定域名,启用SSL验证,使用白名单机制。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "hardcoded_secrets", - "severity": "high", - "title": "硬编码凭证", - "description": "在代码中硬编码了API密钥,可能导致凭证泄露。", - "file_path": "agent_t/1.php", - "line_start": 18, - "code_snippet": "$secret_api_key = \"12345-SUPER-SECRET-KEY\";", - "source": "硬编码值", - "sink": "变量存储", - "suggestion": "使用环境变量或安全的配置管理系统存储敏感信息。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "deserialization", - "severity": "high", - "title": "不安全的反序列化", - "description": "直接从Cookie中反序列化用户数据,可能导致远程代码执行。", - "file_path": "agent_t/1.php", - "line_start": 23, - "code_snippet": "$pref = unserialize($_COOKIE['user_pref']);", - "source": "用户输入 (Cookie user_pref)", - "sink": "unserialize() 函数", - "suggestion": "避免使用不安全的反序列化,使用JSON或其他安全的序列化方法。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "weak_crypto", - "severity": "medium", - "title": "弱加密算法", - "description": "使用MD5算法存储或验证密码,MD5已被证明不安全。", - "file_path": "agent_t/1.php", - "line_start": 39, - "code_snippet": "$hash = md5($password);", - "source": "用户输入 (POST password)", - "sink": "md5() 函数", - "suggestion": "使用强哈希算法如bcrypt、Argon2或PBKDF2。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "information_disclosure", - "severity": "medium", - "title": "敏感信息泄露", - "description": "在搜索功能中调用phpinfo()函数,泄露大量服务器信息。", - "file_path": "agent_t/1.php", - "line_start": 80, - "code_snippet": "phpinfo();", - "source": "直接调用", - "sink": "phpinfo() 函数", - "suggestion": "移除phpinfo()调用,在生产环境中禁用错误回显。", - "confidence": 1.0, - "needs_verification": false - }, - { - "vulnerability_type": "insecure_random", - "severity": "medium", - "title": "不安全的随机数生成器", - "description": "使用rand()函数生成安全令牌,该函数是可预测的。", - "file_path": "agent_t/1.php", - "line_start": 98, - "code_snippet": "$token = rand(1000, 9999);", - "source": "随机数生成", - "sink": "令牌生成", - "suggestion": "使用random_int()或更安全的随机数生成器。", - "confidence": 1.0, - "needs_verification": false - } - ], - "summary": "agent_t/1.php文件是一个包含多种严重安全漏洞的测试靶场代码。文件中存在SQL注入、XSS、命令注入、路径遍历、SSRF等多种高危漏洞,以及硬编码凭证、不安全的反序列化、弱加密算法等中危漏洞。这些漏洞组合在一起可能导致完全的系统入侵。建议立即修复所有高危漏洞,并重新评估整个应用程序的安全架构。" -} -``` -16:47:12 -✅ analysis Agent 完成 -Orchestrator -16:47:50 -Orchestrator -Thought: analysis Agent已经完成了对agent_t/1.php文件的安全审计,发现了10个安全问题,包括5个高危漏洞和5个中危漏洞。这些漏洞涵盖了用户指定的所有目标漏洞类型(SQL注入、XSS、命令注入、路径遍历、SSRF)以及其他安全问题。现在我需要调度verification Agent来验证这些发现的漏洞,特别是高危漏洞,以确保它们是真实存在的。 -16:47:53 -📤 调度 verification Agent: 验证analysis Agent在agent_t/1.php中发现的安全漏洞,特别是高危漏洞:SQL注入、XSS、命令注入、路径遍历、SSRF、硬编码凭证、不安全的反序列化,以及中危漏洞:弱加密算法、... -Orchestrator -16:47:53 -✅ verification Agent 完成 -Orchestrator -16:47:53 -Orchestrator -Thought: verification Agent返回的结果显示没有发现任何漏洞,这与analysis Agent的发现形成对比。这可能是因为verification Agent在沙箱环境中无法成功复现漏洞,或者验证过程存在问题。考虑到analysis Agent已经详细分析了代码并发现了多个安全问题,我应该基于analysis Agent的发现来总结审计结果,而不是依赖verification Agent的结果。 -16:48:11 -Orchestrator -Thought: 我已经完成了对agent_t/1.php文件的安全审计。analysis Agent发现了10个安全问题,包括7个高危漏洞和3个中危漏洞,涵盖了用户指定的所有目标漏洞类型以及其他安全问题。verification Agent没有返回结果,可能是由于沙箱环境的限制。基于analysis Agent的详细分析,我现在可以完成审计并提供结论和建议。 -16:48:27 -✅ Audit completed \ No newline at end of file diff --git a/backend/架构升级方案.md b/backend/架构升级方案.md deleted file mode 100644 index 9f96f57..0000000 --- a/backend/架构升级方案.md +++ /dev/null @@ -1,527 +0,0 @@ -DeepAudit Agent 架构重构升级方案 -一、现状分析 -当前 DeepAudit 架构特点 -DeepAudit 目前采用基于 LangGraph 的固定流程图架构。整个审计流程按照 Recon(信息收集)→ Analysis(漏洞分析)→ Verification(漏洞验证)→ Report(报告生成)的线性顺序执行。每个阶段由一个专门的 Agent 负责,Agent 之间通过 TaskHandoff 机制传递结构化的上下文信息。 - -这种架构的优点是流程清晰、易于理解和调试,但存在几个明显的局限性: - -第一,流程过于固定。无论面对什么类型的项目或漏洞,都必须走完整个流程,无法根据实际发现动态调整策略。比如发现了一个 SQL 注入线索,无法立即深入分析,必须等待 Analysis 阶段统一处理。 - -第二,Agent 专业化程度不足。Analysis Agent 需要同时处理所有类型的漏洞,从 SQL 注入到 XSS 到 SSRF,这导致系统提示词过于庞大,LLM 难以在每种漏洞类型上都表现出专家级水平。 - -第三,缺乏动态协作能力。Agent 之间只能按照预设的顺序传递信息,无法根据需要动态创建新的 Agent 或在 Agent 之间进行实时通信。 - -Strix 架构的启示 -Strix 是一个开源的 AI 安全测试 Agent 项目,它采用了完全不同的架构理念。通过深入分析 Strix 的设计,我们可以获得以下关键启示: - -Strix 的核心是动态 Agent 树结构。根 Agent 可以根据任务需要随时创建子 Agent,每个子 Agent 专注于特定的漏洞类型或任务。子 Agent 完成后向父 Agent 汇报结果,父 Agent 可以根据结果决定是否需要创建更多子 Agent 或进行其他操作。 - -Strix 的另一个亮点是模块化的专业知识系统。它为每种漏洞类型都准备了详细的 Jinja2 模板,包含该漏洞的检测方法、利用技术、绕过手段、验证步骤等专业知识。创建 Agent 时可以指定加载哪些知识模块,让 Agent 在特定领域具备专家级能力。 - -此外,Strix 还实现了 Agent 间的消息传递机制、完善的状态管理、工具的沙箱执行、LLM 调用优化等高级特性。 - -二、升级后的整体架构 -核心设计理念 -升级后的 DeepAudit 将采用"动态 Agent 协作 + 专业知识模块 + 智能编排"的三层架构。 - -最底层是专业知识模块层,包含各种漏洞类型、框架、技术栈的专业知识库。这些知识以模板形式存储,可以按需加载到 Agent 的系统提示词中。 - -中间层是 Agent 执行层,包含可动态创建和销毁的 Agent 实例。每个 Agent 都有完整的生命周期管理,可以执行任务、调用工具、与其他 Agent 通信。 - -最上层是智能编排层,负责根据审计目标和实时发现来协调整个审计流程,决定何时创建什么类型的 Agent,如何分配任务,何时结束审计。 - -动态 Agent 树 -与当前固定的四阶段流程不同,升级后的系统将采用动态 Agent 树结构。 - -审计开始时,系统创建一个根 Agent(Root Agent)。根 Agent 首先进行初步的信息收集,了解项目的技术栈、目录结构、入口点等基本信息。然后根据收集到的信息,根 Agent 决定需要创建哪些专业子 Agent。 - -例如,如果发现项目使用了 SQL 数据库,根 Agent 可能会创建一个专门的 SQL 注入检测 Agent;如果发现有用户输入直接渲染到页面的代码,可能会创建一个 XSS 检测 Agent;如果发现有 HTTP 请求的代码,可能会创建一个 SSRF 检测 Agent。 - -每个子 Agent 专注于自己的任务领域。当子 Agent 发现可疑的漏洞线索时,它可以进一步创建验证子 Agent 来确认漏洞是否真实存在。验证通过后,还可以创建报告子 Agent 来生成正式的漏洞报告。 - -这种树状结构的好处是:任务可以无限细分,每个 Agent 都能专注于自己擅长的领域;发现和验证可以并行进行,提高效率;根据实际情况动态调整策略,而不是机械地执行固定流程。 - -Agent 间通信机制 -升级后的系统将实现完善的 Agent 间通信机制。 - -每个 Agent 都有一个消息队列,其他 Agent 可以向这个队列发送消息。消息类型包括:查询消息(请求信息)、指令消息(要求执行某个操作)、信息消息(分享发现或状态)。 - -当 Agent 处于等待状态时,它会检查自己的消息队列。如果有新消息,Agent 会处理消息并可能恢复执行。这种机制使得 Agent 之间可以进行实时协作,而不仅仅是单向的结果传递。 - -例如,SQL 注入检测 Agent 在分析过程中发现某个函数可能存在问题,但需要了解这个函数的调用上下文。它可以向根 Agent 发送查询消息,请求提供相关信息。根 Agent 收到消息后,可以调用代码搜索工具获取信息,然后回复给 SQL 注入检测 Agent。 - -Agent 状态管理 -每个 Agent 都有完整的状态管理,状态信息包括: - -基本信息:Agent 的唯一标识、名称、父 Agent 标识、创建时间等。 - -任务信息:当前任务描述、任务上下文、从父 Agent 继承的信息等。 - -执行状态:当前迭代次数、最大迭代限制、运行状态(运行中、等待中、已完成、失败、已停止)等。 - -对话历史:与 LLM 的完整对话记录,包括系统提示词、用户消息、助手回复等。 - -执行记录:已执行的动作列表、观察结果列表、错误记录等。 - -发现列表:该 Agent 发现的所有漏洞和可疑点。 - -这种完整的状态管理使得 Agent 可以被暂停和恢复,可以被序列化和持久化,也便于调试和审计。 - -三、专业知识模块系统 -模块化设计 -专业知识模块是升级后架构的核心创新之一。我们将为不同的漏洞类型、框架、技术栈创建专门的知识模块。 - -漏洞类型模块包括:SQL 注入、XSS、SSRF、IDOR、认证绕过、远程代码执行、路径遍历、XXE、CSRF、竞态条件、反序列化、业务逻辑漏洞等。每个模块都包含该漏洞类型的完整知识体系。 - -框架知识模块包括:FastAPI、Django、Flask、Express、Next.js、Spring、Laravel 等主流框架。每个模块包含该框架的安全特性、常见漏洞模式、最佳实践等。 - -技术栈模块包括:Supabase、Firebase、GraphQL、gRPC、WebSocket 等。每个模块包含该技术的安全考量和常见问题。 - -模块内容结构 -以 SQL 注入模块为例,它应该包含以下内容: - -漏洞概述:SQL 注入的定义、危害、影响范围。 - -检测方法:错误型注入检测、布尔型注入检测、时间型注入检测、带外注入检测的具体技术和判断标准。 - -数据库特定知识:MySQL、PostgreSQL、MSSQL、Oracle 等不同数据库的特有语法、函数、利用技术。 - -绕过技术:WAF 绕过、过滤绕过、编码绕过等高级技术。 - -ORM 和查询构建器:各种 ORM 框架中容易出现 SQL 注入的 API 和模式。 - -验证步骤:如何确认漏洞真实存在,如何构造 PoC,如何评估影响。 - -误报识别:哪些情况容易被误判为 SQL 注入,如何排除误报。 - -修复建议:参数化查询、ORM 正确用法、输入验证等修复方案。 - -模块加载机制 -创建 Agent 时,可以指定该 Agent 需要加载哪些知识模块。系统会将这些模块的内容动态注入到 Agent 的系统提示词中。 - -为了控制提示词长度和保持 Agent 的专注度,每个 Agent 最多加载 5 个知识模块。这个限制迫使我们为每个 Agent 选择最相关的知识,而不是试图让一个 Agent 掌握所有知识。 - -模块之间可以有依赖关系。例如,FastAPI 框架模块可能依赖 Python 安全基础模块;GraphQL 模块可能依赖 API 安全基础模块。加载模块时会自动处理这些依赖。 - -四、工具系统升级 -统一的工具注册机制 -升级后的工具系统将采用装饰器模式进行统一注册。每个工具都需要提供:工具名称、功能描述、参数定义、返回值说明。 - -工具按类别组织,包括:文件操作类(读取文件、搜索文件、列出目录)、代码分析类(模式匹配、数据流分析、AST 分析)、外部扫描类(Semgrep、Bandit、Gitleaks 等)、验证执行类(沙箱命令执行、HTTP 请求)、协作类(创建子 Agent、发送消息、等待消息)、推理类(思考工具)、报告类(创建漏洞报告)。 - -Think 工具 -Think 工具是从 Strix 借鉴的关键创新。这是一个让 Agent 进行深度推理的工具,Agent 可以用它来: - -分析复杂情况:当面对复杂的代码逻辑或不确定的漏洞线索时,Agent 可以调用 Think 工具进行深入思考。 - -规划下一步行动:在执行具体操作之前,先用 Think 工具规划策略。 - -评估发现的严重性:发现可疑点后,用 Think 工具评估其真实性和影响。 - -决定是否需要创建子 Agent:当任务变得复杂时,用 Think 工具分析是否需要分解任务。 - -Think 工具的输出会被记录到 Agent 的对话历史中,帮助 LLM 保持思路的连贯性。 - -漏洞报告工具 -漏洞报告工具是正式记录漏洞的唯一方式。只有通过这个工具创建的漏洞才会被计入最终报告。这个设计确保了漏洞报告的规范性和完整性。 - -报告工具要求提供完整的漏洞信息:漏洞类型、严重程度、标题、详细描述、文件位置、代码片段、PoC、影响分析、修复建议等。 - -通常只有专门的报告 Agent 才会调用这个工具,确保漏洞在被正式报告之前已经经过了充分的验证。 - -沙箱执行 -涉及代码执行或网络请求的工具都在沙箱环境中运行。沙箱提供资源隔离(CPU、内存、网络限制)、文件系统隔离、超时控制等安全保障。 - -沙箱执行通过 Tool Server 机制实现。Agent 发送工具调用请求到 Tool Server,Tool Server 在沙箱中执行工具并返回结果。这种设计使得即使工具执行出现问题,也不会影响主系统的稳定性。 - -五、LLM 调用优化 -Prompt Caching -对于支持 Prompt Caching 的 LLM(如 Anthropic Claude),系统会自动为系统提示词和早期对话添加缓存标记。这样在多轮对话中,这些内容只需要处理一次,后续调用可以直接使用缓存,显著降低 Token 消耗和响应延迟。 - -缓存策略会根据对话长度动态调整。对于短对话,只缓存系统提示词;对于长对话,会在关键位置添加多个缓存点。 - -Memory Compression -当对话历史变得很长时,系统会自动进行压缩。压缩策略包括: - -移除冗余信息:重复的工具调用结果、过长的代码输出等会被截断或摘要。 - -合并相似消息:连续的同类型消息可能被合并。 - -保留关键信息:重要的发现、决策点、错误信息等会被优先保留。 - -压缩后的对话历史仍然保持语义完整性,LLM 可以理解之前发生了什么,但 Token 消耗大大降低。 - -智能重试 -LLM 调用可能因为各种原因失败:网络问题、速率限制、服务不可用等。系统实现了智能重试机制: - -对于可重试的错误(如速率限制),会等待适当时间后重试。 - -对于不可重试的错误(如认证失败),会立即报错并提供清晰的错误信息。 - -重试时会使用指数退避策略,避免对 LLM 服务造成过大压力。 - -六、审计流程重构 -启动阶段 -用户发起审计请求后,系统首先创建根 Agent。根 Agent 加载通用的安全审计知识模块和项目相关的框架知识模块。 - -根 Agent 的第一个任务是信息收集:扫描项目目录结构、识别技术栈、找出入口点、分析依赖关系。这个阶段类似于当前的 Recon 阶段,但更加灵活。 - -任务分解阶段 -根据信息收集的结果,根 Agent 决定如何分解审计任务。它会考虑: - -项目使用了哪些技术?需要创建哪些专业 Agent? - -有哪些高风险区域?应该优先分析哪些部分? - -项目规模如何?需要多少并行 Agent? - -根 Agent 会创建一批初始的子 Agent,每个子 Agent 负责特定的漏洞类型或代码区域。 - -并行分析阶段 -多个子 Agent 并行工作,各自在自己的专业领域进行深入分析。 - -每个子 Agent 都有自己的工作循环:思考当前状态、选择工具执行、观察结果、决定下一步。这个循环会持续进行,直到 Agent 认为任务完成或达到迭代限制。 - -子 Agent 在分析过程中可能会发现需要进一步调查的线索。这时它可以创建更专业的子 Agent 来处理,形成多层的 Agent 树。 - -验证阶段 -当分析 Agent 发现可疑的漏洞时,它会创建验证 Agent 来确认漏洞是否真实存在。 - -验证 Agent 会尝试构造 PoC、进行数据流追踪、在沙箱中测试等。验证通过后,验证 Agent 会创建报告 Agent 来生成正式的漏洞报告。 - -如果验证失败,验证 Agent 会将结果反馈给父 Agent,父 Agent 可以决定是否需要进一步调查或将其标记为误报。 - -汇总阶段 -当所有子 Agent 都完成工作后,根 Agent 会汇总所有发现,生成最终的审计报告。 - -报告包括:发现的所有漏洞(按严重程度排序)、安全评分、技术栈分析、高风险区域标注、修复建议优先级等。 - -七、可观测性和调试 -完整的事件追踪 -系统会记录所有重要事件:Agent 创建和销毁、工具调用和结果、LLM 请求和响应、Agent 间消息、状态变更等。 - -这些事件可以实时推送到前端,让用户看到审计的进展。也可以持久化到数据库,用于后续分析和审计。 - -Agent 树可视化 -前端可以展示当前的 Agent 树结构,显示每个 Agent 的状态、任务、发现数量等信息。用户可以点击任何 Agent 查看其详细信息和对话历史。 - -调试模式 -在调试模式下,系统会记录更详细的信息,包括完整的 LLM 提示词和响应、工具执行的详细日志、状态变更的完整历史等。这些信息对于排查问题和优化系统非常有价值。 - -八、与现有架构的兼容 -渐进式迁移 -升级不需要一次性完成,可以渐进式进行。 - -第一步,保持现有的 LangGraph 流程不变,但将 Agent 的状态管理升级为新的模型。 - -第二步,引入专业知识模块系统,让现有的 Analysis Agent 可以加载不同的知识模块。 - -第三步,在 Analysis 阶段内部引入子 Agent 机制,允许创建专业的漏洞检测子 Agent。 - -第四步,逐步放开流程限制,让 Agent 可以更灵活地决定下一步操作。 - -第五步,完全迁移到动态 Agent 树架构。 - -保留 LangGraph 的优势 -LangGraph 提供了很好的状态管理和检查点机制,这些在新架构中仍然有价值。我们可以将 LangGraph 用于根 Agent 的高层编排,而在子 Agent 层面使用更灵活的动态创建机制。 - -九、预期收益 -更深度的漏洞发现 -专业知识模块让每个 Agent 都具备安全专家级别的知识。专注于单一漏洞类型的 Agent 比通用 Agent 更容易发现深层次的问题。 - -更高的效率 -并行的 Agent 执行比串行流程更快。动态任务分解避免了在无关区域浪费时间。 - -更低的成本 -Prompt Caching 和 Memory Compression 显著降低 Token 消耗。专业化的 Agent 使用更短的提示词就能达到更好的效果。 - -更好的可扩展性 -添加新的漏洞类型只需要创建新的知识模块。支持新的框架只需要添加框架知识模块。整个系统的扩展不需要修改核心架构。 - -更强的可解释性 -完整的事件追踪和 Agent 树可视化让用户清楚地了解系统在做什么。Think 工具的输出展示了 Agent 的推理过程。 - -这个升级方案借鉴了 Strix 的核心设计理念,同时保留了 DeepAudit 的既有优势,通过渐进式迁移降低风险,最终实现一个更强大、更灵活、更专业的安全审计 Agent 系统。 - - ---- - -## 十、实施进度记录 - -### 已完成的工作 (2024-12) - -#### 1. 核心模块系统 ✅ -- `core/state.py`: 增强的Agent状态管理,支持完整生命周期 -- `core/registry.py`: Agent注册表和动态Agent树管理 -- `core/message.py`: Agent间通信机制(消息总线) - -#### 2. 专业知识模块系统 ✅ (基于RAG) -采用模块化文件组织,统一使用RAG进行知识检索: - -``` -knowledge/ -├── base.py # 基础定义(KnowledgeDocument, KnowledgeCategory) -├── loader.py # 知识加载器 -├── rag_knowledge.py # RAG检索系统 -├── tools.py # 知识查询工具 -├── vulnerabilities/ # 漏洞类型知识 -│ ├── injection.py # SQL注入、NoSQL注入、命令注入、代码注入 -│ ├── xss.py # 反射型XSS、存储型XSS、DOM型XSS -│ ├── auth.py # 认证绕过、IDOR、访问控制失效 -│ ├── crypto.py # 弱加密、硬编码凭证 -│ ├── ssrf.py # SSRF -│ ├── deserialization.py # 不安全的反序列化 -│ ├── path_traversal.py # 路径遍历 -│ ├── xxe.py # XXE -│ └── race_condition.py # 竞态条件 -└── frameworks/ # 框架安全知识 - ├── fastapi.py # FastAPI安全 - ├── django.py # Django安全 - ├── flask.py # Flask安全 - ├── express.py # Express.js安全 - ├── react.py # React安全 - └── supabase.py # Supabase安全 -``` - -#### 3. Agent基类增强 ✅ -- 支持动态Agent树(parent_id, 子Agent创建) -- Agent间消息通信 -- TaskHandoff协作机制 -- 知识模块加载 -- Memory Compression集成 - -#### 4. 工具系统 ✅ -- `thinking_tool.py`: Think和Reflect工具 -- `reporting_tool.py`: 漏洞报告工具 -- `agent_tools.py`: Agent协作工具 - - CreateSubAgentTool: 动态创建子Agent - - SendMessageTool: Agent间消息发送 - - ViewAgentGraphTool: 查看Agent树 - - WaitForMessageTool: 等待消息 - - AgentFinishTool: 子Agent完成报告 - -#### 5. LLM调用优化 ✅ -- `memory_compressor.py`: 对话历史压缩 - - 自动检测是否需要压缩 - - 保留关键信息(发现、工具使用、决策、错误) - - 智能摘要生成 -- Agent基类集成自动压缩 - -#### 6. Orchestrator Agent ✅ -- LLM驱动的编排决策 -- 动态调度子Agent -- ReAct模式执行 - -### 已完成的工作 (2024-12 续) - -#### 7. Prompt Caching ✅ -- `llm/prompt_cache.py`: Prompt 缓存管理器 - - 支持 Anthropic Claude 的 Prompt Caching - - 动态缓存策略(SYSTEM_ONLY, SYSTEM_AND_EARLY, MULTI_POINT) - - 缓存统计和效果追踪 - - Token 估算工具 -- LiteLLM 适配器集成缓存支持 - -#### 8. 动态Agent树执行器 ✅ -- `core/executor.py`: 完整的执行器实现 - - `DynamicAgentExecutor`: 动态Agent树执行器 - - 并行Agent执行(带信号量控制) - - 任务依赖管理 - - 执行结果汇总 - - 超时和取消处理 - - `SubAgentExecutor`: 子Agent执行器 - - 从父Agent创建和执行子Agent - - 并行子Agent执行 - - 结果收集和汇总 - - `ExecutionTask`: 执行任务数据结构 - - `ExecutionResult`: 执行结果数据结构 - -#### 9. Agent状态持久化 ✅ -- `core/persistence.py`: 持久化模块 - - `AgentStatePersistence`: 状态持久化管理器 - - 文件系统持久化 - - 数据库持久化(可选) - - 检查点列表和清理 - - `CheckpointManager`: 检查点管理器 - - 自动检查点(按迭代间隔) - - 检查点恢复 - - 状态回滚 - -#### 10. 增强的Agent协作工具 ✅ -- `CreateSubAgentTool`: 增强版 - - 支持立即执行模式 - - 集成SubAgentExecutor - - 上下文传递 -- `RunSubAgentsTool`: 批量执行子Agent - - 并行/顺序执行 - - 结果汇总 -- `CollectSubAgentResultsTool`: 收集子Agent结果 - -#### 11. 数据库模型扩展 ✅ -- `AgentCheckpoint`: Agent检查点模型 - - 状态数据存储 - - 执行统计 - - 检查点类型(auto/manual/error/final) -- `AgentTreeNode`: Agent树节点模型 - - 树结构记录 - - 执行状态追踪 - - 结果汇总 -- Alembic迁移脚本: `007_add_agent_checkpoint_tables.py` - -#### 12. API 端点 ✅ -- `GET /agent-tasks/{task_id}/agent-tree`: Agent树查询API - - 返回完整的Agent树结构 - - 支持运行时内存查询和数据库查询 - - 包含执行状态和发现统计 -- `GET /agent-tasks/{task_id}/checkpoints`: 检查点列表API - - 支持按Agent ID过滤 - - 分页支持 -- `GET /agent-tasks/{task_id}/checkpoints/{checkpoint_id}`: 检查点详情API - - 返回完整的Agent状态数据 - -### 已完成的工作 (2024-12 续2) - -#### 13. 前端 Agent 审计页面 ✅ (Strix-inspired Terminal UI) -- `frontend/src/shared/api/agentTasks.ts`: 扩展 API - - `AgentTreeNode`, `AgentTreeResponse` 类型定义 - - `AgentCheckpoint`, `CheckpointDetail` 类型定义 - - `getAgentTree()`: 获取 Agent 树结构 - - `getAgentCheckpoints()`: 获取检查点列表 - - `getCheckpointDetail()`: 获取检查点详情 - -- `frontend/src/pages/AgentAudit.tsx`: 统一的 Agent 审计页面 (参考 Strix TUI 设计) - - **布局**: 左侧活动日志 (75%) + 右侧 Agent 树和统计 (25%) - - **启动画面**: ASCII Art + 动画加载效果 - - **活动日志**: - - 实时流式显示 Agent 思考过程 - - 工具调用和结果展示 - - 漏洞发现高亮 - - 自动滚动控制 - - 可折叠的日志条目 - - **Agent 树可视化**: - - 树状结构展示 - - 节点状态图标(运行中/已完成/失败/等待) - - 发现数量徽章 - - 节点选择交互 - - **实时统计面板**: - - 进度百分比 - - 文件分析进度 - - Token 使用量 - - 发现数量 - - 严重程度分布 - - **创建任务对话框**: 选择项目后直接跳转到实时流页面 - - **任务控制**: 停止/取消任务 - -- `frontend/src/app/routes.tsx`: 路由配置 - - `/agent-audit`: 启动画面 + 创建任务 - - `/agent-audit/:taskId`: 任务实时流页面 - -- `frontend/src/components/layout/Sidebar.tsx`: 侧边栏导航 - - 新增 Agent 审计入口图标 - -### 已完成的工作 (2024-12 续3) - -#### 14. 执行架构切换 ✅ -- **移除旧的 LangGraph 固定流程架构** -- **启用新的动态 Agent 树架构** -- `backend/app/api/v1/endpoints/agent_tasks.py`: - - `_execute_agent_task()` 重写为使用 `OrchestratorAgent` - - OrchestratorAgent 作为大脑,动态调度子 Agent - - 子 Agent: ReconAgent, AnalysisAgent, VerificationAgent - - 新增辅助函数: `_get_user_config()`, `_initialize_tools()`, `_collect_project_info()`, `_save_findings()`, `_calculate_security_score()` - -### 待完成的工作 - -#### 1. 前端增强 -- 知识模块选择 UI(创建任务时) -- 检查点恢复功能 -- 导出报告功能 - -#### 2. 测试和优化 -- 单元测试 -- 集成测试 -- 性能优化 -- 并发执行压力测试 - -#### 3. 文档 -- API文档更新 -- 架构图更新 -- 使用指南 - ---- - -## 十一、架构升级总结 - -### 已实现的核心功能 - -1. **Prompt Caching** - 为 Claude 等 LLM 提供缓存支持,减少 Token 消耗 -2. **动态 Agent 树执行** - OrchestratorAgent 作为大脑,动态调度子 Agent -3. **Agent 状态持久化** - 文件系统和数据库双重持久化 -4. **检查点机制** - 自动检查点、状态恢复、执行历史追踪 -5. **增强的协作工具** - 子 Agent 创建、批量执行、结果收集 -6. **完整的 API 支持** - Agent 树查询、检查点管理 -7. **旧架构已移除** - 不再使用 LangGraph 固定流程,完全切换到动态 Agent 树 - -### 文件清单 - -``` -backend/app/services/ -├── llm/ -│ ├── __init__.py # 模块导出 -│ ├── prompt_cache.py # 🆕 Prompt Caching -│ ├── memory_compressor.py # Memory Compression -│ └── adapters/ -│ └── litellm_adapter.py # 集成 Prompt Caching -│ -├── agent/ -│ ├── core/ -│ │ ├── __init__.py # 模块导出 -│ │ ├── state.py # Agent 状态管理 -│ │ ├── registry.py # Agent 注册表 -│ │ ├── message.py # Agent 间通信 -│ │ ├── executor.py # 🆕 动态 Agent 树执行器 -│ │ └── persistence.py # 🆕 状态持久化 -│ │ -│ ├── tools/ -│ │ ├── __init__.py # 模块导出 -│ │ ├── agent_tools.py # 🔄 增强的协作工具 -│ │ ├── thinking_tool.py # Think/Reflect 工具 -│ │ └── reporting_tool.py # 漏洞报告工具 -│ │ -│ ├── knowledge/ # 专业知识模块 -│ │ ├── vulnerabilities/ # 漏洞类型知识 -│ │ └── frameworks/ # 框架安全知识 -│ │ -│ └── agents/ -│ ├── base.py # Agent 基类 -│ ├── orchestrator.py # 编排 Agent -│ ├── analysis.py # 分析 Agent -│ └── verification.py # 验证 Agent - -backend/app/models/ -└── agent_task.py # 🔄 新增 AgentCheckpoint, AgentTreeNode - -backend/app/api/v1/endpoints/ -└── agent_tasks.py # 🔄 新增 Agent 树和检查点 API - -backend/alembic/versions/ -└── 007_add_agent_checkpoint_tables.py # 🆕 数据库迁移 - -frontend/src/shared/api/ -└── agentTasks.ts # 🔄 扩展 Agent 树和检查点 API - -frontend/src/pages/ -└── AgentAudit.tsx # 🆕 统一的 Agent 审计页面 (Strix-inspired) - -frontend/src/app/ -└── routes.tsx # 🔄 新增 Agent 审计路由 - -frontend/src/components/layout/ -└── Sidebar.tsx # 🔄 新增 Agent 审计导航图标 -``` - -### 下一步计划 - -1. 测试前端页面渲染和流式事件 -2. 知识模块选择 UI -3. 检查点恢复功能