enterprise 企业版扩展
OpenHands 不只是单机工具,还能做成企业级 SaaS。本仓 enterprise/ 目录就是这层。今天看它如何在核心之上加多租户、鉴权、计费、集成——而不改动核心。
OSS 模式 vs 企业版
回忆 Day 10:config.py 根据部署模式选不同实现——比如生命周期钩子,OSS 用 OssAppLifespanService(跑 Alembic 迁移),SaaS 用 SaasAppLifespanService(初始化 PostHog 埋点)。enterprise/ 目录就是这套"SaaS 增强"的集中地。
| 维度 | OSS(开源单机) | Enterprise(企业 SaaS) |
|---|---|---|
| 用户 | 单用户,无需登录 | 多租户,需鉴权 |
| 付费 | 免费,自带模型 key | 计费、预算、配额 |
| 集成 | 基础 | GitHub/GitLab/Slack 深度集成 |
| 协作 | 个人 | 会话分享、团队 profile |
enterprise/ 目录就是这圈"写字楼配套",装在同一套核心之外。enterprise 目录一览
enterprise/
├── server/
│ ├── routes/ # 22 个企业级路由:auth, billing, api_keys,
│ │ # github_proxy, agent_profiles, integration...
│ ├── auth/ # 鉴权(Keycloak)
│ ├── maintenance_task_processor/ # 后台维护任务
│ ├── rate_limit.py # 企业级限流
│ ├── sharing/ # 会话分享
│ └── verified_models/ # 认证过的模型清单
├── integrations/ # GitHub/GitLab/Slack/Jira 等深度集成
├── migrations/ # 企业版自己的 DB 迁移(135 个版本文件)
├── saas_server.py # SaaS 服务入口
├── run_budget_maintenance.py # 预算维护任务
└── storage/ # 企业级存储实现
saas_server.py(SaaS 入口)、自己的 migrations(比 OSS 多得多,135 个版本,因为企业功能表更多)。鉴权(Keycloak)
OSS 单机无需登录,企业版必须区分用户。enterprise/server/auth/ + routes/auth.py、oauth_device.py 实现了完整的身份认证(对接 Keycloak 这类身份平台,仓库里有 allhands-realm-github-provider.json.tmpl 即 Keycloak realm 模板)。
👨🏫 老师:登录只是第一步——难的是登录后,怎么保证"公司 A 的人绝对翻不到公司 B 的会话、沙箱、账单"。
👶 小白:那靠什么保证?
👨🏫 老师:靠把
user_id 编码进每一处资源标识(存储路径 {prefix}/{user_id}/...、沙箱归属)。鉴权先可靠地确定"你是谁"(Keycloak/SSO),之后所有访问都被这个 id 框住。就像写字楼门禁卡:刷卡确认你是哪家公司的(鉴权),电梯就只让你到自己那层(隔离)。alice 用 GitHub 账号登录 → Keycloak 发一个带身份的 token → 请求携带该 token 访问会话 → app_server 解析出 user_id=alice → 只在路径 .../alice/conversations/ 下找数据。若 alice 手改 URL 想访问 bob 的会话,因为她的 token 里是 alice,拼不出也无权读 bob 的路径 → 被拒。计费与预算
routes/billing.py + run_budget_maintenance.py 处理付费。回忆 Day 14 的用量/成本统计——企业版把它接到计费系统:用户消耗的 token 折算成费用、扣预算、超额限制。
max_budget_per_task、token 统计,在企业版里升级成完整的"配额 + 计费 + 预算维护"体系。run_budget_maintenance.py 是定时任务,定期结算/重置预算。把"每个动作花多少钱"一路追踪到"每个用户/团队的账单"——这是 AI 产品商业化的基础设施。Git 平台深度集成
enterprise/integrations/ + routes/github_proxy.py/bitbucket_dc_proxy.py/integration/ 提供和 GitHub、GitLab、Bitbucket、Slack、Jira 等的深度集成。
github_proxy.py 这类"代理"让 OpenHands 能安全地代表用户操作这些平台(用 OAuth 授权)。集成把 Agent 从"聊天框里的工具"变成"嵌入你工作流的自动化队友"。会话分享
enterprise/server/sharing/ 让用户能把一次会话(Agent 干活的完整过程)分享给同事看。
iter_events_for_export)"吗?正因为整个会话就是一串结构化事件,"分享会话"= 把这串事件给另一个人回放——天然可行。好的底层抽象(一切皆事件)让上层功能(分享、审计、回放)几乎白送。这再次印证第 1 周事件模型的威力。会话分享就像写字楼里"把会议全程录像发给没到场的同事":因为会议全程被完整录了下来(事件流持久化),转发录像给同事回放是天然可行的——不用额外重开一场会。
靠什么优雅扩展(不改核心)
企业版这么多功能,核心 app_server 却几乎没被改动。靠三个机制(都是前面学过的):
- 依赖注入(Day 06):企业版提供自己的 Service 实现(带鉴权的用户服务、企业存储),通过配置注入替换。
- 路由聚合(Day 10):企业路由作为额外的 router 挂上,不动 OSS 路由。
- 模式选择(Day 10):
config.py按 app_mode 选 OSS/SaaS 的不同实现(如 lifespan)。
今日小结 + 动手
🧠 今天你应该能回答
- OSS 和企业版的区别?同一核心怎么支撑两种形态?
- 企业版加了哪些能力?(鉴权/计费/集成/分享)
- 企业鉴权为什么是多租户安全的入口?
- 为什么"会话分享"能轻松实现?(回到事件流)
- 靠哪三个机制做到"扩展不改核心"?开闭原则是什么?
✋ 动手
ls enterprise/server/routes/ # 22 个企业路由
ls enterprise/server/ enterprise/integrations/
grep -rn 'SaasAppLifespanService\|app_mode\|AppMode' openhands/app_server/config.py | head
cat enterprise/README.md | head -40