Luxx/asserts/ARCHITECTURE.md

339 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 项目架构
## 技术栈
- **框架**: FastAPI 0.109+
- **数据库**: SQLAlchemy 2.0+
- **认证**: JWT (PyJWT)
- **HTTP客户端**: httpx
- **配置**: YAML (PyYAML)
- **代码执行**: Python 原生执行
## 目录结构
```
luxx/
├── __init__.py # FastAPI 应用工厂
├── run.py # 入口文件
├── config.py # 配置管理YAML
├── database.py # 数据库连接
├── models.py # ORM 模型
├── routes/ # API 路由层
│ ├── auth.py # 认证
│ ├── conversations.py # 会话管理
│ ├── messages.py # 消息处理
│ ├── providers.py # LLM 提供商管理
│ └── tools.py # 工具管理
├── services/ # 服务层
│ ├── chat.py # 聊天服务
│ └── llm_client.py # LLM 客户端
├── tools/ # 工具系统
│ ├── core.py # 核心类
│ ├── factory.py # 装饰器
│ ├── executor.py # 执行器
│ └── builtin/ # 内置工具
│ ├── code.py # 代码执行
│ ├── crawler.py # 网页爬虫
│ ├── data.py # 数据处理
│ └── weather.py # 天气查询
└── utils/ # 工具函数
└── helpers.py
```
## 核心组件
### 1. 应用工厂 (`__init__.py`)
FastAPI 应用入口,使用 lifespan 管理生命周期:
- 启动:初始化数据库、加载工具
- 关闭:清理资源
### 2. 配置管理 (`config.py`)
使用 YAML 文件管理配置:
- 配置文件:`config.yaml`
- 环境变量替换:`${VAR_NAME}`
- 单例模式全局访问
- 默认值支持
```yaml
# config.yaml 示例
app:
secret_key: ${APP_SECRET_KEY}
debug: true
llm:
provider: deepseek
api_key: ${DEEPSEEK_API_KEY}
```
### 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
boolean is_active
datetime created_at
}
CONVERSATION {
string id PK
int user_id FK
string project_id FK
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
datetime created_at
}
USER ||--o{ CONVERSATION : "has"
CONVERSATION ||--o{ MESSAGE : "has"
USER ||--o{ LLM_PROVIDER : "configures"
LLM_PROVIDER {
int id PK
int user_id FK
string name
string provider_type
string base_url
string api_key
string default_model
boolean is_default
boolean enabled
datetime created_at
datetime updated_at
}
```
### Message Content JSON 结构
`content` 字段统一使用 JSON 格式存储:
**User 消息:**
```json
{
"text": "用户输入的文本内容",
"attachments": [
{"name": "utils.py", "extension": "py", "content": "..."}
]
}
```
**Assistant 消息:**
```json
{
"text": "AI 回复的文本内容",
"tool_calls": [...],
"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": "..."}
]
}
```
`steps` 字段是**渲染顺序的唯一数据源**,按 `index` 顺序排列。thinking、text、tool_call、tool_result 可以在多轮迭代中穿插出现。
### 5. 工具系统
```mermaid
classDiagram
class ToolDefinition {
+str name
+str description
+dict parameters
+Callable handler
+str category
+to_openai_format() dict
}
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~
+execute(name, arguments) dict
}
class ToolExecutor {
+registry: ToolRegistry
+enable_cache: bool
+cache_ttl: int
+_cache: Dict
+process_tool_calls(tool_calls, context) list
+process_tool_calls_parallel(tool_calls, context, max_workers) list
}
```
#### 内置工具
| 工具 | 功能 | 说明 |
|------|------|------|
| `python_execute` | 执行 Python 代码 | 支持 print 输出、变量访问 |
| `python_eval` | 计算表达式 | 快速求值 |
| `web_crawl` | 网页抓取 | BeautifulSoup + httpx |
| `get_weather` | 天气查询 | 支持城市名查询 |
| `process_data` | 数据处理 | JSON 转换、格式化等 |
### 6. 服务层
#### ChatService (`services/chat.py`)
核心聊天服务:
- Agentic Loop 迭代执行
- 流式 SSE 响应
- 工具调用编排
- 消息历史管理
- 自动重试机制
#### LLMClient (`services/llm_client.py`)
LLM API 客户端:
- 多提供商DeepSeek、GLM、OpenAI
- 流式/同步调用
- 错误处理和重试
- Token 计数
### 7. 认证系统 (`routes/auth.py`)
- JWT Bearer Token
- Bcrypt 密码哈希
- 用户注册/登录
### 8. API 路由
| 路由 | 方法 | 说明 |
|------|------|------|
| `/auth/register` | POST | 用户注册 |
| `/auth/login` | POST | 用户登录 |
| `/conversations` | GET/POST | 会话列表/创建 |
| `/conversations/{id}` | GET/DELETE | 会话详情/删除 |
| `/messages/stream` | POST | 流式消息发送 |
| `/providers` | GET/POST | LLM 提供商列表/创建 |
| `/providers/{id}` | GET/PUT/DELETE | 提供商详情/更新/删除 |
| `/providers/{id}/test` | POST | 测试提供商连接 |
| `/tools` | GET | 可用工具列表 |
## 数据流
### 消息处理流程
```mermaid
sequenceDiagram
participant Client
participant API as POST /messages/stream
participant CS as ChatService
participant LLM as LLM API
participant TE as ToolExecutor
Client->>API: POST {content, tools}
API->>CS: stream_response()
loop MAX_ITERATIONS
CS->>LLM: call(messages, tools)
LLM-->>CS: SSE Stream
alt tool_calls
CS->>TE: process_tool_calls_parallel()
TE-->>CS: tool_results
CS->>CS: 追加到 messages
end
end
CS->>API: SSE Stream
API-->>Client: 流式响应
```
## SSE 事件
| 事件 | 说明 |
|------|------|
| `process_step` | 结构化步骤thinking/text/tool_call/tool_result携带 `id`、`index` 确保渲染顺序 |
| `done` | 响应完成 |
| `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 的返回结果) |
## 配置示例
### 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
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
```
## 环境变量
| 变量 | 说明 | 示例 |
|------|------|------|
| `APP_SECRET_KEY` | 应用密钥 | `your-secret-key` |
| `DEEPSEEK_API_KEY` | DeepSeek API | `sk-xxxx` |
| `DATABASE_URL` | 数据库连接 | `sqlite:///./chat.db` |