Luxx/assets/ARCHITECTURE.md

21 KiB
Raw Blame History

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 管理生命周期:

  • 启动:初始化数据库、注册内置工具、创建默认管理员用户
  • 关闭:清理资源
# 默认管理员账号
username: admin
password: admin123

2. 配置管理 (config.py)

使用 YAML 文件管理配置:

  • 配置文件:config.yaml
  • 环境变量替换:${VAR_NAME}
  • 单例模式全局访问
  • 默认值支持
# 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 消息:

{
  "text": "用户输入的文本内容",
  "attachments": [
    {"name": "utils.py", "extension": "py", "content": "..."}
  ]
}

Assistant 消息:

{
  "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 可以在多轮迭代中穿插出现。

注意textcontent 字段通过解析 steps 中所有 type: "text" 的内容动态计算得出。

5. 工具系统

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 {
        <<enumeration>>
        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

权限检查机制

工具执行时自动检查用户权限:

工具要求的权限 <= 用户拥有的权限 → 允许执行
工具要求的权限 >  用户拥有的权限 → 拒绝执行

工具开发规范

所有工具必须遵循统一的开发规范,确保错误处理和返回格式一致。

核心原则:装饰器自动处理一切,工具函数只写业务逻辑

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 格式:

classDiagram
    class ProviderAdapter {
        <<abstract>>
        +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)

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
# 执行流程
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)

用于自主任务执行和依赖管理:

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 服务信息

数据流

消息处理流程

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携带 idindex 确保渲染顺序
done 响应完成,携带 message_id、token_count、usage
error 错误信息

process_step 事件格式

{"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 事件格式

{"type": "done", "message_id": "uuid", "token_count": 1234, "usage": {"prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}}

配置示例

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

环境变量

变量 说明 示例
APP_SECRET_KEY 应用密钥 your-secret-key
DEEPSEEK_API_KEY DeepSeek API sk-xxxx
DATABASE_URL 数据库连接 sqlite:///./chat.db

LLM 适配器配置

OpenAI 兼容 (DeepSeek/GLM 等)

llm:
  provider: openai
  api_key: ${API_KEY}
  api_url: https://api.deepseek.com/v1  # 或其他兼容端点

Anthropic Claude

llm:
  provider: anthropic
  api_key: ${ANTHROPIC_API_KEY}
  api_url: https://api.anthropic.com/v1

项目结构说明

入口文件

  • run.py - 启动 Uvicorn 服务器

响应格式

所有 API 统一使用响应封装:

// 成功
{"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 内容中提取文本