Suna(现 Kortix)AI Management System 技术全景
- [一、从 Suna 到 Kortix:项目解决什么问题,最终能交付什么](#一、从 Suna 到 Kortix:项目解决什么问题,最终能交付什么)
-
- [1.1 它管理的不是一次对话,而是一套可版本化的工作环境](#1.1 它管理的不是一次对话,而是一套可版本化的工作环境)
- [1.2 管理界面与交付效果](#1.2 管理界面与交付效果)
- 二、系统架构与一次任务的完整数据流
-
- [2.1 技术分层与源码目录](#2.1 技术分层与源码目录)
- [2.2 一次 Session 怎样从请求变成可审核成果](#2.2 一次 Session 怎样从请求变成可审核成果)
- [2.3 Git 分支与 Change Request 是核心状态机](#2.3 Git 分支与 Change Request 是核心状态机)
- [2.4 Trigger:Git 配置怎样变成可恢复的自动执行](#2.4 Trigger:Git 配置怎样变成可恢复的自动执行)
-
- [两类常规 Trigger 与实验性 Monitor 共用 Session 触发链](#两类常规 Trigger 与实验性 Monitor 共用 Session 触发链)
- [Session Mode 决定自动事件怎样继承上下文](#Session Mode 决定自动事件怎样继承上下文)
- [Webhook 在进入 Agent 前先完成认证、过滤与幂等](#Webhook 在进入 Agent 前先完成认证、过滤与幂等)
- [调度器依靠事务、CAS、Lease 和 Dead Letter 保证可恢复](#调度器依靠事务、CAS、Lease 和 Dead Letter 保证可恢复)
- [三、Agent 怎样设计:Prompt、子 Agent、上下文、记忆与 RAG 边界](#三、Agent 怎样设计:Prompt、子 Agent、上下文、记忆与 RAG 边界)
-
- [3.1 Agent 的行为提示与 Manifest 授权为什么分开保存](#3.1 Agent 的行为提示与 Manifest 授权为什么分开保存)
- [3.2 OpenCode 是执行内核,Kortix 负责装配和运行边界](#3.2 OpenCode 是执行内核,Kortix 负责装配和运行边界)
- [3.3 从源码归纳四类上下文与持久状态](#3.3 从源码归纳四类上下文与持久状态)
- [3.4 当前核心不是向量 RAG,不要把"文件记忆"写成知识库检索](#3.4 当前核心不是向量 RAG,不要把“文件记忆”写成知识库检索)
- [四、工具、MCP、Skills 和浏览器怎样暴露给 LLM](#四、工具、MCP、Skills 和浏览器怎样暴露给 LLM)
-
- [4.1 不是所有能力都以同一种方式进入模型](#4.1 不是所有能力都以同一种方式进入模型)
- [4.2 Connector 默认先发现再调用,MCP 只暴露固定 Meta-Tools](#4.2 Connector 默认先发现再调用,MCP 只暴露固定 Meta-Tools)
- [4.3 Connector Gateway 把凭据、策略、审批和审计留在服务端](#4.3 Connector Gateway 把凭据、策略、审批和审计留在服务端)
- [4.4 浏览器自动化是沙箱能力,不是平台后端代替浏览器点击](#4.4 浏览器自动化是沙箱能力,不是平台后端代替浏览器点击)
- 五、快速使用与自托管部署
-
- [5.1 使用 Kortix Cloud 跑通第一个 Session](#5.1 使用 Kortix Cloud 跑通第一个 Session)
- [5.2 自托管是一套 Compose 控制平面,Agent 沙箱默认仍在外部 Provider](#5.2 自托管是一套 Compose 控制平面,Agent 沙箱默认仍在外部 Provider)
- [5.3 自托管上线前要明确的持久化、更新与镜像边界](#5.3 自托管上线前要明确的持久化、更新与镜像边界)
- 六、权限、并发与生产边界:怎样把演示变成可靠系统
-
- [6.1 权限是"人类角色 ∩ Agent Grant ∩ Connector Policy"](#6.1 权限是“人类角色 ∩ Agent Grant ∩ Connector Policy”)
- [6.2 沙箱隔离不等于可以忽略 Secret 和供应链风险](#6.2 沙箱隔离不等于可以忽略 Secret 和供应链风险)
- [6.3 一 Session 一沙箱利于并行,但源码没有给出可直接承诺的吞吐指标](#6.3 一 Session 一沙箱利于并行,但源码没有给出可直接承诺的吞吐指标)
- [6.4 适用场景与落地建议](#6.4 适用场景与落地建议)
- 参考资料
suna仍然是 GitHub 仓库名,但当前main分支的产品名、命令和官方文档已经统一使用 Kortix ,可替代 Claude Cowork 和 ChatGPT Work。官方仓库将它定位为 AI Management System(AI管理系统):用户发起 Session,平台为它创建独立分支和隔离沙箱,OpenCode Agent 在真实 Linux环境中读写文件、运行命令和调用外部系统,最后将值得保留的结果通过 Change Request 送回默认分支。
它用 Git 仓库保存 Agent、Skills、项目记忆、Trigger 和权限配置,让任务在独立分支与沙箱中运行,再通过 ChangeRequest 审核成果。本文基于固定源码,详解 Agent 编排、工具与 MCP 暴露、Cron/Webhook 自动执行、实验性Monitor、四种 Session 复用、浏览器沙箱、权限边界与自托管实践。
GitHub仓库:https://github.com/cmyk-labs/suna.git(如果这个仓库对你有帮助,欢迎在 GitHub 上点一个 Star ⭐ 支持一下。)
官方GitHub仓库:https://github.com/kortix-ai/suna
一、从 Suna 到 Kortix:项目解决什么问题,最终能交付什么
1.1 它管理的不是一次对话,而是一套可版本化的工作环境
普通聊天产品通常把重点放在"本轮回答是否足够聪明"。Kortix 把问题扩大为:Agent 怎样继承团队规则,怎样获得最小范围的工具和密钥,怎样在真实计算机中完成长任务,怎样让多人审核结果,以及怎样让后续 Session 复用已经沉淀的知识。
项目因此围绕一组相互关联的对象和入口组织:
| 功能对象 | 实际载体 | 与执行链的关系 |
|---|---|---|
| Project | Git 仓库与根目录 kortix.yaml |
保存 Agent、Skills、Memory、Connector 和 Trigger 的版本化配置 |
| Agent、Skills 与 Memory | .kortix/opencode/ 下的 Markdown、脚本和工具文件 |
分开描述"怎样工作"、按需加载的方法以及跨 Session 的项目知识 |
| Session | 一条独立 Git 分支 + 一个独立沙箱 | 隔离一次任务的文件、进程、运行环境和工作成果 |
| Connector、Secret 与浏览器 | Manifest 授权 + 服务端 Connection/Gateway + 沙箱能力 | 连接 SaaS、MCP、OpenAPI、GraphQL、HTTP、远程计算机和网页登录态 |
| Trigger 与 Channel | Cron、Webhook、实验性 Monitor、Slack 等入口 | 将定时或外部事件转换为 Session Prompt;Monitor 需显式开启实验能力 |
| Change Request | Session 分支到默认分支的真实 Git 合并 | 在成果进入团队事实源之前加入人工审核、Diff 和冲突检查 |
| 使用与部署入口 | Web、CLI、SDK、自托管 Compose | 创建和管理项目/Session,或把控制平面接入现有系统 |
它适合研究报告、演示文稿、数据分析、代码修改、运维巡检、销售或支持自动化等需要"读资料---使用工具---生成文件---提交结果"的工作。成果不是只能留在消息气泡里;它可以是代码、文档、表格、幻灯片、页面、Git 提交或外部系统中的受控操作。
图片来源:项目 GitHub 仓库固定提交中的 Kortix 官方展示动画。

这段动画串起了完整使用路径:创建项目与 Session,关联工具和 Skills,观察 Agent 在云端计算机中检索、编辑与执行,最后查看交付物。它更接近"可管理的数字工作环境",而不是一个只有对话框的聊天前端。
1.2 管理界面与交付效果
仓库提供了完整 Web 管理界面。项目首页用于创建 Session 和观察运行记录,Customize 区域管理 Agent、Skills、Connector、Secret、Channel、Schedule 和 Webhook;Session 页面还可展示文件、终端、预览页面、执行过程和 Change Request。
图片来源:项目 GitHub 仓库固定提交的 apps/web/public/images/landing-showcase/platform/。
|-----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
|
项目首页:创建任务并管理多个 Session |
Agent:Markdown Prompt、模式与工具行为 |
|
Skills:按需加载的领域方法与脚本 |
Channels:从 Slack 等协作入口发起工作 |
下面三张图展示的是 Agent 可以生成的典型成品,而不是三项固定业务模板。真正的能力来自沙箱中的文件工具、浏览器、Office/PDF 工具、代码运行环境和可按需加载的 Skills。
图片来源:项目 GitHub 仓库固定提交的 apps/web/public/images/landing-showcase/。
|-------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
|
研究与资料整理 |
演示文稿与视觉交付 |
表格与数据分析 |
二、系统架构与一次任务的完整数据流
2.1 技术分层与源码目录
当前仓库已经不是旧版 Suna 的 Python 主体。根目录通过 pnpm Workspace 管理多个应用与共享包,Web 使用 Next.js 16、React 19 和 TypeScript,API 是基于 Bun、Hono、Drizzle 与 PostgreSQL/Supabase 的 TypeScript 服务;OpenCode 负责 Agent Runtime,kortix-agent 守护进程负责沙箱内的启动、鉴权、PTY 与反向代理。
这套架构最关键的边界是"控制平面"和"执行平面"分开:
text
浏览器 / CLI / SDK
│
▼
Kortix API ─── PostgreSQL / Supabase Storage
│ │
│ ├── LLM Gateway
│ └── Connector Gateway ─── SaaS / MCP / OpenAPI / HTTP
│
▼
Sandbox Provider(Daytona / Platinum / E2B)
└── 独立 Session Sandbox
├── /workspace:Session Git 分支
├── kortix-agent:守护、鉴权、PTY、端口代理
├── OpenCode:Agent 循环与对话状态
└── shell / files / browser / document tools
| 层次 | 主要实现 | 关键职责 |
|---|---|---|
| 交互入口 | apps/web、apps/cli、SDK |
项目配置、Session 管理、执行观察、CR 审核和集成调用 |
| 控制面 | apps/api、LLM/Connector Gateway |
身份、项目、Session、授权、模型路由、连接和自动触发 |
| 数据与配置 | PostgreSQL、Supabase Storage、packages/db、Manifest |
保存业务状态、对象、审计记录以及 Git 内的版本化规则 |
| 执行面 | Sandbox Provider、kortix-sandbox-agent-server、OpenCode |
为每个 Session 准备隔离环境并运行 Agent、PTY 和文件工具 |
| 外部能力 | Connector、MCP、浏览器、远程计算机、模型供应商 | 提供 SaaS、网页和推理能力,受 Manifest、Gateway 与审批约束 |
text
suna/
├── apps/
│ ├── web/ # Next.js 管理端、产品页面与公开文档
│ │ └── content/docs/host/ # 自托管架构与使用文档
│ ├── api/
│ │ └── src/ # Bun/Hono 控制面 API 与领域逻辑
│ ├── cli/
│ │ └── src/self-host/ # CLI 自托管初始化与管理逻辑
│ ├── kortix-sandbox-agent-server/
│ │ └── src/ # 沙箱守护、OpenCode、PTY 与代理
│ ├── sandbox/ # 默认沙箱镜像与运行层资源
│ └── llm-gateway/ # 模型请求网关
├── packages/
│ ├── db/ # Drizzle Schema、迁移与数据访问
│ ├── sdk/ # Web、CLI 与集成共用客户端
│ ├── manifest-schema/ # kortix.yaml 类型与校验
│ ├── starter/
│ │ └── templates/base/.kortix/ # 默认 Agent、Skills、Tools 与 Memory
│ └── shared/ # 跨应用共享类型与逻辑
└── self-host/ # 自托管说明与 Terraform 资源
控制平面保存账户、项目、Session、授权、连接与审计;执行平面给每个 Session 一台独立沙箱。Connector 凭据由控制平面解析,不应进入沙箱;项目显式授权的运行时 Secret 则可能以环境变量注入,因此两者的风险模型不同。
官方仓库的自托管架构说明主要描述 Compose 控制平面与外部 Sandbox Provider 的关系,不是所有产品入口的完整架构图。目录划分进一步说明:Web、API、CLI 和执行守护进程可以独立演进,共享 Schema/SDK 保持协议一致,而真正有副作用的工作留在每个 Session 的沙箱和分支中。
2.2 一次 Session 怎样从请求变成可审核成果
源码中的真实主链路可以概括为:
text
创建 Session
→ 解析 project、agent_name、base_ref、sandbox template 与 provider
→ 校验账户并发上限、Agent 是否启用、必须连接的 Connector 是否可用
→ 计算 user role ∩ agent grant,解析允许注入的 Secret 与 CLI 能力
→ 创建 project_sessions / session_sandboxes 记录
→ 从默认分支切出以 session_id 命名的分支
→ 异步请求 Daytona / Platinum / E2B 创建沙箱
→ 注入项目、分支、Agent、Token、模型网关和允许的环境变量
→ kortix-agent 克隆仓库并启动 opencode serve
→ OpenCode 根据 Agent Prompt、上下文、Skills 和工具执行任务
→ Agent 提交并推送 Session 分支
→ 打开 Change Request
→ 人工查看 Diff、冲突与 Manifest 校验结果后决定是否合并
Session 的 session_id、分支名和 sandbox_id 使用同一个 UUID。它减少了"会话记录、工作分支、运行机器"之间的映射成本,也让日志和审计更容易沿同一标识串联。
Session 与沙箱还有两套状态。当前 Session 流程实际写入 provisioning、running、stopped、failed;沙箱则使用 provisioning、active、stopped、error、archived。枚举中虽然还有 queued、branching、completed,当前流程并不写入,客户端不应把它们当成活跃生命周期。
2.3 Git 分支与 Change Request 是核心状态机
任务运行时不会直接写默认分支。Agent 在 Session 分支中实验、安装依赖、修改文件和提交,只有推送到远程的 Git 内容才是跨沙箱销毁仍可恢复的记录。Stop/Resume 保留同一个沙箱身份与文件系统,Delete 会销毁沙箱;没有 Commit + Push 的临时文件会随之丢失。
Change Request 不是一条"建议记录",其 Diff、快进、三方合并和冲突检测都是真实 Git 操作:
text
open ── merge ──▶ merged(终态)
└── close ──▶ closed ── reopen ──▶ open
合并前,服务端会读取候选分支中的 kortix.yaml 并执行 Manifest 校验。无效配置返回 422 MANIFEST_INVALID;Git 冲突返回 409 和冲突文件列表。project.cr.open 与 project.cr.merge 是分离的能力,因此可以让 Agent 打开 CR,却不给它自我合并的权限。
2.4 Trigger:Git 配置怎样变成可恢复的自动执行
Session 与 Change Request 解释了"人发起一次任务"怎样运行,但 Kortix 还允许项目在无人打开聊天窗口时自动工作。当前 Trigger 不是只存在数据库中的后台任务:cron、webhook 与 monitor 的声明集中保存在 kortix.yaml 的 triggers 列表中,旧版 v1 项目才可能使用 kortix.toml。Git Manifest 是配置真源,数据库只保存调度和执行运行态,从而让 Agent、Prompt、模型、触发条件与 Session 策略随代码审查和版本回滚。
这里必须区分成熟度:在本文固定提交中,cron 与 webhook 是常规 Trigger;monitor 虽已进入 Manifest、数据库和执行代码,Feature Flag Registry 仍把它标为 experimental,且 monitors 默认关闭。它还依赖能够运行常驻 Monitor Box 的 Provider;固定实现只在配置 PLATINUM_API_KEY 时报告可用,因为 Daytona 会限制自动停止下限、E2B 的运行时长也不适合 24×7 常驻。因此,下文对 Monitor 的分析是固定提交中的实验设计,不表示任意部署开箱即用。
text
kortix.yaml / kortix.toml
└─ Trigger 配置:slug、type、agent、prompt、model、session_mode......
↓ 解析、校验、计算 schedule_revision
project_trigger_runtime
└─ enabled、next_fire_at、last_fired_at、last_error、pinned session......
↓ 到期槽或外部事件
project_trigger_executions / project_monitor_events
├─ Cron Execution:queued → running → succeeded/skipped/dead_lettered
└─ Monitor Event:pending → fired/skipped/failed
或因速率限制直接以 suppressed 入库
↓ fireGitTrigger
创建新 Session,或向既有 Session 持久化投递 Prompt
project_trigger_runtime 不是另一份人工维护的配置。Reconciler 会按项目重新读取 Manifest:新增或修改 Trigger 时 Upsert Runtime,并依据调度内容生成 schedule_revision 和下次执行时间;Manifest 中已经删除的 Slug 会从运行态目录移除。这样调度器可以高频读取数据库,不必每个 Tick 拉 Git,也不会为了更新 last_fired_at 不断向仓库制造提交。
两类常规 Trigger 与实验性 Monitor 共用 Session 触发链
| 类型 | 输入与触发方式 | 运行时关键点 |
|---|---|---|
cron |
六段 Cron 表达式加时区,或一次性的 run_at |
到期槽进入持久化 Execution Queue,再渲染 Prompt 并创建或复用 Session |
webhook |
POST /v1/webhooks/projects/{projectId}/{slug} |
使用项目 Secret 验证请求、生成幂等键、应用 Payload Filter 后立即触发 |
monitor(实验性) |
Monitor Box 监督仓库内的 run 命令,支持 poll 与 stream |
需显式开启 Feature Flag 并配置支持持久沙箱的 Platinum Provider;命令标准输出形成事件,Observer 再通过相同 fireGitTrigger 链路运行 Agent |
monitor 不是"另一种 Cron"。poll 按 interval 周期启动命令,stream 让命令持续运行;可选的 expect_event_within 会在过久没有事件时生成静默异常事件,避免监控进程卡死却无人察觉。Monitor 默认使用 reuse,而 Cron/Webhook 默认使用 fresh,因为持续监控事件通常需要累积上下文,普通定时或外部交付更适合相互隔离。
Session Mode 决定自动事件怎样继承上下文
session_mode |
实际行为 | 适合场景 |
|---|---|---|
fresh |
每次触发创建新 Session | 独立日报、一次性处理、互不相关的 Webhook |
reuse |
找到该 Trigger 最近一个未失败、未删除的 Session,并持久化投递新 Prompt | 连续巡检、长期积累上下文的自动任务 |
pinned |
优先投递到指定 session_id;Pin 失效时回退到可复用 Session,最后才新建 |
持续唤醒一条人工选定会话 |
keyed |
用 session_key 模板从 Payload 派生 Key,每个客户、聊天或仓库复用自己的 Session |
WhatsApp/SMS、客户工单、按仓库归档的事件流 |
keyed 不是把所有事件塞进一个共享会话。例如 session_key: "{``{ body.data.chat_jid }}" 会让不同 Chat ID 进入不同 Session;如果模板无法得到非空 Key,代码降级为 fresh,避免把所有异常 Payload 错误聚合到同一上下文。复用与 Pin 路径也不会直接进行一次易丢失的内存调用,而是写入持久化 continue_session 命令,由生命周期队列重试和退避;Session 已失败或软删除时则创建新 Session。
Webhook 在进入 Agent 前先完成认证、过滤与幂等
Webhook 的 secret_env 只引用 Project Secret 名称,真实 Secret 由服务端读取。首选认证是对原始请求体 计算 HMAC-SHA256,接受 X-Kortix-Signature 或 GitHub 兼容的 X-Hub-Signature-256,比较过程使用 timingSafeEqual。对于不能签名请求体的系统,在没有签名 Header 时也支持 X-Kortix-Token 或 Authorization Bearer/Basic 的共享 Token 回退;两条路径都必须知道同一个 Trigger Secret。
认证通过后,Payload 才进入 Prompt Template、session_key 和 filter。Filter 是 Payload 路径到期望值的映射;不匹配时接口返回 200 skipped,而不是返回 4xx 诱使上游重试。它最重要的用途是防止自动回复环路:只接受 direction=inbound,就能阻止 Agent 自己发出的 outbound 消息再次唤醒自身。
Webhook 优先使用 X-Kortix-Delivery-Id、X-GitHub-Delivery 或 X-Request-Id 生成幂等键;缺失时退化为请求体、签名和认证指纹的 SHA-256。相同交付即使因网络超时被上游重发,也会沿同一幂等键收敛,而不是重复创建 Session。
调度器依靠事务、CAS、Lease 和 Dead Letter 保证可恢复
Cron 到期时,next_fire_at 前移与 project_trigger_executions 插入发生在同一事务:进程崩溃不会出现"时间已经推进但任务没有落库"的丢失窗口。更新条件同时比较 Project、Slug、Schedule Revision 和旧的执行时间,构成 Compare-And-Swap;再配合唯一的 Schedule Slot 索引,多副本调度器同时看到同一任务时也只有一个能够成功认领。
系统重启后不会补发停机期间的每一个周期,而是把错过的重复槽合并成一次 Catch-up,并将 next_fire_at 推到未来,避免恢复时形成无界任务风暴。执行 Worker 使用带过期时间的 Lease 认领队列,失败后可再次认领;达到 5 次尝试仍未完成则进入 dead_lettered。Trigger Fire 还设置单次超时、批量并发上限、Scheduler Heartbeat 与停滞检测,防止某一个无法恢复的 Session 阻塞全局 Cron。
此外,项目元数据中的 triggers_paused 是控制平面的紧急停止开关:它不会修改 Git 中的 Trigger 声明,但 Cron Sweep 会跳过该项目,Webhook 会返回成功的 skipped,适合避免同一仓库部署到两个控制平面后重复执行。真正创建 Session 时仍会解析 Trigger 指定的 Agent,并应用该 Agent 在 Manifest 中声明的 Connector、Secret 与权限范围;自动触发不等于绕开 Agent Grant。
三、Agent 怎样设计:Prompt、子 Agent、上下文、记忆与 RAG 边界
3.1 Agent 的行为提示与 Manifest 授权为什么分开保存
Kortix v2 没有把所有设置塞进一个大 JSON。一个 Agent 由两部分组成:
text
.kortix/opencode/agents/researcher.md
├── frontmatter:mode、model、temperature、OpenCode tools/permission
└── Markdown body:系统提示词与工作方法
kortix.yaml
└── agents.researcher:connectors、secrets、skills、kortix_cli、sandbox、enabled
前者由 OpenCode 读取,回答"模型怎样做事";后者由 Kortix 控制平面读取,回答"这个 Agent 能接触什么"。二者只通过 Agent 名称关联。这种拆分避免把 Prompt 内一句"不要调用生产数据库"误当成真正的安全边界:行为约束可以改善模型决策,平台授权才负责强制限制。
下面是一个按最小权限收缩的简化配置,字段与当前 v2 Manifest 对应:
yaml
kortix_version: 2
default_agent: researcher
agents:
researcher:
connectors: [github-read, web-search]
connectors_required: [github-read]
secrets: none
skills: [competitive-analysis, presentations]
kortix_cli: [project.read, project.cr.open]
sandbox:
default: research
templates:
- slug: research
image: ubuntu:24.04
cpu: 4
memory: 8
disk: 50
connectors_required 必须是 connectors 的子集。启动前若无法解析必需 Connection,API 返回 409 CONNECTOR_CONNECTION_REQUIRED,避免 Agent 工作到一半才发现关键系统不可用。
3.2 OpenCode 是执行内核,Kortix 负责装配和运行边界
kortix-agent 在沙箱中运行:
text
opencode serve --port 4096 --hostname 127.0.0.1
同时将 OPENCODE_CONFIG_DIR 指向项目的 .kortix/opencode/。OpenCode 负责消息循环、工具调用、Primary Agent 和 Subagent;Kortix 负责 Session、沙箱、Git、Agent 授权、模型网关、Connector、Token、触发器和 CR。
项目支持两种不同粒度的并行协作:
| 方式 | 运行位置 | 适合场景 | 隔离程度 |
|---|---|---|---|
| OpenCode Subagent | 同一个 Session 沙箱内,由 Primary Agent 通过 Task Tool 调用 | 代码审阅、资料分析、测试等共享工作区的短子任务 | 共享文件系统与 Session,但可配置独立 Prompt 和工具权限 |
| Kortix Child Session | 通过 kortix sessions new 创建另一 Session |
需要独立分支、独立沙箱或长时间运行的并行任务 | 独立 Session、Git 分支与沙箱 |
默认 Starter 就提供了一个可读源码的例子:harness-reflector 定时汇总近期 Session,再并行调用只读 session-reviewer Subagent;后者只允许读取 Git 和 Session/CR 记录,返回结构化问题,最终由主 Agent 修改 Prompt、Subagent、Skills、Tools 或 Memory,并打开一条人工审核的 CR。
这不是一个固定的中心调度算法。编排规则主要写在 Agent Markdown 与 Skill 中,实际的子 Agent 循环交给 OpenCode;需要更强隔离时才升级为多个 Kortix Session。
3.3 从源码归纳四类上下文与持久状态
当前实现很容易被误写成"长期记忆数据库"。本文按数据载体和用途将相关状态归纳为四类;这是对源码的分析,不是 Kortix 官方命名的四层记忆架构:
| 类别 | 存储位置 | 生命周期 | 怎样进入模型上下文 |
|---|---|---|---|
| 当前对话上下文 | OpenCode 当前会话 | 当前 Agent 对话 | 由 OpenCode Runtime 管理 |
| Session 对话状态 | /opt/kortix/home 的 OpenCode Object Store |
同一沙箱 Stop/Resume 可继续;Delete 后不应依赖 | 恢复同一 Session Runtime |
| 项目记忆 | Git 仓库 .kortix/memory/*.md |
跨 Session、跨成员,随 CR 合并长期保存 | Agent 必须主动调用 memory view 读取 |
| 可审计事实 | Git Commit、Branch、CR、外部系统记录 | 取决于 Git 和外部系统 | 通过 Git、Connector、CLI 或文件工具检索 |
Starter Prompt 明确要求先查看 .kortix/memory/MEMORY.md 索引,再读取与任务有关的子文件;"Nothing is auto-injected" 是真实设计,不是文案细节。这样可以避免把整个公司知识都复制进每轮 Prompt,也让记忆的读取成本由任务相关性决定。
memory.ts 将 view/create/str_replace/insert/delete/rename 六类操作限制在 .kortix/memory 根目录。它还做了尾部分隔符路径边界校验、符号链接逃逸检查、0600/0700 权限以及临时文件 + fsync + rename 原子写入。记忆修改仍是普通 Git 文件变更,必须经过 Session 分支和 CR 才能成为默认分支上的团队记忆。
3.4 当前核心不是向量 RAG,不要把"文件记忆"写成知识库检索
当前提交没有实现类似"文档上传 → Chunk → Embedding → Vector DB → Reranker → 上下文拼接"的平台级 RAG 管线。仓库的模型目录中虽然列出了 Embedding/Reranker 型号,但这只说明模型 Catalog 能描述这些模型,不等于产品已经构建了知识库入库与检索系统。
当前上下文获取更接近工具增强的 Agent:
text
任务 Prompt
→ Agent 先读取项目 Memory 索引
→ 用 read / grep / glob / git 检索仓库文件与历史
→ 用 web_search / scrape_webpage / agent-browser 获取外部信息
→ 用 Connector 查询业务系统
→ 选择性加载 Skill
→ 将工具返回结果放入当前 OpenCode 对话
因此,设计这类 Agent 时应优先考虑文件组织、索引入口、Skill 描述、工具可发现性、上下文预算和证据引用。若业务需要海量文档的语义检索,需要通过外部 Connector/MCP 接入现有 RAG 服务,或在项目中另行实现索引管线;不能仅凭 .kortix/memory 目录就宣称已经具备企业知识库 RAG。
四、工具、MCP、Skills 和浏览器怎样暴露给 LLM
4.1 不是所有能力都以同一种方式进入模型
当前实现把扩展能力分为四条通道:
| 能力 | 配置或源码位置 | 暴露方式 | 上下文特征 |
|---|---|---|---|
| OpenCode 内置工具 | OpenCode Runtime | read/edit/bash/task 等 Tool Schema |
基础能力,直接参与 Agent 工具循环 |
| 项目本地工具 | .kortix/opencode/tools/*.ts |
OpenCode 自动发现 TypeScript Tool | Schema 直接暴露;模块在启动时加载,重依赖应延迟导入 |
| Skills | .kortix/opencode/skills/<name>/SKILL.md |
先发现名称与描述,任务匹配后按需加载正文和脚本 | 不把全部 Skill 正文注入每轮 Prompt |
| Connector/MCP | kortix.yaml、Connector Gateway、平台默认启用的 Connector MCP |
通过 CLI 渐进发现,或使用固定 Meta-Tools | 不把数千个外部 Action Schema 一次塞给模型 |
项目内的 web_search.ts 与 scrape_webpage.ts 展示了本地工具的工程取舍。它们分别使用 Tavily 和 Firecrawl,但 SDK 采用执行时动态 import():源码注释说明,OpenCode 启动会加载工具模块,若在顶层加载重型 SDK,会增加每个 Session 的冷启动时间。
Skills 的策略相反:OpenCode 先发现 Skill,Agent 在任务确实匹配时才读取 SKILL.md。Manifest 的 agents.<name>.skills 再将可加载范围收缩为 all、none 或名字列表。这是"渐进披露",不是在系统 Prompt 中拼接几十份完整教程。
4.2 Connector 默认先发现再调用,MCP 只暴露固定 Meta-Tools
对"工具、MCP、Skills 是先路由还是全量一起给 LLM"这个问题,当前代码给出了清晰答案:
- Skills:按需加载,不全量注入正文;
- 项目本地工具:由 OpenCode 直接发现其 Tool Schema;
- 外部 Connector Action:默认不把全部 Action 变成 LLM 工具,而是让 Agent 通过 CLI 先列举/搜索,再查看 Schema,最后调用;
- Connector MCP :沙箱守护进程以
KORTIX_CONNECTORS_MCP_ENABLED=1为注册门槛;当前控制平面默认开启该能力并自动向沙箱注入这个值,运维显式设置CONNECTORS_MCP_ENABLED=false时才全局关闭。即使开启,也只暴露一组固定 Meta-Tools; - 原生 OpenCode MCP :用户也可以在
opencode.jsonc中配置,遵循 OpenCode 自身机制。
Connector CLI 的典型路径为:
bash
kortix connectors ls
kortix connectors discover "send a weekly report to slack"
kortix connectors show slack.chat.post_message
kortix connectors call slack chat.post_message '{"channel":"...","text":"..."}'
可选 MCP Server 使用同一个数据面,固定暴露九个 Meta-Tools:
text
connectors # 列出本 Session 可用 Connector
discover # 按意图搜索 Action
describe # 获取一个 Action 的完整 JSON Schema、风险与说明
call # 调用 Action
connect # 为未连接的 Connector 生成一次性连接链接
request_secret # 生成由人填写密钥的短期链接
secret_call # 服务端代理带密钥的 HTTPS 请求
add_connector # 添加 Connector
remove_connector # 删除 Connector
这里的"按意图搜索"目前不是 Embedding 或 LLM Router。searchConnectorTools() 会将查询转为小写,先做完整子串匹配,再要求每个空格分词都出现在 tool + description 文本中,最后截取默认 20 条。因此它是基于子串与分词匹配的轻量词法搜索:成本较低、结果可解释,但同义词、跨语言和模糊意图的召回能力依赖工具命名与描述质量。
这套固定 Meta-Tool 设计解决了一个实际问题:即使某个 Pipedream、OpenAPI 或远程 MCP Connector 暴露数百个 Action,模型初始上下文也只需理解少量稳定入口。它先通过 discover 缩小范围,再用 describe 读取目标 Schema,最后 call。与"把全部 Action Schema 一次交给 LLM"相比,它明显降低了工具描述占用,但增加了一到两次发现调用。
4.3 Connector Gateway 把凭据、策略、审批和审计留在服务端
Agent 发起 call 后,不会直接读取第三方 Token。请求会经过:
text
Agent / CLI / MCP Meta-Tool
→ 校验当前 Session 的 agent grant 是否允许该 connector
→ Connector Gateway 解析 connector + action
→ 服务端选择 Project/User Connection 并解密凭据
→ 依次应用项目策略、Connector 策略和默认风险策略
→ always_run:直接执行
block:拒绝
require_approval:创建一次性审批记录并返回 202
→ 执行 Pipedream / MCP / OpenAPI / Postman / GraphQL / HTTP / Channel
→ 保存脱敏审计结果
→ 将结果返回 Agent
审批不是"本 Session 后续都允许"。Gateway 对 Connector、Action 和完整参数计算请求摘要;收件人、正文、URL 或其他参数变化后,旧审批不能复用。202 pending_approval 会返回审批链接,用户登录并具备项目权限后才能批准。决定通过持久回调送回 Session,不需要让原 HTTP 请求一直挂起。
需要注意,policy.default_mode 默认是 allow_all。若希望未匹配的写入/破坏性 Action 必须人工审批,应设置:
yaml
policy:
default_mode: risk
connectors:
- slug: stripe-read
provider: openapi
spec: https://raw.githubusercontent.com/stripe/openapi/24e4796f5aa12204d7e208ef447a5d11705b9b41/openapi/spec3.json
authorization_strategy: project
auth:
type: bearer
policies:
- match: "get_*"
action: always_run
- match: "*"
action: block
示例把外部 Stripe OpenAPI 定义固定到提交 24e4796f5aa12204d7e208ef447a5d11705b9b41,避免 master 更新后同一 Connector 配置产生不同 Action;升级规范时应重新审阅接口和策略匹配结果。
策略应按最坏副作用设计:读取客户数据也可能敏感,写入 CRM、发邮件、创建支付或删除资源更应使用白名单、参数约束和人工门禁。
4.4 浏览器自动化是沙箱能力,不是平台后端代替浏览器点击
当前默认 Runtime Layer 安装了 agent-browser 和 Chromium。对应 Skill 指导 Agent 先按需加载与当前 CLI 版本匹配的工作流,再通过 CDP、Accessibility Tree 和元素引用执行打开页面、点击、输入、截图、文件下载、登录状态复用或 Web 应用测试。
text
OpenCode Agent
→ 加载 agent-browser Skill
→ agent-browser open <url>
→ 获取 Accessibility Snapshot 与 @eN 元素引用
→ click / fill / press / screenshot
→ 文件和截图写入 /workspace
→ 通过 show 工具展示,或 Commit + CR 交付
agent-browser 是集成到沙箱的外部浏览器自动化工具,不能写成 Kortix 自研了整个浏览器引擎。Web 搜索与页面抽取也有单独的 Tavily/Firecrawl 工具:搜索、静态抽取和交互式浏览器分别解决不同问题,Agent 应先使用成本最低且证据足够的通道。
浏览器拥有真实登录态和网页操作能力,风险不低于 API Connector。生产项目应为浏览器任务使用专门账号、最小权限、独立环境和人工审批;不要让 Agent 在个人管理员浏览器会话中自由执行不可逆操作。
五、快速使用与自托管部署
5.1 使用 Kortix Cloud 跑通第一个 Session
当前官方 Quickstart 提供 macOS 和 Linux CLI,尚未提供 Windows CLI Binary。Windows 用户可以使用 WSL,或直接通过 Web 界面体验。命令行最短路径如下:
bash
# 1. 下载并审阅官方 CLI 安装器,再执行
curl -fsSL https://kortix.com/install -o kortix-install.sh
less kortix-install.sh
bash kortix-install.sh
# 2. 登录
kortix login
# 3. 创建一个项目并同步到 Kortix Cloud
kortix init my-ai-team
cd my-ai-team
kortix ship
# 4. 创建 Session
kortix sessions new --prompt "分析本周提交并生成一份带来源的项目周报"
# 5. 进入对话观察 Agent 工作
kortix sessions chat
# 6. 查看并人工合并 Change Request
kortix cr ls
kortix cr merge 1
kortix init 会生成 kortix.yaml 以及 .kortix/opencode/ 下的 Agent、Tool、Skill 和 Memory 基础结构。kortix ship 首次创建云项目并推送仓库,以后用于同步本地变更。Agent 完成工作后应提交、推送并打开 CR;没有审核前,默认分支不会改变。
完整成功判据是:Session 已进入可工作状态,沙箱中产生了预期文件或提交,Session 分支已经推送,Change Request 可以查看真实 Diff;执行 kortix cr merge 1 后,默认分支出现预期成果。只有聊天界面出现回答,但没有文件、分支或 CR,并不能证明这条交付链已经跑通。
第一轮不要同时开放所有 Connector 和 Secret。推荐顺序是:
- 用默认 Agent 和一个无副作用任务打通 Session、文件产出与 CR;
- 新建一个职责单一的 Agent Markdown,限制 Prompt 与工具;
- 在
kortix.yaml中只授予必需 Skill、Connector 和kortix_cliAction; - 为 Connector 设置只读或
risk审批策略; - 验证 Stop/Resume、失败恢复、CR 冲突和删除 Session 后的 Git 恢复;
- 再加入 Cron、Webhook、Slack 等自动入口。
5.2 自托管是一套 Compose 控制平面,Agent 沙箱默认仍在外部 Provider
自托管由一套 Docker Compose 运行 Frontend、Kortix API、LLM Gateway 与 Supabase 发行版;配置域名时再加入 Caddy 与 ACME TLS。默认 Agent Session 仍由 Daytona 提供,也可以配置 Platinum 或 E2B。换句话说,自托管控制平面不等于把 Agent 计算也放进同一台服务器,更不等于离线部署。
text
Internet
→ Caddy(域名模式,80/443)
├── Frontend
├── Kortix API
├── LLM Gateway
└── Supabase Kong
├── Auth
├── PostgREST
├── Storage
└── PostgreSQL
Kortix API ── 出站网络 ── Daytona / Platinum / E2B Session Sandboxes
Linux 服务器的一次性引导命令是:
bash
curl -fsSL https://raw.githubusercontent.com/kortix-ai/suna/56de37154b7aa00e6e172c691fb6aac36152ebfe/scripts/kortix-selfhost-up.sh \
-o kortix-selfhost-up.sh
less kortix-selfhost-up.sh
bash kortix-selfhost-up.sh --domain kortix.example.com --email ops@example.com
官方文档中的引导地址可能跟随 main 分支持续变化。上面改用本文已经审阅的固定提交,便于复现;生产执行前仍应检查脚本内容,再在测试主机验证环境变量、端口、域名和数据目录。
希望逐步检查配置时,使用手动路径:
bash
curl -fsSL https://kortix.com/install -o kortix-install.sh
less kortix-install.sh
bash kortix-install.sh
# 让 kortix.example.com 和 api.kortix.example.com 指向服务器,开放 80/443
kortix self-host init --domain kortix.example.com
kortix self-host start
kortix self-host status
kortix self-host logs
kortix self-host doctor
# 交互配置 Sandbox Provider Key 等必需连接
kortix self-host configure
没有域名时,可用 Cloudflare Tunnel 做评估:
bash
kortix self-host init --tunnel cloudflare
kortix self-host start
Tunnel URL 每次重启会变化,只适合试用。生产必须提供稳定的回调地址,因为远程沙箱需要主动访问 Kortix API;没有域名或 Tunnel,Session 无法运行。
5.3 自托管上线前要明确的持久化、更新与镜像边界
每个实例的核心持久化数据位于:
text
~/.config/kortix/self-host/<instance>/
├── docker-compose.yml
├── .env # 所有服务密钥与签名 Key
├── volumes/db/data/ # PostgreSQL
└── volumes/storage/ # Supabase Storage
项目当前没有独立备份系统,必须同时备份数据库目录、Storage 目录和 .env,并做恢复演练。kortix self-host uninstall 会删除实例目录及数据,执行前必须确认备份。
自托管实例默认跟随 stable 更新通道,也可以选择 latest 或固定版本。生产更适合固定经过验证的版本:
bash
kortix self-host update --tag <已验证版本>
官方 Compose 的 Updater 会拉取镜像、运行迁移再滚动替换。只有域名模式下的双副本才具备启动新副本后再停止旧副本的切换条件;单副本 Tunnel/本地模式会出现短暂停机。升级前应验证数据库备份、Manifest、Agent 启动、Connector、审批回调、CR 合并和至少一个真实 Session。
六、权限、并发与生产边界:怎样把演示变成可靠系统
6.1 权限是"人类角色 ∩ Agent Grant ∩ Connector Policy"
Kortix v2 对未声明的 connectors、secrets、skills 和 kortix_cli 采用 none。Starter 中的默认 kortix Agent 为了开箱即用,明确写了四个 all;这是一项模板选择,不是平台默认安全结论,生产项目应主动收缩。
一次受控操作至少经过三层:
text
用户 / PAT / Service Account 的项目角色
∩
kortix.yaml 中 agents.<name> 的 Connector、Secret、Skill、CLI Grant
∩
项目策略 + Connector 策略 + 本次人工审批
agent-scope.ts 明确将结果定义为 userRole ∩ agentGrant:Agent 不能超过启动它的用户,也不能超过自身 Manifest Grant。管理面 API 还区分浏览器登录、外部 PAT/Service Account、Session Scoped Token 和 Sandbox Service Token。
沙箱内最重要的两类 Token 不应混用:
| Token | 身份 | 用途 |
|---|---|---|
KORTIX_SANDBOX_TOKEN |
沙箱自身 | 守护进程控制面签名、短期 Git Clone Credential、执行 Lease 等沙箱身份路由 |
KORTIX_CLI_TOKEN |
启动者的项目级身份,并受 Agent Grant 收缩 | 在沙箱中调用 Kortix CLI、Connector 和项目 API |
Git Token 也不是静态注入。守护进程使用 Sandbox Token 向 API 获取短期 Clone Credential;推送只能进入 Session 分支,默认分支仍需 CR 合并。
6.2 沙箱隔离不等于可以忽略 Secret 和供应链风险
每个 Session 使用独立沙箱、分支和运行身份,但隔离强度依赖实际 Provider。自定义 Sandbox Image 还要遵循当前 Runtime Layer 约束:Debian/Ubuntu Base、不能占用 8000、不要设置会被覆盖的 ENTRYPOINT/CMD,不要在镜像中烘焙密钥。
Connector Credential 由 Gateway 服务端解析,原始值不会进入沙箱;项目 Runtime Secret 则会在 Agent 获得授权后以环境变量注入。后者可以被 Shell、子进程或恶意依赖读取,因此要做到:
- 一个 Agent 只获得本任务需要的 Secret Identifier;
- 数据库和云账号使用专用、短期、只读或最小权限凭据;
- Connector 优先于直接注入长期 Token,因为 Gateway 能集中审批、撤销和审计;
- 第三方 Skill、Tool、Docker Image 和安装脚本进入项目前先审查;
- 浏览器自动化使用专用账号,不复用个人管理员会话;
- 对外部网页、Issue、邮件和文档中的指令按不可信输入处理,防止 Prompt Injection 扩大工具权限。
6.3 一 Session 一沙箱利于并行,但源码没有给出可直接承诺的吞吐指标
架构允许不同 Session 使用独立分支和沙箱并发执行,控制平面也把 Provisioning 设计为异步。当前文档明确存在账户级并发 Session 上限,超过套餐限制返回 429;活跃 Turn 每 60 秒续租一次以阻止 Idle Reaper,中止或空闲后释放。
这些实现可以说明系统支持并行任务,不能据此宣称某个固定 QPS 或"稳定运行数千个 Agent"。实际容量还受以下因素限制:
- 账户并发上限和 Sandbox Provider 配额;
- 镜像 Snapshot 构建与冷启动时间;
- API、PostgreSQL/Supabase、LLM Gateway 的连接和资源;
- 模型供应商速率、Token 和费用限制;
- Connector 上游 API 限额与审批等待;
- 自托管服务器 CPU、内存、磁盘 IOPS、网络与更新方式。
生产容量应通过自己的任务组合压测,分别记录 Session 创建成功率、沙箱就绪时间、首个 Agent Token、工具调用时延、CR 交付时间、Provider/模型错误率和成本。不要把"独立沙箱"直接等价为"无限横向扩展"。
6.4 适用场景与落地建议
Kortix 适合以下项目:
- 需要在真实 Linux 环境中生成代码、文档、表格、幻灯片或网页;
- 希望把 Agent、Skills、流程和团队记忆作为 Git 文件审查;
- 需要多个专业 Agent/Session 并行,但成果必须通过人工 CR 进入事实源;
- 需要连接 SaaS、MCP、OpenAPI、GraphQL、HTTP、Slack 或远程计算机;
- 需要 Cron/Webhook 驱动的周期任务,同时保留权限、审批与审计;
- 希望自托管控制平面并自带模型 Key,但可以接受外部 Sandbox Provider。
它不是现成的向量知识库 RAG 平台,也不是默认离线的一体化 Agent 集群。如果首要需求是海量内部文档的 Chunk、Embedding、混合检索和 Rerank,应接入专门知识库;如果要求完全断网、所有计算都在本地或跨地域高可用,需要继续设计本地执行平面、模型、对象存储、数据库高可用、备份、监控和升级体系。
最稳妥的落地路线是:先让一个最小权限 Agent 在一个测试项目中生成可审核文件,再引入项目 Memory 与一个 Skill;随后接入只读 Connector,验证审批和审计;最后才启用写操作、定时触发、多 Session 并行和生产自托管。Kortix 真正值得借鉴的不是某个 Prompt,而是四个工程原则:配置进 Git、执行进沙箱、权限在服务端、结果经审核合并。
参考资料
- Suna/Kortix GitHub 仓库:https://github.com/cmyk-labs/suna
- Kortix 官方 GitHub 仓库:https://github.com/kortix-ai/suna
- Kortix 官方文档:https://kortix.com/docs/