# Luxx 项目架构 ## 技术栈 - **框架**: FastAPI 0.109+ - **数据库**: SQLAlchemy 2.0+ (同步模式) - **认证**: JWT (PyJWT) - **HTTP客户端**: httpx, requests - **配置**: YAML (PyYAML) - **代码执行**: Python 原生执行 - **网页爬虫**: - `httpx` - HTTP 客户端 - `beautifulsoup4` - HTML 解析 - `lxml` - XML/HTML 解析器 ## 目录结构 ``` luxx/ ├── __init__.py # FastAPI 应用工厂 ├── config.py # 配置管理(YAML) ├── database.py # 数据库连接 ├── models.py # ORM 模型 ├── routes/ # API 路由层 │ ├── __init__.py # 路由聚合 │ ├── auth.py # 认证 (登录/注册) │ ├── conversations.py # 会话管理 (CRUD) │ ├── messages.py # 消息处理 (流式/同步) │ ├── providers.py # LLM 提供商管理 │ └── tools.py # 工具管理 ├── services/ # 服务层 │ ├── __init__.py # 服务导出 │ ├── chat.py # 聊天服务门面 │ ├── agentic_loop.py # Agentic Loop 执行器 │ ├── stream_context.py # 流式状态管理 │ ├── llm_response.py # LLM 响应数据类 │ ├── process_result.py # [已移除] │ ├── task.py # 任务系统 (Task/TaskGraph/TaskService) │ ├── llm_client.py # LLM 客户端 │ └── llm_adapters/ # LLM API 适配器 │ ├── __init__.py # 适配器导出 │ ├── base.py # ProviderAdapter 基类 │ ├── openai_adapter.py # OpenAI/DeepSeek/GLM 适配器 │ └── anthropic_adapter.py # Anthropic Claude 适配器 ├── tools/ # 工具系统 │ ├── __init__.py # 工具注册入口 │ ├── core.py # 核心类 (ToolRegistry, ToolDefinition, ToolResult, ToolContext) │ ├── factory.py # @tool 装饰器 │ ├── executor.py # 工具执行器 (缓存/并行) │ ├── services.py # 工具服务层 │ └── builtin/ # 内置工具 │ ├── __init__.py # 工具注册入口 │ ├── code.py # 代码执行 (python_execute, python_eval) │ ├── crawler.py # 网页爬虫 (web_search, web_fetch, batch_fetch) │ ├── data.py # 数据处理 (process_data) │ ├── file.py # 文件操作 (file_read, file_write, file_list, file_exists, file_grep) │ └── shell.py # Shell 命令 (shell_execute) └── utils/ # 工具函数 ├── __init__.py └── helpers.py # 密码哈希、ID生成、响应封装 run.py # 应用入口文件 config.yaml # 配置文件 ``` ## 核心组件 ### 1. 应用工厂 (`__init__.py`) FastAPI 应用入口,使用 lifespan 管理生命周期: - 启动:初始化数据库、注册内置工具、创建默认管理员用户 - 关闭:清理资源 ```python # 默认管理员账号 username: admin password: admin123 ``` ### 2. 配置管理 (`config.py`) 使用 YAML 文件管理配置: - 配置文件:`config.yaml` - 环境变量替换:`${VAR_NAME}` - 单例模式全局访问 - 默认值支持 ```yaml # config.yaml 示例 app: secret_key: ${APP_SECRET_KEY} debug: true host: 0.0.0.0 port: 8000 database: type: sqlite url: sqlite:///./chat.db workspace: root: ./workspaces # 用户工作空间根目录 auto_create: true # 自动创建用户目录 llm: provider: deepseek api_key: ${DEEPSEEK_API_KEY} api_url: https://api.deepseek.com/v1 tools: enable_cache: true cache_ttl: 300 max_workers: 4 max_iterations: 10 logging: level: INFO ``` **工作空间隔离机制:** - 每个用户的工作空间路径基于 `user_id` 的 SHA256 哈希值 - 格式:`{workspace_root}/{hash_of_user_id}` - 所有文件操作必须在用户工作空间内,防止路径穿越攻击 ``` ### 3. 数据库 (`database.py`) - SQLAlchemy 同步支持 - SQLite 默认数据库 - 依赖注入获取会话 ### 4. ORM 模型 (`models.py`) ```mermaid erDiagram USER { int id PK string username UK string email UK string password_hash string role int permission_level "1=READ_ONLY, 2=WRITE, 3=EXECUTE, 4=ADMIN" string workspace_path "用户工作空间路径" boolean is_active datetime created_at } PROJECT { string id PK int user_id FK string name text description datetime created_at datetime updated_at } CONVERSATION { string id PK int user_id FK int provider_id FK "optional" string project_id FK "optional" string title string model text system_prompt float temperature int max_tokens boolean thinking_enabled datetime created_at datetime updated_at } MESSAGE { string id PK string conversation_id FK string role longtext content "JSON 格式" int token_count text usage "JSON 格式" datetime created_at } LLM_PROVIDER { int id PK int user_id FK string name string provider_type string base_url string api_key string default_model int max_tokens boolean is_default boolean enabled datetime created_at datetime updated_at } USER ||--o{ PROJECT : "has" USER ||--o{ CONVERSATION : "has" USER ||--o{ LLM_PROVIDER : "configures" PROJECT ||--o{ CONVERSATION : "contains" LLM_PROVIDER ||--o{ CONVERSATION : "uses" CONVERSATION ||--o{ MESSAGE : "has" ``` **用户权限级别 (permission_level):** | 级别 | 名称 | 说明 | |------|------|------| | 1 | READ_ONLY | 只读权限 | | 2 | WRITE | 写入权限(文件写入) | | 3 | EXECUTE | 执行权限(代码执行、Shell命令) | | 4 | ADMIN | 管理员权限 | ### Message Content JSON 结构 `content` 字段统一使用 JSON 格式存储: **User 消息:** ```json { "text": "用户输入的文本内容", "attachments": [ {"name": "utils.py", "extension": "py", "content": "..."} ] } ``` **Assistant 消息:** ```json { "steps": [ {"id": "step-0", "index": 0, "type": "thinking", "content": "..."}, {"id": "step-1", "index": 1, "type": "text", "content": "..."}, {"id": "step-2", "index": 2, "type": "tool_call", "id_ref": "call_xxx", "name": "...", "arguments": "..."}, {"id": "step-3", "index": 3, "type": "tool_result", "id_ref": "call_xxx", "name": "...", "content": "...", "success": true} ] } ``` `steps` 字段是**唯一数据源**,按 `index` 顺序排列。thinking、text、tool_call、tool_result 可以在多轮迭代中穿插出现。 **注意**:`text` 和 `content` 字段通过解析 `steps` 中所有 `type: "text"` 的内容动态计算得出。 ### 5. 工具系统 ```mermaid classDiagram class ToolDefinition { +str name +str description +dict parameters +Callable handler +str category +CommandPermission required_permission +to_openai_format() dict } class ToolContext { +int user_id +str username +str workspace +int user_permission_level } class CommandPermission { <> READ_ONLY = 1 WRITE = 2 EXECUTE = 3 ADMIN = 4 } class ToolResult { +bool success +Any data +str error +to_dict() dict +ok(data) ToolResult$ +fail(error) ToolResult$ } class ToolRegistry { +_tools: Dict +register(tool) void +get(name) ToolDefinition? +list_all() List~dict~ +list_by_category(category) List~dict~ +execute(name, arguments, context) dict +remove(name) bool } class ToolExecutor { +enable_cache: bool +cache_ttl: int +max_workers: int +_cache: Dict +_call_history: List +process_tool_calls(tool_calls, context) list +process_tool_calls_parallel(tool_calls, context) list +clear_cache() void +get_history(limit) List } ``` #### 内置工具 **代码执行 (code.py)** | 工具 | 功能 | 权限 | |------|------|------| | `python_execute` | 执行 Python 代码 | EXECUTE | | `python_eval` | 计算表达式 | EXECUTE | **文件操作 (file.py)** | 工具 | 功能 | 权限 | |------|------|------| | `file_read` | 读取文件内容 | READ_ONLY | | `file_write` | 写入文件内容 | WRITE | | `file_list` | 列出目录内容 | READ_ONLY | | `file_exists` | 检查文件是否存在 | READ_ONLY | | `file_grep` | 正则搜索文件内容 | READ_ONLY | **Shell 命令 (shell.py)** | 工具 | 功能 | 权限 | |------|------|------| | `shell_execute` | 执行 Shell 命令 | EXECUTE | **网页爬虫 (crawler.py)** | 工具 | 功能 | 权限 | |------|------|------| | `web_search` | DuckDuckGo HTML 搜索 | READ_ONLY | | `web_fetch` | 网页抓取 | READ_ONLY | | `batch_fetch` | 批量并发抓取 | READ_ONLY | **数据处理 (data.py)** | 工具 | 功能 | 权限 | |------|------|------| | `process_data` | JSON 转换、格式化 | READ_ONLY | #### 权限检查机制 工具执行时自动检查用户权限: ``` 工具要求的权限 <= 用户拥有的权限 → 允许执行 工具要求的权限 > 用户拥有的权限 → 拒绝执行 ``` #### 工具开发规范 所有工具必须遵循统一的开发规范,确保错误处理和返回格式一致。 **核心原则:装饰器自动处理一切,工具函数只写业务逻辑** ```python from luxx.tools.factory import tool @tool( name="my_tool", description="工具描述", parameters={...}, required_params=["arg1"], # 自动验证 category="my_category" ) def my_tool(arguments: dict): # 业务逻辑 - 只管返回数据 data = fetch_data(arguments["arg1"]) return {"items": data, "count": len(data)} # 或者直接抛出异常(装饰器自动捕获并转换) if invalid: raise ValueError("Invalid input") ``` **装饰器自动处理:** 1. 必需参数验证(`required_params`) 2. 所有异常捕获和转换 3. 结果格式统一包装 **返回格式转换** | 工具函数返回/抛出 | 装饰器转换为 | |-------------------|-------------| | `return {"result": "ok"}` | `{"success": true, "data": {...}, "error": null}` | | `raise ValueError("msg")` | `{"success": false, "data": null, "error": "ValueError: msg"}` | | `raise Exception()` | `{"success": false, "data": null, "error": "..."}` | **工具调用流程** ``` LLM 请求 ↓ ToolRegistry.execute(name, args) ↓ @tool 装饰器 ├─ 验证 required_params ├─ 执行工具函数 (try-except 包裹) ├─ 捕获异常 → 转换为 error ├─ 包装返回格式 └─ 返回 ToolResult ↓ ToolExecutor 返回结果 ↓ 前端 ProcessBlock 显示 ``` ### 6. 服务层 #### LLM 适配器 (`services/llm_adapters/`) 适配器模式统一处理不同 LLM API 格式: ```mermaid classDiagram class ProviderAdapter { <> +str provider_type +build_request() tuple +parse_stream_chunk() AsyncGenerator +parse_response() Dict +supports_thinking() bool +supports_tools() bool } class OpenAIAdapter { +str provider_type = "openai" +build_request() tuple +parse_stream_chunk() AsyncGenerator +parse_response() Dict +supports_tools() bool } class AnthropicAdapter { +str provider_type = "anthropic" +build_request() tuple +parse_stream_chunk() AsyncGenerator +parse_response() Dict +supports_thinking() bool +supports_tools() bool } ProviderAdapter <|-- OpenAIAdapter ProviderAdapter <|-- AnthropicAdapter ``` **支持的功能对比:** | 适配器 | 工具调用 | Thinking/Reasoning | 流式响应 | |--------|----------|-------------------|----------| | OpenAI | ✅ | ✅ (DeepSeek) | ✅ | | Anthropic | ✅ | ✅ | ✅ | #### LLM 响应数据类 (`services/llm_response.py`) ```python class StepType: """步骤类型常量""" THINKING = "thinking" TEXT = "text" TOOL_CALL = "tool_call" TOOL_RESULT = "tool_result" @dataclass class Step: """单个步骤 - 用于存储和传输""" id: str index: int type: str # thinking, text, tool_call, tool_result content: str = "" name: str = "" # tool_call/tool_result arguments: str = "" # tool_call id_ref: str = "" # tool_result success: bool = True @dataclass class ParsedDelta: """LLM 流式响应增量""" thinking: str = "" # 思考内容(增量) text: str = "" # 文本内容(增量) tool_call: Optional[Dict] = None # 单个工具调用 usage: Dict[str, int] = {} # Token 用量 is_complete: bool = False ``` #### ChatService (`services/chat.py`) 核心聊天服务: - Agentic Loop 迭代执行(最多 10 轮) - 流式 SSE 响应 - 工具调用编排(并行执行) - 消息历史管理 - Token 用量追踪 - 工作空间上下文传递 #### AgenticLoop (`services/agentic_loop.py`) 执行 Agentic Loop 的核心循环: - 调用 LLM 获取响应(流式) - 解析 ParsedDelta,更新步骤状态 - 管理 thinking/text/tool_call/tool_result 步骤 - 工具并行执行 - 最大迭代次数:10 ```python # 执行流程 async for delta in llm.stream_call(...): events = self._process_delta(delta, context, total_usage) yield from events # 工具调用时 tool_results = self.tool_executor.process_tool_calls_parallel(...) messages.append({"role": "assistant", ...}) messages.extend(tool_results) ``` #### StreamContext (`services/stream_context.py`) 流式状态管理: - 追踪当前步骤类型和索引 - 累积 thinking 和 text 内容 - 管理 tool_calls 列表和 tool_results - 生成 SSE 事件 - 构建完整消息内容 #### LLMClient (`services/llm_client.py`) LLM API 客户端: - 多提供商:OpenAI、DeepSeek、Anthropic - 自动适配器选择 - 流式/同步调用 - 错误处理和重试 - Token 计数 ### 7. 任务系统 (`services/task.py`) 用于自主任务执行和依赖管理: ```mermaid classDiagram class Task { +str id +str name +str goal +TaskStatus status +List~Step~ steps +List~Task~ subtasks } class Step { +str id +str name +List~str~ depends_on +StepStatus status } class TaskGraph { +topological_sort() List~Step~ +get_ready_steps() List~Step~ +detect_cycles() List~List~str~~ +validate() tuple } class TaskService { +create_task() Task +get_task() Task +update_task_status() Task +add_steps() List~Step~ +build_graph() TaskGraph } Task "1" o-- "*" Step Task "1" o-- "*" Task TaskService ..> TaskGraph ``` **任务状态 (TaskStatus):** - `PENDING` - 待处理 - `READY` - 就绪 - `RUNNING` - 运行中 - `BLOCK` - 阻塞 - `TERMINATED` - 已终止 **步骤状态 (StepStatus):** - `PENDING` - 待执行 - `RUNNING` - 执行中 - `COMPLETED` - 已完成 - `FAILED` - 失败 - `SKIPPED` - 跳过 ### 7. 认证系统 (`routes/auth.py`) - JWT Bearer Token - Bcrypt 密码哈希 - 用户注册/登录 ### 8. API 路由 | 路由 | 方法 | 说明 | |------|------|------| | `/auth/register` | POST | 用户注册 | | `/auth/login` | POST | 用户登录 | | `/conversations` | GET | 会话列表(分页) | | `/conversations` | POST | 创建会话 | | `/conversations/{id}` | GET | 会话详情 | | `/conversations/{id}` | PUT | 更新会话 | | `/conversations/{id}` | DELETE | 删除会话 | | `/messages` | GET | 消息列表 | | `/messages` | POST | 发送消息(同步) | | `/messages/stream` | POST | 发送消息(流式 SSE) | | `/messages/{id}` | DELETE | 删除消息 | | `/providers` | GET | LLM 提供商列表 | | `/providers` | POST | 创建提供商 | | `/providers/{id}` | GET | 提供商详情 | | `/providers/{id}` | PUT | 更新提供商 | | `/providers/{id}` | DELETE | 删除提供商 | | `/providers/{id}/test` | POST | 测试提供商连接 | | `/tools` | GET | 可用工具列表 | | `/health` | GET | 健康检查 | | `/` | GET | 服务信息 | ## 数据流 ### 消息处理流程 ```mermaid sequenceDiagram participant Client participant API as POST /messages/stream participant CS as ChatService participant AL as AgenticLoop participant Parser as LLMResponseParser participant LLM as LLM API participant TE as ToolExecutor Client->>API: POST {content, tools, thinking_enabled} API->>CS: stream_response() CS->>AL: execute() loop MAX_ITERATIONS (10) AL->>LLM: stream_call(messages, tools) LLM-->>AL: SSE Stream AL->>Parser: parse_chunk() Parser-->>AL: ParsedDelta {thinking, text, tool_calls} alt tool_calls AL->>TE: process_tool_calls_parallel() TE-->>AL: tool_results AL->>AL: 追加到 messages end end AL->>CS: done event CS->>CS: _save_message() CS->>API: SSE Stream API-->>Client: 流式响应 ``` ## SSE 事件 | 事件 | 说明 | |------|------| | `process_step` | 结构化步骤(thinking/text/tool_call/tool_result),携带 `id`、`index` 确保渲染顺序 | | `done` | 响应完成,携带 message_id、token_count、usage | | `error` | 错误信息 | ### process_step 事件格式 ```json {"type": "process_step", "step": {"id": "step-0", "index": 0, "type": "thinking", "content": "..."}} {"type": "process_step", "step": {"id": "step-1", "index": 1, "type": "text", "content": "回复文本..."}} {"type": "process_step", "step": {"id": "step-2", "index": 2, "type": "tool_call", "id_ref": "call_abc", "name": "web_search", "arguments": "{\"query\": \"...\"}"}} {"type": "process_step", "step": {"id": "step-3", "index": 3, "type": "tool_result", "id_ref": "call_abc", "name": "web_search", "content": "{...}", "success": true}} ``` | 字段 | 说明 | |------|------| | `id` | 步骤唯一标识(格式 `step-{index}`) | | `index` | 步骤序号,确保按正确顺序显示 | | `type` | 步骤类型:`thinking` / `text` / `tool_call` / `tool_result` | | `id_ref` | 工具调用引用 ID(仅 tool_call/tool_result) | | `name` | 工具名称(仅 tool_call/tool_result) | | `arguments` | 工具调用参数 JSON 字符串(仅 tool_call) | | `content` | 内容(thinking 的思考内容、text 的文本、tool_result 的返回结果) | | `success` | 工具执行是否成功(仅 tool_result) | ### done 事件格式 ```json {"type": "done", "message_id": "uuid", "token_count": 1234, "usage": {"prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}} ``` ## 配置示例 ### config.yaml ```yaml app: secret_key: ${APP_SECRET_KEY} debug: true host: 0.0.0.0 port: 8000 database: type: sqlite url: sqlite:///./chat.db workspace: root: ./workspaces # 用户工作空间根目录 auto_create: true # 自动创建用户工作空间 llm: provider: deepseek api_key: ${DEEPSEEK_API_KEY} api_url: https://api.deepseek.com/v1 tools: enable_cache: true cache_ttl: 300 max_workers: 4 max_iterations: 10 logging: level: INFO ``` ## 环境变量 | 变量 | 说明 | 示例 | |------|------|------| | `APP_SECRET_KEY` | 应用密钥 | `your-secret-key` | | `DEEPSEEK_API_KEY` | DeepSeek API | `sk-xxxx` | | `DATABASE_URL` | 数据库连接 | `sqlite:///./chat.db` | ## LLM 适配器配置 ### OpenAI 兼容 (DeepSeek/GLM 等) ```yaml llm: provider: openai api_key: ${API_KEY} api_url: https://api.deepseek.com/v1 # 或其他兼容端点 ``` ### Anthropic Claude ```yaml llm: provider: anthropic api_key: ${ANTHROPIC_API_KEY} api_url: https://api.anthropic.com/v1 ``` ## 项目结构说明 ### 入口文件 - `run.py` - 启动 Uvicorn 服务器 ### 响应格式 所有 API 统一使用响应封装: ```json // 成功 {"success": true, "data": {...}, "message": "操作成功"} // 错误 {"success": false, "error": "错误信息", "code": 404} ``` ### 工具缓存机制 ToolExecutor 支持结果缓存: - TTL: 5 分钟(可配置) - 缓存 Key: `{tool_name}:{sorted_arguments_json}` - 调用历史记录最近 1000 条 ### 流式响应特点 1. 实时返回 thinking_content(模型思考过程) 2. 实时返回 text 增量更新 3. 工具调用并行执行,结果批量返回 4. 最终 `done` 事件包含完整 message_id 和 token 用量 ### 工作空间隔离 每个用户的工作空间完全隔离: - 用户目录基于 user_id 的 SHA256 哈希生成 - 所有文件操作强制在用户工作空间内 - 支持权限级别控制文件操作能力 ### MessageBuilder 用于构建发送给 LLM 的消息列表: - `add_system()` - 添加系统消息 - `add_user()` - 添加用户消息(JSON 格式) - `add_assistant()` - 添加助手消息 - `add_tool_result()` - 添加工具结果消息 - `extract_text()` - 从 JSON 内容中提取文本