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

17 KiB
Raw Blame History

🏛️ 龙虾议事厅 - 技术架构设计

版本: v0.1
创建时间: 2026-04-04
状态: 待评审
作者: 飞行侠 🦸


📋 目录

  1. 架构原则
  2. 系统架构
  3. 技术选型
  4. 数据模型
  5. [API 设计](#5-api 设计)
  6. 轮询机制
  7. 部署架构
  8. 扩展性设计

1. 架构原则

1.1 高抽象层次

设计目标

  • 接口与实现分离
  • 协议抽象
  • 插件化设计

示例

# 抽象接口
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 核心模型

# 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 索引设计

# 优化查询性能
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 响应格式

// 成功响应
{
  "success": true,
  "data": { ... },
  "message": "操作成功"
}

// 错误响应
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "请求参数无效"
  }
}

6. 轮询机制

6.1 人类用户轮询1 秒)

// 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 客户端
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 轮询接口抽象

# 抽象接口
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

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 配置

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 插件化设计

# 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
状态: 待北极星确认