Appearance
部署 Agent Service
到此为止,前面所有页面都在讲"一个 Agent 怎么跑起来"——在 Python 进程里 await agent.reply_stream(),事件流直接消费。但在真实交付里,你面对的是多用户、多会话、浏览器与移动端并发订阅、定时任务与后台工具回调。AgentScope 2.x 用 Agent Service 把这一层收口:一个 create_app() 工厂返回的 FastAPI 应用,把 Agent 包成多租户、多会话的 HTTP/SSE 服务,开箱即得会话状态、持久化、调度与工具卸载。
版本基线:本文以 Python
agentscope 2.0.4(PyPI,2026-07-07)为准,要求 Python>=3.11。导入路径为from agentscope.app import create_app, SubAgentTemplate,配套模块agentscope.app.storage/agentscope.app.message_bus/agentscope.app.workspace_manager/agentscope.app.middleware(源:src/agentscope/app/__init__.py及各子包__init__.py,已逐项核对)。2.x 文档站存在版本化陷阱: 非版本化的/en/URL 会 404,本页所有官方链接均使用versions/2.0.4/en/形式。
为什么需要服务化
Agent.reply_stream() 解决的是"单进程内一次推理"的问题。一旦你把 Agent 对外提供,立刻会遇到四类 reply_stream 本身不处理的需求:
- 多租户隔离:不同用户的凭据、Agent、会话、消息必须互不可见。服务层把所有资源都挂在请求解析出的
user_id下,并在路由层强制归属校验。 - 多会话并发:一个用户可能同时开多个会话,同一 Agent 模板驱动多个会话。服务层把"Agent 模板"与 "会话运行时状态"拆开——Agent 是可复用模板,Session 才是运行时状态单元。
- 外部触发回流:定时任务、后台工具完成、Agent Team 中队友发来的消息,都要能把一个"空闲"会话重新唤醒。 服务层用消息总线(inbox + wakeup)把这些外部事件统一送回会话。
- 前端友好:浏览器不能直接
awaitPython,需要 HTTP 触发 + SSE 订阅的标准接入,以及凭据表单、 模型卡片等 schema 驱动的 UI 渲染。
create_app() 就是这四件事的入口:它接收存储后端、消息总线、工作区管理器,注册全部内置路由,返回一个 可以直接 uvicorn.run 的 FastAPI 应用。
前端类比
如果你来自前端,可以把 Agent Service 类比为 BFF(Backend for Frontend)+ 后端微服务的组合:
- 把
create_app()类比为 Next.js 的 API Route 工厂或 NestJS 的bootstrap():一行调用把一组 路由装配成一个可运行的服务,差别在于这里装配的不是手写 controller,而是 Agent 运行时。 - 把
/chat+/sessions/{id}/stream类比为 "提交任务 + SSE 订阅" 的异步模式——就像前端调一个fetch('/api/chat')拿到job_id,再用EventSource('/api/chat/stream')订阅进度,而不是等一个 长轮询。 - 把
RedisStorage+RedisMessageBus类比为 Redis 作为 Pub/Sub + 持久层 的经典后端组合:存储负责 落盘,消息总线负责跨进程事件分发,两者解耦。 - 把
extra_middlewares类比为 Express / Koa 的app.use():协议适配、CORS、鉴权都以 ASGI 中间件 形式包裹整个应用。
AgentScope 原生语义:Agent Service 不是一个"Web 框架包装",而是把 Agent 运行时服务化的完整层。 它的核心抽象是 资源模型——User、Credential、Agent、Session、Schedule、Workspace、MessageBus 七类 资源,全部按 user_id 隔离,由 ChatService 驱动单会话单运行(ChatRunRegistry 强制同一 session 同时 只有一个 /chat 运行,重复提交返回 409)。create_app() 的三个必填参数 (storage / message_bus / workspace_manager)分别对应"落盘在哪""事件怎么分发""工具在哪执行"三 个独立可替换的后端。和前端"API Route = 一组手写 handler"不同,这里你几乎不写路由——全部内置,你只配置 后端与扩展点。
Agent Service 架构
下面这张图说明一次 /chat 请求如何穿过服务层各管理器,最终通过消息总线回流到 SSE 流。注意消息总线是 所有外部触发(调度、后台工具、队友消息)汇聚到会话的唯一通道,这也是多进程部署能成立的关键。
关键节点:
create_app()返回的 FastAPI 应用在 lifespan 里按顺序进入各资源(storage → message bus → workspace manager → background task manager → scheduler manager → chat run registry → 各 service → wakeup dispatcher),关闭时逆序释放;调度器在进入时恢复持久化的 cron 任务,所以重启不丢调度。ChatService是运行或中断一个会话的唯一入口:加载记录、装配 Toolkit、构建中间件、获取会话锁、 驱动Agent.reply_stream()。SchedulerManager基于 APScheduler,触发时只往目标会话 inbox 推HintBlock并 enqueue wakeup, 不直接调用ChatService——所有触发都走消息总线统一回流。BackgroundTaskManager是纯 asyncio 任务注册表;ToolOffloadMiddleware在工具超时时把调用挪到 这里,完成后结果经消息总线(inbox + wakeup)回到会话,而不是被这个管理器持有。RedisMessageBus提供会话锁、replay 日志、inbox 队列、wakeup 信号四类原语,是把"空闲会话"重新 唤醒的唯一通道,也是多进程部署的前提。- SSE 流 从消息总线消费事件,并对迟到的订阅者先回放缓冲历史,再发送实时事件。
构造与启动
create_app() 的三个必填参数对应三个可替换后端。最小可运行示例用 Redis 做存储与消息总线, LocalWorkspaceManager 做工作区管理(工具在宿主文件系统执行,无强隔离,仅适合开发):
python
import os
import uvicorn
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 LocalWorkspaceManager
# 持久化层:agents / sessions / credentials / messages / schedules / teams。
# 连接池在 app 启动时打开、关闭时释放(lifespan 管理)。
# 生产环境务必通过环境变量注入 host / password,不要写进代码。
storage = RedisStorage(
host=os.environ.get("REDIS_HOST", "localhost"),
port=int(os.environ.get("REDIS_PORT", "6379")),
password=os.environ.get("REDIS_PASSWORD", None),
)
# 消息总线:会话锁、replay 日志、inbox 队列、wakeup 信号。
# 它与 storage 解耦——持久化后端可以是 SQL,传输后端仍用 Redis。
message_bus = RedisMessageBus(
host=os.environ.get("REDIS_HOST", "localhost"),
port=int(os.environ.get("REDIS_PORT", "6379")),
password=os.environ.get("REDIS_PASSWORD", None),
)
# 工作区生命周期:工作目录、MCP 客户端、Skills。
# 内置隔离粒度默认 per_agent(同一 agent 的会话共享一个工作区);
# 空闲工作区在 ttl 秒后驱逐。LocalWorkspaceManager 无强隔离,仅用于开发。
workspace_manager = LocalWorkspaceManager(
basedir="/data/workspaces",
ttl=3600.0,
)
app = create_app(
storage=storage,
message_bus=message_bus,
workspace_manager=workspace_manager,
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)切换工作区后端只改一行——DockerWorkspaceManager(容器隔离)或 E2BWorkspaceManager(云沙箱隔离), 其余代码不动。E2B 的密钥通过环境变量 E2B_API_KEY 注入或构造时传入:
python
from agentscope.app.workspace_manager import DockerWorkspaceManager, E2BWorkspaceManager
# 容器隔离:每个工作区跑在独立 Docker 容器里,host 工作目录 bind-mount 进容器。
docker_wm = DockerWorkspaceManager(basedir="/data/docker-workspaces")
# 云沙箱隔离:每个工作区跑在远程 E2B 云 VM。api_key 留空时读取 E2B_API_KEY 环境变量。
e2b_wm = E2BWorkspaceManager()create_app() 还接受若干可选扩展参数(源:src/agentscope/app/_app.py,已核对):extra_middlewares (ASGI 中间件,如协议适配、CORS、鉴权)、extra_credentials(注册自定义凭据类型)、 extra_agent_middlewares(按 (user_id, agent_id, session_id) 生产 Agent 级中间件的异步工厂)、 extra_agent_tools(按调用者生产额外工具的异步工厂)、custom_subagent_templates(Agent Team 用的子 Agent 模板,详见 Agent Team)、custom_agent_cls(替换内置 Agent 子类)、resource_access_policy(跨用户资源访问策略,默认 DenyAllResourceAccessPolicy 即归属隔离)。
REST API 速查
服务把资源模型暴露为 REST 端点,外加流式聊天端点。下表按类别列出核心端点;完整请求/响应形状见服务自带的 OpenAPI 文档(启动后访问 /docs)。所有端点都按请求解析出的 user_id 隔离。
| 端点 | 方法 | 作用 |
|---|---|---|
/agent | GET / POST / PATCH / DELETE | 管理 Agent 记录:显示名、system prompt、运行时配置(context、ReAct) |
/agent/schema/v2 | GET | 返回完整 AgentData JSON Schema,供前端渲染 Agent 表单 |
/credential | GET / POST / PATCH / DELETE | 管理各模型厂商的 API Key 与连接配置,可跨会话/Agent 复用 |
/credential/schemas | GET | 发现所有已注册凭据类型及其 JSON 参数 Schema,供前端渲染凭据表单 |
/sessions | GET / POST / PATCH / DELETE | 创建与管理会话,含模型绑定与权限级别 |
/sessions/{id}/messages | GET | 分页查询会话消息记录(offset / limit) |
/sessions/{id}/status | GET | 探测统一会话状态:running / parked / idle / gone |
/chat | POST | 触发一次会话运行,立即返回 {"status":"started","session_id":"..."} |
/sessions/{id}/stream | GET(SSE) | 订阅会话事件流,含缓冲回放与多订阅者扇出 |
/sessions/{id}/interrupt | POST | 中断运行中或 HITL 挂起的会话,Agent 干净退出并等待下一次 /chat |
/schedule | GET / POST / PATCH / DELETE | 管理 cron 定时执行,可选 stateless(每次新会话)或 stateful(累积上下文) |
/workspace/mcp | GET / POST / DELETE | 管理会话工作区的 MCP 客户端,响应含实时工具列表与健康状态 |
/workspace/skill | GET / POST / DELETE | 管理会话工作区内可用的 Skills |
/model | GET | 按 provider 列出候选聊天模型及其 ModelCard(能力、参数 Schema) |
/knowledge_bases | GET / POST / PATCH / DELETE | 知识库 CRUD,仅在 create_app 传入 knowledge_base_manager 时启用 |
典型的一次聊天流程是五步:POST /agent 注册 Agent → POST /credential 存 API Key → POST /sessions 建会话并绑定模型 → (可选)POST /workspace/mcp 与 POST /workspace/skill 配置工具 → POST /chat 触发运行,同时 GET /sessions/{id}/stream 订阅事件。/chat 立即返回,事件全部经 SSE 流外发。
后台工具卸载不是独立端点:当工具调用超过超时,
ToolOffloadMiddleware把它挪到BackgroundTaskManager的后台任务,完成后结果经消息总线回流到同一会话的 SSE 流——没有单独的/background-tasks端点,前端只需持续订阅/sessions/{id}/stream即可收到。
SSE 流与回放
GET /sessions/{id}/stream 是 Agent Service 的输出主干。它以 SSE 形式持续推送 AgentScope 原生的 AgentEvent(文本块、工具调用、工具结果、思考块、HITL 确认请求等,事件结构见 消息与事件)。两个关键能力让前端无需自己处理"断线"与"多端同步":
- 缓冲回放:迟到的订阅者(刷新页面、新开 tab、重连)会先收到该会话已缓冲的历史事件,再接收实时 事件。多个客户端可以同时订阅同一会话,互相不干扰。
- 跨触发统一:同一会话的
/chat触发、cron 调度触发、后台工具完成、Agent Team 队友消息,全部 汇聚到这一条流。前端不需要为不同触发源分别建连。
流式事件的完整语义、HITL 中断恢复、事件到 Msg 的重建,见 流式事件(本文聚焦部署层,不展开事件类型)。中断一个运行中或 HITL 挂起的会话用 POST /sessions/{id}/interrupt,Agent 会干净退出并保持可立即接受下一次 /chat。
协议扩展点
/sessions/{id}/stream 默认输出 AgentScope 原生 AgentEvent 流。若你的前端使用其他协议,可以通过 协议中间件拦截 SSE 响应、把每一帧 AgentEvent 转换成目标协议的格式。AgentScope 2.0.4 在 agentscope.app.middleware 中导出(源:src/agentscope/app/middleware/__init__.py,已核对):
ProtocolMiddlewareBase— 协议中间件抽象基类,子类实现_convert_to_protocol(event) -> dict即可。AGUIProtocolMiddleware— 面向 AG-UI 协议的 shipped 适配器。
安装 shipped 的 AG-UI 适配器,把它作为 ASGI 中间件通过 extra_middlewares 传入:
python
from fastapi.middleware import Middleware
from agentscope.app import create_app
from agentscope.app.middleware import AGUIProtocolMiddleware
app = create_app(
storage=storage,
message_bus=message_bus,
workspace_manager=workspace_manager,
extra_middlewares=[
Middleware(AGUIProtocolMiddleware),
],
)新增一个协议适配,子类化 ProtocolMiddlewareBase 即可——中间件会自动拦截会话流端点的 StreamingResponse, 把每个 SSE 帧反序列化回 AgentEvent,调用你的 _convert_to_protocol() 转换后再重新序列化:
python
from agentscope.app.middleware import ProtocolMiddlewareBase
from agentscope.event import AgentEvent
class MyProtocolMiddleware(ProtocolMiddlewareBase):
def _convert_to_protocol(self, event: AgentEvent) -> dict:
# 把 AgentEvent 转成你的协议帧格式。
return {"type": event.type, "data": event.model_dump()}A2A 没有 shipped 适配器:官方文档把 AG-UI、A2A 等并列为"可适配协议",但 2.0.4 实际只随包发布了
AGUIProtocolMiddleware。A2A(Agent-to-Agent)当前仅作为扩展点存在——你需要自行子类化ProtocolMiddlewareBase实现,不要把它当成开箱即用的能力。官方 capabilities 表里提到的 "Protocol adaptation" 是框架能力,不等于每个协议都有现成适配器。
前端的 TypeScript SDK 消费 SSE 流、对接 Web UI 的方式,见 版本与生态。
预览能力(2.0.5dev,API 可能变动)
下面两项不在 2.0.4 稳定版内,对应官方文档站的 deploy/sharing 与 deploy/workspace-manager 页面 随 main 分支(2.0.5dev)发布,可能领先 PyPI。接入前务必固定版本号并对照源码,API 可能在正式发布前 调整。本教程把它们标注为预览,仅作入口介绍,不展开稳定 API 示例。
- Resource Sharing(资源分享):在多租户归属隔离之上,提供受控的跨用户资源访问策略 (
ResourceAccessPolicyBase的进阶用法)。2.0.4 的create_app已暴露resource_access_policy参数且默认DenyAllResourceAccessPolicy,但完整的 sharing 文档页与配套策略实现属 dev 期。 - Workspace Manager 部署页:
deploy/workspace-manager页系统讲解工作区管理器的部署形态与隔离策略 切换。注意:构建块类(LocalWorkspaceManager/DockerWorkspaceManager/E2BWorkspaceManager及WorkspaceManagerBase)在 2.0.4 已稳定可用(本文上一节示例即基于它们),dev-only 的只是那张 集中讲部署的文档页与其涉及的进阶配置。
如果你需要这两项,先在 版本与生态 确认当前安装版本,再 对照官方 2.0.5dev 文档与源码,不要把 dev 行为写进生产代码。
部署注意
- Redis 是生产前提:
RedisStorage与RedisMessageBus是 shipped 的唯一稳定后端。存储与消息总线 故意解耦——持久化后端理论上可换成 SQL(实现StorageBase即可),但传输后端仍建议用 Redis,因为 wakeup / inbox / replay 依赖 Redis 的 Pub/Sub 与原语。 InMemoryMessageBus仅开发:agentscope.app.message_bus同时导出InMemoryMessageBus,它无需 Redis、单进程内嵌。但它无法跨进程,任何多 worker / 多节点部署都必须换回RedisMessageBus。把它 用于生产会导致调度触发、后台工具完成、队友消息全部无法送达其他进程的会话。- 生产需独立 Redis:多 worker 部署时,所有进程共享同一 Redis 实例(storage + bus),这是
ChatRunRegistry单会话单运行规则与 wakeup 跨进程分发能成立的前提。单进程内嵌消息总线仅适合本地 调试。 - 鉴权是占位符:内置的
get_current_user_id只从X-User-ID请求头取值,不是鉴权。生产部署 前必须用app.dependency_overrides[default_dependency] = your_auth替换为 JWT / OAuth2 / 会话 token 等真实鉴权依赖。 - 工作区后端按隔离需求选:
LocalWorkspaceManager无强隔离,工具直接操作宿主文件系统;生产建议DockerWorkspaceManager(容器隔离)或E2BWorkspaceManager(云沙箱隔离)。隔离粒度 (per_agent/per_session/per_user)由工作区管理器决定。 - 固定版本:PyPI 当前
4 - Beta分类,生产接入请固定agentscope==2.0.4并跟踪 release notes, 不要浮动到2.0.5dev。
先修
- 可观测性 - 服务层的 Tracing、事件流可观测基础
下一步
- Agent Team - Leader-Worker 多 Agent 协作,
SubAgentTemplate与团队工具
官方参考
- Agent Service(2.0.4)
- API Reference(2.0.4)
- AgentScope GitHub 仓库
- 源码:
src/agentscope/app/__init__.py/_app.py/_types.py/middleware/__init__.py(raw.githubusercontent.com/agentscope-ai/agentscope/main/src/agentscope/app/)