docs: 更新文档
This commit is contained in:
parent
4543fed58a
commit
535eefa8de
|
|
@ -1,9 +1,9 @@
|
||||||
# 项目架构
|
# Luxx 项目架构
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
- **框架**: FastAPI 0.109+
|
- **框架**: FastAPI 0.109+
|
||||||
- **数据库**: SQLAlchemy 2.0+
|
- **数据库**: SQLAlchemy 2.0+ (同步模式)
|
||||||
- **认证**: JWT (PyJWT)
|
- **认证**: JWT (PyJWT)
|
||||||
- **HTTP客户端**: httpx, requests
|
- **HTTP客户端**: httpx, requests
|
||||||
- **配置**: YAML (PyYAML)
|
- **配置**: YAML (PyYAML)
|
||||||
|
|
@ -18,40 +18,49 @@
|
||||||
```
|
```
|
||||||
luxx/
|
luxx/
|
||||||
├── __init__.py # FastAPI 应用工厂
|
├── __init__.py # FastAPI 应用工厂
|
||||||
├── run.py # 入口文件
|
|
||||||
├── config.py # 配置管理(YAML)
|
├── config.py # 配置管理(YAML)
|
||||||
├── database.py # 数据库连接
|
├── database.py # 数据库连接
|
||||||
├── models.py # ORM 模型
|
├── models.py # ORM 模型
|
||||||
├── routes/ # API 路由层
|
├── routes/ # API 路由层
|
||||||
│ ├── auth.py # 认证
|
│ ├── __init__.py # 路由聚合
|
||||||
│ ├── conversations.py # 会话管理
|
│ ├── auth.py # 认证 (登录/注册)
|
||||||
│ ├── messages.py # 消息处理
|
│ ├── conversations.py # 会话管理 (CRUD)
|
||||||
|
│ ├── messages.py # 消息处理 (流式/同步)
|
||||||
│ ├── providers.py # LLM 提供商管理
|
│ ├── providers.py # LLM 提供商管理
|
||||||
│ └── tools.py # 工具管理
|
│ └── tools.py # 工具管理
|
||||||
├── services/ # 服务层
|
├── services/ # 服务层
|
||||||
│ ├── chat.py # 聊天服务
|
│ ├── chat.py # 聊天服务 (Agentic Loop)
|
||||||
│ └── llm_client.py # LLM 客户端
|
│ └── llm_client.py # LLM 客户端
|
||||||
├── tools/ # 工具系统
|
├── tools/ # 工具系统
|
||||||
│ ├── core.py # 核心类
|
│ ├── core.py # 核心类 (ToolRegistry, ToolDefinition, ToolResult)
|
||||||
│ ├── factory.py # 装饰器
|
│ ├── factory.py # @tool 装饰器
|
||||||
│ ├── executor.py # 执行器
|
│ ├── executor.py # 工具执行器 (缓存/并行)
|
||||||
|
│ ├── services.py # 工具服务层
|
||||||
│ └── builtin/ # 内置工具
|
│ └── builtin/ # 内置工具
|
||||||
│ ├── code.py # 代码执行
|
│ ├── __init__.py # 工具注册入口
|
||||||
│ ├── crawler.py # 网页爬虫
|
│ ├── code.py # 代码执行 (python_execute, python_eval)
|
||||||
│ ├── data.py # 数据处理
|
│ ├── crawler.py # 网页爬虫 (web_search, web_fetch, batch_fetch)
|
||||||
│ └── weather.py # 天气查询
|
│ └── data.py # 数据处理 (process_data)
|
||||||
│ └── services.py # 工具服务层
|
|
||||||
└── utils/ # 工具函数
|
└── utils/ # 工具函数
|
||||||
└── helpers.py
|
└── helpers.py # 密码哈希、ID生成、响应封装
|
||||||
|
|
||||||
|
run.py # 应用入口文件
|
||||||
|
config.yaml # 配置文件
|
||||||
```
|
```
|
||||||
|
|
||||||
## 核心组件
|
## 核心组件
|
||||||
|
|
||||||
### 1. 应用工厂 (`__init__.py`)
|
### 1. 应用工厂 (`__init__.py`)
|
||||||
FastAPI 应用入口,使用 lifespan 管理生命周期:
|
FastAPI 应用入口,使用 lifespan 管理生命周期:
|
||||||
- 启动:初始化数据库、加载工具
|
- 启动:初始化数据库、注册内置工具、创建默认管理员用户
|
||||||
- 关闭:清理资源
|
- 关闭:清理资源
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 默认管理员账号
|
||||||
|
username: admin
|
||||||
|
password: admin123
|
||||||
|
```
|
||||||
|
|
||||||
### 2. 配置管理 (`config.py`)
|
### 2. 配置管理 (`config.py`)
|
||||||
使用 YAML 文件管理配置:
|
使用 YAML 文件管理配置:
|
||||||
- 配置文件:`config.yaml`
|
- 配置文件:`config.yaml`
|
||||||
|
|
@ -65,13 +74,18 @@ app:
|
||||||
secret_key: ${APP_SECRET_KEY}
|
secret_key: ${APP_SECRET_KEY}
|
||||||
debug: true
|
debug: true
|
||||||
|
|
||||||
|
database:
|
||||||
|
type: sqlite
|
||||||
|
url: sqlite:///./chat.db
|
||||||
|
|
||||||
llm:
|
llm:
|
||||||
provider: deepseek
|
provider: deepseek
|
||||||
api_key: ${DEEPSEEK_API_KEY}
|
api_key: ${DEEPSEEK_API_KEY}
|
||||||
|
api_url: https://api.deepseek.com/v1
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 数据库 (`database.py`)
|
### 3. 数据库 (`database.py`)
|
||||||
- SQLAlchemy 异步支持
|
- SQLAlchemy 同步支持
|
||||||
- SQLite 默认数据库
|
- SQLite 默认数据库
|
||||||
- 依赖注入获取会话
|
- 依赖注入获取会话
|
||||||
|
|
||||||
|
|
@ -89,10 +103,20 @@ erDiagram
|
||||||
datetime created_at
|
datetime created_at
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROJECT {
|
||||||
|
string id PK
|
||||||
|
int user_id FK
|
||||||
|
string name
|
||||||
|
text description
|
||||||
|
datetime created_at
|
||||||
|
datetime updated_at
|
||||||
|
}
|
||||||
|
|
||||||
CONVERSATION {
|
CONVERSATION {
|
||||||
string id PK
|
string id PK
|
||||||
int user_id FK
|
int user_id FK
|
||||||
string project_id FK
|
int provider_id FK "optional"
|
||||||
|
string project_id FK "optional"
|
||||||
string title
|
string title
|
||||||
string model
|
string model
|
||||||
text system_prompt
|
text system_prompt
|
||||||
|
|
@ -109,14 +133,10 @@ erDiagram
|
||||||
string role
|
string role
|
||||||
longtext content "JSON 格式"
|
longtext content "JSON 格式"
|
||||||
int token_count
|
int token_count
|
||||||
|
text usage "JSON 格式"
|
||||||
datetime created_at
|
datetime created_at
|
||||||
}
|
}
|
||||||
|
|
||||||
USER ||--o{ CONVERSATION : "has"
|
|
||||||
CONVERSATION ||--o{ MESSAGE : "has"
|
|
||||||
|
|
||||||
USER ||--o{ LLM_PROVIDER : "configures"
|
|
||||||
|
|
||||||
LLM_PROVIDER {
|
LLM_PROVIDER {
|
||||||
int id PK
|
int id PK
|
||||||
int user_id FK
|
int user_id FK
|
||||||
|
|
@ -125,11 +145,19 @@ erDiagram
|
||||||
string base_url
|
string base_url
|
||||||
string api_key
|
string api_key
|
||||||
string default_model
|
string default_model
|
||||||
|
int max_tokens
|
||||||
boolean is_default
|
boolean is_default
|
||||||
boolean enabled
|
boolean enabled
|
||||||
datetime created_at
|
datetime created_at
|
||||||
datetime updated_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"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Message Content JSON 结构
|
### Message Content JSON 结构
|
||||||
|
|
@ -157,7 +185,7 @@ erDiagram
|
||||||
{"id": "step-0", "index": 0, "type": "thinking", "content": "..."},
|
{"id": "step-0", "index": 0, "type": "thinking", "content": "..."},
|
||||||
{"id": "step-1", "index": 1, "type": "text", "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-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": "..."}
|
{"id": "step-3", "index": 3, "type": "tool_result", "id_ref": "call_xxx", "name": "...", "content": "...", "success": true}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -191,16 +219,21 @@ classDiagram
|
||||||
+register(tool) void
|
+register(tool) void
|
||||||
+get(name) ToolDefinition?
|
+get(name) ToolDefinition?
|
||||||
+list_all() List~dict~
|
+list_all() List~dict~
|
||||||
|
+list_by_category(category) List~dict~
|
||||||
+execute(name, arguments) dict
|
+execute(name, arguments) dict
|
||||||
|
+remove(name) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
class ToolExecutor {
|
class ToolExecutor {
|
||||||
+registry: ToolRegistry
|
|
||||||
+enable_cache: bool
|
+enable_cache: bool
|
||||||
+cache_ttl: int
|
+cache_ttl: int
|
||||||
|
+max_workers: int
|
||||||
+_cache: Dict
|
+_cache: Dict
|
||||||
|
+_call_history: List
|
||||||
+process_tool_calls(tool_calls, context) list
|
+process_tool_calls(tool_calls, context) list
|
||||||
+process_tool_calls_parallel(tool_calls, context, max_workers) list
|
+process_tool_calls_parallel(tool_calls, context) list
|
||||||
|
+clear_cache() void
|
||||||
|
+get_history(limit) List
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -213,7 +246,6 @@ classDiagram
|
||||||
| `web_search` | DuckDuckGo HTML | DuckDuckGo HTML 搜索 |
|
| `web_search` | DuckDuckGo HTML | DuckDuckGo HTML 搜索 |
|
||||||
| `web_fetch` | 网页抓取 | httpx + BeautifulSoup,支持 text/links/structured |
|
| `web_fetch` | 网页抓取 | httpx + BeautifulSoup,支持 text/links/structured |
|
||||||
| `batch_fetch` | 批量抓取 | 并发获取多个页面 |
|
| `batch_fetch` | 批量抓取 | 并发获取多个页面 |
|
||||||
| `get_weather` | 天气查询 | 支持城市名查询 |
|
|
||||||
| `process_data` | 数据处理 | JSON 转换、格式化等 |
|
| `process_data` | 数据处理 | JSON 转换、格式化等 |
|
||||||
|
|
||||||
#### 工具开发规范
|
#### 工具开发规范
|
||||||
|
|
@ -269,38 +301,22 @@ ToolRegistry.execute(name, args)
|
||||||
├─ 包装返回格式
|
├─ 包装返回格式
|
||||||
└─ 返回 ToolResult
|
└─ 返回 ToolResult
|
||||||
↓
|
↓
|
||||||
|
ToolExecutor 返回结果
|
||||||
|
↓
|
||||||
前端 ProcessBlock 显示
|
前端 ProcessBlock 显示
|
||||||
```
|
```
|
||||||
|
|
||||||
| 工具函数返回 | 装饰器转换为 |
|
|
||||||
|-------------|-------------|
|
|
||||||
| `{"result": "ok"}` | `{"success": true, "data": {...}, "error": null}` |
|
|
||||||
| `{"error": "msg"}` | `{"success": false, "data": null, "error": "msg"}` |
|
|
||||||
| `raise Exception()` | `{"success": false, "data": null, "error": "..."}` |
|
|
||||||
|
|
||||||
**工具调用流程**
|
|
||||||
|
|
||||||
```
|
|
||||||
LLM 请求 → ToolRegistry.execute() → @tool 装饰器包装
|
|
||||||
↓
|
|
||||||
工具函数执行
|
|
||||||
↓
|
|
||||||
返回 ToolResult 或 dict
|
|
||||||
↓
|
|
||||||
自动转换为标准格式 {"success": bool, "data": any, "error": str}
|
|
||||||
↓
|
|
||||||
前端 ProcessBlock 显示结果
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 服务层
|
### 6. 服务层
|
||||||
|
|
||||||
#### ChatService (`services/chat.py`)
|
#### ChatService (`services/chat.py`)
|
||||||
核心聊天服务:
|
核心聊天服务:
|
||||||
- Agentic Loop 迭代执行
|
- Agentic Loop 迭代执行(最多 10 轮)
|
||||||
- 流式 SSE 响应
|
- 流式 SSE 响应
|
||||||
- 工具调用编排
|
- 工具调用编排(并行执行)
|
||||||
- 消息历史管理
|
- 消息历史管理
|
||||||
- 自动重试机制
|
- 自动重试机制
|
||||||
|
- 支持 thinking_content 提取
|
||||||
|
- Token 用量追踪
|
||||||
|
|
||||||
#### LLMClient (`services/llm_client.py`)
|
#### LLMClient (`services/llm_client.py`)
|
||||||
LLM API 客户端:
|
LLM API 客户端:
|
||||||
|
|
@ -320,13 +336,24 @@ LLM API 客户端:
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| `/auth/register` | POST | 用户注册 |
|
| `/auth/register` | POST | 用户注册 |
|
||||||
| `/auth/login` | POST | 用户登录 |
|
| `/auth/login` | POST | 用户登录 |
|
||||||
| `/conversations` | GET/POST | 会话列表/创建 |
|
| `/conversations` | GET | 会话列表(分页) |
|
||||||
| `/conversations/{id}` | GET/DELETE | 会话详情/删除 |
|
| `/conversations` | POST | 创建会话 |
|
||||||
| `/messages/stream` | POST | 流式消息发送 |
|
| `/conversations/{id}` | GET | 会话详情 |
|
||||||
| `/providers` | GET/POST | LLM 提供商列表/创建 |
|
| `/conversations/{id}` | PUT | 更新会话 |
|
||||||
| `/providers/{id}` | GET/PUT/DELETE | 提供商详情/更新/删除 |
|
| `/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 | 测试提供商连接 |
|
| `/providers/{id}/test` | POST | 测试提供商连接 |
|
||||||
| `/tools` | GET | 可用工具列表 |
|
| `/tools` | GET | 可用工具列表 |
|
||||||
|
| `/health` | GET | 健康检查 |
|
||||||
|
| `/` | GET | 服务信息 |
|
||||||
|
|
||||||
## 数据流
|
## 数据流
|
||||||
|
|
||||||
|
|
@ -340,10 +367,10 @@ sequenceDiagram
|
||||||
participant LLM as LLM API
|
participant LLM as LLM API
|
||||||
participant TE as ToolExecutor
|
participant TE as ToolExecutor
|
||||||
|
|
||||||
Client->>API: POST {content, tools}
|
Client->>API: POST {content, tools, thinking_enabled}
|
||||||
API->>CS: stream_response()
|
API->>CS: stream_response()
|
||||||
|
|
||||||
loop MAX_ITERATIONS
|
loop MAX_ITERATIONS (10)
|
||||||
CS->>LLM: call(messages, tools)
|
CS->>LLM: call(messages, tools)
|
||||||
LLM-->>CS: SSE Stream
|
LLM-->>CS: SSE Stream
|
||||||
|
|
||||||
|
|
@ -354,6 +381,7 @@ sequenceDiagram
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
CS->>CS: _save_message()
|
||||||
CS->>API: SSE Stream
|
CS->>API: SSE Stream
|
||||||
API-->>Client: 流式响应
|
API-->>Client: 流式响应
|
||||||
```
|
```
|
||||||
|
|
@ -363,7 +391,7 @@ sequenceDiagram
|
||||||
| 事件 | 说明 |
|
| 事件 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `process_step` | 结构化步骤(thinking/text/tool_call/tool_result),携带 `id`、`index` 确保渲染顺序 |
|
| `process_step` | 结构化步骤(thinking/text/tool_call/tool_result),携带 `id`、`index` 确保渲染顺序 |
|
||||||
| `done` | 响应完成 |
|
| `done` | 响应完成,携带 message_id、token_count、usage |
|
||||||
| `error` | 错误信息 |
|
| `error` | 错误信息 |
|
||||||
|
|
||||||
### process_step 事件格式
|
### process_step 事件格式
|
||||||
|
|
@ -372,7 +400,7 @@ sequenceDiagram
|
||||||
{"type": "process_step", "step": {"id": "step-0", "index": 0, "type": "thinking", "content": "..."}}
|
{"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-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-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, ...}"}}
|
{"type": "process_step", "step": {"id": "step-3", "index": 3, "type": "tool_result", "id_ref": "call_abc", "name": "web_search", "content": "{...}", "success": true}}
|
||||||
```
|
```
|
||||||
|
|
||||||
| 字段 | 说明 |
|
| 字段 | 说明 |
|
||||||
|
|
@ -384,6 +412,13 @@ sequenceDiagram
|
||||||
| `name` | 工具名称(仅 tool_call/tool_result) |
|
| `name` | 工具名称(仅 tool_call/tool_result) |
|
||||||
| `arguments` | 工具调用参数 JSON 字符串(仅 tool_call) |
|
| `arguments` | 工具调用参数 JSON 字符串(仅 tool_call) |
|
||||||
| `content` | 内容(thinking 的思考内容、text 的文本、tool_result 的返回结果) |
|
| `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}}
|
||||||
|
```
|
||||||
|
|
||||||
## 配置示例
|
## 配置示例
|
||||||
|
|
||||||
|
|
@ -419,3 +454,35 @@ tools:
|
||||||
| `APP_SECRET_KEY` | 应用密钥 | `your-secret-key` |
|
| `APP_SECRET_KEY` | 应用密钥 | `your-secret-key` |
|
||||||
| `DEEPSEEK_API_KEY` | DeepSeek API | `sk-xxxx` |
|
| `DEEPSEEK_API_KEY` | DeepSeek API | `sk-xxxx` |
|
||||||
| `DATABASE_URL` | 数据库连接 | `sqlite:///./chat.db` |
|
| `DATABASE_URL` | 数据库连接 | `sqlite:///./chat.db` |
|
||||||
|
|
||||||
|
## 项目结构说明
|
||||||
|
|
||||||
|
### 入口文件
|
||||||
|
|
||||||
|
- `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 用量
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue