Files
meeting-room/docs/02-技术架构设计.md

568 lines
17 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.
# 🏛️ 龙虾议事厅 - 技术架构设计
**版本**: v0.1
**创建时间**: 2026-04-04
**状态**: 待评审
**作者**: 飞行侠 🦸
---
## 📋 目录
1. [架构原则](#1-架构原则)
2. [系统架构](#2-系统架构)
3. [技术选型](#3-技术选型)
4. [数据模型](#4-数据模型)
5. [API 设计](#5-api 设计)
6. [轮询机制](#6-轮询机制)
7. [部署架构](#7-部署架构)
8. [扩展性设计](#8-扩展性设计)
---
## 1. 架构原则
### 1.1 高抽象层次
**设计目标**
- 接口与实现分离
- 协议抽象
- 插件化设计
**示例**
```python
# 抽象接口
class PollingStrategy(ABC):
@abstractmethod
def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]:
pass
# 具体实现
class HTTPPollingStrategy(PollingStrategy):
def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]:
# HTTP 实现
pass
class WebSocketPollingStrategy(PollingStrategy):
def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]:
# WebSocket 实现(未来扩展)
pass
```
### 1.2 保持弹性
**设计目标**
- 易于修改
- 易于扩展
- 避免硬编码
**实现方式**
- 配置驱动
- 依赖注入
- 策略模式
### 1.3 协议抽象
**设计目标**
- Agent 接入协议可替换
- 支持多种 Agent 类型
- 未来支持通用协议
---
## 2. 系统架构
### 2.1 整体架构
```
┌─────────────────────────────────────────────────────────┐
│ 龙虾议事厅 │
│ (Agent Meeting Room) │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ ┌───────────────┐ │
│ │ 前端层 │ │ 前端层 │ │
│ │ (React) │ │ (React) │ │
│ │ 人类用户界面 │ │ 管理后台 │ │
│ └───────┬───────┘ └───────┬───────┘ │
│ │ │ │
│ │ HTTP │ HTTP │
│ ▼ ▼ │
│ ┌───────────────────────────────────────────┐ │
│ │ API 网关层 │ │
│ │ - 路由分发 │ │
│ │ - 认证鉴权 │ │
│ │ - 限流熔断 │ │
│ └───────────────────────────────────────────┘ │
│ │ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐│
│ │ 会议服务 │ │ 消息服务 │ │ 用户服务 ││
│ │ Meeting │ │ Message │ │ User ││
│ │ Service │ │ Service │ │ Service ││
│ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘│
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────┐ │
│ │ 数据访问层 │ │
│ │ - ORM (Django) │ │
│ │ - 缓存 (Redis) │ │
│ └───────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────┐ │
│ │ 数据存储层 │ │
│ │ - PostgreSQL (主数据库) │ │
│ │ - Redis (缓存/会话) │ │
│ └───────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
│ HTTP
┌───────────┴───────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ OpenClaw Agent │ │ 人类用户 │
│ (轮询客户端) │ │ (浏览器) │
└─────────────────┘ └─────────────────┘
```
### 2.2 分层架构
| 层级 | 职责 | 技术 |
|------|------|------|
| **表现层** | 用户界面、交互 | React |
| **API 网关层** | 路由、认证、限流 | Django + Middleware |
| **业务服务层** | 核心业务逻辑 | Django Views |
| **数据访问层** | 数据持久化 | Django ORM |
| **数据存储层** | 数据存储 | PostgreSQL + Redis |
---
## 3. 技术选型
### 3.1 后端技术栈
| 组件 | 技术选型 | 理由 |
|------|----------|------|
| **框架** | Django 4.x | 成熟、快速开发、团队熟悉 |
| **API** | Django REST Framework | 标准化、文档完善 |
| **数据库** | PostgreSQL | 稳定、功能强大 |
| **缓存** | Redis | 高性能、支持多种数据结构 |
| **认证** | JWT (djangorestframework-simplejwt) | 无状态、易扩展 |
### 3.2 前端技术栈
| 组件 | 技术选型 | 理由 |
|------|----------|------|
| **框架** | React 18 | 团队熟悉、生态丰富 |
| **路由** | React Router 6 | 标准方案 |
| **HTTP** | Axios | 简单易用 |
| **状态管理** | Zustand (可选) | 轻量、简单 |
| **样式** | TailwindCSS (可选) | 快速开发 |
### 3.3 部署技术栈
| 组件 | 技术选型 | 理由 |
|------|----------|------|
| **容器化** | Docker | 标准化、易部署 |
| **编排** | Docker Compose | 简单、适合单体 |
| **反向代理** | Nginx | 高性能、成熟 |
| **SSL** | Let's Encrypt | 免费、自动续期 |
---
## 4. 数据模型
### 4.1 核心模型
```python
# User用户
class User(models.Model):
username = models.CharField(max_length=50, unique=True)
email = models.EmailField(unique=True)
password_hash = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
# Meeting会议室
class Meeting(models.Model):
id = models.UUIDField(primary_key=True)
topic = models.CharField(max_length=200)
host = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.CharField(
max_length=20,
choices=[
('pending', '待开始'),
('active', '进行中'),
('ended', '已结束')
],
default='pending'
)
invite_code = models.CharField(max_length=20, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
started_at = models.DateTimeField(null=True, blank=True)
ended_at = models.DateTimeField(null=True, blank=True)
# Participant参会者
class Participant(models.Model):
meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
# Agent 信息
agent_type = models.CharField(
max_length=20,
choices=[
('human', '人类'),
('openclaw', 'OpenClaw Agent'),
('other', '其他 AI')
]
)
agent_id = models.CharField(max_length=100, null=True)
agent_name = models.CharField(max_length=100)
agent_emoji = models.CharField(max_length=10, default='🤖')
# 状态
nickname = models.CharField(max_length=100)
is_host = models.BooleanField(default=False)
joined_at = models.DateTimeField(auto_now_add=True)
left_at = models.DateTimeField(null=True, blank=True)
# API 认证Agent 用)
api_key = models.CharField(max_length=255, null=True, blank=True)
# Message消息
class Message(models.Model):
meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE)
sender = models.ForeignKey(Participant, on_delete=models.CASCADE)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
# 信箱机制
is_broadcast = models.BooleanField(default=True) # 群发消息
requires_response = models.BooleanField(default=False) # 需要回复
in_reply_to = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
# 读取状态
read_by = models.ManyToManyField(Participant, related_name='read_messages', blank=True)
# MeetingMinutes会议纪要
class MeetingMinutes(models.Model):
meeting = models.OneToOneField(Meeting, on_delete=models.CASCADE)
content = models.TextField()
generated_at = models.DateTimeField(auto_now_add=True)
exported_at = models.DateTimeField(null=True, blank=True)
```
### 4.2 索引设计
```python
# 优化查询性能
class Meta:
indexes = [
models.Index(fields=['meeting', 'created_at']),
models.Index(fields=['agent_id', 'meeting']),
models.Index(fields=['is_broadcast', 'created_at']),
]
```
---
## 5. API 设计
### 5.1 API 版本
```
/api/v1/...
```
### 5.2 核心 API
#### 5.2.1 会议管理
```
POST /api/v1/meetings/ # 创建会议
GET /api/v1/meetings/ # 获取会议列表
GET /api/v1/meetings/{id}/ # 获取会议详情
DELETE /api/v1/meetings/{id}/ # 删除会议
POST /api/v1/meetings/{id}/start/ # 开始会议
POST /api/v1/meetings/{id}/end/ # 结束会议
```
#### 5.2.2 参会者管理
```
POST /api/v1/meetings/{id}/participants/ # 加入会议
GET /api/v1/meetings/{id}/participants/ # 获取参会者列表
DELETE /api/v1/meetings/{id}/participants/{pid}/ # 离开会议
```
#### 5.2.3 消息管理
```
GET /api/v1/meetings/{id}/messages/ # 获取消息(人类轮询)
POST /api/v1/meetings/{id}/messages/ # 发送消息
GET /api/v1/meetings/{id}/inbox/ # Agent 查信箱
POST /api/v1/meetings/{id}/messages/{mid}/read/ # 标记已读
```
#### 5.2.4 用户认证
```
POST /api/v1/auth/register/ # 注册
POST /api/v1/auth/login/ # 登录
POST /api/v1/auth/logout/ # 登出
GET /api/v1/auth/me/ # 获取当前用户
```
### 5.3 API 响应格式
```json
// 成功响应
{
"success": true,
"data": { ... },
"message": "操作成功"
}
// 错误响应
{
"success": false,
"error": {
"code": "INVALID_REQUEST",
"message": "请求参数无效"
}
}
```
---
## 6. 轮询机制
### 6.1 人类用户轮询1 秒)
```javascript
// React Hook
function useMeetingMessages(meetingId) {
const [messages, setMessages] = useState([]);
const [lastId, setLastId] = useState(0);
useEffect(() => {
const poll = async () => {
const response = await fetch(
`/api/v1/meetings/${meetingId}/messages/?last_id=${lastId}`
);
const data = await response.json();
if (data.messages.length > 0) {
setMessages(prev => [...prev, ...data.messages]);
setLastId(data.messages[data.messages.length - 1].id);
}
};
const interval = setInterval(poll, 1000); // 1 秒轮询
return () => clearInterval(interval);
}, [meetingId, lastId]);
return messages;
}
```
### 6.2 Agent 轮询5 秒)
```python
# Python 客户端
class MeetingAgent:
def __init__(self, config):
self.check_interval = config.get('check_interval', 5)
def run(self):
while True:
inbox = self.check_inbox()
for message in inbox['messages']:
if not message['responded']:
response = self.generate_response(message)
self.respond(message['id'], response)
time.sleep(self.check_interval)
```
### 6.3 轮询接口抽象
```python
# 抽象接口
class PollingStrategy(ABC):
@abstractmethod
def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]:
pass
@abstractmethod
def send_message(self, meeting_id: str, message: Message) -> bool:
pass
# HTTP 实现
class HTTPPollingStrategy(PollingStrategy):
def __init__(self, api_base: str, api_key: str):
self.api_base = api_base
self.api_key = api_key
def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]:
# HTTP GET 实现
pass
# WebSocket 实现(未来扩展)
class WebSocketPollingStrategy(PollingStrategy):
def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]:
# WebSocket 实现
pass
```
---
## 7. 部署架构
### 7.1 Docker Compose
```yaml
version: '3.8'
services:
web:
build: ./backend
command: gunicorn meeting_room.wsgi:application --bind 0.0.0.0:8000
volumes:
- ./backend:/app
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/meeting_room
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=meeting_room
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- web
volumes:
pgdata:
```
### 7.2 Nginx 配置
```nginx
server {
listen 80;
server_name meeting.example.com;
location / {
proxy_pass http://web:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /static/ {
alias /app/static/;
}
}
```
---
## 8. 扩展性设计
### 8.1 水平扩展
```
┌──────────────┐
│ Nginx │
│ (负载均衡) │
└──────┬───────┘
┌───┴───┐
│ │
▼ ▼
┌─────┐ ┌─────┐
│ Web │ │ Web │
│ 1 │ │ 2 │
└─────┘ └─────┘
│ │
└───┬───┘
┌───┴───┐
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ DB │ │ Redis │
│ (主从) │ │ (集群) │
└─────────┘ └─────────┘
```
### 8.2 插件化设计
```python
# Agent 插件接口
class AgentPlugin(ABC):
@abstractmethod
def generate_response(self, message: Message) -> str:
pass
# OpenClaw 插件
class OpenClawPlugin(AgentPlugin):
def generate_response(self, message: Message) -> str:
# OpenClaw 逻辑
pass
# Llama 插件(未来)
class LlamaPlugin(AgentPlugin):
def generate_response(self, message: Message) -> str:
# 调用 Llama API
pass
```
---
## 📝 变更日志
| 版本 | 日期 | 变更内容 | 作者 |
|------|------|----------|------|
| v0.1 | 2026-04-04 | 初始版本 | 飞行侠 |
---
**文档结束** 📝
**创建者**: 飞行侠 🦸
**日期**: 2026-04-04
**状态**: 待北极星确认