- 后端: FastAPI + SQLAlchemy 2.0 + Pydantic v2 + Celery (19个API模块) - 前端: React 18 + TypeScript + Ant Design 5 + Zustand (19个页面组件) - 权限: RBAC四维权限体系 (RB-01~RB-13) - 任务: 四步向导创建 + 双执行器(龙虾/脚本) + 定时调度 - 部署: Docker Compose 6服务 + Nginx反代 + Alembic迁移 统计: 88个文件 | 8779行代码 | 默认账号: admin/admin123
985 lines
43 KiB
HTML
985 lines
43 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>Agent任务系统 · 架构设计方案</title>
|
|
<style>
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
:root{
|
|
--pri:#6366f1;--pri-dark:#4f46e5;
|
|
--bg:#f8fafc;--bg-card:#fff;--txt:#1e293b;--sub:#64748b;
|
|
--bdr:#e2e8f0;--ok:#22c55e;--warn:#f59e0b;--err:#ef4444;
|
|
--blue:#3b82f6;--purple:#8b5cf6;--cyan:#06b6d4
|
|
}
|
|
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:var(--bg);color:var(--txt);line-height:1.7}
|
|
.wrap{max-width:1200px;margin:0 auto;padding:40px 24px 80px}
|
|
h1{font-size:28px;margin-bottom:8px;color:var(--pri)}
|
|
h2{font-size:20px;margin:48px 0 16px;padding-bottom:8px;border-bottom:2px solid var(--pri);color:var(--pri)}
|
|
h3{font-size:16px;margin:24px 0 12px;color:var(--txt)}
|
|
h4{font-size:14px;margin:20px 0 10px;color:var(--sub);border-left:3px solid var(--pri);padding-left:10px}
|
|
p,li{font-size:14px;margin-bottom:8px}
|
|
ul,ol{padding-left:24px}
|
|
table{width:100%;border-collapse:collapse;font-size:13px;margin:12px 0}
|
|
th,td{padding:10px 12px;text-align:left;border:1px solid var(--bdr)}
|
|
th{background:#f1f5f9;font-weight:600;color:var(--sub);font-size:12px}
|
|
tr:nth-child(even) td{background:#fafbfc}
|
|
.card{background:var(--bg-card);border-radius:12px;padding:24px;margin:16px 0;box-shadow:0 1px 3px rgba(0,0,0,.06);border:1px solid var(--bdr)}
|
|
.tag{display:inline-block;padding:2px 10px;border-radius:99px;font-size:11px;font-weight:600;margin-left:6px}
|
|
.tag-blue{background:#dbeafe;color:#1e40af}
|
|
.tag-green{background:#dcfce7;color:#166534}
|
|
.tag-purple{background:#f3e8ff;color:#6b21a8}
|
|
.tag-orange{background:#fef3c7;color:#92400e}
|
|
.tag-cyan{background:#cffafe;color:#0e7490}
|
|
.highlight{background:#fef3c7;padding:2px 4px;border-radius:3px}
|
|
code{background:#f1f5f9;padding:2px 6px;border-radius:4px;font-size:12px;color:#e11d48;font-family:Consolas,monospace}
|
|
pre{background:#1e293b;color:#e2e8f0;padding:16px;border-radius:8px;overflow-x:auto;font-size:13px;line-height:1.5}
|
|
.architecture-box{background:#1e293b;color:#e2e8f0;border-radius:12px;padding:20px;margin:16px 0;font-family:Consolas,monospace;font-size:12px;line-height:1.6;overflow-x:auto}
|
|
.architecture-box .comment{color:#64748b}
|
|
.architecture-box .keyword{color:#f472b6}
|
|
.architecture-box .string{color:#a5f3fc}
|
|
.architecture-box .function{color:#fbbf24}
|
|
.layer{background:linear-gradient(135deg,var(--pri),var(--purple));color:#fff;padding:14px 20px;border-radius:10px;margin:20px 0 12px;font-weight:600}
|
|
.component{display:inline-block;background:#fff;border:2px solid var(--bdr);border-radius:8px;padding:8px 14px;margin:4px;font-size:13px;font-weight:500;transition:all .2s}
|
|
.component:hover{border-color:var(--pri);box-shadow:0 2px 8px rgba(99,102,241,.2)}
|
|
.timeline{position:relative;padding-left:30px}
|
|
.timeline::before{content:'';position:absolute;left:8px;top:0;bottom:0;width:2px;background:var(--bdr)}
|
|
.timeline-item{position:relative;margin-bottom:20px}
|
|
.timeline-item::before{content:'';position:absolute;left:-26px;top:6px;width:12px;height:12px;border-radius:50%;background:var(--pri);border:3px solid #fff;box-shadow:0 0 0 2px var(--pri)}
|
|
.phase{background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff;padding:16px 24px;border-radius:12px;margin:32px 0 16px}
|
|
.phase h3{color:#fff;margin:0;font-size:18px}
|
|
.phase p{color:rgba(255,255,255,.85);margin:4px 0 0;font-size:14px}
|
|
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
|
@media(max-width:768px){.two-col{grid-template-columns:1fr}}
|
|
.badge{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500}
|
|
.badge-primary{background:#eef2ff;color:#4338ca}
|
|
.badge-success{background:#ecfdf5;color:#059669}
|
|
.badge-warning{background:#fffbeb;color:#d97706}
|
|
.arrow{color:var(--pri);font-weight:700}
|
|
.flow{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:12px 0;font-size:13px}
|
|
.flow-item{background:#f1f5f9;border:1px solid var(--bdr);border-radius:8px;padding:8px 14px;font-weight:500}
|
|
.summary-table{background:#1e293b;color:#e2e8f0;border-radius:12px;padding:20px;margin:16px 0}
|
|
.summary-table table{color:#e2e8f0}
|
|
.summary-table th{background:#334155;color:#94a3b8}
|
|
.summary-table td{border-color:#475569}
|
|
.toc{background:#f8fafc;border:1px solid var(--bdr);border-radius:10px;padding:20px;margin:16px 0}
|
|
.toc h4{margin-top:0;border:none;padding:0}
|
|
.toc a{color:var(--pri);text-decoration:none;font-size:14px}
|
|
.toc a:hover{text-decoration:underline}
|
|
.toc li{margin:8px 0}
|
|
@media print{.wrap{padding:20px}.card{box-shadow:none}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="wrap">
|
|
|
|
<h1>🤖 Agent任务系统 · 架构设计方案</h1>
|
|
<div style="color:var(--sub);font-size:14px;margin-bottom:24px">
|
|
版本 v1.0 | 2026-04-23 | 前后端分离架构<br>
|
|
技术栈:React + FastAPI + PostgreSQL + Redis + Celery
|
|
</div>
|
|
|
|
<!-- 目录 -->
|
|
<div class="toc">
|
|
<h4>📑 目录</h4>
|
|
<ol>
|
|
<li><a href="#section1">一、架构选型分析</a></li>
|
|
<li><a href="#section2">二、技术栈选型</a></li>
|
|
<li><a href="#section3">三、系统架构图</a></li>
|
|
<li><a href="#section4">四、后端模块设计</a></li>
|
|
<li><a href="#section5">五、前端模块设计</a></li>
|
|
<li><a href="#section6">六、部署架构</a></li>
|
|
<li><a href="#section7">七、数据流设计</a></li>
|
|
<li><a href="#section8">八、安全设计</a></li>
|
|
<li><a href="#section9">九、开发里程碑</a></li>
|
|
</ol>
|
|
</div>
|
|
|
|
<!-- 一、架构选型分析 -->
|
|
<h2 id="section1">一、架构选型分析</h2>
|
|
|
|
<div class="card">
|
|
<h3>1.1 需求特点</h3>
|
|
<p>从功能清单来看,这是一个<strong>中等复杂度</strong>的企业级SaaS应用:</p>
|
|
<table>
|
|
<tr><th>需求维度</th><th>特点描述</th></tr>
|
|
<tr><td>权限系统</td><td>部门级RBAC、多角色权限并集、产品/Skill双重范围校验</td></tr>
|
|
<tr><td>任务执行</td><td>脚本执行器异步执行任务,支持Python/Shell</td></tr>
|
|
<tr><td>LLM集成</td><td>多Provider路由、Token统计、成本计算</td></tr>
|
|
<tr><td>实时通知</td><td>SSE/Telegram推送</td></tr>
|
|
<tr><td>部署要求</td><td>前后端分离式独立部署</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>1.2 推荐架构</h3>
|
|
<p><strong>前后端分离 + 分层后端 + 模块化设计</strong></p>
|
|
<table>
|
|
<tr><th>架构特点</th><th>说明</th></tr>
|
|
<tr><td>前后端分离</td><td>React SPA + FastAPI REST API,独立部署</td></tr>
|
|
<tr><td>后端分层</td><td>API层 → Service层 → Repository层</td></tr>
|
|
<tr><td>异步任务</td><td>Celery + Redis 实现脚本异步执行</td></tr>
|
|
<tr><td>缓存层</td><td>Redis 缓存权限数据、Session</td></tr>
|
|
<tr><td>容器化</td><td>Docker Compose 一键部署</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 二、技术栈选型 -->
|
|
<h2 id="section2">二、技术栈选型</h2>
|
|
|
|
<div class="card">
|
|
<h3>2.1 前端技术栈 <span class="tag tag-blue">React</span></h3>
|
|
<table>
|
|
<tr><th>组件</th><th>技术选型</th><th>说明</th></tr>
|
|
<tr><td><strong>框架</strong></td><td>React 18 + TypeScript</td><td>类型安全,生态成熟</td></tr>
|
|
<tr><td><strong>构建工具</strong></td><td>Vite 5</td><td>快速启动,热更新快</td></tr>
|
|
<tr><td><strong>UI组件库</strong></td><td>Ant Design 5</td><td>企业级组件,RBAC友好</td></tr>
|
|
<tr><td><strong>状态管理</strong></td><td>Zustand</td><td>轻量,比Redux简洁</td></tr>
|
|
<tr><td><strong>路由</strong></td><td>React Router 6</td><td>路由守卫+权限控制</td></tr>
|
|
<tr><td><strong>表单</strong></td><td>react-jsonschema-form</td><td>动态表单渲染</td></tr>
|
|
<tr><td><strong>HTTP</strong></td><td>Axios + React Query</td><td>请求拦截、缓存</td></tr>
|
|
<tr><td><strong>图表</strong></td><td>@ant-design/charts</td><td>用量统计图表</td></tr>
|
|
<tr><td><strong>CSS</strong></td><td>Tailwind CSS</td><td>工具类,快速开发</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>2.2 后端技术栈 <span class="tag tag-green">Python FastAPI</span></h3>
|
|
<table>
|
|
<tr><th>组件</th><th>技术选型</th><th>说明</th></tr>
|
|
<tr><td><strong>Web框架</strong></td><td>FastAPI</td><td>异步、高性能、自动API文档</td></tr>
|
|
<tr><td><strong>ORM</strong></td><td>SQLAlchemy 2.0 + asyncpg</td><td>异步数据库操作</td></tr>
|
|
<tr><td><strong>认证</strong></td><td>Python-Jose + Passlib</td><td>JWT签发/验证</td></tr>
|
|
<tr><td><strong>验证</strong></td><td>Pydantic v2</td><td>数据校验</td></tr>
|
|
<tr><td><strong>任务队列</strong></td><td>Celery + Redis</td><td>异步脚本执行</td></tr>
|
|
<tr><td><strong>定时任务</strong></td><td>Celery Beat</td><td>Cron任务调度</td></tr>
|
|
<tr><td><strong>缓存</strong></td><td>Redis</td><td>会话、权限缓存</td></tr>
|
|
<tr><td><strong>加密</strong></td><td>Cryptography</td><td>AES-256 API Key加密</td></tr>
|
|
<tr><td><strong>LLM SDK</strong></td><td>OpenAI SDK + 各Provider SDK</td><td>统一接口封装</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>2.3 基础设施</h3>
|
|
<table>
|
|
<tr><th>组件</th><th>技术选型</th><th>说明</th></tr>
|
|
<tr><td><strong>数据库</strong></td><td>PostgreSQL 16</td><td>JSON支持,复杂查询</td></tr>
|
|
<tr><td><strong>缓存/队列</strong></td><td>Redis 7</td><td>多用途</td></tr>
|
|
<tr><td><strong>对象存储</strong></td><td>MinIO / S3</td><td>脚本模板存储</td></tr>
|
|
<tr><td><strong>反向代理</strong></td><td>Nginx</td><td>静态资源、负载均衡</td></tr>
|
|
<tr><td><strong>容器化</strong></td><td>Docker + Docker Compose</td><td>开发/生产环境</td></tr>
|
|
<tr><td><strong>CI/CD</strong></td><td>GitHub Actions</td><td>自动构建部署</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 三、系统架构图 -->
|
|
<h2 id="section3">三、系统架构图</h2>
|
|
|
|
<div class="architecture-box">
|
|
<pre>
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ 客户端层 │
|
|
│ ┌─────────────────────────┐ ┌─────────────────────────────┐ │
|
|
│ │ React SPA │ │ Telegram Bot │ │
|
|
│ │ (Web管理后台) │ │ (消息通知) │ │
|
|
│ │ ┌─────────────────────┐ │ │ /start /help /task │ │
|
|
│ │ │ Ant Design UI │ │ └──────────────┬──────────────┘ │
|
|
│ │ │ Zustand Store │ │ │ │
|
|
│ │ │ React Router │ │ │ Bot API │
|
|
│ │ └─────────────────────┘ │ │ │
|
|
│ └─────────────┬───────────┘ │ │
|
|
└────────────────┼──────────────────────────────────────────┼──────────────────┘
|
|
│ HTTPS │
|
|
┌────────────────▼──────────────────────────────────────────▼──────────────────┐
|
|
│ API网关层 (Nginx) │
|
|
│ • SSL终结 • 静态资源服务 (Web) │
|
|
│ • API路由转发 • 请求限流/鉴权 │
|
|
│ • WebSocket代理 • SSE支持 │
|
|
└─────────────────────────────────────────────────────────────────┬────────────┘
|
|
│
|
|
┌─────────────────────────────────────────────────────────────────▼────────────┐
|
|
│ 后端服务层 (Python FastAPI) │
|
|
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ FastAPI Application │ │
|
|
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
|
│ │ │ Auth │ │ User │ │ Role │ │ Menu │ │ Product │ │ │
|
|
│ │ │ Module │ │ Module │ │ Module │ │ Module │ │ Module │ │ │
|
|
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
|
|
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
|
│ │ │ Skill │ │ Task │ │ LLM │ │Platform │ │Schedule │ │ │
|
|
│ │ │ Module │ │ Module │ │ Module │ │ Account │ │ Module │ │ │
|
|
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
|
|
│ │ └──────────┬┴───────────┬┴───────────┬┴──────────┬┘ │ │
|
|
│ │ ┌─────────────────────────┴─────────────────────────────────────────┐ │ │
|
|
│ │ │ Core Services (权限/加密/缓存) │ │ │
|
|
│ │ └────────────────────────────────────────┬────────────────────────┘ │ │
|
|
│ └───────────────────────────────────────────┼────────────────────────────┘ │
|
|
└──────────────────────────────────────────────┼──────────────────────────────┘
|
|
│
|
|
┌──────────────────────────────────────────────▼──────────────────────────────┐
|
|
│ 基础设施层 │
|
|
│ │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────────┐ │
|
|
│ │ PostgreSQL │ │ Redis │ │ Script Executor │ │
|
|
│ │ (主数据库) │ │ (缓存/队列) │ │ (Celery Worker) │ │
|
|
│ │ │ │ │ │ ┌────────────────────────┐ │ │
|
|
│ │ • 用户数据 │ │ • 会话缓存 │ │ │ Python/Shell 执行 │ │ │
|
|
│ │ • 权限数据 │ │ • 权限缓存 │ │ │ 沙箱隔离执行 │ │ │
|
|
│ │ • 任务记录 │ │ • Celery │ │ │ 超时控制 │ │ │
|
|
│ │ • LLM用量 │ │ Broker │ │ └────────────────────────┘ │ │
|
|
│ └──────────────┘ └──────────────┘ └──────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────────┐ │
|
|
│ │ MinIO │ │ Celery Beat │ │ Telegram Bot │ │
|
|
│ │ (文件存储) │ │ (定时任务) │ │ (通知推送) │ │
|
|
│ └──────────────┘ └──────────────┘ └──────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
</pre>
|
|
</div>
|
|
|
|
<!-- 四、后端模块设计 -->
|
|
<h2 id="section4">四、后端模块设计</h2>
|
|
|
|
<div class="card">
|
|
<h3>4.1 项目目录结构</h3>
|
|
<div class="architecture-box">
|
|
<pre>
|
|
agent-system-backend/
|
|
├── app/
|
|
│ ├── __init__.py
|
|
│ ├── main.py # FastAPI 应用入口
|
|
│ ├── config.py # 配置管理 (Pydantic Settings)
|
|
│ │
|
|
│ ├── api/ # API 路由层
|
|
│ │ ├── __init__.py
|
|
│ │ ├── deps.py # 依赖注入 (get_db, get_current_user)
|
|
│ │ └── v1/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── auth.py # 认证接口
|
|
│ │ ├── users.py # 用户管理
|
|
│ │ ├── roles.py # 角色管理
|
|
│ │ ├── menus.py # 菜单管理
|
|
│ │ ├── products.py # 产品管理
|
|
│ │ ├── skills.py # Skill管理
|
|
│ │ ├── tasks.py # 任务管理
|
|
│ │ ├── llm.py # LLM管理
|
|
│ │ ├── platform_accounts.py # 平台账号
|
|
│ │ ├── schedules.py # 定时任务
|
|
│ │ └── logs.py # 日志
|
|
│ │
|
|
│ ├── core/ # 核心模块
|
|
│ │ ├── security.py # JWT/加密工具
|
|
│ │ ├── permission.py # 权限校验服务
|
|
│ │ ├── database.py # 数据库连接
|
|
│ │ └── cache.py # Redis缓存
|
|
│ │
|
|
│ ├── models/ # SQLAlchemy 模型
|
|
│ │ ├── base.py # 基础模型 (timestamp, uuid)
|
|
│ │ ├── user.py # 用户、角色、组织架构
|
|
│ │ ├── menu.py # 菜单、按钮
|
|
│ │ ├── product.py # 产品、渠道码
|
|
│ │ ├── skill.py # Skill、脚本模板
|
|
│ │ ├── task.py # 任务
|
|
│ │ ├── llm.py # LLM供应商、模型、路由、用量
|
|
│ │ ├── platform_account.py # 平台账号
|
|
│ │ └── schedule.py # 定时任务
|
|
│ │
|
|
│ ├── schemas/ # Pydantic 请求/响应模型
|
|
│ │ ├── auth.py # LoginRequest, Token
|
|
│ │ ├── user.py # UserCreate, UserUpdate, UserResponse
|
|
│ │ ├── role.py # RoleCreate, RolePermissionUpdate
|
|
│ │ ├── task.py # TaskCreate, TaskResponse
|
|
│ │ └── ...
|
|
│ │
|
|
│ ├── services/ # 业务逻辑层
|
|
│ │ ├── auth_service.py # 登录、Token刷新
|
|
│ │ ├── user_service.py # 用户CRUD
|
|
│ │ ├── role_service.py # 角色CRUD
|
|
│ │ ├── permission_service.py # 权限计算核心
|
|
│ │ ├── skill_service.py # Skill管理
|
|
│ │ ├── task_service.py # 任务创建/执行
|
|
│ │ ├── llm_service.py # LLM路由+调用+用量
|
|
│ │ ├── script_executor.py # 脚本执行器
|
|
│ │ └── platform_account_service.py
|
|
│ │
|
|
│ └── utils/ # 工具函数
|
|
│ ├── encrypt.py # AES加密 (API Key)
|
|
│ ├── llm_providers.py # 各Provider SDK封装
|
|
│ └── exceptions.py # 自定义异常
|
|
│
|
|
│ └── celery_app/ # Celery 配置
|
|
│ ├── celery.py # Celery实例
|
|
│ └── tasks/
|
|
│ ├── script_tasks.py # 脚本执行任务
|
|
│ └── schedule_tasks.py # 定时任务
|
|
│
|
|
├── tests/ # 测试
|
|
├── scripts/
|
|
│ └── init_db.py # 数据库初始化脚本
|
|
├── alembic/ # 数据库迁移
|
|
├── Dockerfile # API服务镜像
|
|
├── Dockerfile.worker # Worker镜像
|
|
├── docker-compose.yml
|
|
├── requirements.txt
|
|
└── .env.example
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>4.2 核心模块详解</h3>
|
|
|
|
<h4>4.2.1 权限服务 (Permission Service)</h4>
|
|
<p>实现 v2.2 的三要素权限模型:菜单/按钮权限 + 产品范围 + Skill权限</p>
|
|
<pre>
|
|
class PermissionService:
|
|
"""权限服务 - 实现部门级RBAC三要素模型"""
|
|
|
|
async def get_user_effective_permissions(self, user_id: int) -> EffectivePermissions:
|
|
"""
|
|
计算用户有效权限 = 所有角色权限并集
|
|
RB-04: 多角色权限取并集
|
|
"""
|
|
user = await self.user_repo.get_with_roles(user_id)
|
|
|
|
# 合并所有角色的菜单/按钮权限
|
|
menu_permissions = set()
|
|
button_permissions = set()
|
|
data_scopes = []
|
|
skill_scopes = []
|
|
|
|
for role in user.roles:
|
|
# 仅计算同部门角色 (RB-02)
|
|
if role.org_id != user.org_id:
|
|
continue
|
|
menu_permissions.update(role.menus)
|
|
button_permissions.update(role.buttons)
|
|
data_scopes.append(role.data_scope)
|
|
skill_scopes.append(role.skill_scope)
|
|
|
|
return EffectivePermissions(
|
|
menus=list(menu_permissions),
|
|
buttons=list(button_permissions),
|
|
data_scope=self._merge_data_scope(data_scopes),
|
|
skill_scope=list(set().union(*skill_scopes)),
|
|
platform_accounts=user.platform_accounts # 用户直接拥有 (RB-15)
|
|
)
|
|
|
|
async def verify_task_permission(
|
|
self,
|
|
user_id: int,
|
|
skill_id: int,
|
|
product_id: int
|
|
) -> bool:
|
|
"""
|
|
任务创建权限校验
|
|
RB-12: Skill权限 + 产品范围交集双重校验
|
|
"""
|
|
perms = await self.get_user_effective_permissions(user_id)
|
|
|
|
# 校验1: Skill权限 (RB-07)
|
|
if skill_id not in perms.skill_scope:
|
|
raise PermissionDeniedError("无权使用此Skill")
|
|
|
|
# 校验2: 产品范围交集 (RB-12)
|
|
skill = await self.skill_repo.get(skill_id)
|
|
allowed_products = (
|
|
set(perms.data_scope.product_ids)
|
|
& set(skill.product_scope.product_ids)
|
|
)
|
|
if product_id not in allowed_products:
|
|
raise PermissionDeniedError("该Skill不可操作此产品")
|
|
|
|
return True
|
|
</pre>
|
|
|
|
<h4>4.2.2 LLM服务 (LLM Service)</h4>
|
|
<p>实现多Provider统一管理和智能路由</p>
|
|
<pre>
|
|
class LLMService:
|
|
"""LLM服务 - 多Provider统一管理"""
|
|
|
|
async def route_model(self, scenario: str, product_id: int, model_type: str) -> LLMModel:
|
|
"""
|
|
模型路由:根据条件匹配最佳模型
|
|
RB-20: 按优先级匹配,无匹配用默认模型
|
|
"""
|
|
# 查询匹配规则
|
|
rules = await self.routing_rule_repo.get_matching_rules(
|
|
scenario=scenario,
|
|
product_id=product_id,
|
|
model_type=model_type
|
|
)
|
|
|
|
if rules:
|
|
return await self.model_repo.get(rules[0].target_model_id)
|
|
|
|
# 无匹配规则,使用默认模型
|
|
default = await self.config_repo.get("default_llm_model")
|
|
return await self.model_repo.get(default)
|
|
|
|
async def chat(self, user_id: int, params: ChatParams) -> ChatResponse:
|
|
"""
|
|
LLM调用入口
|
|
RB-21: 自动记录用量
|
|
"""
|
|
# 1. 路由匹配
|
|
model = await self.route_model(params.scenario, params.product_id, params.model_type)
|
|
|
|
# 2. 获取Provider API Key (解密 RB-18)
|
|
provider = await self.provider_repo.get(model.provider_id)
|
|
api_key = self.encrypt_service.decrypt(provider.api_keys)
|
|
|
|
# 3. 调用LLM
|
|
client = self._get_provider_client(provider.provider_type)
|
|
response = await client.chat(
|
|
base_url=provider.base_url,
|
|
api_key=api_key,
|
|
model=model.model_name,
|
|
messages=params.messages,
|
|
**model.default_params
|
|
)
|
|
|
|
# 4. 记录用量 (RB-21, RB-22)
|
|
await self.usage_service.record(
|
|
user_id=user_id,
|
|
model_id=model.model_id,
|
|
input_tokens=response.usage.input_tokens,
|
|
output_tokens=response.usage.output_tokens,
|
|
latency=response.latency
|
|
)
|
|
|
|
return response
|
|
</pre>
|
|
|
|
<h4>4.2.3 脚本执行器 (Script Executor)</h4>
|
|
<p>支持Python/Shell多类型脚本,RB-13/RB-14/RB-17</p>
|
|
<pre>
|
|
class ScriptExecutorService:
|
|
"""脚本执行器 - 支持Python/Shell多类型"""
|
|
|
|
async def execute(
|
|
self,
|
|
template_id: int,
|
|
params: dict,
|
|
user_env: dict
|
|
) -> ExecutionResult:
|
|
"""
|
|
执行脚本
|
|
RB-13/14/17: 脚本沙箱隔离执行
|
|
"""
|
|
# 1. 获取脚本模板
|
|
template = await self.template_repo.get(template_id)
|
|
|
|
# 2. 渲染脚本 (注入参数和环境变量)
|
|
script = self._render_script(template, params, user_env)
|
|
|
|
# 3. 提交Celery任务
|
|
task = execute_script_task.delay(
|
|
script=script,
|
|
script_type=template.script_type,
|
|
timeout=template.default_timeout,
|
|
work_dir=self.config.script_work_dir
|
|
)
|
|
|
|
return ExecutionResult(task_id=task.id, status="PENDING")
|
|
|
|
@celery_app.task(bind=True, max_retries=3)
|
|
def execute_script_task(self, script: str, script_type: str, timeout: int, work_dir: str):
|
|
"""独立进程执行脚本 - 沙箱隔离"""
|
|
import subprocess
|
|
|
|
result = subprocess.run(
|
|
["python" if script_type == "python" else "bash", "-c", script],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=timeout, # 超时控制
|
|
cwd=work_dir,
|
|
env={**os.environ, **user_env} # 环境变量隔离
|
|
)
|
|
|
|
return {
|
|
"stdout": result.stdout,
|
|
"stderr": result.stderr,
|
|
"returncode": result.returncode
|
|
}
|
|
</pre>
|
|
</div>
|
|
|
|
<!-- 五、前端模块设计 -->
|
|
<h2 id="section5">五、前端模块设计</h2>
|
|
|
|
<div class="card">
|
|
<h3>5.1 项目目录结构</h3>
|
|
<div class="architecture-box">
|
|
<pre>
|
|
agent-system-frontend/
|
|
├── src/
|
|
│ ├── api/ # API 请求层
|
|
│ │ ├── request.ts # Axios 实例 (拦截器)
|
|
│ │ ├── auth.ts # 登录、Token
|
|
│ │ ├── user.ts # 用户管理
|
|
│ │ ├── role.ts # 角色管理
|
|
│ │ ├── skill.ts # Skill管理
|
|
│ │ ├── task.ts # 任务管理
|
|
│ │ ├── llm.ts # LLM管理
|
|
│ │ └── ...
|
|
│ │
|
|
│ ├── components/ # 组件库
|
|
│ │ ├── Common/ # 通用组件 (PageHeader, EmptyState)
|
|
│ │ ├── Form/ # 表单组件 (DynamicForm, ProductSelector)
|
|
│ │ ├── Table/ # 表格组件 (ProTable)
|
|
│ │ └── Layout/ # 布局组件 (AppLayout)
|
|
│ │
|
|
│ ├── pages/ # 页面
|
|
│ │ ├── Login/ # 登录页
|
|
│ │ ├── Dashboard/ # 首页仪表盘
|
|
│ │ ├── System/ # 系统管理
|
|
│ │ │ ├── Users/ # 用户管理
|
|
│ │ │ ├── Roles/ # 角色管理
|
|
│ │ │ ├── Menus/ # 菜单管理
|
|
│ │ │ └── Orgs/ # 组织架构
|
|
│ │ ├── Product/ # 产品管理
|
|
│ │ ├── Skill/ # Skill中心
|
|
│ │ ├── Task/ # 任务中心
|
|
│ │ ├── LLM/ # 大模型管理
|
|
│ │ │ ├── Providers/ # 供应商管理
|
|
│ │ │ ├── Models/ # 模型配置
|
|
│ │ │ ├── Routing/ # 路由规则
|
|
│ │ │ └── Usage/ # 用量统计
|
|
│ │ └── Settings/ # 系统设置
|
|
│ │
|
|
│ ├── hooks/ # React Hooks
|
|
│ │ ├── usePermission.ts # 权限判断
|
|
│ │ ├── useUser.ts # 用户状态
|
|
│ │ └── useQueryParams.ts
|
|
│ │
|
|
│ ├── stores/ # Zustand 状态
|
|
│ │ ├── authStore.ts # 认证状态
|
|
│ │ ├── permissionStore.ts # 权限缓存
|
|
│ │ └── settingsStore.ts
|
|
│ │
|
|
│ ├── types/ # TypeScript类型
|
|
│ │ ├── api.d.ts # API响应类型
|
|
│ │ └── model.d.ts # 数据模型类型
|
|
│ │
|
|
│ ├── router/ # 路由配置
|
|
│ │ └── index.tsx # React Router + 路由守卫
|
|
│ │
|
|
│ └── App.tsx
|
|
│
|
|
├── package.json
|
|
├── vite.config.ts
|
|
├── tsconfig.json
|
|
└── tailwind.config.js
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>5.2 权限控制实现</h3>
|
|
<pre>
|
|
// hooks/usePermission.ts
|
|
export function usePermission() {
|
|
const { permissions } = useUserStore();
|
|
|
|
const can = (action: string) => {
|
|
return permissions.buttons.includes(action);
|
|
};
|
|
|
|
const canAccessMenu = (menuPath: string) => {
|
|
return permissions.menus.some(m => m.path === menuPath);
|
|
};
|
|
|
|
const canUseSkill = (skillId: number) => {
|
|
return permissions.skillScope.includes(skillId);
|
|
};
|
|
|
|
const canAccessProduct = (productId: number) => {
|
|
return permissions.dataScope.productIds.includes(productId);
|
|
};
|
|
|
|
return { can, canAccessMenu, canUseSkill, canAccessProduct };
|
|
}
|
|
|
|
// 路由守卫
|
|
function PrivateRoute({ children, requiredPermission }: Props) {
|
|
const { can } = usePermission();
|
|
const location = useLocation();
|
|
|
|
if (!hasAuth()) {
|
|
return <Navigate to="/login" state={{ from: location }} />;
|
|
}
|
|
|
|
if (requiredPermission && !can(requiredPermission)) {
|
|
return <Navigate to="/403" />;
|
|
}
|
|
|
|
return children;
|
|
}
|
|
|
|
// Skill选择器 - 只显示有权限的Skill
|
|
function SkillSelector() {
|
|
const { canUseSkill } = usePermission();
|
|
const { data: skills } = useQuery(['skills'], fetchSkills);
|
|
|
|
// 过滤:只显示用户有权限的Skill
|
|
const availableSkills = skills?.filter(s => canUseSkill(s.id)) || [];
|
|
|
|
return (
|
|
<Select placeholder="选择Skill">
|
|
{availableSkills.map(skill => (
|
|
<Option key={skill.id} value={skill.id}>
|
|
{skill.name} - {skill.description}
|
|
</Option>
|
|
))}
|
|
</Select>
|
|
);
|
|
}
|
|
|
|
// 产品选择器 - 只显示在交集范围内的产品
|
|
function ProductSelector({ skillId }: { skillId: number }) {
|
|
const { canAccessProduct } = usePermission();
|
|
const { data: products } = useQuery(['products'], fetchProducts);
|
|
|
|
// RB-12: Skill.product_scope ∩ 用户角色.data_scope
|
|
const availableProducts = products?.filter(p => canAccessProduct(p.id)) || [];
|
|
|
|
return (
|
|
<Select placeholder="选择产品">
|
|
{availableProducts.map(product => (
|
|
<Option key={product.id} value={product.id}>
|
|
{product.name} ({product.platform.name})
|
|
</Option>
|
|
))}
|
|
</Select>
|
|
);
|
|
}
|
|
</pre>
|
|
</div>
|
|
|
|
<!-- 六、部署架构 -->
|
|
<h2 id="section6">六、部署架构</h2>
|
|
|
|
<div class="card">
|
|
<h3>6.1 Docker Compose 配置</h3>
|
|
<pre>
|
|
# docker-compose.yml
|
|
|
|
version: '3.8'
|
|
|
|
services:
|
|
# 前端 (Nginx 托管静态资源)
|
|
frontend:
|
|
build:
|
|
context: ./frontend
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
depends_on:
|
|
- backend
|
|
networks:
|
|
- agent-network
|
|
|
|
# 后端 API
|
|
backend:
|
|
build:
|
|
context: ./backend
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "8000:8000"
|
|
environment:
|
|
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@db:5432/agent_system
|
|
- REDIS_URL=redis://redis:6379/0
|
|
- SECRET_KEY=${SECRET_KEY}
|
|
- ENCRYPT_KEY=${ENCRYPT_KEY}
|
|
depends_on:
|
|
- db
|
|
- redis
|
|
networks:
|
|
- agent-network
|
|
|
|
# Celery Worker (脚本执行)
|
|
celery-worker:
|
|
build:
|
|
context: ./backend
|
|
dockerfile: Dockerfile.worker
|
|
command: celery -A celery_app worker -l info
|
|
volumes:
|
|
- script-data:/app/scripts
|
|
depends_on:
|
|
- redis
|
|
- backend
|
|
networks:
|
|
- agent-network
|
|
|
|
# Celery Beat (定时任务调度器)
|
|
celery-beat:
|
|
build:
|
|
context: ./backend
|
|
dockerfile: Dockerfile.worker
|
|
command: celery -A celery_app beat -l info
|
|
depends_on:
|
|
- redis
|
|
networks:
|
|
- agent-network
|
|
|
|
# PostgreSQL 数据库
|
|
db:
|
|
image: postgres:16-alpine
|
|
environment:
|
|
POSTGRES_DB: agent_system
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
ports:
|
|
- "5432:5432"
|
|
networks:
|
|
- agent-network
|
|
|
|
# Redis (缓存 + 消息队列)
|
|
redis:
|
|
image: redis:7-alpine
|
|
volumes:
|
|
- redis-data:/data
|
|
ports:
|
|
- "6379:6379"
|
|
networks:
|
|
- agent-network
|
|
|
|
volumes:
|
|
postgres-data:
|
|
redis-data:
|
|
script-data:
|
|
|
|
networks:
|
|
agent-network:
|
|
driver: bridge
|
|
</pre>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>6.2 Nginx 配置</h3>
|
|
<pre>
|
|
# nginx/nginx.conf
|
|
|
|
events {
|
|
worker_connections 1024;
|
|
}
|
|
|
|
http {
|
|
include /etc/nginx/mime.types;
|
|
|
|
upstream backend {
|
|
server backend:8000;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
server_name your-domain.com;
|
|
|
|
ssl_certificate /etc/nginx/ssl/cert.pem;
|
|
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
|
|
|
# 静态资源 (前端)
|
|
location / {
|
|
root /usr/share/nginx/html;
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
# API 代理
|
|
location /api/ {
|
|
proxy_pass http://backend;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
|
|
# SSE 支持
|
|
proxy_buffering off;
|
|
proxy_cache off;
|
|
proxy_read_timeout 86400s;
|
|
}
|
|
|
|
# WebSocket (实时日志)
|
|
location /ws/ {
|
|
proxy_pass http://backend;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
}
|
|
}
|
|
}
|
|
</pre>
|
|
</div>
|
|
|
|
<!-- 七、数据流设计 -->
|
|
<h2 id="section7">七、数据流设计</h2>
|
|
|
|
<div class="card">
|
|
<h3>7.1 任务执行流程</h3>
|
|
<div class="flow">
|
|
<span class="flow-item">用户提交任务</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">POST /tasks</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">Permission Service</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">校验Skill权限</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">校验产品交集</span>
|
|
</div>
|
|
<div class="flow">
|
|
<span class="flow-item">任务入库</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">获取平台账号</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">Celery任务入队</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">Worker执行脚本</span>
|
|
</div>
|
|
<div class="flow">
|
|
<span class="flow-item">LLM调用(如需要)</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">记录用量</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">SSE推送结果</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">Telegram通知</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>7.2 LLM调用流程</h3>
|
|
<div class="flow">
|
|
<span class="flow-item">Skill执行请求</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">LLM路由匹配</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">获取API Key</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">调用Provider</span>
|
|
</div>
|
|
<div class="flow">
|
|
<span class="flow-item">记录Token用量</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">计算成本</span>
|
|
<span class="arrow">→</span>
|
|
<span class="flow-item">返回结果</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 八、安全设计 -->
|
|
<h2 id="section8">八、安全设计</h2>
|
|
|
|
<div class="card">
|
|
<table>
|
|
<tr><th>安全项</th><th>实现方案</th><th>对应规则</th></tr>
|
|
<tr><td><strong>API Key加密</strong></td><td>AES-256-GCM加密存储,密钥由环境变量注入</td><td>RB-18</td></tr>
|
|
<tr><td><strong>JWT认证</strong></td><td>Access Token(7天) + Refresh Token(30天)</td><td>-</td></tr>
|
|
<tr><td><strong>密码存储</strong></td><td>bcrypt哈希</td><td>-</td></tr>
|
|
<tr><td><strong>权限校验</strong></td><td>每次请求校验按钮级别权限</td><td>RB-05</td></tr>
|
|
<tr><td><strong>数据范围</strong></td><td>SQL级别行级过滤(product_scope)</td><td>RB-06, RB-12</td></tr>
|
|
<tr><td><strong>脚本隔离</strong></td><td>独立进程+超时控制+环境变量隔离</td><td>RB-17</td></tr>
|
|
<tr><td><strong>敏感信息</strong></td><td>日志脱敏、API响应过滤</td><td>-</td></tr>
|
|
<tr><td><strong>部门隔离</strong></td><td>角色归属部门,用户只能绑本部门角色</td><td>RB-01, RB-02</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 九、开发里程碑 -->
|
|
<h2 id="section9">九、开发里程碑</h2>
|
|
|
|
<div class="card">
|
|
<div class="timeline">
|
|
<div class="timeline-item">
|
|
<strong>Phase 1: 项目骨架 + 认证 + 组织架构 <span class="tag tag-blue">2周</span></strong>
|
|
<ul>
|
|
<li>项目脚手架搭建 (FastAPI + React)</li>
|
|
<li>数据库设计 + Alembic迁移</li>
|
|
<li>JWT认证模块</li>
|
|
<li>组织架构管理 (公司→部门→小组)</li>
|
|
<li>基础RBAC (菜单/按钮权限)</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<strong>Phase 2: 产品/渠道管理 + 角色三要素权限 <span class="tag tag-purple">1.5周</span></strong>
|
|
<ul>
|
|
<li>产品CRUD + 渠道码管理</li>
|
|
<li>角色管理 (部门级 + 三要素)</li>
|
|
<li>用户管理 (部门角色绑定 + 多角色)</li>
|
|
<li>权限服务实现 (多角色并集计算)</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<strong>Phase 3: Skill管理 + 脚本执行器 + 任务模块 <span class="tag tag-green">2周</span></strong>
|
|
<ul>
|
|
<li>脚本模板管理</li>
|
|
<li>Skill CRUD + 产品范围绑定</li>
|
|
<li>Celery Worker部署</li>
|
|
<li>脚本执行器实现</li>
|
|
<li>任务创建/执行/查询</li>
|
|
<li>权限双重校验 (Skill权限 + 产品交集)</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<strong>Phase 4: 平台账号管理 + LLM模块 <span class="tag tag-orange">2周</span></strong>
|
|
<ul>
|
|
<li>平台账号模板管理</li>
|
|
<li>用户平台账号CRUD</li>
|
|
<li>LLM供应商管理 (多Provider)</li>
|
|
<li>模型配置 + 成本设置</li>
|
|
<li>LLM路由规则</li>
|
|
<li>LLM调用服务 + 用量统计</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<strong>Phase 5: 定时任务 + 日志统计 + 通知推送 <span class="tag tag-cyan">1.5周</span></strong>
|
|
<ul>
|
|
<li>Celery Beat定时任务</li>
|
|
<li>操作日志记录</li>
|
|
<li>Skill调用统计报表</li>
|
|
<li>SSE实时推送</li>
|
|
<li>Telegram Bot通知</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<strong>Phase 6: 部署优化 + 集成测试 + 上线 <span class="tag tag-blue">1周</span></strong>
|
|
<ul>
|
|
<li>Docker Compose优化</li>
|
|
<li>环境变量配置</li>
|
|
<li>集成测试</li>
|
|
<li>性能优化</li>
|
|
<li>上线部署</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 总结 -->
|
|
<div class="card" style="background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff;margin-top:32px">
|
|
<h3 style="color:#fff;margin-top:0">📋 架构总结</h3>
|
|
<table style="color:#e2e8f0">
|
|
<tr><th>维度</th><th>选型</th></tr>
|
|
<tr><td>前端</td><td>React 18 + TypeScript + Ant Design + Zustand</td></tr>
|
|
<tr><td>后端</td><td>FastAPI + SQLAlchemy 2.0 + Pydantic v2</td></tr>
|
|
<tr><td>数据库</td><td>PostgreSQL 16 + Redis 7</td></tr>
|
|
<tr><td>任务队列</td><td>Celery + Redis</td></tr>
|
|
<tr><td>部署</td><td>Docker Compose + Nginx</td></tr>
|
|
<tr><td>预计工期</td><td><strong>约9周</strong></td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div style="text-align:center;color:var(--sub);font-size:13px;padding:40px 0;border-top:1px solid var(--bdr);margin-top:40px">
|
|
<p>🤖 Agent任务系统 · 架构设计方案 v1.0</p>
|
|
<p>生成时间:2026-04-23 | 技术栈:React + FastAPI + PostgreSQL</p>
|
|
</div>
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|