跳转至

Swarm studio cn

Swarm Studio 是 Jianmu 的多 Agent Web 应用,以对话协作为核心,把 AgentRuntime(Swarm 运行时)放进一套完整的持久化、SSE 实时事件流和 React 前端界面中。它关注的不只是“把多个 Agent 放进一个聊天框”,而是把群聊协作里最容易失控的几件事约束清楚:谁在说话、消息走哪条通道、一次唤醒如何结束。这样多个专家 Agent 才能在可视化界面里进行可追踪、可恢复的结构化对话。

如果只想先建立整体印象,可以先抓住三件事:

  • 它的产品模型是“模板 × 角色 × 对话”
  • 它的运行约束是 Identity、Channel、Turn 三条规则
  • 它的技术路径是 React 前端 + FastAPI 后端 + Jianmu Runtime 内核

架构全景

Swarm Studio 的运行时架构分为五个层次:前端 SPA → FastAPI 路由层 → ChatController 编排层 → ChatRuntimeAdapter 运行适配层 → Jianmu AgentRuntime 内核。前端通过 SSE(Server-Sent Events)长连接接收实时事件推送,后端将 Jianmu 的底层 Agent 事件(AgentEvent)翻译为面向 UI 的 chat_event 和 workspace_event,同时将用户消息转化为 Agent 收件箱中的 MessageEnvelope。

graph TB
    subgraph Frontend["Frontend (React + Vite)"]
        CP[ConversationPage]
        AP[AgentsPage]
        HP[HistoryPage]
        CSP[ConversationsPage]
        SSE_STREAM[SSE Event Stream]
    end

    subgraph Backend["Backend (FastAPI)"]
        API[REST API /api/chat/*]
        CC[ChatController]
        CRA[ChatRuntimeAdapter]
        ST[Storage - SQLite]
        PRS[ProviderRuntimeSupport]
    end

    subgraph Jianmu["Jianmu Core"]
        AR[AgentRuntime]
        AT[AgentTeam]
        MC[ModelClient]
        SC[SkillsCatalog]
    end

    CP --> SSE_STREAM
    CP --> API
    API --> CC
    CC --> CRA
    CC --> ST
    CRA --> AR
    CRA --> AT
    CRA --> PRS
    CRA --> ST
    CRA --> MC
    CRA --> SC
    AR --> MC

核心产品模型:「模板 × 角色 × 对话」

Swarm Studio 的核心数据模型围绕三个概念展开:

概念 数据库表 定位 生命周期
Agent Profile contacts 可复用的专家模板/配置对象 持久化,跨对话复用
Workspace Agent workspace_agents 工作空间中的运行时角色 由 Profile 实例化,绑定到 workspace
Conversation conversations + chat_messages 协作界面(群聊 or 私聊) 消息积累,可归档为 History Snapshot

可以把它理解为:Agent Profile 是模板,Workspace Agent 是实例化后的角色,Conversation 是这些角色协作的场景。Human 用户也会被持久化为一个特殊的 Agent(human-{workspace_id})。Direct Chat 本质上仍是一个两成员对话,因此整套消息路由不需要为“私聊”和“群聊”分成两套模型。

数据库表全景

Swarm Studio 使用 SQLite 作为持久化存储,包含以下核心表:

表名 用途 关键索引
contacts Agent Profile 配置(名称、角色、专注领域、系统提示词、模型、最大迭代次数) updated_at DESC
workspace_agents 工作空间中的 Agent 运行时实例 关联 contact_id
conversations 对话元数据(name, kind, member_agent_ids, metadata) updated_at DESC
conversation_members 对话-成员关联 + last_read_message_id (conversation_id, contact_id)
conversation_agents 对话中的运行时 Agent 列表 (conversation_id, agent_id)
chat_messages 所有消息(sender_id, sender_type, content, kind, reply_policy) (conversation_id, created_at)
chat_reads 已读状态追踪 (conversation_id, reader_id)
chat_events 事件日志(AUTOINCREMENT id,用于 SSE since_id 分页) (conversation_id, created_at)
chat_agent_states Agent 运行时状态(status, last_error, metadata) (conversation_id, updated_at DESC)
chat_agent_memories Agent 对话记忆(llm_history, reasoning, tool_calls, open_loops 等) (conversation_id, updated_at DESC)
agent_global_memories Agent 全局记忆(summary, facts, preferences) (workspace_id, updated_at DESC)
chat_history_snapshots 对话历史快照(完整消息归档) (conversation_id, created_at DESC)

三条硬合约:Identity、Channel、Turn

与仅依赖 Prompt 引导的多 Agent 方案相比,Swarm Studio 在运行时层面补充了三条明确约束,用来限制 Agent 的对话行为。这些约束被写进工具描述、消息结构和事件处理流程,而不只是停留在 System Prompt 中。

Identity 合约:名称解析与引用消歧

Agent 之间通过 @name 互相引用。运行时的 _resolve_agent_reference 方法执行多级消歧匹配:首先按 agent_id 精确匹配,然后扫描所有 Agent Profiles 的 display_name 和 metadata.aliases 字段,使用归一化键(去空格、去连字符、小写)进行模糊匹配。当匹配到多个候选时,返回 ambiguous_target 错误并列出所有候选项,由调用 Agent 自行澄清——这避免了「错误 @ 人」导致的对话混乱。

Channel 合约:私聊作为显式 Side Thread

当 Agent A 使用 send_direct_message 工具向 Agent B 发送私聊时,系统自动创建一个 kind=direct 的新 Conversation,并将该私聊对话标记为源对话的 Side Thread。Agent 在完成私聊追问后,需要通过 sync_back_to_source 将关键信息同步回源对话,或显式调用 dismiss_sync_back 声明无需回传。这种显式合约避免了「信息在私聊中丢失」的常见问题。对话诊断接口(/api/chat/conversations/{id}/diagnostics)会暴露未完成的 sync-back 义务和脏 Direct Thread。

Turn 合约:每次唤醒必须以显式 Action 结束

每当 Agent 被唤醒处理未读消息时,它在本轮结束后必须执行以下动作之一:send_message(公开回复)、send_direct_message(私聊追问)、no_send(明确选择不发言)、sync_back_to_source、或 dismiss_sync_back。Turn 合约通过 reply_policy 字段控制强度:

reply_policy 含义 强制执行
optional 可选择是否回复 否(但空转触发 no_send_retry 提醒)
preferred 建议回复 否
required_once 必须回复一次 是(自动发布 final_answer 兜底)

当 Agent 在一轮中未执行任何 send 动作时,系统会自动注入 no_send_retry 提醒消息到其收件箱,并在 Human Direct Mention 场景下加强催促语气。

运行时生命周期:从启动到自动发布

Conversation Runtime 的创建与装配

当用户向某个对话发送消息时,ensure_conversation_runtime 被调用。该方法执行以下流程:

sequenceDiagram
    participant U as User (Frontend)
    participant API as FastAPI
    participant CC as ChatController
    participant CRA as ChatRuntimeAdapter
    participant AR as AgentRuntime (Jianmu)
    participant DB as SQLite

    U->>API: POST /api/chat/conversations/{id}/messages
    API->>CC: post_human_message()
    CC->>DB: append message
    CC->>CRA: wake_agents_for_message()
    CRA->>CRA: ensure_conversation_runtime()
    Note over CRA: 1. Create AgentTeam with ModelClient
    CRA->>AR: AgentTeam.runtime
    CRA->>AR: runtime.subscribe_events()
    Note over CRA: 2. For each member agent:
    CRA->>DB: get agent profile
    CRA->>CRA: _build_role_prompt()
    CRA->>AR: register_role(StudioAgentRole)
    CRA->>AR: runtime.spawn(role, task)
    Note over CRA: 3. Build tools per agent
    CRA->>CRA: _build_tools()
    Note over CRA: 4. Set auto_mode = True
    CRA->>DB: upsert agent state (idle)
    CRA-->>U: SSE event: agent.wakeup

可以先抓住三个结果: - 每个 Conversation 对应一个独立的 AgentRuntime 实例,所有成员 Agent 共享这个 Runtime - 每个 Agent 使用经过包装的 ModelClient,调用前会注入记忆摘要、未读批处理提示和 Turn Contract 上下文 - Agent 默认进入 auto_mode,收件箱收到消息后会自动被 Runtime 调度

消息唤醒与批处理

wake_agents_for_message 负责消息分发。它不会把消息广播给所有 Agent,而是按目标、未读状态和回复策略做选择性唤醒:

  1. 目标解析:如果发送者是 Agent(非 Human),从消息内容中提取 @mention 目标,并结合当前有 required_once 活跃 Turn 的 Agent 列表
  2. 未读批处理:为每个目标 Agent 查询未处理消息(list_chat_unprocessed_messages),选择触发消息(_pick_unread_trigger_message)
  3. Turn 排队:根据 reply_policy 和优先级(human_direct_mention > required_once > optional)将触发消息入队到 Agent 的 pending_reply_turns
  4. 忙检测:如果 Agent 当前正在运行(host_status == "running")或有活跃的 Reply Turn,则只更新元数据而不注入新消息——避免打断正在进行的推理
  5. 消息注入:构建 _build_unread_batch_prompt,将多条未读消息压缩为一条「未读批处理提示」注入 Agent 收件箱,其中包含消息发送者、回复策略、以及格式化的 Delta Lines
  6. 唤醒:调用 runtime.wake() 激活 Agent

Runtime 事件处理与自动发布

_handle_runtime_event 是 Runtime 事件到 UI 事件的翻译器。它处理来自 Jianmu 内核的所有 AgentEvent,并根据事件类型执行不同策略:

事件类型 处理逻辑
agent_wake / agent_resumed 更新状态为 running/idle,发射 ui.agent.state.changed
agent_run_completed 核心路径:提取 final_answer、检查 Turn Contract、执行自动发布
agent_mailbox_continue (FAILURE) 区分 rate_limited 错误和普通错误;rate_limited 时设置退避计时器并延迟重试

agent_run_completed 中最重要的一步是自动发布:系统会按优先级从 Turn Contract、final_answer、Skill 输出以及最后一条 assistant 消息中提取可发布文本,然后调用 _publish_agent_message 发回对话。这样即使 Agent 没有显式调用 send_message,大多数情况下它的有效输出仍然能被保留下来。

工具系统:Agent 的能力边界

Swarm Studio 为每个 Agent 动态构建工具集。工具构建函数 _build_tools 接收 conversation_id、runtime_agent_id 和 sender_agent_id,返回一个包含以下工具的列表:

工具名 描述 副作用标签 并行安全
send_message 向当前对话发送可见消息 message_send 否
send_direct_message 向另一个 Agent 发送私聊(自动创建 Direct Conversation) message_send 否
get_conversation_messages 查看对话中的可见消息 context_fetch 否
list_conversations 列出工作空间中可见的对话 — 是
list_conversation_members 列出指定对话的成员 — 是
list_agents 列出系统中可用的专家身份 — 是
list_agent_profiles 列出可复用的 Agent 模板 — 是
self 返回当前 Agent 的身份和默认对话上下文 — 是

每个工具在执行前后通过 emit_tool_event 发射 tool.{name}.started / tool.{name}.completed 事件,同时更新 Agent 状态为 running,确保前端能实时观测到工具调用进度。send_message 和 send_direct_message 还具备重复消息抑制机制——通过消息指纹(sender + conversation + kind + content 的 SHA256)在 20 秒 TTL 内去重。

此外,Agent 还能访问 Jianmu 的 Skill 系统(通过 SwarmNode 内嵌的技能配置),工具和技能共同构成 Agent 在对话中的完整行动空间。

Provider 管理:并发控制与速率限制

ProviderRuntimeSupport 提供了一套完整的 LLM Provider 管理层,解决多 Agent 并发调用时的资源竞争问题:

graph LR
    subgraph ProviderRuntimeSupport
        SEM[Semaphore<br/>并发控制]
        BUDGET[TPM Budget Bucket<br/>Token 速率限制]
        COOLDOWN[Cooldown<br/>全局退避]
        WRAP[RecordingChatProvider<br/>上下文注入 + Turn Contract 提取]
    end

    MC[ModelClient] --> WRAP
    WRAP --> SEM
    SEM --> BUDGET
    BUDGET --> PROVIDER[LLM Provider API]
    PROVIDER --> |429/rate_limit| COOLDOWN
    COOLDOWN --> SEM
  • 并发控制:通过 asyncio.Semaphore 限制同时进行的 Provider 调用数(默认 provider_max_concurrency: 1,避免多个 Agent 同时调用耗尽 API 配额)
  • TPM 预算桶:基于 Token Bucket 算法的速率限制器,每分钟按配置的 provider_tpm_limit(默认 30000)和 provider_tpm_refill_seconds 速率补充 Token。每个请求根据消息数量估算 Token 消耗,超限时排队等待
  • 错误分类与退避:Provider 返回的错误被解析为 rate_limited / retryable / fatal 三类。rate_limited 错误触发全局 Cooldown(默认 20s)+ Agent 级别退避重试;retryable 错误使用指数退避重试(最多 3 次)。一次 retryable 尝试耗尽后,Agent 会带着下一次重试延迟显示为 waiting_retry,而不会被当作终态失败。
  • RecordingChatProvider:在每次 LLM 调用前后注入动态上下文(记忆摘要、未读批处理提示)并提取 Turn Contract(Agent 的结构化输出决策)

前端架构:React SPA + SSE 实时流

前端是一个基于 React + TypeScript + Vite 构建的单页应用,采用四 Tab 布局:

Tab 页面组件 核心功能
💬 消息 ConversationPage 对话消息流、Composer 发送、运行时控制(中断/恢复)、Markdown 渲染
👥 联系人 AgentsPage Agent Profile 的 CRUD、双栏编辑布局
🕘 历史 HistoryPage 对话历史快照的浏览与管理
⚙️ 设置 内联于 App 技能设置、模型配置、后端 URL

实时事件驱动

前端通过两个 SSE 端点接收实时更新: - /api/chat/conversations/{id}/stream:针对单个对话的事件流(新消息、Agent 状态变更、工具调用开始/完成) - /api/chat/stream:工作空间级别的事件流(对话创建、全局状态变更)

事件流使用 since_id 分页机制(基于 SQLite AUTOINCREMENT 的 chat_events.id),配合 15 秒心跳保活和自动重连。前端将 SSE 事件分派到 React State 中,驱动 UI 的增量更新而非全量刷新。

运行时状态可视化

前端聚合了多维度的 Agent 状态展示:

  • Agent 状态派生:底层 host_status(来自 Runtime)+ metadata 中的 Reply Turn 和 Provider 节流状态 → 派生出面向用户的 display_status(idle / running / waking / blocked / failed / stopped)
  • Conversation 聚合状态:汇总所有成员 Agent 的状态,生成对话级别的运行状态(running / partially_stopped / stopped 等),并在 UI 中呈现为可交互的中断/恢复按钮
  • BT Skill Trace 可视化:BTSkillTraceView 组件将 Agent 执行的行为树技能渲染为树形节点图,实时展示每个节点的状态(RUNNING / SUCCESS / FAILURE),支持节点 I/O 的展开查看

API 路由全景

Swarm Studio 的 API 主要分成两组:传统的 /api/*,以及面向运行时对话管理的 /api/chat/*。

方法 路径 功能
GET /api/health 健康检查(返回 Agent 数、对话数、默认工作空间 ID)
GET /api/defaults 获取全局默认配置
PATCH /api/defaults 更新全局默认配置
POST /api/bootstrap 初始化默认工作空间
GET/POST/PATCH/DELETE /api/agents Agent Profile CRUD
GET/POST/PATCH/DELETE /api/conversations 传统会话模板 CRUD
GET/POST/PATCH/DELETE /api/chat/conversations Chat 对话 CRUD(核心路径)
POST /api/chat/agents/{id}/direct 创建或获取与某 Agent 的 Direct Chat
POST /api/chat/conversations/{id}/messages 发送消息(触发 Agent 唤醒)
GET /api/chat/conversations/{id}/stream SSE 事件流(对话级别)
GET /api/chat/stream SSE 事件流(工作空间级别)
POST /api/chat/conversations/{id}/interrupt 中断对话中所有 Agent
POST /api/chat/conversations/{id}/resume 恢复对话中所有 Agent
POST /api/chat/interrupt / /api/chat/resume 中断/恢复整个工作空间
GET /api/chat/runtime-status 获取工作空间运行时状态摘要
GET /api/chat/conversations/{id}/diagnostics 对话诊断(Side Thread、Agent 状态、失败事件)
POST /api/chat/conversations/{id}/reset-memory 重置对话记忆
POST /api/chat/conversations/{id}/clear-messages 清空对话消息
GET /api/chat/history-snapshots 历史快照列表
GET /api/chat/agents/{id} Agent 详情(含状态、对话列表、记忆)
POST /api/chat/agents/{id}/retry 重试失败的 Agent
POST /api/chat/agents/{id}/reset-history 重置 Agent 历史
GET /api/chat/search 全局搜索(Agent、对话)

配置体系

Swarm Studio 使用 config.yaml 进行配置,分为三大块:

Storage:SQLite 数据库路径(db_path),支持相对路径和绝对路径。默认存储在 .outputs/swarm_studio/swarm_studio.db,使本地对话与运行时数据留在源码树之外。

Defaults:新建对话时的默认值,包括 Provider 名称(默认 openai)、模型、最大运行时秒数(600s)、默认启用的技能列表(tavily_search、web_research)、技能目录、技能文件、技能 Prompt 模式(summary)。

模型默认值与会话覆盖

MODEL 与 BASE_URL(兼容 OPENAI_BASE_URL)是 Swarm Studio 的全局模型默认值,并优先于 config.yaml 中的同名 Defaults。它们不会被自动写入每个 Conversation;因此未设置会话级覆盖的对话会随 .env 更新使用新的默认值。

配置来源 优先级 .env 修改后的行为
Conversation 显式的 provider / model / Base URL 覆盖 高 保持不变,直到用户明确修改或清除
.env 的 MODEL、BASE_URL / OPENAI_BASE_URL 中 对未覆盖的会话立即作为新默认值生效
config.yaml 的 Defaults 低 仅在对应环境变量未设置时作为回退

更新对话名称、话题、技能等无关字段不会删除已有的会话级模型覆盖。

Runtime:Provider 运行时参数,包括最大并发数(1)、重试次数(3)、退避秒数(2.0)、429 退避秒数(15.0)、速率限制冷却秒数(20.0)、TPM 限制(30000)、TPM 补充秒数(60.0)、TPM 最小请求 Token(768)、上下文最大 Token(6000)。

这些默认值可在 Workspace 级别被覆盖(通过 metadata 字段),也可在每个 Conversation 创建时独立指定。

项目结构

下面这份目录更适合拿来定位代码入口,而不是逐项记忆。阅读时可以先关注三处:

  • backend/app.py:HTTP 路由与 SSE 入口
  • backend/chat_controller.py / backend/chat_runtime.py:后端编排与运行时适配
  • frontend/src/App.tsx:前端状态与事件流主入口
apps/swarm_studio/
├── README.md                      # 项目说明与对齐笔记
├── __init__.py
├── config.yaml                    # 应用配置(Storage / Defaults / Runtime)
├── backend/
│   ├── __main__.py                # python -m 入口
│   ├── main.py                    # uvicorn 启动(端口 8111)
│   ├── app.py                     # FastAPI 应用 + 全部 API 路由 + SSE 流
│   ├── chat_controller.py         # 编排层:对话 CRUD、消息发布、事件查询
│   ├── chat_runtime.py            # 核心:5000+ 行的运行时适配器
│   ├── runtime_common.py          # Provider 管理、StudioAgentRole、Skill 解析
│   ├── config.py                  # Pydantic 配置模型 + YAML 加载
│   ├── models.py                  # 数据模型:Pydantic Request + Dataclass Record
│   ├── storage.py                 # SQLite 持久化层(~2000 行,含自动 Schema 迁移)
│   ├── schema.sql                 # 数据库 Schema 定义
│   ├── agents.py                  # Agent Profile CRUD Service
│   ├── conversations.py           # 传统 Conversation CRUD Service
│   ├── status_utils.py            # Agent 状态派生逻辑
│   ├── env.py                     # .env 加载
│   ├── seeds.py                   # 默认工作空间初始化
│   └── data/                      # SQLite 数据库文件目录
├── frontend/
│   ├── src/
│   │   ├── App.tsx                # 主应用:Tab 路由、SSE 连接、全部状态管理
│   │   ├── main.tsx               # React 入口
│   │   ├── styles.css             # 全局样式
│   │   ├── pages/
│   │   │   ├── ConversationPage.tsx  # 消息流 + Composer
│   │   │   ├── AgentsPage.tsx        # 联系人列表 + 编辑
│   │   │   ├── ConversationsPage.tsx # 群聊列表 + 编辑
│   │   │   └── HistoryPage.tsx       # 历史快照浏览
│   │   ├── components/
│   │   │   ├── AgentEditor.tsx       # Agent Profile 编辑表单
│   │   │   ├── ConversationEditor.tsx # 对话编辑表单(成员选择 + 技能设置)
│   │   │   ├── Composer.tsx          # 消息输入框
│   │   │   ├── Avatar.tsx            # 头像组件
│   │   │   ├── BTSkillTraceView.tsx  # 行为树技能追踪可视化
│   │   │   └── SkillSettingsFields.tsx # 技能设置表单控件
│   │   └── lib/
│   │       ├── types.ts              # TypeScript 类型定义
│   │       └── skillSettings.ts      # 技能设置序列化/反序列化
│   ├── dist/                         # Vite 构建产物
│   └── vite.config.ts
└── scripts/
    └── inspect_chat_runtime_health.py  # 数据库健康检查脚本

信息来源:项目目录结构扫描

运行与调试

启动后端(默认 http://localhost:8111):

python -m apps.swarm_studio.backend.main

启动前端开发服务器(默认 http://localhost:5180):

cd apps/swarm_studio/frontend
npm run dev

数据库健康检查:

python apps/swarm_studio/scripts/inspect_chat_runtime_health.py /path/to/swarm_studio.db
检查报告包括:脏 Direct Thread(成员不规范)、未完成的 Side Thread sync-back 义务、长时间处于 running 状态的 Agent。

与核心模块的关系

Swarm Studio 位于 Jianmu 的上层应用层,和以下核心模块关系最紧密:

  • Swarm 运行时:AgentRuntime 提供 Agent 生命周期管理、邮箱路由、事件总线。Swarm Studio 的 ChatRuntimeAdapter 是对 AgentRuntime 的高层包装
  • 角色与团队:AgentTeam 和 StudioAgentRole 提供多 Agent 编组能力
  • 模型接入:ModelClient 是 LLM 调用的统一入口,被 ProviderRuntimeSupport 包装
  • 技能系统:SkillsCatalog 提供技能发现,SwarmNode 将技能嵌入到 Agent 的行为树中
  • 上下文构建器:ContextBuilder 和 TokenBudgetFilter 用于动态组装 LLM 上下文

阅读建议

完成本文后,建议按以下路径深入:

  1. Swarm 运行时:理解 Swarm Studio 底层的 Agent 生命周期和事件机制
  2. 角色与团队:理解 AgentTeam 和 StudioAgentRole 的协作编排
  3. Tree Studio:了解另一个可视化应用——工作流创建与技能导出
  4. 上下文构建器:理解 Swarm Studio 中动态上下文组装的具体实现