From 9f3f21f605af6fe7700d3f1ad206e0b0aadf4447 Mon Sep 17 00:00:00 2001 From: qbc Date: Tue, 14 Jul 2026 15:48:46 +0800 Subject: [PATCH 1/2] add zh docs for practices --- docs.json | 16 + .../best-practices/architecture-overview.mdx | 37 ++ .../2.0.5dev/zh/best-practices/comparison.mdx | 59 ++ .../2.0.5dev/zh/best-practices/desktop.mdx | 242 +++++++++ .../zh/best-practices/distributed.mdx | 506 ++++++++++++++++++ .../zh/best-practices/microservice.mdx | 400 ++++++++++++++ .../2.0.5dev/zh/best-practices/serverless.mdx | 374 +++++++++++++ 7 files changed, 1634 insertions(+) create mode 100644 versions/2.0.5dev/zh/best-practices/architecture-overview.mdx create mode 100644 versions/2.0.5dev/zh/best-practices/comparison.mdx create mode 100644 versions/2.0.5dev/zh/best-practices/desktop.mdx create mode 100644 versions/2.0.5dev/zh/best-practices/distributed.mdx create mode 100644 versions/2.0.5dev/zh/best-practices/microservice.mdx create mode 100644 versions/2.0.5dev/zh/best-practices/serverless.mdx diff --git a/docs.json b/docs.json index a7e03bb..059f44e 100644 --- a/docs.json +++ b/docs.json @@ -371,6 +371,22 @@ ] } ] + }, + { + "tab": "最佳实践", + "groups": [ + { + "group": "部署场景", + "pages": [ + "versions/2.0.5dev/zh/best-practices/architecture-overview", + "versions/2.0.5dev/zh/best-practices/serverless", + "versions/2.0.5dev/zh/best-practices/desktop", + "versions/2.0.5dev/zh/best-practices/microservice", + "versions/2.0.5dev/zh/best-practices/distributed", + "versions/2.0.5dev/zh/best-practices/comparison" + ] + } + ] } ] }, diff --git a/versions/2.0.5dev/zh/best-practices/architecture-overview.mdx b/versions/2.0.5dev/zh/best-practices/architecture-overview.mdx new file mode 100644 index 0000000..c8985b8 --- /dev/null +++ b/versions/2.0.5dev/zh/best-practices/architecture-overview.mdx @@ -0,0 +1,37 @@ +--- +title: "架构基础:可组合的部署模型" +description: "了解 agentscope.app 的可插拔组件与扩展点,是选择部署方案的基础" +--- + +`agentscope.app` 的核心是 `create_app()` 工厂函数,通过构造注入三大可插拔组件来适配不同部署形态: + +| 组件 | 接口 | 职责 | +|------|------|------| +| `StorageBase` | 持久化 | Credential、Agent、Session、Message 的 CRUD | +| `MessageBus` | 实时传输 | 分布式锁、Pub/Sub、Inbox 队列、SSE 事件流 | +| `WorkspaceManagerBase` | 执行沙箱 | Agent 代码执行的文件系统/容器隔离 | + +扩展点: + +| 扩展点 | 用途 | +|--------|------| +| `extra_middlewares` | ASGI 层中间件(Auth、CORS、限流等) | +| `extra_agent_middlewares` | Agent 层中间件工厂(审计、Quota、RAG 等) | +| `extra_agent_tools` | 租户级工具注入 | +| `resource_access_policy` | 跨租户资源访问策略 | +| `knowledge_base_manager` + `blob_store` | RAG 知识库 | + +四种部署场景([Serverless 部署](/versions/2.0.5dev/zh/best-practices/serverless)、[桌面应用](/versions/2.0.5dev/zh/best-practices/desktop)、[微服务嵌入三方系统](/versions/2.0.5dev/zh/best-practices/microservice)、[分布式部署](/versions/2.0.5dev/zh/best-practices/distributed))正是通过不同的组件组合和扩展配置来实现的。 + +## 已有组件 vs 需自行实现 + +| 组件 | 已有实现(开箱即用) | 需自行实现 | +|------|---------------------|-----------| +| **Storage** | `RedisStorage` | SQLiteStorage(桌面场景理想选择,当前未实现) | +| **MessageBus** | `InMemoryMessageBus`、`RedisMessageBus` | NatsMessageBus 等(如有特殊需求) | +| **WorkspaceManager** | `Local`、`Docker`、`E2B`、`K8s`、`Daytona`、`OpenSandbox` | — | +| **BlobStore** | `LocalBlobStore`、`S3BlobStore` | 企业自定义 OSS 适配(如非 S3 兼容) | +| **VectorStore** | `QdrantStore`、`MilvusStore`、`MongoDBStore` | — | +| **ResourceAccessPolicy** | `DenyAllResourceAccessPolicy`(默认全隔离) | 平台共享策略、企业 RBAC 策略 | +| **认证** | `X-User-ID` Header(临时方案) | JWT 认证、三方 SSO 对接 | +| **Agent 中间件** | `InboxMiddleware`、`StateChangeMiddleware`、`ToolOffloadMiddleware`、`RAGMiddleware` | 审计日志、Quota 限流、租户功能开关 | diff --git a/versions/2.0.5dev/zh/best-practices/comparison.mdx b/versions/2.0.5dev/zh/best-practices/comparison.mdx new file mode 100644 index 0000000..8a7d49f --- /dev/null +++ b/versions/2.0.5dev/zh/best-practices/comparison.mdx @@ -0,0 +1,59 @@ +--- +title: "方案对比总结" +description: "四种部署方案的横向对比、关键决策树与首要技术风险一览" +--- + +## 方案对比 + +| 维度 | Serverless | 桌面应用 | 微服务嵌入 | 分布式部署 | +|------|-----------|---------|-----------|-----------| +| **用户规模** | 多用户 (SaaS) | 单用户 | 多租户 | 大规模多租户 | +| **Storage** | Redis Cloud | Redis (本地) | Redis (企业) | Redis Cluster | +| **MessageBus** | RedisMessageBus | InMemoryMessageBus | RedisMessageBus | RedisMessageBus | +| **Workspace** | E2B / OpenSandbox | Local / Docker | Docker / K8s | K8s | +| **Blob Store** | S3 | LocalBlobStore | S3 / 企业 OSS | S3 | +| **Vector Store** | Qdrant Cloud | Qdrant (内存) | Qdrant / Milvus | Qdrant Cluster | +| **认证** | API Gateway JWT | 固定用户 | 三方 JWT/SSO | JWT + OAuth | +| **Credential** | 平台预置 + 用户自有 | 用户本地配置 | RBAC 控制 | RBAC + Quota | +| **Index Worker** | 嵌入式 | 嵌入式 | 独立进程 | 独立集群 | +| **运维复杂度** | ⭐⭐ | ⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | +| **成本模型** | 按调用计费 | 零(本地) | 企业内部分摊 | 固定 + 弹性 | +| **冷启动** | 有(需优化) | 无 | 无 | 无 | +| **SSE 支持** | 受限 | 完整 | 完整 | 完整 | + +## 关键决策树 + +``` +需求分析 +├── 单用户、本地运行? +│ └── → 桌面应用方案 +├── 多用户、已有企业系统需要集成? +│ └── → 微服务嵌入方案 +├── 多用户、需要低运维 SaaS? +│ └── → Serverless 方案 +└── 大规模多租户、需要水平扩展? + └── → 分布式部署方案 +``` + +- [Serverless 部署](/versions/2.0.5dev/zh/best-practices/serverless) +- [桌面应用](/versions/2.0.5dev/zh/best-practices/desktop) +- [微服务嵌入三方系统](/versions/2.0.5dev/zh/best-practices/microservice) +- [分布式部署](/versions/2.0.5dev/zh/best-practices/distributed) + +## 各方案的首要技术风险 + +| 方案 | 首要风险 | 缓解措施 | +|------|---------|---------| +| Serverless | SSE 长连接受限、冷启动延迟 | 使用 Cloud Run(原生 HTTP streaming)、设置 min_instances=1 | +| 桌面应用 | 强依赖 Redis 不够轻量 | 未来实现 SQLiteStorage;当前可用 Docker 内置 Redis | +| 微服务嵌入 | 权限对接复杂度 | 渐进实现:先 DenyAll,再逐步对接 RBAC | +| 分布式 | Redis 单点 / SchedulerManager 重复触发 / Workspace 跨节点一致性 | Redis Cluster + Sentinel;K8s/E2B Workspace;如需精确调度可自行扩展单 scheduler 模式 | + +## MessageBus 选择指南 + +| MessageBus | 适用场景 | 限制 | +|------------|---------|------| +| `InMemoryMessageBus` | 单进程(桌面应用、开发环境) | 分布式锁和 Pub/Sub 仅在本进程内生效,多进程/多节点**完全不可用** | +| `RedisMessageBus` | 多进程、多节点、生产环境 | 依赖 Redis;所有节点必须连接同一 Redis 实例/集群 | + +> **关键规则**:只要使用 `uvicorn --workers > 1` 或多节点部署,就**必须**使用 `RedisMessageBus`。`InMemoryMessageBus` 会导致分布式锁失效(同一 Session 可能并发执行)、Wakeup/Cancel 信号丢失、SSE 事件无法跨进程传播。 diff --git a/versions/2.0.5dev/zh/best-practices/desktop.mdx b/versions/2.0.5dev/zh/best-practices/desktop.mdx new file mode 100644 index 0000000..6cd00ea --- /dev/null +++ b/versions/2.0.5dev/zh/best-practices/desktop.mdx @@ -0,0 +1,242 @@ +--- +title: "桌面应用" +description: "单用户、本地运行的 AgentScope 部署方案,适用于个人 AI 助手等场景" +--- + +## 场景定位 + +单用户、本地运行,无需联网(除 LLM API 调用)。典型场景:个人 AI 助手、本地代码助手、离线办公 Agent。 + +## 前置依赖 + +```bash +# 最小安装(service + storage) +pip install "agentscope[service,storage]" + +# 启动本地 Redis(三选一) +# 方式 A: Docker(推荐) +docker run --rm -d -p 6379:6379 --name agentscope-redis redis:7 + +# 方式 B: macOS Homebrew +brew install redis && brew services start redis + +# 方式 C: Ubuntu/Debian +sudo apt install redis-server && sudo systemctl start redis +``` + +## 关键约束 + +- **单用户**:无租户隔离需求,`user_id` 固定为常量 +- **本地运行**:所有组件在本机进程内,无需分布式协调 +- **沙箱选择**:本地文件系统或 Docker(如有安全需求) +- **最小依赖**:尽量避免外部服务(如 Redis) + +## 组件选型 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 桌面应用架构 │ +├──────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ localhost:8000 ┌──────────────────┐ │ +│ │ Electron / │◄──────────────────► │ agentscope.app │ │ +│ │ Tauri / Web │ HTTP + SSE │ (FastAPI) │ │ +│ │ Browser │ └────────┬─────────┘ │ +│ └─────────────┘ │ │ +│ ┌─────────────┼──────────┐ │ +│ │ │ │ │ +│ SQLite/Redis InMemory Local │ +│ (Storage) MessageBus Workspace│ +│ ~/agent/ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### Storage:本地轻量存储 + +桌面场景应避免强依赖 Redis 服务。有两种策略: + +| 方案 | 优点 | 缺点 | 推荐 | +|------|------|------|------| +| **嵌入式 Redis (via Docker)** | 完全兼容已有 `RedisStorage` | 需要 Docker 或嵌入 Redis 进程 | 快速方案 | +| **实现 SQLite StorageBase** | 零依赖、单文件、便携 | 需要新增实现 | 长期方案 | +| **Redis on localhost** | 现有代码直接用 | macOS/Linux 安装简单 | 开发期方案 | + +**快速方案**(使用本地 Redis): + +```python +storage = RedisStorage( + host="localhost", + port=6379, + # key_ttl 默认为 None,表示 key 永不过期。 + # 桌面场景数据应永久保留,不要设置 key_ttl。 +) +``` + +**长期方案**(SQLiteStorage 接口设计,需新增实现): + +```python +# 未来实现 — 提供零依赖桌面体验 +# storage = SQLiteStorage(db_path="~/.agentscope/data.db") +``` + +### MessageBus:进程内消息总线 + +单进程场景下 `InMemoryMessageBus` 完全满足需求,无需分布式能力: + +```python +from agentscope.app.message_bus import InMemoryMessageBus + +message_bus = InMemoryMessageBus() +``` + +`InMemoryMessageBus` 已实现所有 `MessageBus` 接口(drain queue、replay log、broadcast、lock、registry),全部基于 `asyncio` 原语,零外部依赖。 + +### Workspace:本地文件系统 + +```python +from agentscope.app.workspace_manager import LocalWorkspaceManager, IsolationPolicy + +workspace_manager = LocalWorkspaceManager( + basedir=os.path.expanduser("~/.agentscope/workspaces"), + # isolation 默认为 PER_AGENT(同一 Agent 的不同 Session 共享工作目录) + default_mcps=[ + # 本地文件浏览器、终端等 MCP Server + ], +) +``` + +如需代码执行安全隔离(Agent 执行不可信代码),改用 Docker: + +```python +from agentscope.app.workspace_manager import DockerWorkspaceManager + +workspace_manager = DockerWorkspaceManager( + basedir=os.path.expanduser("~/.agentscope/workspaces"), + base_image="python:3.11-slim", + ttl=7200.0, # 2 小时空闲后回收容器 + sweep_interval=600.0, +) +``` + +### 用户身份:固定单用户 + +覆盖 `get_current_user_id`,始终返回固定用户名: + +```python +from agentscope.app.deps import get_current_user_id + +DESKTOP_USER_ID = "local-user" + +async def desktop_user_id() -> str: + return DESKTOP_USER_ID + +app = create_app(...) +app.dependency_overrides[get_current_user_id] = desktop_user_id +``` + +### 前端集成 + +| 方案 | 技术栈 | 特点 | +|------|--------|------| +| **Electron + Web UI** | Electron 主进程管理后端进程 + 渲染进程加载 Web UI | 跨平台、最成熟 | +| **Tauri + Web UI** | Rust 后端启动 Python 进程 + WebView 加载 UI | 轻量、安装包小 | +| **系统浏览器** | 纯 Python 后端 + `webbrowser.open()` | 最简单 | + +Electron 集成示例(主进程启动后端): + +```javascript +// electron/main.js +const { spawn } = require('child_process'); +const path = require('path'); + +let backendProcess; + +function startBackend() { + backendProcess = spawn('python', [ + path.join(__dirname, '../backend/desktop_main.py') + ], { + env: { ...process.env, AGENTSCOPE_MODE: 'desktop' } + }); + + backendProcess.stdout.on('data', (data) => { + if (data.toString().includes('Uvicorn running')) { + createWindow('http://localhost:8000'); + } + }); +} +``` + +### 知识库(可选) + +桌面场景使用内存向量存储即可: + +```python +from agentscope.rag import QdrantStore +from agentscope.app.rag.knowledge_base_manager import CollectionPerKbManager +from agentscope.app.rag.blob_store import LocalBlobStore + +knowledge_base_manager = CollectionPerKbManager( + storage=storage, + vector_store=QdrantStore(location=":memory:"), # 或持久化到本地文件 + # vector_store=QdrantStore(path="~/.agentscope/qdrant"), +) +blob_store = LocalBlobStore(root_dir=os.path.expanduser("~/.agentscope/blobs")) +``` + +### 完整启动代码 + +```python +# desktop_main.py — 可直接复制运行(需先启动本地 Redis) +import os +import uvicorn +from agentscope.app import create_app +from agentscope.app.storage import RedisStorage +from agentscope.app.message_bus import InMemoryMessageBus +from agentscope.app.workspace_manager import LocalWorkspaceManager +from agentscope.app.deps import get_current_user_id + +DESKTOP_USER_ID = "local-user" +DATA_DIR = os.path.expanduser("~/.agentscope") + +storage = RedisStorage(host="localhost", port=6379) + +app = create_app( + storage=storage, + message_bus=InMemoryMessageBus(), + workspace_manager=LocalWorkspaceManager( + basedir=os.path.join(DATA_DIR, "workspaces"), + ), + enable_index_worker=True, +) + + +async def desktop_user_id() -> str: + return DESKTOP_USER_ID + + +app.dependency_overrides[get_current_user_id] = desktop_user_id + +if __name__ == "__main__": + uvicorn.run(app, host="127.0.0.1", port=8000) +``` + +### 部署流程 + +``` +1. 打包分发 + ├── Python 环境打包(PyInstaller / conda-pack / 嵌入 Python) + ├── Redis 嵌入(redis-server 二进制 / Docker Compose) + └── 前端打包(Electron Builder / Tauri Build) + +2. 首次启动 + ├── 创建 ~/.agentscope/ 目录结构 + ├── 启动嵌入 Redis(或等待用户自行启动) + ├── 启动 FastAPI 后端(localhost:8000) + └── 打开前端界面 + +3. 用户体验 + ├── 无需注册/登录(固定 user_id) + ├── 在 UI 中配置自己的 LLM API Key (Credential) + ├── 创建 Agent → 开始对话 + └── 数据完全本地,关闭应用即停止 +``` diff --git a/versions/2.0.5dev/zh/best-practices/distributed.mdx b/versions/2.0.5dev/zh/best-practices/distributed.mdx new file mode 100644 index 0000000..dd1090f --- /dev/null +++ b/versions/2.0.5dev/zh/best-practices/distributed.mdx @@ -0,0 +1,506 @@ +--- +title: "分布式部署" +description: "大规模生产环境下的多租户、多节点水平扩展与高可用部署方案" +--- + +## 场景定位 + +大规模生产环境:多租户、多节点水平扩展、高可用。典型场景:大型 SaaS 平台、企业级 Agent 平台。 + +## 前置依赖 + +```bash +pip install "agentscope[full]" + +# 基础设施 +# - Redis Cluster(推荐 6 节点:3 主 3 从) +# - K8s 集群(API 节点池 + Sandbox 节点池) +# - S3 / MinIO(Blob 存储) +# - Qdrant Cluster 或 Milvus(向量数据库) +# - 负载均衡(Nginx Ingress / AWS ALB) +``` + +## 关键约束 + +- **多租户隔离**:数据、执行环境、资源配额全面隔离 +- **多节点部署**:API 无状态、分布式协调、负载均衡 +- **消息总线**:跨节点事件传播、会话锁、任务调度 +- **高可用**:节点故障自动恢复、无单点瓶颈 + +## 架构总览 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 分布式部署架构 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ Client ──► Load Balancer (Nginx / ALB / Istio) │ +│ │ │ +│ ┌─────────┼──────────┐ │ +│ ▼ ▼ ▼ │ +│ ┌────────┐ ┌────────┐ ┌────────┐ │ +│ │ Node A │ │ Node B │ │ Node C │ API 层 (无状态) │ +│ │ 4 wkr │ │ 4 wkr │ │ 4 wkr │ │ +│ └───┬────┘ └───┬────┘ └───┬────┘ │ +│ │ │ │ │ +│ └──────────┼──────────┘ │ +│ │ │ +│ ┌──────────────┼──────────────────────┐ │ +│ │ │ │ │ +│ ┌────▼─────┐ ┌─────▼──────┐ ┌────────────▼────────────┐ │ +│ │ Redis │ │ Redis │ │ Workspace 集群 │ │ +│ │ Cluster │ │ Cluster │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ +│ │(Storage) │ │(MessageBus)│ │ │ K8s │ │ K8s │ │ K8s │ │ │ +│ └──────────┘ └────────────┘ │ │Pod A│ │Pod B│ │Pod C│ │ │ +│ │ └─────┘ └─────┘ └─────┘ │ │ +│ └──────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ Index Worker 集群 (独立进程) │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │ Worker1 │ │ Worker2 │ │ Worker3 │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ │ │ +│ └──────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────┐ ┌──────────┐ │ +│ │ S3 / OSS │ │ Qdrant / │ │ +│ │ (Blob) │ │ Milvus │ │ +│ └──────────┘ │ (Vector) │ │ +│ └──────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +## 组件选型详解 + +### Redis Cluster 策略 + +分布式场景建议 Storage 和 MessageBus 使用**同一 Redis Cluster**(简化运维),但也可以分开部署以实现读写分离: + +| 部署策略 | 优点 | 缺点 | +|---------|------|------| +| **共享 Redis Cluster** | 运维简单、成本低 | 持久化和实时流量互相影响 | +| **分离 Redis** | Storage 可独立优化持久化策略 | 多一套 Redis 运维 | + +```python +# 共享模式 +REDIS_OPTS = dict( + host=os.environ["REDIS_HOST"], + port=6379, + password=os.environ["REDIS_PASSWORD"], +) + +storage = RedisStorage(**REDIS_OPTS, key_ttl=86400 * 30) +message_bus = RedisMessageBus(**REDIS_OPTS) +``` + +```python +# 分离模式 +storage = RedisStorage( + host=os.environ["REDIS_STORAGE_HOST"], + port=6379, password=os.environ["REDIS_STORAGE_PASSWORD"], + key_ttl=86400 * 30, +) +message_bus = RedisMessageBus( + host=os.environ["REDIS_BUS_HOST"], + port=6379, password=os.environ["REDIS_BUS_PASSWORD"], +) +``` + +### 多节点 API 部署 + +每个节点运行多个 uvicorn worker,所有 worker 共享 Redis: + +```bash +# Node A +uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 + +# Node B +uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 +``` + +> **重要**:`--workers 4` 意味着每个节点启动 4 个独立进程,每个进程都有自己的 `WakeupDispatcher`、`CancelDispatcher`、`ChatRunRegistry`、`SchedulerManager`。3 节点 × 4 workers = 12 个进程全部连接同一 Redis,通过 Redis 分布式锁 + 竞争消费来协调。 + +**跨节点协调机制**(已内置,无需额外配置): + +| 机制 | 实现 | 作用 | +|------|------|------| +| **分布式会话锁** | `MessageBus.acquire_lock()` → Redis SETNX + 心跳续期 | 同一 Session 全局串行执行 | +| **竞争消费 Wakeup** | `WakeupDispatcher` drain 共享 queue(Mode A,ack-on-read) | 多节点先到先得,不重复执行 | +| **广播 Cancel** | `CancelDispatcher` subscribe cancel channel(Mode D) | 所有节点收到,持有 task 的节点执行取消 | +| **广播 Interrupt** | `CancelDispatcher` subscribe interrupt channel(Mode D) | 同上,但只取消 chat run,不取消 BG task | +| **SSE 事件跨节点** | `log_append`(Mode C replay log)+ `publish`(Mode D) | 客户端连接到任意节点都能收到事件 | + +**SSE 跨节点工作原理**: + +``` +1. ChatService.run() 在 Node B 运行 + ├── 事件 → log_append(Redis Stream) ← 持久化到共享 Redis + └── 事件 → publish(Redis Pub/Sub) ← 实时通知 + +2. 客户端 SSE 连接到 Node A + ├── 先 log_read() 重放已有事件 ← 从 Redis Stream 读取 + └── 再 subscribe() 接收实时事件 ← 订阅 Redis Pub/Sub + +结论:SSE 不需要 sticky session,任何节点都能提供完整事件流。 +``` + +**跨节点注意事项**: + +| 问题 | 说明 | 建议 | +|------|------|------| +| **SchedulerManager 重复触发** | 每个 worker 进程独立运行 APScheduler,都会加载所有 schedule 并触发。多进程/多节点会产生 N 次重复的 inbox HintBlock 推送 | 影响可控:wakeup 是竞争消费的,重复 wakeup 被分布式锁过滤;Agent 可能看到重复的 HintBlock 但只执行一次。如需严格去重,可只在 1 个 worker 上启用 scheduler(其他 worker 设 `enable_scheduler=False`,需自行扩展) | +| **Load Balancer SSE** | SSE 是长连接,标准 HTTP 负载均衡可能超时断开 | 配置 Nginx `proxy-read-timeout: 600s` + `proxy-buffering: off`;或使用支持 streaming 的 ALB/Istio | +| **Workspace 跨节点一致性** | `DockerWorkspaceManager` 每个节点有独立 Docker daemon,容器不共享 | 多节点**必须**使用 `K8sWorkspaceManager`(共享集群)或 `E2BWorkspaceManager`(云沙箱)。`DockerWorkspaceManager` 仅适用于单节点或开发环境 | + +### Workspace 集群 + +分布式多节点场景对 WorkspaceManager 有严格要求——**Agent 的执行沙箱必须对所有 API 节点可达**: + +| 方案 | 多节点可用 | 原理 | 适用场景 | +|------|-----------|------|---------| +| **K8sWorkspaceManager** | ✅ 推荐 | Pod 在共享 K8s 集群中,任何 API 节点都可通过 K8s API 访问 | 已有 K8s 集群 | +| **E2BWorkspaceManager** | ✅ | 云端沙箱,任何节点通过 HTTP API 访问 | 不想管基础设施 | +| **DaytonaWorkspaceManager** | ✅ | 远程开发环境,HTTP 可达 | 需要完整 IDE 环境 | +| **OpenSandboxWorkspaceManager** | ✅ | 自托管沙箱服务,HTTP 可达 | 安全合规要求 | +| **DockerWorkspaceManager** | ❌ 仅单节点 | 每个节点有独立 Docker daemon,容器不共享 | 仅开发/单节点 | +| **LocalWorkspaceManager** | ❌ 仅单节点 | 依赖本地文件系统 | 仅开发/单节点 | + +> **关键提醒**:分布式部署中,如果 Session S1 的 ChatService.run() 在 Node A 创建了容器/沙箱,后续 S1 的新请求可能被 WakeupDispatcher 在 Node B 消费。如果 Workspace 不是全局可达的(如 Docker/Local),Node B 会找不到之前的沙箱,导致运行失败。务必使用 K8s/E2B 等全局可达的方案。 + +K8s Workspace 配置: + +```python +from agentscope.app.workspace_manager import K8sWorkspaceManager, IsolationPolicy + +workspace_manager = K8sWorkspaceManager( + namespace="agentscope-sandboxes", + image="company-registry/sandbox:latest", + isolation=IsolationPolicy.PER_SESSION, + resources={ + "requests": {"cpu": "500m", "memory": "512Mi"}, + "limits": {"cpu": "1000m", "memory": "1Gi"}, + }, + storage_class="gp3", + storage_size="5Gi", + image_pull_secrets=["company-registry-secret"], + ttl=3600.0, + sweep_interval=300.0, +) +``` + +### 多租户隔离策略 + +分布式场景下的隔离策略矩阵: + +| 维度 | 实现 | 级别 | +|------|------|------| +| **数据隔离** | Redis key 前缀 `user:{user_id}:` | 逻辑隔离 | +| **计算隔离** | K8s Pod 资源配额 + 网络策略 | 物理隔离 | +| **存储隔离** | Blob 按 tenant 分目录/分 Bucket | 逻辑/物理 | +| **向量隔离** | 每个 KB 独立 collection | 逻辑隔离 | +| **API 隔离** | Rate Limiting per tenant | 逻辑隔离 | + +实现租户级 Quota 和限流(示例思路,`TokenQuotaMiddleware` 等需自行实现): + +```python +from agentscope.middleware import MiddlewareBase + +# 通过 extra_agent_middlewares 注入 Quota 检查 +async def distributed_middleware_factory( + user_id: str, agent_id: str, session_id: str +) -> list[MiddlewareBase]: + tenant_id = user_id.split(":")[1] # 假设 user_id 格式为 tenant:{tid}:user:{uid} + # quota = await get_tenant_quota(tenant_id) # 自行实现的配额查询 + + middlewares = [] + # 以下 Middleware 需自行实现,继承 agentscope.middleware.MiddlewareBase + # if quota.max_tokens_per_day: + # middlewares.append(TokenQuotaMiddleware( + # tenant_id=tenant_id, + # daily_limit=quota.max_tokens_per_day, + # )) + return middlewares +``` + +> **API 层限流**可通过 `extra_middlewares` 添加第三方 ASGI 限流中间件(如 `slowapi`),这是 ASGI 层面的限流,与 Agent 层的 `extra_agent_middlewares` 互补。 + +### RAG 索引服务 + +分布式场景下 RAG 索引应**独立部署**。Index Worker 通过环境变量 `AGENTSCOPE_WORKER_BOOTSTRAP` 指定一个 bootstrap 函数来获取后端配置: + +**1. 编写 bootstrap 模块**: + +```python +# worker_bootstrap.py +import os +from agentscope.app.storage import RedisStorage +from agentscope.app.message_bus import RedisMessageBus +from agentscope.app.rag.blob_store import S3BlobStore +from agentscope.app.rag.knowledge_base_manager import CollectionPerKbManager +from agentscope.rag import QdrantStore, ApproxTokenChunker, TextParser + +def bootstrap() -> dict: + """返回 run_worker() 所需的 kwargs dict。""" + storage = RedisStorage( + host=os.environ["REDIS_HOST"], + port=int(os.environ.get("REDIS_PORT", 6379)), + password=os.environ.get("REDIS_PASSWORD"), + ) + return { + "storage": storage, + "message_bus": RedisMessageBus( + host=os.environ["REDIS_HOST"], + port=int(os.environ.get("REDIS_PORT", 6379)), + password=os.environ.get("REDIS_PASSWORD"), + ), + "blob_store": S3BlobStore( + bucket=os.environ["S3_BUCKET"], + region_name=os.environ.get("AWS_REGION", "us-east-1"), + ), + "knowledge_base_manager": CollectionPerKbManager( + storage=storage, + vector_store=QdrantStore( + url=os.environ["QDRANT_URL"], + api_key=os.environ.get("QDRANT_API_KEY"), + ), + ), + "parsers": [TextParser()], + "chunker": ApproxTokenChunker(), + } +``` + +**2. 启动独立 Index Worker**: + +```bash +# API 进程:enable_index_worker=False(不启动嵌入式 Worker) + +# 独立 Index Worker(可水平扩展,启动多个实例竞争消费) +AGENTSCOPE_WORKER_BOOTSTRAP=worker_bootstrap:bootstrap \ + python -m agentscope.app.rag.index_worker +``` + +Index Worker 的分布式协调通过 `MessageBus` 的 drain queue 语义实现:多个 Worker 竞争消费同一 index task queue,加上文档级 lease 防止重复索引。 + +### 完整启动代码 + +```python +# distributed_main.py — 可直接复制运行 +# +# 本代码块已内联最小可运行的占位实现。 +# 如需完整功能,替换以下占位: +# - jwt_get_current_user_id → 实现你的 JWT 验证逻辑 +# - DenyAllResourceAccessPolicy → 替换为你的 RBAC 策略 +# - extra_agent_middlewares → 取消注释并实现 Quota/审计等中间件 +# +import os +from fastapi import Header, HTTPException +from fastapi.middleware import Middleware +from fastapi.middleware.cors import CORSMiddleware +from agentscope.app import create_app +from agentscope.app.storage import RedisStorage +from agentscope.app.message_bus import RedisMessageBus +from agentscope.app.workspace_manager import K8sWorkspaceManager, IsolationPolicy +from agentscope.app.rag.blob_store import S3BlobStore +from agentscope.app.rag.knowledge_base_manager import CollectionPerKbManager +from agentscope.app.access import DenyAllResourceAccessPolicy +from agentscope.app.deps import get_current_user_id +from agentscope.rag import QdrantStore + + +# ---- JWT 认证(替换为你的 JWT 验证逻辑) ---- +async def jwt_get_current_user_id( + authorization: str = Header(default=""), +) -> str: + if not authorization.startswith("Bearer "): + raise HTTPException(status_code=401, detail="Missing Bearer token") + token = authorization[7:] + # payload = verify_jwt(token) # 替换为你的 JWT 验证 + # return payload["sub"] + raise HTTPException(status_code=501, detail="JWT验证未实现,请替换此占位") + + +# ---- 组装应用 ---- +REDIS_OPTS = dict( + host=os.environ["REDIS_HOST"], + port=int(os.environ.get("REDIS_PORT", 6379)), + password=os.environ.get("REDIS_PASSWORD"), +) + +storage = RedisStorage(**REDIS_OPTS, key_ttl=86400 * 30) + +app = create_app( + storage=storage, + message_bus=RedisMessageBus(**REDIS_OPTS), + workspace_manager=K8sWorkspaceManager( + namespace="agentscope-sandboxes", + image=os.environ.get("SANDBOX_IMAGE", "python:3.11-slim"), + isolation=IsolationPolicy.PER_SESSION, + resources={ + "requests": {"cpu": "500m", "memory": "512Mi"}, + "limits": {"cpu": "1000m", "memory": "1Gi"}, + }, + ), + knowledge_base_manager=CollectionPerKbManager( + storage=storage, + vector_store=QdrantStore( + url=os.environ["QDRANT_URL"], + api_key=os.environ.get("QDRANT_API_KEY"), + ), + ), + blob_store=S3BlobStore( + bucket=os.environ["S3_BUCKET"], + region_name=os.environ.get("AWS_REGION", "us-east-1"), + ), + resource_access_policy=DenyAllResourceAccessPolicy(), # 替换为你的 RBAC 策略 + # extra_agent_middlewares=..., # 可选:注入 Quota/审计等中间件 + enable_index_worker=False, # 独立 Worker 集群 + extra_middlewares=[ + Middleware( + CORSMiddleware, + allow_origins=os.environ.get("CORS_ORIGINS", "*").split(","), + allow_methods=["*"], + allow_headers=["*"], + ), + ], +) + +app.dependency_overrides[get_current_user_id] = jwt_get_current_user_id +``` + +### 部署流程(K8s) + +```yaml +# k8s/api-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: agentscope-api +spec: + replicas: 3 # 3 节点 + selector: + matchLabels: + app: agentscope-api + template: + metadata: + labels: + app: agentscope-api + spec: + containers: + - name: api + image: company/agentscope-api:latest + command: ["uvicorn", "distributed_main:app", + "--host", "0.0.0.0", "--port", "8000", + "--workers", "4"] # 每节点 4 worker = 12 并发 + ports: + - containerPort: 8000 + resources: + requests: { cpu: "1", memory: "2Gi" } + limits: { cpu: "2", memory: "4Gi" } + env: + - name: REDIS_HOST + valueFrom: { secretKeyRef: { name: redis, key: host } } + # ... 其他环境变量 (REDIS_PASSWORD, QDRANT_URL, S3_BUCKET 等) + +--- +# k8s/index-worker-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: agentscope-index-worker +spec: + replicas: 2 # 2 个 Index Worker + selector: + matchLabels: + app: agentscope-index-worker + template: + metadata: + labels: + app: agentscope-index-worker + spec: + containers: + - name: worker + image: company/agentscope-api:latest + command: ["python", "-m", "agentscope.app.rag.index_worker"] + env: + - name: AGENTSCOPE_WORKER_BOOTSTRAP + value: "worker_bootstrap:bootstrap" + # ... REDIS_HOST, QDRANT_URL 等环境变量同 API 节点 + resources: + requests: { cpu: "2", memory: "4Gi" } + limits: { cpu: "4", memory: "8Gi" } + +--- +# k8s/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: agentscope-api +spec: + type: ClusterIP + ports: + - port: 8000 + selector: + app: agentscope-api + +--- +# k8s/ingress.yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: agentscope + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" # Agent 长运行 + nginx.ingress.kubernetes.io/proxy-buffering: "off" # SSE 流式 +spec: + rules: + - host: agent.company.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: agentscope-api + port: { number: 8000 } +``` + +### 部署流程 + +``` +1. 基础设施 + ├── Redis Cluster(3 主 3 从,高可用) + ├── K8s 集群(API 节点 + Sandbox 节点池) + ├── S3 / MinIO(Blob 存储) + ├── Qdrant Cluster / Milvus(向量数据库) + └── 负载均衡(Nginx Ingress / ALB) + +2. 镜像准备 + ├── API 镜像:agentscope[full] + 业务代码 + ├── Index Worker 镜像:同 API 镜像(不同 entrypoint) + └── Sandbox 镜像:Agent 代码执行环境 + +3. K8s 部署 + ├── API Deployment: 3 replicas × 4 workers + ├── Index Worker Deployment: 2 replicas + ├── Ingress: SSL + SSE 优化 + ├── HPA: CPU > 70% 自动扩容 + └── PDB: maxUnavailable=1 + +4. 故障恢复机制(框架已内置) + ├── API 节点重启 → WakeupDispatcher.__aenter__() 执行初始 drain, + │ 恢复队列中所有未处理的 wakeup(设计上 wakeup queue 是持久的) + ├── 分布式锁超时 → TTL 600s 后自动释放(由 acquire_lock 心跳续期, + │ 只有持有者真正崩溃时才超时) + ├── Redis 短暂不可用 → Storage/MessageBus 内部重试 + ├── Sandbox Pod 被 sweep 回收 → 下次 get_workspace() 自动重建 + │ (K8sWorkspaceManager 通过 deterministic Pod name 重新 attach) + └── 进程关闭 → ChatRunRegistry.__aexit__() 取消所有 in-flight chat run, + 释放所有分布式锁 + +5. 监控 + ├── OpenTelemetry Tracing(agentscope 已内置 trace hook) + ├── Redis 监控(内存、连接数、命令延迟) + │ └── 关键指标:wakeup queue 长度(积压 = 处理能力不足) + ├── K8s 监控(Pod 状态、资源使用) + └── 业务指标(活跃会话数、Agent 执行时长、Token 用量) +``` diff --git a/versions/2.0.5dev/zh/best-practices/microservice.mdx b/versions/2.0.5dev/zh/best-practices/microservice.mdx new file mode 100644 index 0000000..7ff4f41 --- /dev/null +++ b/versions/2.0.5dev/zh/best-practices/microservice.mdx @@ -0,0 +1,400 @@ +--- +title: "微服务嵌入三方系统" +description: "将 AgentScope 作为 Agent 执行引擎嵌入企业系统,对接三方用户体系与权限体系" +--- + +## 场景定位 + +将 AgentScope 作为 Agent 执行引擎嵌入已有的企业系统中(如 CRM、ERP、协同平台),与三方系统的用户体系、权限体系、文件服务对接。 + +## 前置依赖 + +```bash +# 按需安装扩展 +pip install "agentscope[service,storage]" # 基础 +pip install "agentscope[workspace]" # Docker/K8s 沙箱 +pip install "agentscope[rag,s3]" # 知识库 + S3 Blob +# 或 +pip install "agentscope[full]" +``` + +## 关键约束 + +- **用户体系对接**:三方系统已有用户/租户管理,AgentScope 不自建用户系统 +- **权限体系对接**:三方系统控制谁能创建/使用哪些 Agent 和 Credential +- **沙箱安全**:企业环境通常要求强隔离(Docker/K8s) +- **文件服务对接**:三方系统可能有自己的 OSS/文件服务 + +## 架构模式 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ 三方系统 + AgentScope 微服务 │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ │ +│ │ 三方系统前端 │──────┐ │ +│ └──────────────┘ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ 三方系统后端 (API Gateway) │ │ +│ │ ┌─────────┐ ┌──────────┐ ┌─────────────┐ │ │ +│ │ │ 用户认证 │ │ 权限引擎 │ │ 文件服务 │ │ │ +│ │ │ (JWT/SSO)│ │ (RBAC) │ │ (OSS/MinIO) │ │ │ +│ │ └────┬─────┘ └─────┬────┘ └──────┬──────┘ │ │ +│ └───────┼──────────────┼───────────────┼────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ agentscope.app (mount 或独立部署) │ │ +│ │ │ │ +│ │ Storage ──► Redis │ │ +│ │ MessageBus ──► Redis │ │ +│ │ Workspace ──► Docker/K8s │ │ +│ │ BlobStore ──► 对接三方 OSS │ │ +│ │ AccessPolicy ──► 对接三方 RBAC │ │ +│ └──────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### 集成方式选择 + +| 方式 | 代码 | 适用场景 | +|------|------|---------| +| **Mount 模式** | `main_app.mount("/agentscope", agentscope_app)` | 三方系统也是 FastAPI/Starlette | +| **独立部署 + 反向代理** | Nginx 路由 `/agent-api/*` → AgentScope 服务 | 三方系统非 Python / 独立运维 | +| **SDK 调用** | 三方后端直接 HTTP 调用 AgentScope API | 松耦合、语言无关 | + +**Mount 模式**(推荐,同进程最低延迟): + +```python +# 三方系统的 main.py +from fastapi import FastAPI +from agentscope.app import create_app + +main_app = FastAPI(title="企业协同平台") + +# ... 三方系统的路由 ... + +agentscope_app = create_app( + storage=..., + message_bus=..., + workspace_manager=..., +) + +main_app.mount("/agentscope", agentscope_app) +``` + +### 对接多租户用户系统 + +覆盖 `get_current_user_id`,从三方系统的 JWT / Session 中提取身份: + +```python +from fastapi import Depends, Header, HTTPException, Request +from agentscope.app.deps import get_current_user_id + +async def extract_tenant_user(request: Request) -> str: + """从三方系统的认证上下文中提取 tenant_id + user_id。 + 格式: tenant:{tenant_id}:user:{user_id},确保跨租户隔离。""" + + # 方案 A: 从三方网关转发的 header 中读取 + tenant_id = request.headers.get("X-Tenant-ID") + user_id = request.headers.get("X-User-ID") + + # 方案 B: 从 JWT 中解析 + # auth_header = request.headers.get("Authorization", "") + # payload = verify_jwt(auth_header.replace("Bearer ", "")) + # tenant_id = payload["tenant_id"] + # user_id = payload["sub"] + + if not tenant_id or not user_id: + raise HTTPException(status_code=401, detail="Missing identity") + + # 组合 tenant + user 作为 AgentScope 的 user_id, + # 确保不同租户的用户数据完全隔离 + return f"tenant:{tenant_id}:user:{user_id}" + +agentscope_app.dependency_overrides[get_current_user_id] = extract_tenant_user +``` + +### 对接自定义权限体系 + +通过 `ResourceAccessPolicyBase` 对接三方 RBAC: + +```python +from agentscope.app.access import ( + ResourceAccessPolicyBase, + ResourceKind, + ResourceRef, + ResourcePermission, +) +from agentscope.app.storage import StorageBase + +class EnterpriseRBACPolicy(ResourceAccessPolicyBase): + """对接企业 RBAC 权限引擎,决定谁能使用哪些共享资源。""" + + def __init__(self, rbac_client): + self._rbac = rbac_client # 三方系统的 RBAC SDK + + async def list_accessible( + self, + viewer_id: str, + kind: ResourceKind, + storage: StorageBase, + ) -> list[ResourceRef]: + # 从三方权限引擎查询该用户可访问的资源 + grants = await self._rbac.list_grants( + user_id=viewer_id, + resource_type=f"agentscope:{kind.value}", + ) + + refs = [] + for grant in grants: + refs.append(ResourceRef( + kind=kind, + owner_id=grant.owner_id, + resource_id=grant.resource_id, + permission=( + ResourcePermission.EDIT + if "write" in grant.actions + else ResourcePermission.READ + ), + )) + return refs +``` + +通过 `extra_agent_middlewares` 注入运行时权限检查: + +```python +from agentscope.middleware import MiddlewareBase + +async def enterprise_middleware_factory( + user_id: str, agent_id: str, session_id: str +) -> list[MiddlewareBase]: + """注入企业级中间件:审计日志、用量计量、功能开关等。""" + tenant_id = user_id.split(":")[1] # 从 tenant:{tid}:user:{uid} 中提取 + + middlewares = [ + AuditLogMiddleware(tenant_id=tenant_id, user_id=user_id), + UsageMeteringMiddleware(tenant_id=tenant_id), + ] + + # 检查租户功能开关 + features = await feature_flags.get_tenant_features(tenant_id) + if features.get("rag_enabled"): + # knowledge_bases 需从 knowledge_base_manager 获取 + middlewares.append(RAGMiddleware(knowledge_bases=[...])) + + return middlewares +``` + +通过 `extra_agent_tools` 注入租户专属工具: + +```python +from agentscope.tool import ToolBase + +async def enterprise_tool_factory( + user_id: str, agent_id: str, session_id: str +) -> list[ToolBase]: + """根据租户配置注入企业专属工具(CRM、ERP 集成等)。""" + tenant_id = user_id.split(":")[1] + + tools = [] + integrations = await get_tenant_integrations(tenant_id) + + if "salesforce" in integrations: + tools.append(SalesforceTool( + api_key=integrations["salesforce"]["api_key"], + )) + if "jira" in integrations: + tools.append(JiraTool( + base_url=integrations["jira"]["base_url"], + token=integrations["jira"]["token"], + )) + + return tools +``` + +### 沙箱服务选型 + +企业场景需要强隔离 + 可审计: + +| 方案 | 特点 | 适用场景 | +|------|------|---------| +| **DockerWorkspaceManager** | 容器级隔离、bind-mount、可自定义镜像 | 自有基础设施 | +| **K8sWorkspaceManager** | Pod 级隔离、资源配额、网络策略 | K8s 集群环境 | +| **DaytonaWorkspaceManager** | 开发环境管理平台 | 需要完整 IDE 环境 | + +```python +from agentscope.app.workspace_manager import K8sWorkspaceManager, IsolationPolicy + +workspace_manager = K8sWorkspaceManager( + namespace="agentscope-workspaces", + image="company-registry.com/agent-sandbox:latest", + isolation=IsolationPolicy.PER_SESSION, + # K8s 资源限制(标准 K8s ResourceRequirements 格式) + resources={ + "requests": {"cpu": "250m", "memory": "256Mi"}, + "limits": {"cpu": "500m", "memory": "512Mi"}, + }, + # 企业镜像仓库需要 pull secret + image_pull_secrets=["company-registry-secret"], +) +``` + +> **K8sWorkspaceManager 构造参数一览**:`namespace`(K8s 命名空间)、`kubeconfig`(kubeconfig 路径,None 用 in-cluster)、`image`(Pod 镜像)、`image_pull_policy`、`image_pull_secrets`、`resources`(K8s ResourceRequirements dict)、`node_selector`、`tolerations`、`service_account`、`gateway_port`、`extra_pip`、`storage_class`、`storage_size`(PVC 大小,默认 "1Gi")、`env`、`default_mcps`、`skill_paths`、`ttl`(默认 3600s)、`sweep_interval`(默认 300s)、`delete_pvc_on_close`(默认 False)、`isolation`。 + +### 分布式文件服务对接 + +如果三方 OSS 兼容 S3 协议(MinIO、阿里云 OSS S3 兼容模式、腾讯 COS 等),直接使用 `S3BlobStore` 即可,无需自定义实现。只有完全不兼容 S3 的私有存储才需要自行实现 `BlobStoreBase`(需实现 `write_stream`、`open`、`delete`、`exists` 四个抽象方法)。 + +或直接使用已有的 `S3BlobStore`(兼容 S3 协议的 OSS 均可使用): + +```python +from agentscope.app.rag.blob_store import S3BlobStore + +blob_store = S3BlobStore( + bucket="company-agentscope", + endpoint_url="https://minio.internal:9000", # MinIO 兼容 S3 协议 + region_name="cn-hangzhou", +) +``` + +> **S3BlobStore 构造参数**:`bucket`(必填,Bucket 名称)、`region_name`、`endpoint_url`(非 AWS S3 时指定,如 MinIO/阿里云 OSS)、`aws_access_key_id`、`aws_secret_access_key`、`session_token`、`use_ssl`(默认 True)、`config`。URI 格式为 `s3://{bucket}/{key}`。 + +### 完整启动代码 + +```python +# enterprise_integration.py — 可直接复制运行 +# +# 本代码块已内联最小可运行的占位实现。 +# 如需完整功能,替换以下占位: +# - extract_tenant_user() → 对接你的 JWT/SSO(参见前文"对接多租户用户系统"小节) +# - resource_policy → 替换 DenyAllResourceAccessPolicy 为你的 RBAC 策略 +# - extra_agent_middlewares → 取消注释并实现审计/Quota 等中间件 +# - extra_agent_tools → 取消注释并实现企业工具注入 +# +import os +from fastapi import FastAPI, HTTPException, Request +from agentscope.app import create_app +from agentscope.app.storage import RedisStorage +from agentscope.app.message_bus import RedisMessageBus +from agentscope.app.workspace_manager import DockerWorkspaceManager, IsolationPolicy +from agentscope.app.rag.blob_store import S3BlobStore +from agentscope.app.rag.knowledge_base_manager import CollectionPerKbManager +from agentscope.app.access import DenyAllResourceAccessPolicy +from agentscope.app.deps import get_current_user_id +from agentscope.rag import QdrantStore + +# 实现完整 RBAC/中间件/工具时需要的额外 import: +# from agentscope.app.storage import StorageBase +# from agentscope.app.access import ( +# ResourceAccessPolicyBase, ResourceKind, ResourceRef, ResourcePermission, +# ) +# from agentscope.middleware import MiddlewareBase +# from agentscope.tool import ToolBase + + +# ---- 1. 身份提取(参见前文"对接多租户用户系统") ---- +async def extract_tenant_user(request: Request) -> str: + tenant_id = request.headers.get("X-Tenant-ID") + user_id = request.headers.get("X-User-ID") + if not tenant_id or not user_id: + raise HTTPException(status_code=401, detail="Missing identity") + return f"tenant:{tenant_id}:user:{user_id}" + + +# ---- 2. RBAC 策略(参见前文"对接自定义权限体系") ---- +# 此处用 DenyAll 占位,替换为你的 EnterpriseRBACPolicy 实现 +resource_policy = DenyAllResourceAccessPolicy() + + +# ---- 3. 组装应用 ---- +storage = RedisStorage( + host=os.environ["REDIS_HOST"], + port=6379, + password=os.environ["REDIS_PASSWORD"], +) + +agentscope_app = create_app( + storage=storage, + message_bus=RedisMessageBus( + host=os.environ["REDIS_HOST"], + port=6379, + password=os.environ["REDIS_PASSWORD"], + ), + workspace_manager=DockerWorkspaceManager( + basedir="/data/agent-workspaces", + base_image="company-registry/agent-sandbox:latest", + isolation=IsolationPolicy.PER_SESSION, + ttl=3600.0, + ), + knowledge_base_manager=CollectionPerKbManager( + storage=storage, + vector_store=QdrantStore( + url=os.environ["QDRANT_URL"], + api_key=os.environ.get("QDRANT_API_KEY"), + ), + ), + blob_store=S3BlobStore( + bucket=os.environ["OSS_BUCKET"], + endpoint_url=os.environ.get("OSS_ENDPOINT"), + ), + resource_access_policy=resource_policy, + # extra_agent_middlewares=enterprise_middleware_factory, # 取消注释以启用 + # extra_agent_tools=enterprise_tool_factory, # 取消注释以启用 + enable_index_worker=False, # 使用独立 Index Worker 进程 +) + +agentscope_app.dependency_overrides[get_current_user_id] = extract_tenant_user + +# 方式 A: Mount 到三方系统 +main_app = FastAPI(title="企业协同平台") +main_app.mount("/agentscope", agentscope_app) + +# 方式 B: 独立部署 +# if __name__ == "__main__": +# import uvicorn +# uvicorn.run(agentscope_app, host="0.0.0.0", port=8001) +``` + +### 独立 Index Worker(RAG 索引) + +上面的完整代码设置了 `enable_index_worker=False`,意味着 API 进程不自带索引能力。如果使用了 RAG 知识库,需要单独运行 Index Worker 进程。启动方式与分布式部署相同(参见[分布式部署 > RAG 索引服务](/versions/2.0.5dev/zh/best-practices/distributed#rag-索引服务)),编写一个返回后端配置的 bootstrap 函数并通过环境变量指定: + +```bash +AGENTSCOPE_WORKER_BOOTSTRAP=worker_bootstrap:bootstrap \ + python -m agentscope.app.rag.index_worker +``` + +> 如果不使用 RAG 知识库(未传 `knowledge_base_manager`),则无需运行 Index Worker,`enable_index_worker` 设为 True 或 False 均无影响。 + +### 部署流程 + +``` +1. 基础设施准备 + ├── Redis 集群(企业已有 / 新建,Storage + MessageBus 共用) + ├── Docker Registry(推送 Agent 沙箱镜像) + ├── 对象存储(MinIO / 阿里云 OSS / S3) + └── 向量数据库(Qdrant / Milvus,用于 RAG) + +2. 权限对接 + ├── 实现 extract_tenant_user() — 从 JWT/Session 提取 tenant + user + ├── 实现 EnterpriseRBACPolicy — 对接 RBAC 引擎 + └── 配置 extra_agent_middlewares — 审计/计量/功能开关 + +3. 集成部署 + ├── Mount 模式:agentscope_app mount 到三方 FastAPI + ├── 独立模式:独立进程 + Nginx 反向代理 + └── 独立 Index Worker 进程(如使用 RAG) + +4. 沙箱镜像准备 + ├── 基于 python:3.11-slim 构建企业沙箱镜像 + ├── 预装企业内部 Python 包、证书、代理配置 + └── 推送到企业 Docker Registry + +5. 监控与运维 + ├── OpenTelemetry → 企业 APM(Datadog / 阿里云 ARMS) + ├── 审计日志 → 企业日志中心 + └── 用量计量 → 企业计费系统 +``` diff --git a/versions/2.0.5dev/zh/best-practices/serverless.mdx b/versions/2.0.5dev/zh/best-practices/serverless.mdx new file mode 100644 index 0000000..9393a5f --- /dev/null +++ b/versions/2.0.5dev/zh/best-practices/serverless.mdx @@ -0,0 +1,374 @@ +--- +title: "Serverless 部署" +description: "适用于 SaaS 平台、Demo 站点等一次部署、多用户开箱即用的场景" +--- + +## 场景定位 + +一次部署后,所有用户通过平台提供的 Credential 和 Agent 开箱即用,无需自行搭建基础设施。典型场景包括:SaaS 平台、Demo 站点、面向终端用户的 Agent 服务。 + +## 前置依赖 + +```bash +# 安装 AgentScope(含 service + storage + s3 + rag 扩展) +pip install "agentscope[service,storage,rag,s3]" + +# 或一次安装所有可选依赖 +pip install "agentscope[full]" +``` + +## 关键约束 + +- **冷启动优化**:Serverless 函数有冷启动延迟(100ms~数秒),需最小化启动路径 +- **无状态要求**:函数实例随时销毁/重建,所有状态必须外部化 +- **并发模型**:单实例通常处理单请求或少量并发,分布式协调完全依赖外部服务 +- **SSE 长连接**:Serverless 对长连接支持有限,需额外方案 + +## 组件选型 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ Serverless 部署架构 │ +├──────────────────────────────────────────────────────────────────┤ +│ │ +│ Client ──► API Gateway ──► Lambda/Cloud Run/Vercel Function │ +│ │ │ +│ ┌───────────────────────┼───────────────────┐ │ +│ │ │ │ │ +│ Redis Cloud E2B/OpenSandbox S3 Blob │ +│ (Storage + (Workspace) (知识库) │ +│ MessageBus) │ +│ │ │ +│ Qdrant Cloud │ +│ (向量检索) │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### Storage:托管 Redis + +| 选项 | 推荐场景 | 理由 | +|------|---------|------| +| **Redis Cloud (Upstash / AWS ElastiCache Serverless)** | ✅ 首选 | 免运维、按需计费、连接池友好 | +| Vercel KV (Upstash 封装) | 轻量演示 | 与 Vercel 平台深度集成 | + +```python +from agentscope.app.storage import RedisStorage + +storage = RedisStorage( + host="xxx.upstash.io", + port=6379, + password=os.environ["REDIS_PASSWORD"], + key_ttl=86400 * 30, # 30 天滑动过期,控制存储成本 + ssl=True, # TLS 连接(Upstash 等云服务需要) +) +``` + +> **注意**:`RedisStorage` 的构造函数接受 `host`、`port`、`db`、`password`、`key_ttl`、`key_config` 和 `**kwargs`。所有额外的关键字参数(如 `ssl=True`、`max_connections=20`、`socket_timeout=5`)会被直接转发给 `redis.asyncio.ConnectionPool`。如需更精细控制,也可以传入预配置好的 `connection_pool` 参数。`RedisMessageBus` 的构造函数签名完全相同。 + +### MessageBus:共享 Redis + +Serverless 函数实例无共享内存,**必须使用 `RedisMessageBus`**,不能用 `InMemoryMessageBus`。 + +```python +from agentscope.app.message_bus import RedisMessageBus + +message_bus = RedisMessageBus( + host="xxx.upstash.io", + port=6379, + password=os.environ["REDIS_PASSWORD"], + # 与 RedisStorage 相同,额外参数通过 **kwargs 转发给 ConnectionPool +) +``` + +### Workspace:云端沙箱 + +Serverless 函数无持久化本地磁盘,必须使用云端沙箱: + +| 选项 | 特点 | 适用场景 | +|------|------|---------| +| **E2BWorkspaceManager** | 托管沙箱、按秒计费、隔离性强 | ✅ 推荐,最低运维 | +| **OpenSandboxWorkspaceManager** | 自托管沙箱服务 | 合规要求严格 | + +```python +from agentscope.app.workspace_manager import E2BWorkspaceManager, IsolationPolicy + +workspace_manager = E2BWorkspaceManager( + api_key=os.environ["E2B_API_KEY"], + # template 默认为 E2B 预置模板,也可指定自定义模板 ID + isolation=IsolationPolicy.PER_SESSION, # 每会话独立沙箱 +) +``` + +> **E2BWorkspaceManager 构造参数一览**:`template`(E2B 沙箱模板 ID)、`api_key`、`domain`、`timeout_seconds`、`gateway_port`、`env`(环境变量 dict)、`sandbox_metadata`、`extra_pip`(额外安装包)、`default_mcps`(预装 MCP Server)、`skill_paths`、`ttl`(空闲回收秒数,默认 3600)、`sweep_interval`(扫描间隔,默认 300s)、`isolation`。 + +### Credential 共享策略 + +**核心关键点**:平台预置的 Credential 需要对所有用户可用。 + +实现方案:通过 `ResourceAccessPolicyBase` 暴露平台级 Credential: + +```python +from agentscope.app.access import ( + ResourceAccessPolicyBase, + ResourceKind, + ResourceRef, + ResourcePermission, +) +from agentscope.app.storage import StorageBase + +PLATFORM_USER_ID = "__platform__" + +class PlatformSharedPolicy(ResourceAccessPolicyBase): + """让所有用户都能使用平台预置的 Credential 和 Agent。 + + platform user 预先通过 seed 脚本写入的 Credential/Agent, + 通过 list_accessible() 暴露给所有普通用户(只读)。 + """ + + async def list_accessible( + self, + viewer_id: str, + kind: ResourceKind, + storage: StorageBase, + ) -> list[ResourceRef]: + if viewer_id == PLATFORM_USER_ID: + return [] + + if kind == ResourceKind.CREDENTIAL: + # storage.list_credentials(user_id) → list[CredentialRecord] + # CredentialRecord.id 是记录 ID(继承自 _RecordBase) + records = await storage.list_credentials(PLATFORM_USER_ID) + return [ + ResourceRef( + kind=ResourceKind.CREDENTIAL, + owner_id=PLATFORM_USER_ID, + resource_id=r.id, # _RecordBase.id + permission=ResourcePermission.READ, + ) + for r in records + ] + + if kind == ResourceKind.AGENT: + # storage.list_agents(user_id) → list[AgentRecord] + records = await storage.list_agents(PLATFORM_USER_ID) + return [ + ResourceRef( + kind=ResourceKind.AGENT, + owner_id=PLATFORM_USER_ID, + resource_id=r.id, # _RecordBase.id + permission=ResourcePermission.READ, + ) + for r in records + ] + + return [] +``` + +**启动时预置 Credential**(独立脚本,在部署后执行一次): + +```python +# seed_credentials.py +import asyncio +import os +from agentscope.app.storage import RedisStorage +from agentscope.credential import OpenAICredential, AnthropicCredential + +PLATFORM_USER_ID = "__platform__" + +async def main() -> None: + storage = RedisStorage( + host=os.environ["REDIS_HOST"], + port=int(os.environ.get("REDIS_PORT", 6379)), + password=os.environ.get("REDIS_PASSWORD"), + ) + async with storage: # 必须先进入 async context 以建立 Redis 连接 + await storage.upsert_credential( + PLATFORM_USER_ID, + OpenAICredential(api_key=os.environ["OPENAI_API_KEY"]), + ) + await storage.upsert_credential( + PLATFORM_USER_ID, + AnthropicCredential(api_key=os.environ["ANTHROPIC_API_KEY"]), + ) + print("Platform credentials seeded successfully.") + +if __name__ == "__main__": + asyncio.run(main()) +``` + +```bash +# 部署后执行一次 +python seed_credentials.py +``` + +### SSE 事件流处理 + +Serverless 平台对长连接的支持有限(AWS Lambda 默认 29s 超时、Vercel 30s)。有两种处理方案: + +| 方案 | 实现 | 适用平台 | +|------|------|---------| +| **A: 流式响应网关** | 使用 Cloud Run(支持 HTTP streaming)、AWS Lambda 响应流(Response Streaming) | GCP Cloud Run, AWS Lambda | +| **B: 轮询替代** | 前端改为轮询 `GET /sessions/{sid}/messages`,放弃 SSE 实时推送 | 所有 Serverless 平台 | + +**推荐方案 A**(以 Cloud Run 为例): + +```dockerfile +FROM python:3.11-slim +WORKDIR /app +COPY . . +RUN pip install "agentscope[full]" +CMD ["uvicorn", "serverless_main:app", "--host", "0.0.0.0", "--port", "8080"] +``` + +Cloud Run 的 HTTP/2 + SSE 不受 30s 限制,且支持最小实例为 0(真正的 Serverless 计费模式)。 + +### 认证方案 + +Serverless 场景下通常前面有 API Gateway / Auth 网关: + +```python +from fastapi import Header, HTTPException +from agentscope.app.deps import get_current_user_id + +async def api_gateway_user_id( + x_user_id: str = Header(default=""), + x_forwarded_user: str = Header(default=""), +) -> str: + """从 API Gateway 注入的 header 中提取已验证的 user_id。 + 网关负责 JWT 验证,这里只信任转发的身份。""" + user_id = x_forwarded_user or x_user_id + if not user_id: + raise HTTPException(status_code=401, detail="Unauthenticated") + return user_id + +app = create_app(...) +app.dependency_overrides[get_current_user_id] = api_gateway_user_id +``` + +### 完整启动代码 + +```python +# serverless_main.py — 可直接复制运行 +import os + +from fastapi import Header, HTTPException +from agentscope.app import create_app +from agentscope.app.deps import get_current_user_id +from agentscope.app.storage import RedisStorage, StorageBase +from agentscope.app.message_bus import RedisMessageBus +from agentscope.app.workspace_manager import E2BWorkspaceManager, IsolationPolicy +from agentscope.app.rag.blob_store import S3BlobStore +from agentscope.app.rag.knowledge_base_manager import CollectionPerKbManager +from agentscope.app.access import ( + ResourceAccessPolicyBase, + ResourceKind, + ResourceRef, + ResourcePermission, +) +from agentscope.rag import QdrantStore + + +# ---- 1. 平台级 Credential 共享策略 ---- + +PLATFORM_USER_ID = "__platform__" + + +class PlatformSharedPolicy(ResourceAccessPolicyBase): + """让所有用户都能使用平台预置的 Credential 和 Agent(只读)。""" + + async def list_accessible( + self, + viewer_id: str, + kind: ResourceKind, + storage: StorageBase, + ) -> list[ResourceRef]: + if viewer_id == PLATFORM_USER_ID: + return [] + + if kind in (ResourceKind.CREDENTIAL, ResourceKind.AGENT): + if kind == ResourceKind.CREDENTIAL: + records = await storage.list_credentials(PLATFORM_USER_ID) + else: + records = await storage.list_agents(PLATFORM_USER_ID) + return [ + ResourceRef( + kind=kind, + owner_id=PLATFORM_USER_ID, + resource_id=r.id, + permission=ResourcePermission.READ, + ) + for r in records + ] + return [] + + +# ---- 2. 认证(信任 API Gateway 转发的身份) ---- + +async def api_gateway_user_id( + x_user_id: str = Header(default=""), + x_forwarded_user: str = Header(default=""), +) -> str: + user_id = x_forwarded_user or x_user_id + if not user_id: + raise HTTPException(status_code=401, detail="Unauthenticated") + return user_id + + +# ---- 3. 组装应用 ---- + +REDIS_OPTS = dict( + host=os.environ["REDIS_HOST"], + port=int(os.environ.get("REDIS_PORT", 6379)), + password=os.environ.get("REDIS_PASSWORD"), +) + +storage = RedisStorage(**REDIS_OPTS, key_ttl=86400 * 30) + +app = create_app( + storage=storage, + message_bus=RedisMessageBus(**REDIS_OPTS), + workspace_manager=E2BWorkspaceManager( + api_key=os.environ["E2B_API_KEY"], + isolation=IsolationPolicy.PER_SESSION, + ), + knowledge_base_manager=CollectionPerKbManager( + storage=storage, + vector_store=QdrantStore( + url=os.environ["QDRANT_URL"], + api_key=os.environ["QDRANT_API_KEY"], + ), + ), + blob_store=S3BlobStore( + bucket=os.environ["S3_BUCKET"], + region_name=os.environ.get("AWS_REGION", "us-east-1"), + ), + resource_access_policy=PlatformSharedPolicy(), + enable_index_worker=True, # 嵌入式 Worker,与 API 同进程运行,简化 Serverless 部署 +) + +app.dependency_overrides[get_current_user_id] = api_gateway_user_id +``` + +### 部署流程 + +``` +1. 环境变量配置 + ├── REDIS_HOST, REDIS_PASSWORD → Upstash / ElastiCache + ├── E2B_API_KEY → E2B 沙箱 + ├── S3_BUCKET, AWS_REGION → S3 Blob 存储 + ├── QDRANT_URL, QDRANT_API_KEY → Qdrant Cloud + ├── OPENAI_API_KEY, ANTHROPIC_API_KEY → 平台预置 Credential + └── AUTH_SECRET → JWT / 网关密钥 + +2. 容器镜像构建 → 推送 Registry + +3. 部署到 Cloud Run / AWS Lambda (Container) / Fly.io + ├── 最小实例: 0 (真 Serverless) + ├── 最大实例: 按需(如 10) + ├── 内存: 1~2 GB(含 Agent 推理时的上下文) + └── 超时: 300s~900s(Agent 执行可能较长) + +4. 预置平台 Credential(一次性 / CI 中执行 seed 脚本) + +5. 配置 API Gateway / CDN → 自定义域名 + Auth +``` From a8cd0d12b309dfe3807679b72a88003d0fee04af Mon Sep 17 00:00:00 2001 From: qbc Date: Fri, 17 Jul 2026 14:24:53 +0800 Subject: [PATCH 2/2] update --- docs.json | 3 +- .../best-practices/architecture-overview.mdx | 67 ++++++++++++++++++- .../2.0.5dev/zh/best-practices/comparison.mdx | 59 ---------------- 3 files changed, 67 insertions(+), 62 deletions(-) delete mode 100644 versions/2.0.5dev/zh/best-practices/comparison.mdx diff --git a/docs.json b/docs.json index 059f44e..f7e7ae6 100644 --- a/docs.json +++ b/docs.json @@ -382,8 +382,7 @@ "versions/2.0.5dev/zh/best-practices/serverless", "versions/2.0.5dev/zh/best-practices/desktop", "versions/2.0.5dev/zh/best-practices/microservice", - "versions/2.0.5dev/zh/best-practices/distributed", - "versions/2.0.5dev/zh/best-practices/comparison" + "versions/2.0.5dev/zh/best-practices/distributed" ] } ] diff --git a/versions/2.0.5dev/zh/best-practices/architecture-overview.mdx b/versions/2.0.5dev/zh/best-practices/architecture-overview.mdx index c8985b8..f9e65f2 100644 --- a/versions/2.0.5dev/zh/best-practices/architecture-overview.mdx +++ b/versions/2.0.5dev/zh/best-practices/architecture-overview.mdx @@ -21,7 +21,22 @@ description: "了解 agentscope.app 的可插拔组件与扩展点,是选择 | `resource_access_policy` | 跨租户资源访问策略 | | `knowledge_base_manager` + `blob_store` | RAG 知识库 | -四种部署场景([Serverless 部署](/versions/2.0.5dev/zh/best-practices/serverless)、[桌面应用](/versions/2.0.5dev/zh/best-practices/desktop)、[微服务嵌入三方系统](/versions/2.0.5dev/zh/best-practices/microservice)、[分布式部署](/versions/2.0.5dev/zh/best-practices/distributed))正是通过不同的组件组合和扩展配置来实现的。 +以下四种部署场景正是通过不同的组件组合和扩展配置来实现的: + + + + 适用于 SaaS 平台、Demo 站点等多用户开箱即用场景 + + + 单用户本地运行,适用于个人 AI 助手等场景 + + + 将 AgentScope 作为 Agent 引擎嵌入企业系统 + + + 大规模多租户、多节点水平扩展与高可用 + + ## 已有组件 vs 需自行实现 @@ -35,3 +50,53 @@ description: "了解 agentscope.app 的可插拔组件与扩展点,是选择 | **ResourceAccessPolicy** | `DenyAllResourceAccessPolicy`(默认全隔离) | 平台共享策略、企业 RBAC 策略 | | **认证** | `X-User-ID` Header(临时方案) | JWT 认证、三方 SSO 对接 | | **Agent 中间件** | `InboxMiddleware`、`StateChangeMiddleware`、`ToolOffloadMiddleware`、`RAGMiddleware` | 审计日志、Quota 限流、租户功能开关 | + +## 方案对比 + +| 维度 | Serverless | 桌面应用 | 微服务嵌入 | 分布式部署 | +|------|-----------|---------|-----------|-----------| +| **用户规模** | 多用户 (SaaS) | 单用户 | 多租户 | 大规模多租户 | +| **Storage** | Redis Cloud | Redis (本地) | Redis (企业) | Redis Cluster | +| **MessageBus** | RedisMessageBus | InMemoryMessageBus | RedisMessageBus | RedisMessageBus | +| **Workspace** | E2B / OpenSandbox | Local / Docker | Docker / K8s | K8s | +| **Blob Store** | S3 | LocalBlobStore | S3 / 企业 OSS | S3 | +| **Vector Store** | Qdrant Cloud | Qdrant (内存) | Qdrant / Milvus | Qdrant Cluster | +| **认证** | API Gateway JWT | 固定用户 | 三方 JWT/SSO | JWT + OAuth | +| **Credential** | 平台预置 + 用户自有 | 用户本地配置 | RBAC 控制 | RBAC + Quota | +| **Index Worker** | 嵌入式 | 嵌入式 | 独立进程 | 独立集群 | +| **运维复杂度** | 低 | 最低 | 较高 | 高 | +| **成本模型** | 按调用计费 | 零(本地) | 企业内部分摊 | 固定 + 弹性 | +| **冷启动** | 有(需优化) | 无 | 无 | 无 | +| **SSE 支持** | 受限 | 完整 | 完整 | 完整 | + +## 关键决策树 + +``` +需求分析 +├── 单用户、本地运行? +│ └── → 桌面应用方案 +├── 多用户、已有企业系统需要集成? +│ └── → 微服务嵌入方案 +├── 多用户、需要低运维 SaaS? +│ └── → Serverless 方案 +└── 大规模多租户、需要水平扩展? + └── → 分布式部署方案 +``` + +## 各方案的首要技术风险 + +| 方案 | 首要风险 | 缓解措施 | +|------|---------|---------| +| Serverless | SSE 长连接受限、冷启动延迟 | 使用 Cloud Run(原生 HTTP streaming)、设置 min_instances=1 | +| 桌面应用 | 强依赖 Redis 不够轻量 | 未来实现 SQLiteStorage;当前可用 Docker 内置 Redis | +| 微服务嵌入 | 需对接三方用户认证(JWT/SSO → `get_current_user_id`)和权限体系(三方 RBAC/IAM → `ResourceAccessPolicyBase.list_accessible`/`can_edit`),涉及租户身份映射、跨系统资源授权等多环节集成 | 渐进实现:先用 `DenyAllResourceAccessPolicy` 实现租户完全隔离,再逐步对接三方 RBAC;认证层先信任网关转发的 Header,再迭代为直接校验 JWT | +| 分布式 | Redis 单点 / SchedulerManager 重复触发 / Workspace 跨节点一致性 | Redis Cluster + Sentinel;K8s/E2B Workspace;如需精确调度可自行扩展单 scheduler 模式 | + +## MessageBus 选择指南 + +| MessageBus | 适用场景 | 限制 | +|------------|---------|------| +| `InMemoryMessageBus` | 单进程(桌面应用、开发环境) | 分布式锁和 Pub/Sub 仅在本进程内生效,多进程/多节点**完全不可用** | +| `RedisMessageBus` | 多进程、多节点、生产环境 | 依赖 Redis;所有节点必须连接同一 Redis 实例/集群 | + +> **关键规则**:只要使用 `uvicorn --workers > 1` 或多节点部署,就**必须**使用 `RedisMessageBus`。`InMemoryMessageBus` 会导致分布式锁失效(同一 Session 可能并发执行)、Wakeup/Cancel 信号丢失、SSE 事件无法跨进程传播。 diff --git a/versions/2.0.5dev/zh/best-practices/comparison.mdx b/versions/2.0.5dev/zh/best-practices/comparison.mdx deleted file mode 100644 index 8a7d49f..0000000 --- a/versions/2.0.5dev/zh/best-practices/comparison.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: "方案对比总结" -description: "四种部署方案的横向对比、关键决策树与首要技术风险一览" ---- - -## 方案对比 - -| 维度 | Serverless | 桌面应用 | 微服务嵌入 | 分布式部署 | -|------|-----------|---------|-----------|-----------| -| **用户规模** | 多用户 (SaaS) | 单用户 | 多租户 | 大规模多租户 | -| **Storage** | Redis Cloud | Redis (本地) | Redis (企业) | Redis Cluster | -| **MessageBus** | RedisMessageBus | InMemoryMessageBus | RedisMessageBus | RedisMessageBus | -| **Workspace** | E2B / OpenSandbox | Local / Docker | Docker / K8s | K8s | -| **Blob Store** | S3 | LocalBlobStore | S3 / 企业 OSS | S3 | -| **Vector Store** | Qdrant Cloud | Qdrant (内存) | Qdrant / Milvus | Qdrant Cluster | -| **认证** | API Gateway JWT | 固定用户 | 三方 JWT/SSO | JWT + OAuth | -| **Credential** | 平台预置 + 用户自有 | 用户本地配置 | RBAC 控制 | RBAC + Quota | -| **Index Worker** | 嵌入式 | 嵌入式 | 独立进程 | 独立集群 | -| **运维复杂度** | ⭐⭐ | ⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | -| **成本模型** | 按调用计费 | 零(本地) | 企业内部分摊 | 固定 + 弹性 | -| **冷启动** | 有(需优化) | 无 | 无 | 无 | -| **SSE 支持** | 受限 | 完整 | 完整 | 完整 | - -## 关键决策树 - -``` -需求分析 -├── 单用户、本地运行? -│ └── → 桌面应用方案 -├── 多用户、已有企业系统需要集成? -│ └── → 微服务嵌入方案 -├── 多用户、需要低运维 SaaS? -│ └── → Serverless 方案 -└── 大规模多租户、需要水平扩展? - └── → 分布式部署方案 -``` - -- [Serverless 部署](/versions/2.0.5dev/zh/best-practices/serverless) -- [桌面应用](/versions/2.0.5dev/zh/best-practices/desktop) -- [微服务嵌入三方系统](/versions/2.0.5dev/zh/best-practices/microservice) -- [分布式部署](/versions/2.0.5dev/zh/best-practices/distributed) - -## 各方案的首要技术风险 - -| 方案 | 首要风险 | 缓解措施 | -|------|---------|---------| -| Serverless | SSE 长连接受限、冷启动延迟 | 使用 Cloud Run(原生 HTTP streaming)、设置 min_instances=1 | -| 桌面应用 | 强依赖 Redis 不够轻量 | 未来实现 SQLiteStorage;当前可用 Docker 内置 Redis | -| 微服务嵌入 | 权限对接复杂度 | 渐进实现:先 DenyAll,再逐步对接 RBAC | -| 分布式 | Redis 单点 / SchedulerManager 重复触发 / Workspace 跨节点一致性 | Redis Cluster + Sentinel;K8s/E2B Workspace;如需精确调度可自行扩展单 scheduler 模式 | - -## MessageBus 选择指南 - -| MessageBus | 适用场景 | 限制 | -|------------|---------|------| -| `InMemoryMessageBus` | 单进程(桌面应用、开发环境) | 分布式锁和 Pub/Sub 仅在本进程内生效,多进程/多节点**完全不可用** | -| `RedisMessageBus` | 多进程、多节点、生产环境 | 依赖 Redis;所有节点必须连接同一 Redis 实例/集群 | - -> **关键规则**:只要使用 `uvicorn --workers > 1` 或多节点部署,就**必须**使用 `RedisMessageBus`。`InMemoryMessageBus` 会导致分布式锁失效(同一 Session 可能并发执行)、Wakeup/Cancel 信号丢失、SSE 事件无法跨进程传播。