1019 lines
27 KiB
Markdown
1019 lines
27 KiB
Markdown
# 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 # 认证 (登录/注册)
|
||
│ ├── agents.py # Agent 模板管理 (CRUD)
|
||
│ ├── chat_rooms.py # 聊天室管理 (多 Agent 协作)
|
||
│ ├── conversations.py # 会话管理 (CRUD)
|
||
│ ├── messages.py # 消息处理 (流式/同步)
|
||
│ ├── providers.py # LLM 提供商管理
|
||
│ ├── agents.py # Agent 模板管理 (CRUD)
|
||
│ └── tools.py # 工具管理
|
||
├── services/ # 服务层
|
||
│ ├── __init__.py # 服务导出
|
||
│ ├── chat.py # 聊天服务门面
|
||
│ ├── chat_room.py # 多 Agent 聊天室编排器
|
||
│ ├── agentic_loop.py # Agentic Loop 执行器
|
||
│ ├── stream_context.py # 流式状态管理
|
||
│ ├── events.py # SSE 事件工具
|
||
│ ├── llm_response.py # LLM 响应数据类
|
||
│ ├── 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
|
||
}
|
||
|
||
USER_SETTINGS {
|
||
int id PK
|
||
int user_id FK UK
|
||
int default_provider_id FK "optional"
|
||
float temperature
|
||
int max_tokens
|
||
boolean thinking_enabled
|
||
text system_prompt
|
||
datetime created_at
|
||
datetime updated_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 "optional"
|
||
string room_id FK "optional"
|
||
string role
|
||
longtext content "JSON 格式"
|
||
int token_count
|
||
text usage "JSON 格式"
|
||
string sender_name "聊天室: 发送者名称"
|
||
string sender_color "聊天室: 发送者颜色"
|
||
int round_number "聊天室: 轮次编号"
|
||
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
|
||
}
|
||
|
||
AGENT {
|
||
int id PK
|
||
int user_id FK
|
||
string name
|
||
string role
|
||
int provider_id FK "optional"
|
||
string model
|
||
text system_prompt
|
||
string color
|
||
datetime created_at
|
||
datetime updated_at
|
||
}
|
||
|
||
CHAT_ROOM {
|
||
string id PK
|
||
int user_id FK
|
||
string title
|
||
text task
|
||
string status "idle/running/paused/completed/error"
|
||
int max_rounds
|
||
int current_round
|
||
datetime created_at
|
||
datetime updated_at
|
||
}
|
||
|
||
ROOM_AGENT {
|
||
int id PK
|
||
string room_id FK
|
||
int agent_id FK "optional"
|
||
string name
|
||
string role
|
||
int provider_id FK "optional"
|
||
string model
|
||
text system_prompt
|
||
string color
|
||
int turn_order
|
||
}
|
||
|
||
USER ||--|| USER_SETTINGS : "has"
|
||
USER ||--o{ PROJECT : "has"
|
||
USER ||--o{ CONVERSATION : "has"
|
||
USER ||--o{ LLM_PROVIDER : "configures"
|
||
USER ||--o{ AGENT : "creates"
|
||
USER ||--o{ CHAT_ROOM : "creates"
|
||
PROJECT ||--o{ CONVERSATION : "contains"
|
||
LLM_PROVIDER ||--o{ CONVERSATION : "uses"
|
||
LLM_PROVIDER ||--o{ AGENT : "used_by"
|
||
LLM_PROVIDER ||--o{ ROOM_AGENT : "used_by"
|
||
CONVERSATION ||--o{ MESSAGE : "has"
|
||
CHAT_ROOM ||--o{ MESSAGE : "has"
|
||
CHAT_ROOM ||--o{ ROOM_AGENT : "contains"
|
||
AGENT ||--o{ ROOM_AGENT : "linked_to"
|
||
```
|
||
|
||
**用户权限级别 (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 {
|
||
<<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 |
|
||
|
||
#### 权限检查机制
|
||
|
||
工具执行时自动检查用户权限:
|
||
|
||
```
|
||
工具要求的权限 <= 用户拥有的权限 → 允许执行
|
||
工具要求的权限 > 用户拥有的权限 → 拒绝执行
|
||
```
|
||
|
||
#### 工具开发规范
|
||
|
||
所有工具必须遵循统一的开发规范,确保错误处理和返回格式一致。
|
||
|
||
**核心原则:装饰器自动处理一切,工具函数只写业务逻辑**
|
||
|
||
```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 {
|
||
<<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`)
|
||
|
||
```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. Agent 系统 (`routes/agents.py`, `models.py`)
|
||
|
||
Agent 是独立的可复用 AI 助手模板,可以在聊天室中使用:
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class Agent {
|
||
+int id
|
||
+int user_id
|
||
+str name
|
||
+str role
|
||
+int provider_id
|
||
+str model
|
||
+str system_prompt
|
||
+str color
|
||
+to_dict() dict
|
||
}
|
||
|
||
class LLMProvider {
|
||
+int id
|
||
+str name
|
||
+str api_key
|
||
+str default_model
|
||
}
|
||
|
||
Agent --> LLMProvider : uses
|
||
```
|
||
|
||
**Agent 字段说明:**
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | int | Agent 唯一标识 |
|
||
| `user_id` | int | 所属用户 ID |
|
||
| `name` | string | Agent 显示名称 |
|
||
| `role` | string | Agent 角色描述(如"后端开发") |
|
||
| `provider_id` | int | 使用的 LLM 提供商 |
|
||
| `model` | string | 模型名称 |
|
||
| `system_prompt` | string | 系统提示词 |
|
||
| `color` | string | 显示颜色(Hex) |
|
||
|
||
### 9. 聊天室系统 (`routes/chat_rooms.py`, `services/chat_room.py`)
|
||
|
||
聊天室支持多个 Agent 同时参与讨论,协作完成复杂任务:
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class ChatRoom {
|
||
+str id
|
||
+int user_id
|
||
+str title
|
||
+str task
|
||
+str status
|
||
+int max_rounds
|
||
+int current_round
|
||
+List~RoomAgent~ agents
|
||
}
|
||
|
||
class RoomAgent {
|
||
+int id
|
||
+str room_id
|
||
+int agent_id
|
||
+str name
|
||
+str role
|
||
+str model
|
||
+str system_prompt
|
||
+str color
|
||
+int turn_order
|
||
}
|
||
|
||
class ChatRoomOrchestrator {
|
||
-Dict~str, Task~ _running_rooms
|
||
+is_running(room_id) bool
|
||
+cancel(room_id) void
|
||
+run_room(room_id) AsyncGenerator
|
||
}
|
||
|
||
ChatRoom "1" o-- "*" RoomAgent : contains
|
||
ChatRoomOrchestrator ..> ChatRoom : orchestrates
|
||
ChatRoomOrchestrator ..> RoomAgent : executes
|
||
```
|
||
|
||
**聊天室状态:**
|
||
|
||
| 状态 | 说明 |
|
||
|------|------|
|
||
| `idle` | 空闲,未开始 |
|
||
| `running` | 运行中 |
|
||
| `paused` | 已暂停(被手动停止) |
|
||
| `completed` | 已完成(达到最大轮次) |
|
||
| `error` | 错误(执行出错) |
|
||
|
||
**聊天室执行流程:**
|
||
|
||
```
|
||
1. 用户调用 /chat-rooms/{id}/start
|
||
2. ChatRoomOrchestrator.run_room() 被调用
|
||
3. 按 turn_order 顺序执行每个 Agent 的发言轮次
|
||
4. 每个 Agent 根据历史消息和系统提示生成回复
|
||
5. SSE 流式推送消息块 (message_chunk)
|
||
6. 消息结束时推送 message_end
|
||
7. 一轮结束后推送 round_end
|
||
8. 达到 max_rounds 或被停止时结束
|
||
```
|
||
|
||
**SSE 事件流:**
|
||
|
||
```
|
||
room_started → round_start → (message_start → message_chunk* → message_end → message) × N_agents
|
||
→ round_end → (重复下一轮) → room_completed
|
||
```
|
||
|
||
### 10. API 路由
|
||
|
||
| 路由 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/auth/register` | POST | 用户注册 |
|
||
| `/auth/login` | POST | 用户登录 |
|
||
| `/auth/logout` | POST | 用户登出 |
|
||
| `/auth/me` | GET | 当前用户信息 |
|
||
| `/auth/users` | GET | 用户列表(管理员) |
|
||
| `/auth/users/{user_id}` | PUT | 更新用户权限 |
|
||
| `/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 | 测试提供商连接 |
|
||
| `/agents` | GET | Agent 列表 |
|
||
| `/agents` | POST | 创建 Agent |
|
||
| `/agents/{id}` | GET | Agent 详情 |
|
||
| `/agents/{id}` | PUT | 更新 Agent |
|
||
| `/agents/{id}` | DELETE | 删除 Agent |
|
||
| `/chat-rooms` | GET | 聊天室列表 |
|
||
| `/chat-rooms` | POST | 创建聊天室 |
|
||
| `/chat-rooms/{id}` | GET | 聊天室详情 |
|
||
| `/chat-rooms/{id}` | PUT | 更新聊天室 |
|
||
| `/chat-rooms/{id}` | DELETE | 删除聊天室 |
|
||
| `/chat-rooms/{id}/start` | POST | 启动聊天室 |
|
||
| `/chat-rooms/{id}/stop` | POST | 停止聊天室 |
|
||
| `/chat-rooms/{id}/reset` | POST | 重置聊天室 |
|
||
| `/chat-rooms/{id}/messages` | GET | 聊天室消息 |
|
||
| `/chat-rooms/{id}/agents` | POST | 添加 Agent |
|
||
| `/chat-rooms/{id}/agents/{agent_id}` | PUT | 更新 Agent |
|
||
| `/chat-rooms/{id}/agents/{agent_id}` | DELETE | 移除 Agent |
|
||
| `/tools` | GET | 可用工具列表 |
|
||
| `/tools/{name}` | GET | 工具详情 |
|
||
| `/tools/{name}/execute` | POST | 执行工具 |
|
||
| `/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 事件
|
||
|
||
### 普通会话 SSE 事件
|
||
|
||
| 事件 | 说明 |
|
||
|------|------|
|
||
| `process_step` | 结构化步骤(thinking/text/tool_call/tool_result),携带 `id`、`index` 确保渲染顺序 |
|
||
| `done` | 响应完成,携带 message_id、token_count、usage |
|
||
| `error` | 错误信息 |
|
||
|
||
### 聊天室 SSE 事件
|
||
|
||
| 事件 | 说明 |
|
||
|------|------|
|
||
| `room_started` | 聊天室启动,携带 room_id 和 task |
|
||
| `round_start` | 回合开始,携带 round 和 max_rounds |
|
||
| `message_start` | 消息开始,携带 msg_id、sender_name、sender_color、round_number |
|
||
| `message_chunk` | 消息内容增量,携带 content 和 accumulated |
|
||
| `message_end` | 消息结束,携带 msg_id、content、token_count |
|
||
| `message` | 完整消息(用于存储和显示) |
|
||
| `round_end` | 回合结束 |
|
||
| `room_completed` | 聊天室完成 |
|
||
| `room_paused` | 聊天室暂停 |
|
||
| `agent_error` | Agent 执行错误 |
|
||
| `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 内容中提取文本
|