SwarmWright
文档 · 构建智能体群快速启动
SwarmWright 以单一 Docker 容器运行。无需外部基础设施 —— 无需消息代理、无需独立数据库服务器、无需构建流水线。一条命令即可启动运行。
docker run -d \
--network=host \
--name swarmwright \
-v ./data:/data \
-e LLM_PROVIDER=anthropic \
-e LLM_MODEL=claude-opus-4-7 \
-e ANTHROPIC_API_KEY=sk-ant-... \
ralphbarendse/swarmwright:latest
或使用 Docker Compose —— 从代码仓库获取 docker/docker-compose.yml 和 .env.example:
cp .env.example .env
# 配置 LLM_PROVIDER、LLM_MODEL 和你的 API 密钥
docker compose -f docker/docker-compose.yml up -d
GUI 界面访问地址:http://localhost:5001。首次访问将跳转至
设置向导,引导您创建管理员账号。完成后进入
设置 → LLM 提供商配置 API 密钥即可开始使用。
API 访问地址:http://localhost:5001/api/v1/health。
说明:全新的 docker compose up 无需手动配置密钥即可运行。
加密密钥在首次启动时自动生成并持久化到 data/.encryption_key。
请将此文件与 data/swarm.db 一起备份。
系统要求
- Docker Engine 24+ 和 Docker Compose v2
- Anthropic、OpenAI 或 Deepseek 的 API 密钥
- 为
data/挂载一个卷(docker-compose.yml 已处理)
环境变量
| 变量名 | 必填 | 默认值 | 说明 |
|---|---|---|---|
LLM_PROVIDER | 是 | anthropic | anthropic、openai 或 deepseek |
LLM_MODEL | 是 | claude-opus-4-6 | 模型标识符字符串 |
ANTHROPIC_API_KEY | 使用 anthropic 时 | — | Anthropic API 密钥 |
OPENAI_API_KEY | 使用 openai 时 | — | OpenAI API 密钥 |
DEEPSEEK_API_KEY | 使用 deepseek 时 | — | Deepseek API 密钥 |
SWARM_ENCRYPTION_KEY | 可选 | 自动生成 | 32 字节 base64 Fernet 密钥。未设置时在首次启动时自动生成。 |
DATABASE_URL | 否 | sqlite:////data/swarm.db | SQLAlchemy 数据库 URL |
DATA_DIR | 否 | /data | 数据卷挂载路径 |
LOG_LEVEL | 否 | INFO | DEBUG / INFO / WARNING / ERROR |
SCHEDULER_TIMEZONE | 否 | Europe/Amsterdam | APScheduler 心跳触发器的时区设置 |
加密密钥
LLM 凭据和机密信息使用 Fernet 对称加密静态加密。 主密钥在每次启动时按以下顺序解析:
SWARM_ENCRYPTION_KEY环境变量 —— 设置时优先使用<DATA_DIR>/.encryption_key文件 —— 由容器自动管理- 如果两者均不存在,则生成新密钥并写入文件
对于高安全要求的部署,建议在外部生成密钥并固定使用:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
核心概念
SwarmWright 将工作组织在三个嵌套作用域中:公司(Company)、工作区(Workspace) 和群组(Swarm)。工作区是类似部门的容器(财务、运营、HR)。 群组是一组协作处理某类工作的智能体集合。
每个群组由两个核心文件定义:
- meta.yaml —— 展示元数据(名称、描述、图标)。文件夹名称是稳定标识符,展示名称保存在此文件中。
- hierarchy.json —— 群组的拓扑结构:存在哪些智能体、哪些连接边、接入了哪些人工节点,以及每条连接的用途。这些内容在运行时被强制执行。
运行时严格执行 hierarchy.json。如果某个智能体试图调用
未在拓扑中声明的其他智能体、工具或感知者,该操作将被阻止并记录为
拓扑违规(topology violation)。此执行机制无法被绕过。
核心理念:你在画布上绘制的图表即配置本身。不存在需要单独维护同步的规范文件。如果连接存在于画布上,它就在 hierarchy.json 中,并在运行时被强制执行。
智能体层级
共有四个层级,不多不少。每个智能体恰好属于一个层级,在其宪章中声明。
| 层级 | 颜色 | 职责 | 典型任务 |
|---|---|---|---|
| 策略层(Policy) | 深蓝 #1e3a5f | 战略决策、治理、最终权威 | 制定规则、批准例外、处理上报、单一责任节点 |
| 编排者(Orchestrator) | 青色 #2a6b6b | 协调、路由、工作流管理 | 接收事件、决定调用哪个执行者、汇总结果、路由到下一步 |
| 执行者(Executioner) | 石板蓝 #3d4f7c | 任务执行、工具使用、外部操作 | 调用技能、写入数据库、调用 API、处理文件、生成产出物 |
| 感知者(Perceptionist) | 琥珀色 #c97c2a | 只读感知 —— 将现实映射为内部数据 | 读取传感器、分类输入、提取结构化数据,从不写入或采取行动 |
层级体系通过约定而非运行时机制来执行。感知者与其他智能体一样 —— 其区别在宪章中声明,并在拓扑图中清晰可见。 UI 通过颜色编码使结构一目了然。
拓扑结构
拓扑结构是 hierarchy.json 中声明的图。它列出了群组可以使用的
每一个智能体、每一条连接边、每一个技能、每一个人工节点和每一个感知者。
运行时强制执行这些声明 —— 智能体不能调用未列出的任何内容。
连接类型
两个智能体之间的每条连接使用以下类型之一:
- escalate(上报) —— 向上传递权威,指向策略层
- delegate(委托) —— 向下传递权威,来自策略层或编排者
- report(汇报) —— 将结果向上返回
用途说明是必填项。每条连接都需要一个非空的 purpose(用途)字符串,用通俗语言写成。这在验证时强制执行。这种阻力是故意设计的 —— 如果你无法说明一条连接为何存在,就不应该添加它。
拓扑违规
当运行中的智能体试图调用其声明连接中未列出的其他智能体、工具或感知者时,
运行时将阻止该调用并生成一条 topology_violation 运行步骤记录。
如果可能,运行继续进行;违规情况会在控制室的步骤追踪和画布上的实时流状态栏中上报。
人机协作
SwarmWright 对工作流中任意位置的人工参与提供一等支持。 两种节点类型代表群组拓扑中的人工角色:调用者(Caller)和通知者(Informer)。 两者都像智能体一样放置在画布上,并使用相同的拖拽连接机制进行连接。
调用者节点
调用者是一个阻塞式人工门控。当工作流到达调用者时,执行暂停,
并在收件箱中创建一个人工操作请求。运行在 awaiting_human(等待人工)
状态下暂停,直到人工以决策(yes、no 或修改后的指令)响应。
之后工作流才继续进行。
适用场景:
- 高风险审批门控(超额发票、合同签署、系统变更)
- 需要人工判断的模糊决策
- 必须被确认的合规检查点
在画布上,调用者节点显示举手图标(✋),并以鼠尾草绿色样式与智能体节点区分。
从智能体的连接把手拖拽到调用者节点即可建立连接,连接模态框会要求填写 purpose(用途)。
通知者节点
通知者是一个非阻塞式通知。当工作流到达通知者时, 向收件箱发送消息,工作流立即继续,无需等待。 通知者适用于进度更新、警报和人工应该知晓但无需处理的 FYI 通知。
在画布上,通知者节点显示扩音器图标(📢)。
连接人工节点
人工节点(调用者和通知者)首先放置在画布上,然后使用与智能体间连接相同的 连接绘制机制与智能体进行连接:
- 将调用者或通知者从调色板拖拽到画布上
- 选择智能体节点打开检查器
- 点击连接到…进入连接模式
- 点击要连接的人工节点
- 在弹出的模态框中填写连接用途
- 保存 —— 连接被写入
hierarchy.json
多个智能体可以连接到同一个调用者或通知者。 节点在画布上保持独立 —— 不"归属"于任何单一智能体。
收件箱交互
收件箱标签页显示两类内容:
- 待处理 —— 挂起的调用者请求。选择一条查看完整上下文,然后批准(
yes)、拒绝(no)或修改(提供替代指令)。工作流从精确暂停的位置继续。 - 通知 —— 未读的通知者消息。这些是信息性内容,不会阻塞运行。可逐条或全部标记为已读。
历史决策显示在已批准和已拒绝标签页下, 附带完整上下文,用于审计目的。
资源作用域
知识文档和技能存在于以下四个作用域之一。 引用按最近优先原则解析:群组 → 工作区 → 公司 → 内置。
群组作用域 → data/workspaces/<wid>/swarms/<sid>/<type>/
工作区作用域 → data/workspaces/<wid>/<type>/
公司作用域 → data/company/<type>/
内置作用域 → app/builtin_skills/ (只读,平台提供)
| 宪章中的引用 | 解析到 |
|---|---|
approval-thresholds | 最近匹配:群组 → 工作区 → 公司 |
workspace/finance-procedures | 仅限工作区作用域 |
company/glossary | 仅限公司作用域 |
write_swarm_file | 未被其他作用域覆盖时解析为内置 |
公司级策略附加到所有智能体;部门级流程对该工作区的所有智能体可用; 群组特定上下文仅对单一工作流保密。 内置作用域是技能的最终回退 —— 它是只读的,不可编辑, 但任何内置技能都可以通过在其他作用域创建同名技能来覆盖。
宪章
宪章是一个带有 YAML 前置元数据的 .md 文件,定义了智能体
是什么 —— 其身份、价值观、角色以及可访问的知识。
它不声明连接。连接保存在 hierarchy.json 中。
宪章在智能体运行时作为系统提示词的一部分逐字传递。 编写一份好的宪章是提升智能体质量最有影响力的单一操作。
---
name: Finance Orchestrator
layer: orchestrator
model: claude-opus-4-6
provider: anthropic
knowledge:
- approval-thresholds
- workspace/finance-procedures
---
You coordinate invoice intake for the Finance workspace.
Route incoming invoices to the appropriate Executioner agent
based on value, vendor, and approval requirements.
Never approve invoices directly. Escalate ambiguous cases
to the Policy layer with full context.
When routing, always state which agent you are delegating to
and why, so the decision is traceable.
允许的前置元数据字段:
| 字段 | 类型 | 说明 |
|---|---|---|
name | 字符串 | UI 中显示的名称 |
layer | 字符串 | policy / orchestrator / executioner / perceptionist |
model | 字符串 | 模型标识符。设置后覆盖群组默认值。 |
provider | 字符串 | 模型服务商(anthropic / openai / deepseek)。设置后覆盖默认服务商。 |
knowledge | 列表 | 知识文档引用列表(可带作用域前缀或直接使用名称) |
连接字段(skills、edges)属于 hierarchy.json,
而非宪章。将身份与拓扑分离意味着你可以更改智能体知道什么
而无需触及它连接什么,反之亦然。
技能
技能是可由执行者智能体调用的沙箱化 Python 脚本。每个技能由两个同名文件组成:
skill-name.py—— 必须暴露顶层函数run(input: dict, context: dict) -> dictskill-name.yaml—— 声明input_schema、output_schema、timeout_seconds、allowed_packages
技能在子进程中运行,永不在 Flask 进程中运行。出错的技能不会导致宿主崩溃。
允许的包在注册时强制执行 —— 如果某个包不在 allowed_packages 中,
导入将在技能启动时失败。
# parse-invoice.yaml
input_schema:
type: object
properties:
text: { type: string }
required: [text]
output_schema:
type: object
properties:
vendor: { type: string }
amount: { type: number }
currency: { type: string }
allowed_packages: [re, json]
timeout_seconds: 10
# parse-invoice.py
import re, json
def run(input: dict, context: dict) -> dict:
text = input["text"]
# ... 提取逻辑 ...
return {"vendor": vendor, "amount": amount, "currency": currency}
技能可以在公司、工作区或群组级别设置作用域。公司作用域的技能对所有群组中的所有智能体可用。 技能在资源库标签页中列出,并通过拓扑画布附加到智能体上。
内置技能
SwarmWright 在内置作用域提供 20 个平台预设技能,随时对任何智能体可用,
无需额外配置,显示在资源库 → 技能 → 内置下的只读卡片中。
无需 allowed_packages —— 它们仅使用 Python 标准库。
要覆盖内置技能,在群组、工作区或公司作用域创建同名技能即可。 解析器会优先找到你的版本。
文件存储
运行时会将 context["files_root"](当前群组 files/ 目录的路径)注入到每次技能调用中。拒绝越过此根目录的路径遍历操作。
| 技能 | 说明 | 主要输入 | 返回值 |
|---|---|---|---|
write_swarm_file |
将文件写入 files/,自动创建父目录。 |
path、content、encoding(utf-8 / base64) |
path、size_bytes、checksum(SHA-256) |
read_swarm_file |
从 files/ 读取文件。 |
path、encoding(utf-8 / base64) |
content、encoding、size_bytes |
list_swarm_files |
列出 files/ 中的文件,可按路径前缀过滤。 |
prefix(可选) |
files[] —— path、filename、size_bytes、modified_at |
delete_swarm_file |
删除文件。文件不存在时静默成功。 | path |
deleted(bool)、path |
HTTP
| 技能 | 说明 | 主要输入 | 返回值 |
|---|---|---|---|
http_get |
执行 HTTP GET 请求,超时 30 秒。 | url、headers(可选)、as_json(bool) |
status、headers、body、json(当 as_json=true 时) |
http_post |
执行带 JSON 正文的 HTTP POST,自动设置 Content-Type: application/json。 |
url、body(对象)、headers(可选)、as_json(bool) |
status、headers、body、json(当 as_json=true 时) |
键值存储
基于群组 files/ 目录中 _kv_store.json 的持久化存储。值在运行间持久保存,可存储任何 JSON 可序列化类型。
| 技能 | 说明 | 主要输入 | 返回值 |
|---|---|---|---|
kv_get |
按键检索值。 | key、default(可选回退值) |
key、value、found(bool) |
kv_set |
按键存储值,原子写入 —— 在并发运行下安全。 | key、value(任意 JSON 类型) |
key、value |
工具类
| 技能 | 说明 | 主要输入 | 返回值 |
|---|---|---|---|
get_datetime |
返回当前 UTC 日期和时间,适用于调度逻辑或给输出加时间戳。 | 无 | utc_iso、unix_timestamp、date、time、weekday、year、month、day、hour、minute |
通知
| 技能 | 说明 | 主要输入 | 返回值 |
|---|---|---|---|
send_webhook |
向任意 Webhook URL POST JSON 负载,兼容 Slack、Discord、Teams 或自定义端点。 | url、payload(对象)、headers(可选) |
status、body、ok(2xx 时为 true) |
对话 —— 平台技能
供内置的运营者和客服群组使用,以公司作用域提供,运营者也可将其附加到自定义群组。与所有内置技能一样,均可在更高作用域使用同名技能覆盖。
| 技能 | 使用方 | 说明 |
|---|---|---|
create_workspace | 运营者 | 创建工作区文件夹及 meta.yaml。 |
create_swarm | 运营者 | 在工作区内创建群组。 |
draft_constitution | 运营者 | 为新智能体生成初始宪章 Markdown 文件。 |
patch_topology | 运营者 | 对群组的 hierarchy.json 应用结构性编辑操作。 |
trigger_run | 运营者 | 以指定输入负载调用现有群组。 |
list_runs | 运营者 | 获取群组的近期运行记录及状态摘要。 |
read_run | 双方 | 按运行 ID 获取运行状态和完整步骤追踪。 |
list_unmet_needs | 运营者 | 读取客服无法路由的请求队列。 |
list_workspace_swarms | 客服 | 枚举当前工作区中的同级群组。 |
flag_unmet_need | 客服 | 将客服无法处理的请求记录到 unmet_needs 表中。 |
触发器
触发器是确定性脚本 —— 不是智能体。它们产生进入群组的事件。 触发器内不进行 LLM 调用。使用正则表达式、JSON Schema、JSONPath 和标准 Python 库。保持简单。它们的职责是检测和路由,而不是思考。
四种触发器类型:
| 类型 | 触发时机 | 配置 |
|---|---|---|
| 心跳(Heartbeat) | 通过 APScheduler 按 cron 调度触发 | cron 表达式、payload 模板 |
| 监听器(Listener) | 外部 Webhook / 传入消息到达监听器端点 | path、可选 filter JSONPath 表达式 |
| 调用(Invocation) | 通过 POST /api/v1/triggers/invocations/<id> 或控制室的触发按钮手动触发 |
用于验证的 payload_schema |
| 文件监视器(File Watcher) | 群组 files/ 目录中匹配 glob 模式的文件被创建或修改 |
glob 模式(如 reports/*.csv)、可选 events 列表(created、modified) |
触发器在群组画布检查器中创建和管理。每个触发器可以单独启用或禁用而无需删除。 控制室的触发按钮可以直接向群组发送原始事件,绕过触发器 —— 适用于测试。
群组文件
每个群组在磁盘上都有一个持久化的 files/ 目录。智能体和人类都可以对其进行读写。
文件在数据库中建立索引,记录完整的来源信息 —— 每个文件的创建者(智能体、人类或未知)、
产生它的运行和步骤,以及最后修改时间。
这个共享文件系统充当运行之间的持久化交接层:一个智能体可以在某次运行中向
files/reports/ 写入 CSV,而人类可以从画布下载它,
同时另一次运行正在处理下一批数据。
智能体如何写入文件
智能体使用内置的 write_swarm_file 技能。运行时将
files_root 路径注入到每次技能调用的 context 字典中,
使技能知道写入位置而无需访问数据库。支持无限深度的子目录嵌套 ——
智能体可以将文件组织到任意所需的文件夹结构中。
# write_swarm_file 输入
{
"path": "reports/2024-06/summary.md",
"content": "# June Summary\n...",
"encoding": "utf-8"
}
每次技能调用后,运行时会对文件索引进行协调:新文件以 origin=agent 插入;
已删除的文件从索引中移除。
人类如何管理文件
群组画布在检查器下方有一个文件面板。在此可以:
- 查看所有文件及其来源(智能体写入 vs. 人工上传)
- 点击↑ 上传或拖拽到面板上传文件
- 点击+ 文件夹按钮创建文件夹 —— 输入如
reports/2024格式的路径 - 点击↓按钮下载任意文件
- 点击✕按钮删除文件
人工上传的文件以 origin=human 建立索引。每行上的彩色圆点
指示来源:强调色表示智能体写入,灰色表示人工上传。
文件浏览器
除了单个群组的文件面板之外,文件页面(顶部导航中的 #files)
是一个覆盖所有群组文件存储的全组织浏览器 —— 在一个地方查找、预览和管理群组产生的所有文件。
左侧的树按工作区 → 群组 → 文件夹分组;选择某个节点即可限定右侧的列表范围。
- 搜索与筛选 —— 按文件名或路径匹配(在服务端解析),并可缩小到单个工作区。
- 表格或网格视图 —— 在密集表格与缩略图网格之间切换(网格中图片会内联渲染);你的选择会被记住。
- 一目了然的元数据 —— 文件类型图标、彩色来源圆点、大小、最后修改时间,以及指向产生该文件的运行的链接。
- 内联预览 —— 侧滑面板可直接渲染图片、PDF 以及类文本文件(Markdown、JSON、CSV、日志)而无需下载;过大的文件则回退为下载。
- 悬停行操作 —— 预览、下载、复制路径、链接到另一个群组以及删除。
- 随处上传 —— 无需先打开群组画布,即可直接上传(或拖拽)到所选群组。
跨群组链接
通过链接,同一个文件可以出现在多个群组中 —— 这是逻辑引用,而非副本。 字节数据只随原始(规范)文件存储一份;其他每个群组都只持有一个指向它的轻量指针。 在文件浏览器中使用 ↗ 行操作即可将文件链接到另一个群组。
- 不重复存储 —— 链接行携带规范文件的大小和类型;下载或预览链接始终提供规范文件的字节数据。
- 安全删除 —— 删除链接只会移除该引用。只要还有链接指向规范文件,删除该规范文件就会被阻止,因此链接绝不会悄无声息地失效。
- 来源追溯 —— 链接行带有
↗ linked标记并显示其来源;规范文件则显示它出现在多少个群组中。 - 被动设计 —— 创建链接不会触发目标群组的文件监视器。链接用于共享和发现,而非启动另一个群组的流程。要启动工作流,请将文件上传到群组(或让智能体写入),使真实文件落到磁盘上。
文件监视器触发器
文件监视器触发器使用 glob 模式监视群组的 files/ 目录。
当匹配的文件被创建或修改时 —— 无论是智能体、人工上传还是写入挂载卷的外部进程 ——
触发器都会向群组发送一个调用事件。
这使基于文件到达的工作流成为可能:将 PDF 放入 files/inbox/,
群组即自动开始处理。跨群组链接是被动的,不会触发监视器 —— 只有写入磁盘的真实文件才会。
索引协调
每次群组加载时,SwarmWright 会将磁盘上 files/ 的内容与数据库索引进行协调。
磁盘上存在但索引中缺失的文件以 origin=unknown 插入。
索引中指向磁盘上不再存在的文件的行被移除。
这意味着即使在手动文件系统操作(备份恢复、外部写入、直接卷挂载)之后,
索引也能保持准确。
跨群组委托
任何智能体都可以将另一个群组作为同步阻塞式子调用来调用 —— 类似于调用不同部门的函数。调用智能体发送输入负载, 目标群组运行完成,然后将结果内联返回。父群组中的执行暂停,直到子群组完成。
这与向另一个群组发送事件不同。群组调用具有以下特点:
- 同步 —— 父群组等待结果
- 拓扑声明 —— 连接必须在画布上绘制;临时调用被阻止
- 支持跨工作区 —— 目标群组可以存在于不同的工作区中
- 别名寻址 —— 智能体使用简短名称(别名)引用目标,而非原始群组 ID
配置群组调用
- 打开调用方群组的画布
- 点击左侧调色板中的外部群组 —— 弹出模态框列出所有工作区的所有群组
- 选择目标群组并点击添加到画布 —— 出现一个青色 ⬡ 节点
- 选择智能体节点并点击连接到…,然后点击 ⬡ 群组节点
- 在模态框中:输入别名(智能体在操作中使用的简短标识符)和用途
- 保存 —— 连接以
swarm_calls条目形式写入hierarchy.json
别名命名:使用简短有意义的标识符 —— hr_lookup、credit_check、compliance_scan。别名是智能体在 invoke_swarm 操作中写入的内容。不能包含空格。
智能体如何调用群组
当智能体声明了群组调用时,运行时会自动将其添加到系统提示词中。
智能体使用 invoke_swarm 操作调用目标:
{
"action": "invoke_swarm",
"alias": "hr_lookup",
"input": {
"employee_id": "EMP-4821",
"query": "Is this employee currently active?"
}
}
运行时将别名解析为目标群组的入口点,创建一个与父运行共享运行 ID 和步骤序列的子执行上下文, 运行目标群组,并将最终输出作为操作结果返回给调用智能体。 子群组的步骤显示在控制室的同一运行追踪中。
跨工作区委托
群组调用可以针对任意工作区的群组,而不仅限于当前工作区。 这使跨部门工作流成为可能 —— 财务群组可以查询 HR 群组,运营群组可以触发合规群组,等等。 目标群组无需知道自己被另一个工作区的群组调用。
在画布上,跨工作区群组节点以琥珀色(而非青色)样式显示, 并带有↗ 跨工作区标签。这是一个刻意的视觉警告: 跨工作区调用会在部门之间引入依赖关系。如果目标群组被禁用、重命名或删除, 调用方群组将在运行时失败。
设计建议:跨工作区调用功能强大,但应谨慎使用。每一个调用都会创建部门间耦合。如果某个调用只需要单向进行,优先考虑通过共享知识或共享技能提供数据,而非实时群组调用。
移除群组节点
点击 ⬡ 群组节点打开其检查器。检查器显示群组名称、工作区以及连接到它的所有智能体。按钮:
- 打开群组 —— 在新标签页中导航到目标群组的画布
- 从画布移除 —— 从拓扑中移除群组节点及其所有 swarm_call 连接边
点击群组调用连接边可检查它:查看别名、连接智能体和用途。点击移除 仅删除该连接边,不移除群组节点。
组织设计
组织标签页是你的公司组织架构图,显示所有工作区(部门)及其中的群组。
工作区
为每个部门或职能领域创建一个工作区:财务、运营、HR、客户成功。 工作区是一个容器 —— 它本身没有运行时行为。它为群组提供命名空间, 并为共享资源(知识、技能、感知者)提供作用域。
群组
每个群组处理一类工作。在工作区内创建群组。群组有一个启用标志 —— 禁用的群组无法接收事件,也不会启动运行。 可从组织视图或控制室激活或暂停群组,无需删除它们。
删除群组会永久移除数据库记录和文件系统目录
(data/workspaces/<ws>/swarms/<swarm>/)。
群组画布
群组画布是你设计群组拓扑的地方。它是一个 Cytoscape.js 图表,
每次更改都直接写入 hierarchy.json —— 没有单独的保存步骤。
添加节点
从左侧调色板拖拽项目到画布:
- 智能体层级(策略层、编排者、执行者、感知者)—— 添加智能体并打开宪章编辑器
- 技能 —— 添加技能引用节点;连接到执行者以声明使用
- 触发器 —— 打开触发器创建模态框
- 调用者 —— 在画布上放置一个未连接的人工调用者节点(✋)
- 通知者 —— 在画布上放置一个未连接的人工通知者节点(📢)
- 外部群组 —— 打开群组选择器(所有工作区)并放置青色 ⬡ 群组节点;连接到智能体以声明跨群组委托
绘制连接
- 点击节点打开检查器
- 在检查器中点击连接到…
- 出现提示横幅:"点击目标节点以建立连接"
- 点击任何兼容目标(智能体、人工节点)
- 在模态框中输入
purpose(用途)—— 此项为必填 - 保存 —— 连接边出现并被写入
hierarchy.json
删除元素
点击任意节点或连接边打开检查器,然后点击删除。 对于智能体,这会从拓扑中移除智能体及其宪章文件。 对于人工节点,这会断开所有连接并从画布移除节点。 对于连接边,只移除连接 —— 两个端点保留。
检查器
右侧检查器面板为所选元素显示上下文相关操作。 智能体:编辑宪章、发送测试事件、查看连接。连接边:查看用途、删除。 画布背景:查看群组信息、发送事件、删除群组。
文件面板
检查器下方是群组的文件面板。它显示群组 files/ 目录中的每个文件,
用彩色圆点指示每个文件是由智能体写入还是人工上传的。
从面板标题可以上传文件、创建文件夹、下载单个文件和删除文件。
也支持拖拽到面板。详细架构请参阅群组文件。
收件箱
收件箱是人机协作系统面向人类的一侧。顶部导航栏中的通知圆点显示需要处理的项目数量。
标签页
| 标签页 | 内容 |
|---|---|
| 待处理 | 挂起的调用者请求。每条显示触发运行、提出请求的智能体和完整上下文。可选择批准、拒绝或修改。 |
| 通知 | 未读的通知者消息。这些是 FYI 信息 —— 工作流已经继续。标记为已读可关闭。 |
| 已批准 | 历史批准记录(决策:yes),附有时间戳和原因。 |
| 已拒绝 | 历史拒绝记录(决策:no),附有时间戳和原因。 |
处理调用者请求
选择一条待处理项目。详情面板显示运行上下文、请求智能体的问题或提议以及完整事件负载。 提供三种操作:
- 批准 —— 决策
yes,工作流继续 - 拒绝 —— 决策
no,工作流继续并记录拒绝 - 修改 —— 提供替代指令;智能体将收到此修改后的上下文
可以为任何决策选择性添加原因说明。此原因会附加到运行步骤记录,用于审计目的。
控制室
控制室是你智能体群舰队的运营仪表盘,将实时组织架构图与过滤后的运行日志相结合。
组织架构面板
左侧面板将所有工作区及其群组显示为可折叠树形结构。对于每个群组:
- 绿色圆点(●)表示群组活跃,可以接收事件
- 灰色圆点(●)表示群组已暂停
- 活跃/暂停切换按钮就地激活或暂停群组
- ▶ 触发按钮打开模态框,直接向群组发送原始事件
点击工作区行将运行日志过滤为该工作区的群组。点击群组行仅过滤该群组。 再次点击取消选择并显示所有运行。
运行日志
右侧面板按时间倒序显示运行记录。过滤条件:
- 状态:运行中、已完成、已失败、挂起、等待人工
- 工作区:过滤为该工作区的所有群组
实时更新通过 SSE 推送 —— 运行日志在运行开始、完成或失败时自动刷新,无需手动刷新。
运行详情
点击运行查看其步骤追踪:按序列排列的每次智能体调用、技能调用、人工交互和拓扑违规。 每个步骤显示智能体名称、连接用途、输入/输出、持续时间和任何错误。 重放按钮可重新发送原始事件负载。
资源库
资源库标签页管理可复用资源:知识(文档)和技能(Python 脚本)。 两者都可以存在于公司、工作区或群组作用域。使用左侧作用域侧边栏切换作用域。 两个标签页都有实时过滤栏,可按名称或描述搜索。
技能作用域侧边栏顶部还包含一个内置条目。内置技能由平台提供,只读, 始终可用。它们显示为信息卡片 —— 可点击查看源码,但无法编辑或删除。 通过在任何其他作用域创建同名技能来覆盖任何内置技能。
知识文档
知识文档是在运行时注入智能体上下文的 Markdown 文件。
通过在宪章的 knowledge 数组中引用文档名称将其附加到智能体。
公司作用域的文档对所有智能体可用,无需显式引用。
点击+ 新建文档或任何现有卡片,打开内联全屏编辑器,包含:
- 编写标签页 —— 带语法高亮的 Markdown 模式 CodeMirror 编辑器
- 预览标签页 —— 渲染后的 Markdown,保存前可检查格式
- AI 起草按钮 —— 描述文档内容,LLM 生成初稿
- ⌘S / Ctrl+S 保存,无需鼠标点击
文档卡片显示内容预览片段和相对的最后修改时间戳。
技能
技能直接在浏览器中使用分屏代码编辑器编写:
左侧面板是 skill.py(Python,CodeMirror),右侧面板是
config.yaml。两者原子保存。
AI 起草按钮根据通俗语言描述生成可运行的 .py + .yaml 组合。
可折叠的可用 Python 库面板显示沙箱中安装的内容,
以及哪些包需要在 YAML 中添加 allowed_packages 条目。
保存后,技能出现在画布调色板中,可以连接到执行者智能体。 技能卡片显示描述、超时时间、包标签和最后修改时间戳。
设置
设置标签页是 SwarmWright 实例的中央控制面板,分为六个子标签页。 其中用户标签页仅对管理员可见。
LLM 提供商
配置 Anthropic、OpenAI 和 DeepSeek 的凭据。每个提供商可设为默认提供商, 在智能体宪章未指定模型时使用。凭据使用 Fernet 加密后写入数据库。 可通过测试连接按钮验证密钥是否有效。
模型
管理智能体可用的模型标识符列表。默认包含 Claude Opus 4.7、Claude Sonnet 4.6、 Claude Haiku 4.5、GPT-4o、GPT-4o mini、DeepSeek Chat 和 DeepSeek Reasoner。 可添加自定义模型标识符(适用于自托管模型或新发布版本),并设置默认模型。
品牌
自定义实例外观:设置公司名称(显示在导航栏)并上传 Logo。 重置按钮可移除自定义 Logo 并恢复默认 SwarmWright 图标。
系统
配置运行时默认值:
- 默认技能超时 —— 未在 YAML 中声明
timeout_seconds的技能的回退超时时间(秒) - 默认心跳计划 —— 创建新心跳触发器时预填充的 cron 表达式
- 审计日志保留期 —— 保留设置变更审计条目的天数(每晚清理)
- 事件总线工作线程 —— 事件总线的线程池大小(需重启容器生效)
包安装器
包面板是技能运行时的包管理器。全局允许列表中的每个包均可被声明了
allowed_packages 的技能使用。未安装的包显示安装按钮,
点击后将在容器内运行 pip install 并注册该包。
安全
查看设置变更审计日志(谁在何时修改了什么)并轮换主加密密钥。 密钥轮换会使用新 Fernet 密钥重新加密所有存储的机密。 用户账号配置完成后,基于 Session 的登录即告激活。
用户与权限
SwarmWright 有两种账号类型:管理员和普通用户。 管理员拥有不受限制的完整访问权限。普通用户拥有 17 个独立的权限开关, 这些开关同时控制 UI 显示(无权限的按钮将被隐藏)和 API 访问 (无权限的端点调用返回 403)。
首次启动
首次启动后访问 http://localhost:5001 将跳转至 /setup。
填写用户名、可选显示名称和密码以创建第一个管理员账号。
创建完成后,后续所有访问将跳转至 /login,直到会话有效为止。
用户管理
管理员可在设置 → 用户中创建、编辑和删除账号。 非管理员账号不可见此标签页。创建或编辑用户时,勾选管理员 可赋予完整访问权限并隐藏权限清单;对于普通用户,可单独切换 15 个权限开关。
新用户的默认权限(创建时未自定义时):
- 默认开启:启动运行、停止运行、处理收件箱事项
- 默认关闭:其余所有权限
权限说明
| 权限标志 | 控制范围 |
|---|---|
can_create_workspace | 创建新工作区 |
can_edit_workspace | 重命名或更新工作区元数据 |
can_delete_workspace | 删除工作区(必须为空) |
can_create_swarm | 在工作区内创建新群组 |
can_edit_swarm | 重命名、启用/禁用、转移群组 |
can_delete_swarm | 删除群组及其内容 |
can_start_run | 触发事件、调用触发器、重放运行 |
can_stop_run | 停止正在运行的群组执行 |
can_edit_constitution | 在画布上添加/移除智能体并编辑其宪章;管理调用者和通知者 |
can_manage_triggers | 创建、编辑和删除触发器 |
can_manage_skills | 在资源库中创建、编辑和删除技能 |
can_manage_knowledge | 创建、编辑和删除知识文档 |
can_decide_inbox | 批准或拒绝人机协作收件箱事项 |
can_view_settings | 访问设置标签页(非管理员只读) |
can_manage_users | 保留字段 —— 用户管理在服务端强制要求管理员权限 |
can_chat_workspace | 访问用户已有权限查看的任意工作区中的客服对话 |
can_chat_operator | 访问组织级别的运营者对话。隐含 can_chat_workspace。此对话可设计拓扑、创建群组并触发运行。 |
会话与安全
身份认证使用服务端签名 Session(Flask 安全 Cookie)。Session 持久有效,
30 天无活动后过期。密码使用 werkzeug.security(PBKDF2-HMAC-SHA256)
哈希存储。无 Token 或 OAuth 流程 —— 这是为小型可信团队在私有网络环境下的
使用场景刻意设计的。
运营者对话
运营者(Operator)是一个随平台内置的群组,位于
data/workspaces/platform/swarms/operator-chat/。
它为拥有 can_chat_operator 权限的用户提供对话式界面,
用于设计和操作平台:创建工作区、起草群组、修改拓扑、触发运行,以及查阅未满足需求队列。
组织(Org)界面工作区画布右上角显示一个圆形对话图标。点击后, 右侧弹出对话面板(宽度 40%,可调整),面板标题显示运营者及 当前默认模型名称,并附有提示:"此对话可编辑您的平台。"
无特殊运行路径。运营者以普通群组运行方式执行。它所采取的每一个操作 —— 创建工作区、修改拓扑、触发运行 —— 都经过与人工操作相同的 API 层,产生相同的运行步骤和审计追踪。
运营者的能力
运营者的拓扑为其提供了 8 个内置技能的访问权限,每个技能都有声明用途。超出这些技能范围的操作请求将被记录为拓扑违规。
- 创建工作区和群组
- 为智能体起草初始宪章
- 对群组拓扑应用结构性编辑
- 以指定输入触发现有群组
- 读取运行追踪和状态
- 读取客服智能体产生的未满足需求队列
未满足需求信号
当新的运营者会话打开时,如果存在超过 24 小时未处理的未满足需求, 运营者会将其作为开场消息主动呈现。对话记录旁边的信号标签页 列出所有未处理的需求条目,按工作区分组,附有用户的原始表述, 以及为此起草群组按钮,点击后会将用户原始请求预填入运营者输入框。
模型
运营者宪章省略了 model: 前置元数据字段,
继承设置 → 模型 → 默认模型中选定的模型。
修改平台默认模型后,下一条运营者消息即生效,无需编辑宪章。
客服对话
每个工作区在创建时,以及每次平台启动时,都会自动配置一个内置客服(Concierge)群组,
位于 data/workspaces/<wid>/swarms/concierge/。
工作区顶部导航栏(现有标签页旁)显示一个圆形对话图标,
点击后弹出面板,标题显示客服 —— <工作区名称>。
拥有 can_chat_workspace 权限的用户可见此按钮;无此权限的用户不可见。
客服将自然语言请求路由到工作区内合适的群组。 默认回复中不使用"群组"或"智能体"等术语,而是以业务领域语言作答。 每条回复下方有一个折叠的"我是如何得出这个答案的?"链接, 展开后显示运行步骤追踪,供用户了解处理过程。
客服的能力
- 列出工作区中的同级群组(
list_workspace_swarms) - 以同步子调用方式调用任意同级群组并将结果内联返回
- 读取运行状态和步骤(
read_run) - 当无群组能处理请求时,记录未满足需求(
flag_unmet_need)
客服的拓扑中没有拓扑变更技能的连接边。
它无法创建群组、修改宪章或编辑 hierarchy 文件。
这一边界是结构性的,而非权限检查 —— 相关技能根本不存在于其 hierarchy.json 中。
客服拓扑自动更新
每次注册表加载时,客服的 swarm_calls 块都会根据工作区当前的同级群组集合重新生成。
在工作区中添加或移除群组后,客服的路由能力立即更新。
对话会话
两个对话界面的会话均在浏览器刷新后持久保留。
每个(用户、作用域)对应一个会话 —— 运营者的作用域为 org,
客服的作用域为特定工作区 ID。会话在首条消息发送时延迟创建。
清除对话按钮(需二次确认)删除可见的 chat_messages 行,
但不删除底层的运行记录和运行步骤 —— 审计追踪保持不变。
对话层遗忘,账本不忘。
当累积的对话上下文超过配置的令牌预算(默认 32 000 个令牌)时, 对话层优先丢弃最旧的消息,并在前面添加摘要行,使智能体保持对情境的基本了解。
API 端点
所有端点均返回 JSON。基础路径:/api/v1。
健康检查
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /health | 健康检查 —— 返回 {"status":"ok"} |
工作区与群组
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /workspaces | 列出所有工作区 |
| POST | /workspaces | 创建工作区。请求体:display_name、description |
| GET | /workspaces/<id> | 获取工作区及嵌套群组列表 |
| PUT | /workspaces/<id> | 更新工作区显示名称/描述 |
| DELETE | /workspaces/<id> | 删除工作区(必须没有群组) |
| GET | /workspaces/<id>/swarms | 列出工作区中的群组 |
| POST | /workspaces/<id>/swarms | 创建群组。请求体:display_name、description |
| GET | /swarms/<id> | 获取群组及完整元数据 |
| PUT | /swarms/<id> | 更新群组。支持 enabled(布尔值)激活/暂停 |
| DELETE | /swarms/<id> | 删除群组 —— 移除数据库记录和文件系统目录 |
智能体
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /swarms/<id>/agents | 列出群组中的智能体 |
| GET | /agents/<id> | 获取单个智能体及宪章文本 |
| PUT | /agents/<id>/constitution | 更新智能体宪章文本 |
拓扑
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /swarms/<id>/topology | 获取完整的 hierarchy.json 内容 |
| PATCH | /swarms/<id>/topology | 对拓扑应用命名操作。参见 hierarchy.json。 |
拓扑 PATCH 操作:
| 操作 | 参数 | 效果 |
|---|---|---|
add_agent | id、layer | 创建智能体,添加到拓扑 |
remove_agent | id | 移除智能体及其所有连接边 |
add_edge | from、to、kind、purpose | 添加智能体间连接边 |
remove_edge | from、to | 移除连接边 |
add_call | agent、caller、purpose | 将智能体连接到调用者节点 |
remove_call | agent、caller | 移除智能体→调用者连接 |
add_inform | agent、informer、purpose | 将智能体连接到通知者节点 |
remove_inform | agent、informer | 移除智能体→通知者连接 |
add_canvas_caller | caller | 在画布上放置调用者节点(未连接) |
remove_canvas_caller | caller | 移除调用者节点及其所有连接 |
add_canvas_informer | informer | 在画布上放置通知者节点(未连接) |
remove_canvas_informer | informer | 移除通知者节点及其所有连接 |
add_canvas_swarm | swarm_id | 在画布上放置外部群组 ⬡ 节点(未连接) |
remove_canvas_swarm | swarm_id | 从拓扑移除群组节点及其所有 swarm_call 连接边 |
add_swarm_call | agent、alias、swarm_id、purpose | 将智能体连接到带命名别名的外部群组;群组必须已在画布上 |
remove_swarm_call | agent、alias | 按智能体和别名移除单条智能体→群组委托边 |
事件与触发器
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /swarms/<id>/events | 向群组发送事件。请求体为事件负载(任意 JSON)。 |
| GET | /events | 列出最近事件。参数:swarm_id、limit |
| GET | /swarms/<id>/triggers | 列出群组的触发器 |
| POST | /swarms/<id>/triggers | 创建触发器。请求体:name、kind、config |
| PUT | /triggers/<id> | 更新触发器(配置、启用标志) |
| DELETE | /triggers/<id> | 删除触发器 |
| POST | /triggers/invocations/<id> | 手动调用触发器 |
运行记录
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /runs | 列出运行记录。参数:status、swarm_id、workspace_id、limit、offset |
| GET | /runs/<id> | 获取单条运行及完整步骤追踪 |
| POST | /runs/<id>/replay | 重新发送原始事件 —— 创建新运行 |
人工操作(调用者收件箱)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /inbox | 列出调用者请求。参数:status(pending / yes / no)、swarm_id |
| GET | /inbox/<id> | 获取单条操作及完整上下文 |
| POST | /inbox/<id>/decide | 响应调用者请求。请求体:decision(yes/no)、reason、amend |
人工通知(通知者收件箱)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /informs | 列出通知者通知。参数:status(unread / read)、swarm_id |
| GET | /informs/<id> | 获取单条通知及完整上下文 |
| POST | /informs/<id>/read | 将通知标记为已读 |
| POST | /informs/<id>/dismiss | 关闭通知 |
知识
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /knowledge | 列出知识文档。参数:scope、workspace_id、swarm_id |
| POST | /knowledge | 创建知识文档。请求体:scope、name、title、content |
| GET | /knowledge/<id> | 获取单篇文档及完整内容 |
| PUT | /knowledge/<id> | 更新文档。请求体:title、content |
| DELETE | /knowledge/<id> | 删除文档及其 .md 文件 |
| POST | /knowledge/<id>/draft | AI 生成文档内容。请求体:prompt(可选描述) |
技能
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /skills | 列出技能。参数:scope、workspace_id、swarm_id |
| POST | /skills | 创建技能。请求体:scope、name、py_content、yaml_content |
| GET | /skills/<name> | 获取单个技能及完整 .py 和 .yaml 内容。参数:scope |
| PUT | /skills/<name> | 更新技能文件。请求体:py_content、yaml_content |
| DELETE | /skills/<name> | 删除技能 —— 移除 .py 和 .yaml 文件。参数:scope |
| POST | /skills/_meta/draft | AI 生成技能文件。请求体:name、prompt |
| GET | /skills/_meta/runtime | 返回 Python 版本、标准库概要及沙箱中可用的第三方包 |
群组文件
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /swarms/<id>/files | 列出群组 files/ 目录中的文件。参数:prefix 按路径前缀过滤 |
| POST | /swarms/<id>/files | 上传文件。带 file 字段和可选 path 字段的 multipart 表单。添加 overwrite=true 可替换已有文件。最大 50 MB。 |
| GET | /swarms/<id>/files/download | 下载文件。参数:path(相对于 files/)。返回正确 MIME 类型的原始字节。 |
| DELETE | /swarms/<id>/files | 删除文件。参数:path。同时移除索引行并清理空的父目录。 |
身份认证
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /auth/setup | 创建第一个管理员账号(仅在无用户时有效)。请求体:username、password、display_name(可选) |
| POST | /auth/login | 登录。请求体:username、password。成功时设置签名 Session Cookie。 |
| POST | /auth/logout | 清除当前 Session。 |
| GET | /auth/me | 返回当前登录用户信息(含全部 15 个权限标志)。未认证时返回 401。 |
用户 (仅限管理员)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /users | 列出所有用户及其权限标志。 |
| GET | /users/<id> | 获取单个用户信息。 |
| POST | /users | 创建用户。请求体:username、password、display_name、is_admin、permissions(标志 → 布尔值映射)。 |
| PUT | /users/<id> | 更新用户。请求体:display_name、password、is_admin、is_active、permissions 的任意子集。不能移除自身管理员权限或停用自身账号。 |
| DELETE | /users/<id> | 删除用户。不能删除自身账号。 |
对话(Chat)
所有对话端点位于 /api/chat/(而非 /api/v1/)。客服端点需要 can_chat_workspace;运营者端点需要 can_chat_operator。
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/chat/sessions | 获取或创建会话。请求体:scope("org" 或 "workspace")、workspace_id(scope 为 "workspace" 时必填)。幂等操作 —— 如已存在同一(用户、作用域、工作区)的会话,则返回已有会话。 |
| GET | /api/chat/sessions | 列出会话。参数:scope、workspace_id。 |
| GET | /api/chat/sessions/<id>/messages | 分页消息历史。参数:before_id、limit(默认 50)。 |
| POST | /api/chat/sessions/<id>/messages | 发送消息。请求体:content。保存用户消息、启动底层群组运行,并通过 SSE 推送响应事件。同步返回 {message_id, run_id}。 |
| DELETE | /api/chat/sessions/<id>/messages | 清除会话消息历史,底层运行记录保留。返回 {deleted: 条数}。 |
| DELETE | /api/chat/sessions/<id> | 删除会话及其消息(级联删除)。底层运行记录保留。 |
未满足需求(Unmet Needs)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/unmet-needs | 列出未满足需求。参数:workspace_id、status(默认 "open")。需要 can_chat_operator。 |
| PATCH | /api/unmet-needs/<id> | 更新状态。请求体:status("dismissed" 或 "addressed")、addressed_by_run_id(可选)。需要 can_chat_operator。 |
设置
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /settings | 列出所有设置键值对 |
| GET | /settings/<key> | 按键获取单个设置 |
| PUT | /settings/<key> | 设置单个配置项 |
| PUT | /settings | 批量设置多个配置项 |
| POST | /settings/llm/test | 使用当前凭据测试 LLM 连接 |
hierarchy.json
群组的完整拓扑。由画布写入,由运行时读取并强制执行。
| 键名 | 类型 | 说明 |
|---|---|---|
swarm | 字符串 | 群组标识符(文件夹名称) |
entry_point | 字符串 | 接收传入事件的智能体 ID |
agents | 数组 | 所有智能体节点:id、layer |
edges | 数组 | 智能体间连接:from、to、kind、purpose |
skills | 数组 | 技能附加:agent、skill |
calls | 数组 | 智能体→调用者连接:agent、caller、purpose |
informs | 数组 | 智能体→通知者连接:agent、informer、purpose |
canvas_callers | 数组 | 画布上存在的调用者节点名称(可能未连接) |
canvas_informers | 数组 | 画布上存在的通知者节点名称(可能未连接) |
canvas_swarms | 数组 | 画布上存在的外部群组节点 ID(可能未连接) |
swarm_calls | 数组 | 声明的跨群组委托:agent、alias、swarm_id、purpose |
consultations | 数组 | 预留给未来的横向对等咨询连接边 |
{
"swarm": "invoice-intake",
"entry_point": "policy-agent",
"agents": [
{ "id": "policy-agent", "layer": "policy" },
{ "id": "finance-orchestrator", "layer": "orchestrator" },
{ "id": "invoice-executor", "layer": "executioner" }
],
"edges": [
{
"from": "policy-agent",
"to": "finance-orchestrator",
"kind": "delegate",
"purpose": "route invoice work to finance orchestrator"
},
{
"from": "finance-orchestrator",
"to": "invoice-executor",
"kind": "delegate",
"purpose": "execute invoice parsing and classification"
}
],
"skills": [
{ "agent": "invoice-executor", "skill": "parse-invoice" }
],
"calls": [
{
"agent": "policy-agent",
"caller": "finance-approval",
"purpose": "request human approval for invoices above 10000"
}
],
"informs": [
{
"agent": "invoice-executor",
"informer": "ops-notifications",
"purpose": "notify ops team when an invoice is successfully processed"
}
],
"canvas_callers": ["finance-approval"],
"canvas_informers": ["ops-notifications"],
"canvas_swarms": ["hr-onboarding"],
"swarm_calls": [
{
"agent": "finance-orchestrator",
"alias": "hr_lookup",
"swarm_id": "hr-onboarding",
"purpose": "look up employee onboarding status for invoice vendor verification"
}
],
"consultations": []
}
目录结构
swarmwright/
├── app/
│ ├── models/ — SQLAlchemy ORM(12 张表,含 chat_sessions、chat_messages、unmet_needs)
│ ├── api/ — Flask 蓝图(/api/v1;对话在 /api/chat/)
│ │ ├── workspaces.py
│ │ ├── swarms.py
│ │ ├── agents.py
│ │ ├── topology.py
│ │ ├── events.py
│ │ ├── triggers.py
│ │ ├── runs.py
│ │ ├── callers.py — 调用者/通知者节点 + 收件箱 + 通知
│ │ ├── knowledge.py
│ │ ├── skills_api.py
│ │ ├── files.py — 群组文件存储端点
│ │ ├── stream.py — SSE 事件流
│ │ ├── chat.py — 对话会话、消息、未满足需求端点
│ │ └── settings.py
│ ├── core/ — 业务逻辑(不导入 Flask)
│ │ ├── registry.py — 文件系统扫描器、层级缓存
│ │ ├── runtime.py — 拓扑强制执行的智能体运行
│ │ ├── file_store.py — 群组文件索引管理
│ │ ├── executor.py — 技能沙箱化
│ │ └── builtin_swarms.py — 内置群组模板的协调逻辑
│ ├── builtin_skills/ — 平台预设技能(只读)
│ │ ├── write_swarm_file.py / .yaml
│ │ ├── read_swarm_file.py / .yaml
│ │ ├── list_swarm_files.py / .yaml
│ │ ├── delete_swarm_file.py / .yaml
│ │ ├── http_get.py / .yaml
│ │ ├── http_post.py / .yaml
│ │ ├── kv_get.py / .yaml
│ │ ├── kv_set.py / .yaml
│ │ ├── get_datetime.py / .yaml
│ │ ├── send_webhook.py / .yaml
│ │ ├── create_workspace.py / .yaml — 运营者对话
│ │ ├── create_swarm.py / .yaml — 运营者对话
│ │ ├── draft_constitution.py / .yaml — 运营者对话
│ │ ├── patch_topology.py / .yaml — 运营者对话
│ │ ├── trigger_run.py / .yaml — 运营者对话
│ │ ├── list_runs.py / .yaml — 运营者对话
│ │ ├── read_run.py / .yaml — 运营者 + 客服
│ │ ├── list_unmet_needs.py / .yaml — 运营者对话
│ │ ├── list_workspace_swarms.py / .yaml — 客服
│ │ └── flag_unmet_need.py / .yaml — 客服
│ ├── builtin_swarms/ — 平台内置群组模板
│ │ ├── operator-chat/ — 平台作用域(实例化到 platform 工作区)
│ │ │ ├── meta.yaml
│ │ │ ├── hierarchy.json
│ │ │ └── agents/operator.md
│ │ └── concierge/ — 工作区作用域(每个工作区一个)
│ │ ├── meta.yaml
│ │ ├── hierarchy.json
│ │ └── agents/concierge.md
│ └── static/ — 原生 JS 前端(无构建步骤)
│ ├── index.html
│ ├── js/
│ │ ├── app.js — 路由
│ │ ├── api.js — fetch 封装
│ │ ├── sse.js — SSE 客户端
│ │ ├── views/ — 每个标签页对应一个文件
│ │ └── components/
│ │ └── chat-panel.js — 运营者和客服共用的对话面板组件
│ └── css/
├── docker/ — Dockerfile、docker-compose.yml、entrypoint.sh
├── migrations/ — Alembic schema 迁移
├── tests/ — pytest 测试套件
└── data/ — 挂载卷(不提交到 git)
├── swarm.db
├── .encryption_key
├── company/
│ ├── knowledge/
│ └── skills/
└── workspaces/
└── <workspace-slug>/
├── meta.yaml
├── knowledge/
├── skills/
└── swarms/
└── <swarm-slug>/
├── meta.yaml
├── hierarchy.json
├── agents/
│ └── <agent-id>.md
├── skills/
├── knowledge/
├── triggers/
└── files/ — 群组文件存储(无限嵌套)
术语表
| 术语 | 定义 |
|---|---|
| 智能体(Agent) | 具有宪章和层级的 LLM 驱动组件 |
| 调用者(Caller) | 阻塞式人机协作节点 —— 暂停运行等待决策 |
| 宪章(Constitution) | 定义智能体身份、角色和知识引用的 Markdown 文件 |
| 控制室(Control Room) | 运营仪表盘 —— 组织架构图 + 运行日志 + 触发控制 |
| 连接边(Edge) | hierarchy.json 中声明的连接,包含类型(escalate/delegate/report)和用途 |
| 入口点(Entry point) | 接收传入事件的智能体,执行的第一个节点 |
| 人工操作(Human Action) | 等待人工决策的挂起调用者请求 |
| 人工通知(Human Inform) | 来自通知者节点的非阻塞通知 |
| 通知者(Informer) | 非阻塞式人机协作节点 —— 发送通知后继续运行 |
| 层级(Layer) | 四种智能体角色之一:策略层 / 编排者 / 执行者 / 感知者 |
| 感知者(Perceptionist) | 只读感知智能体 —— 将外部现实映射为内部数据结构 |
| 用途(Purpose) | 解释连接存在原因的必填通俗语言字符串 |
| 运行(Run) | 响应单个事件的群组的一次执行 |
| 运行步骤(Run step) | 运行中记录的一个操作(智能体调用、技能调用、人工交互、违规) |
| 作用域(Scope) | company / workspace / swarm —— 可复用资源的三个层级 |
| 技能(Skill) | 可由执行者智能体调用的沙箱化 Python 脚本 |
| 群组(Swarm) | 处理一类工作的智能体集合,具有声明的拓扑结构 |
| 拓扑(Topology) | hierarchy.json 中声明的图 —— 在运行时无例外地强制执行 |
| 拓扑违规(Topology violation) | 被阻止的对未声明目标的调用 —— 记录为运行步骤,在 UI 中上报 |
| 内置技能(Built-in skill) | SwarmWright 预装的平台技能,在资源库 → 技能 → 内置中可见;只读但可在任意作用域覆盖 |
| 文件监视器(File Watcher) | 当匹配 glob 模式的文件出现或在群组 files/ 目录中发生变化时触发的触发器 |
| 群组文件(Swarm Files) | 每个群组的 files/ 目录 —— 智能体和人类均可访问的共享持久化文件系统,在数据库中建立索引 |
| 触发器(Trigger) | 产生事件的确定性脚本(心跳、监听器、调用或文件监视器) |
| 工作区(Workspace) | 类似部门的群组容器,提供资源作用域 |
| 别名(Alias,群组调用) | 在群组调用连接边上声明的简短标识符,调用方智能体在 invoke_swarm 操作中使用它来寻址目标群组 |
| 群组调用(Swarm call) | 对另一个群组入口点的拓扑声明式同步调用 —— 调用方阻塞等待目标返回结果 |
| 群组节点(Swarm node) | 代表可委托的外部群组的 ⬡ 画布元素;同工作区目标为青色,跨工作区为琥珀色 |
| 跨工作区委托(Cross-workspace delegation) | 目标群组位于不同工作区的群组调用;以琥珀色显示并带有 ↗ 标签,作为刻意的部门间耦合警告 |
| 运营者(Operator) | 随平台内置的平台级群组,为授权用户提供对话式界面,用于设计和操作平台 —— 创建群组、修改拓扑、触发运行 |
| 客服(Concierge) | 随平台内置的工作区级群组,每个工作区一个,将用户的自然语言请求路由到合适的群组,并将无法处理的请求记录为未满足需求 |
| 对话会话(Chat session) | 用户与对话群组(运营者或客服)之间持久化的对话线程。每个(用户、作用域)对应一个会话。清除会话仅删除消息行,不影响底层运行记录。 |
| 未满足需求(Unmet need) | 客服无法路由到任何群组的请求,记录在 unmet_needs 表中,作为组织反馈信号呈现给运营者 |
| 内置群组(Built-in swarm) | 随平台在 app/builtin_swarms/ 中提供的群组模板,每次启动时自动实例化。运营者的修改会被保留;"恢复默认"操作可从模板重新实例化。 |