Onyx Craft V1:把“AI 同事”做成可审计、可审批、可调度企业级 Agent 的技术路线图
2026/9/10 4:44:00 网站建设 项目流程

Onyx Craft V1:把“AI 同事”做成可审计、可审批、可调度企业级 Agent 的技术路线图

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

本文基于 docs/craft/craft-main-plan.md 展开,完整解读 Onyx 中 Craft——一个“了解公司上下文、在隔离沙箱里端到端完成工作”的 AI 协作面(AI coworker surface)——的 V1 总体规划:九大产品增强、九个工程子项目的边界与依赖、明确不做什么(Out of Scope),以及仓库级编码约定与跨项目决策。读完本文,你能理解 Craft 如何通过“权限化检索 + 出向流量拦截 + 审批 + 定时触发 + 运行审计”把 OpenCode 沙箱执行整合成一个可被企业合规接受的 Agent 产品,并知道如何顺着文档与源码路径继续深入每个子系统。

一、Craft 的定位与 V1 验收标准

Craft 是 Onyx 的“AI coworker”表面:一个知道公司上下文(company context)、并在隔离沙箱中把任务从头做到尾(end-to-end)的 Agent。主计划开宗明义指出,构成 Craft 的各个零件在 V1 之前就已经存在——独立的/craft/v1UI、/api/build后端路由、基于 OpenCode 的沙箱执行、工件(artifact)持久化、文件上传、内置沙箱技能,以及 Kubernetes 沙箱隔离。V1 的任务是把这些零件整合成一个连贯的、企业可批准(enterprise-approvable)的产品,而不是重建运行时(runtime)

对应到当前仓库,这些“已有基础”可以逐一找到落点:

  • 独立 UI:web/src/app/craft/v1(独立于主聊天表面的路由前缀);
  • 后端会话/工件/沙箱管理:backend/onyx/server/features/build,其中会话与消息在session/,工件与审批数据在db/,沙箱管理器在sandbox/
  • 出向拦截代理:backend/onyx/sandbox_proxy(mitmproxy 基座,含身份解析、凭证注入、请求评估与 MCP JSON-RPC 分类);
  • 定时任务框架:backend/onyx/background/celery/tasks/scheduled_tasks/tasks.py;
  • 自托管 Docker 编排:deployment/docker_compose/docker-compose.craft.yml(install.sh --include-craft会将其接入主编排)。

V1 的验收标准(The bar for V1)一句话概括:用户(或定时触发器)给 Craft 一个 prompt 之后,Agent 能用 Onyx 级“带权限的检索”读取公司知识,能通过 Onyx 管控的边界调用外部系统——该边界在服务端注入密钥并把写操作挡在审批之后——最终产出持久化的工件,并留有清晰的审计轨迹。

这个标准拆解出来就是四条能力线:

  1. 权限化读取:检索结果按“运行者”权限过滤,沙箱拿不到语料本身;
  2. 受控的对外写入:密钥在 Onyx 侧注入,写/投递/破坏性操作默认被审批门控;
  3. 持久化产出:工件与运行记录可留存、可复查;
  4. 可追溯:每次运行都有可治理的审计层。

二、V1 的九大产品增强

主计划把 V1 范围明确收敛为九项产品级增强,每一项都直接服务于上面的验收标准。

2.1 沙箱内的 Onyx 混合检索(Hybrid Search)

第一项增强是用第一方检索工具替换旧版files/语料同步:把 Onyx 混合检索直接暴露给沙箱内的 OpenCode Agent,其行为与 Onyx 应用内常规检索工具完全对齐,并且作用域限定为“当前运行用户”的权限。

细节文档 docs/craft/features/search/craft-search.md 给出了关键的实现决策:沙箱不直连 Onyx API 或任何集群内部服务,而是把随沙箱镜像分发的onyx-cli当作一个普通“互联网客户端”来调用;检索请求与其他流量一样,出向经过 egress 代理,代理识别出这是 Onyx 检索流量后,在服务端注入一个按作用域颁发的 Onyx PAT(个人访问令牌)再转发。凭据因此始终留在沙箱外,而检索仍以沙箱对应用户身份执行。文档还特意强调,多走一跳互联网是有意为之:沙箱不应能主动向集群内任何东西发起连接,所以即便是第一方 Onyx API 调用,也必须走与其他网络流量相同的外部出口路径。

这与主计划中“移除对遗留files/公司知识目录的全部引用”的决策一致——检索替代了“把语料搬进沙箱”,权限边界也因此从文件系统变成了 Onyx 自身的权限体系。

2.2 真实的沙箱隔离:Docker Compose 后端

第二项增强是为自托管(self-hosted)场景补齐沙箱隔离:在已有的local(仅开发用)与kubernetes(云端)之外,新增docker后端,由后端直接控制 Docker,不再引入独立的 runner 微服务dockerkubernetes复用同一族沙箱镜像,保证技能、模板、OpenCode、LibreOffice、Python、Node 在不同部署形态下行为一致;本地快照使用 docker volume 或现有 file-store 抽象。自托管文档中应要求dockerkuberneteslocal明确只是开发模式、不作为安全承诺对外宣传。

仓库中对应实现已经落地:

  • Docker 后端管理器:backend/onyx/server/features/build/sandbox/docker/docker_sandbox_manager.py;
  • Kubernetes 后端管理器:backend/onyx/server/features/build/sandbox/kubernetes/kubernetes_sandbox_manager.py;
  • 沙箱镜像(含 OpenCode 插件与模板):backend/onyx/server/features/build/sandbox/image/Dockerfile;
  • 自托管部署编排:deployment/docker_compose/docker-compose.craft.yml,其中沙箱被限定在独立的onyx_craft_sandbox网络中;
  • 开发态本地运行指南:docs/craft/dev/local-compose-craft.md、docs/craft/kubernetes/craft-eks-runbook.md。

2.3 一等公民的技能系统(Skills)

第三项增强是数据库支撑、版本化、可分享的技能包(skill bundles):技能以版本化 bundle 形式存放在现有 file store 中,沙箱初始化时被物化(materialize)到.opencode/skills目录。管理员可以启用/禁用内置技能、上传自定义 bundle,并按组织或按组授权;用户可以把技能“钉住”(pin)到会话或触发器上。V1 的内置技能包括:演示/幻灯片(presentation/deck)、文档/报告(document/report)、仪表板/Web 应用(dashboard/web app)、图像生成(若配置了 provider)、Onyx 检索/研究技能。主计划刻意保持技能形态与 Codex/OpenCode 技能兼容,这样未来的“技能库”基本只是分发 + 信任元数据,而不是一套新运行时。

关键决策有两条:内置技能直接种子(seed)进数据库,使内置与自定义技能共用同一条管理/选择路径;V1 不提供浏览器内技能编辑(后续再议)。仓库中技能基础设施位于 backend/onyx/skills(含大量 XSD 模式与文档),沙箱镜像内则通过 backend/onyx/server/features/build/sandbox/image/opencode-plugins 下的 OpenCode 插件(如connect-app.tssession-proxy-tag.ts)承载运行期行为。

2.4 密钥与外部访问的出向拦截层(Egress Interception)

第四项增强是整个安全模型的核心:沙箱的 HTTP/S 出向流量被强制路由到 Onyx 管理的代理(通过HTTP_PROXY/HTTPS_PROXY环境变量),代理在服务端为白名单上游服务注入凭据,沙箱永远看不到原始 token。Onyx 的 CA 证书被信任进沙箱镜像,直连外部流量被阻断;技能只需调用普通的上游 URL(如https://api.linear.app/graphql),由代理完成“会话 → 授权(grants)→ 策略”的解析与请求分类(读/写/投递/破坏性/未知),对允许注入凭据的请求在服务端注入后再转发;非密钥类的普通互联网访问默认放行(pass-through)。

主计划为此定义了模型:CraftSecretCraftInterceptedServiceCraftInterceptedServiceGrantCraftEgressPolicy。这些是 V1 规划中的命名;从当前仓库结构看,对应实现落在 backend/onyx/sandbox_proxy 及其依赖的backend/onyx/db数据层(如 backend/onyx/db/external_app.py、backend/onyx/db/gated_app.py),具体策略与授权语义由管理员配置的外部 App / 策略表承载。

关键决策值得逐条强调:

  • V1 采用代理环境变量式拦截,而不是透明网络设备(transparent network appliance);
  • 沙箱永远收不到原始 token;
  • 无法明确分类的请求归为UNKNOWN默认需要审批(fail-closed 倾向);
  • 拦截层同时承担两个角色:密钥边界+外部写操作的审批执行点

这一“分类即门控”的实现在源码中非常直观。backend/onyx/sandbox_proxy/request_evaluator.py 的模块注释直接点出了安全边界的设计哲学:

The gate addon treats both aNonereturn and any matcher exception as "not gated" — the real security boundary is the proxy's iptables egress lockdown, not this heuristic.

也就是说,请求分类器(ExternalAppRequestEvaluatorMcpRequestEvaluator,见 request_evaluator.py)负责把出向请求归因到具体的外部 App / MCP 工具并给出策略判定(如 MCP 工具默认策略EndpointPolicy.ASK,无法解析的请求体直接DENY,见 request_evaluator.py),而真正的硬性边界是沙箱内的 iptables 出向锁定——启发式分类器失效时不会让未门控流量溜过去。凭证注入则由同目录下的 backend/onyx/sandbox_proxy/credential_injection.py 完成。更多设计说明见 docs/craft/features/egress-proxy-and-approvals/README.md 及 docs/craft/features/external-apps 下的外部 App 系列文档。

2.5 外部应用的 OAuth

第五项增强允许管理员注册“App”(例如 Linear、HubSpot、Google Calendar 或其他支持 OAuth 的自定义 API),让 Craft Agent 可以提示用户去授权。要点是:

  • OAuth 握手始终发生在 Craft UI 里,绝不在沙箱里
  • 取回的 access/refresh token加密存储在代理/凭证层,按“用户 × App”维度作用域化;
  • Agent 调用已注册 App 的 API 时,egress 代理解析“会话 → 用户 → App 授权”,服务端注入该用户的 access token,并在需要时刷新;
  • 管理员配置形态复用 Onyx 既有的 OAuth-for-actions(自定义工具)流程(client id/secret、auth/token URL、scopes、redirect URI)与用户同意(consent)UX。

每个 App 的定义包含上游 base URL、允许的 method/path 前缀、scopes 与审批策略——与CraftInterceptedService同构,只是凭据从“组织级密钥”换成“用户级 OAuth 凭据”。管理员可按组织或按组授权 App,但用户本人必须先完成 OAuth 握手,Agent 才能代其行动。若用户级 token 缺失或过期且不可刷新,Agent 的调用会收到一个结构化的 “needs auth” 响应,Craft UI 把它渲染为“连接应用”提示。

2.6 审批(Approvals)

第六项增强是把“高风险 Craft 操作”变成一等公民原语:外部写、投递(delivery)、破坏性操作、未知操作、以及定时运行中命中门控的动作。审批的执行分布在两处——egress 代理(管出站 HTTP)与 Craft 编排层(管第一方的发布/投递);而审批的审阅与通知都在 Craft 应用内完成:交互式运行用会话横幅(session banner),定时运行用运行详情面板,跨会话的待办汇总进收件箱(inbox)。被批准的请求携带幂等键经代理重放,保证重试不会造成重复写入。

主计划对审批的几条关键决策,是理解 Craft 安全模型的分水岭:

  • 审批在 V1 范围内;
  • 执行只在后端/代理路径上(enforcement in backend/proxy paths only)——prompt 提示词与 OpenCode 工具权限只是“引导”,不是审批边界
  • 默认允许会话/触发器所有者批准自己的写操作,管理员可覆盖此默认;
  • 请求快照加密 + 幂等键,支撑安全重放;
  • V1 不依赖 Slack/邮件通知(后续以技能方式提供)。

2.7 定时触发器(Scheduled Triggers)

第七项增强是“按调度运行的已保存 Craft prompt”,支持三种调度形态:run-once(一次性)、简单间隔(simple interval)、高级 cron。每个定时运行的执行链路是:

  1. 创建一个全新的 Craft 会话(不复用旧会话);
  2. 物化附件与技能;
  3. 经由后端 runner 运行 Agent(不依赖 SSE);
  4. 持久化工件与运行摘要;
  5. 通知 Craft 应用。

工程实现上,beat 任务以SELECT FOR UPDATE SKIP LOCKED原子认领到期触发器,随后以带expires=参数的run_craft_trigger任务入队;周期任务默认并发策略为SKIP_IF_RUNNING,run-once 与 run-now 为QUEUE_ONE;沙箱操作租约(lease)防止多个 Agent 运行共享同一个沙箱。

关键决策:每次定时运行都是新会话;V1 只有定时触发、没有事件触发;超时逻辑显式写在任务体内——因为 Celery 的 time limits 在线程池场景下不生效;处于WAITING_FOR_APPROVAL的运行会释放沙箱容量,避免“等人审批”占着 CPU。该项依赖审批子系统提供WAITING_FOR_APPROVAL状态、依赖拦截层提供写门控,细节见 docs/craft/features/scheduled-tasks/overview.md,对应任务代码在 backend/onyx/background/celery/tasks/scheduled_tasks/tasks.py。

2.8 共享管理 UI(Shared Admin UI)

第八项增强是围绕 Craft 本身的管理面,全部放在主应用内:

  • 管理端 Craft 页:启用 Craft、管理内置/自定义技能、管理被拦截服务与密钥、管理 OAuth Apps、管理审批策略、设置沙箱后端、查看组织用量;
  • 用户侧 Craft 页:审批收件箱、触发器列表/编辑器、运行历史、已连接应用页(管理 OAuth 授权并可撤销);
  • 只读的可用性/状态面板(模型、检索、技能、被拦截服务),让用户理解一次运行为什么能或不能启动;
  • 既有管理页仍是 LLM provider、connector、用户/组、文档摄入的唯一事实来源——Craft 不为这些领域增加并行的配置表面。

决策要点:Craft UI 保持“运营导向”而非“营销导向”;移除现有 demo 数据 UI 与后端路径;不重复造 connector/LLM/用户管理。

2.9 运行审计与可观测性

第九项增强是在现有 session/message/artifact 记录(它们已经能支撑交互式回放)之上,加一个紧凑的运行/审计层。每次运行持久化一组摘要元数据:user/tenant、session id、trigger id、模型、选中的技能/服务、审批计数、sandbox id/后端/租约、运行来源、开始/结束/耗时、工件 id、摘要;并额外写入索引化的事件记录:Onyx 检索调用、被拦截的上游调用、审批请求、技能使用、准入/限额(admission/limit)决策、通知尝试。

这一层的目标是为管理员与调试查询服务——“上周哪些运行用了 HubSpot?”“这个触发器为什么被跳过?”“哪些写操作被批准了?”——而不是为会话渲染服务。关键决策:不重复存储完整对话转录;永不存储原始密钥;prompt/工具参数按既有隐私模式脱敏;用于审批重放的完整请求快照是加密且短命的。

三、明确不做的事(Out of Scope)

主计划用一整节列出了 V1刻意推迟的事项及原因——这份“不做清单”本身是重要的架构信号:

推迟项原因
把 connector 文件同步进沙箱Onyx 检索已提供权限化读取,无需把语料搬进沙箱
Craft UI 里的一键集成安装器管理员应显式配置被拦截服务;“魔法安装器”未经产品验证就带来风险
Craft 专属的 LLM/connector/数据源配置主管理面板才是事实来源,Craft 只暴露可用性/状态
Demo 数据集 / demo 数据模式V1 从真实用户/组织上下文起步
按用例分叉的 UI(销售/支持/工程/高管)核心平台未定型前过于狭窄
重建 Agent 运行时OpenCode 够用;保留干净边界以便日后替换
把 Craft 合并进主聊天表面留在/craft/v1,保持 UX 与关注点分离
MCP 支持(作为产品方向)优先采用“拦截层 + 技能 + 原始 API 调用”的组合
事件触发(Slack、webhook、日历、文件变更)V1 仅定时触发,事件触发等待
把后端build/模块改名为craft/大规模改名只有迁移风险、没有产品价值
浏览器内技能编辑管理员上传 bundle,浏览器内创作放到之后

四、九个工程子项目的拆分与依赖

主计划把九项增强映射为九个“基本可独立推进”的工程子项目,并预先声明了耦合点:OAuth 与审批都触碰拦截层;触发器依赖审批

  1. Craft 的 Onyx 检索工具:以第一方 HTTP 工具暴露 Onyx 混合检索,行为与常规检索工具精确对等,检索以“会话/触发器所有者”身份执行;更新AGENTS.template.md(见 backend/onyx/server/features/build/AGENTS.template.md)让 Agent 用 Onyx 检索读取公司知识与上传文件,并删除对遗留files/目录的所有引用。关键决策:专用 HTTP 工具而非 MCP、行为精确对齐、按会话属主身份检索。
  2. Docker Compose 沙箱后端:如 2.2 节所述。
  3. 技能系统:如 2.3 节所述。
  4. Egress 拦截与密钥:如 2.4 节所述;与审批强耦合——拦截层是大多数写审批的执行地点。
  5. 外部 App OAuth:构建于 Egress 拦截之上(共用同一代理 + grant + 分类路径),写请求继承审批门控。
  6. 审批:如 2.6 节所述,细节文档同上 egress-proxy-and-approvals 目录。
  7. 定时触发:如 2.7 节所述,依赖审批与拦截。
  8. 共享管理 UI:如 2.8 节所述。
  9. 运行审计与可观测性:如 2.9 节所述。

依赖关系可以概括为一条链:拦截层(4)是安全底座 → OAuth(5)与审批(6)构建其上 → 触发器(7)编排审批状态 → 管理 UI(8)与审计(9)提供治理面;检索(1)、沙箱后端(2)、技能(3)相对独立。

五、仓库约定与已定案的跨项目决策

主计划末尾固化了一批“不再讨论”的决策与仓库级约定,是理解 Craft 代码风格与安全底线的关键。

沙箱永远不应收到:完整的 Onyx 文档语料、原始管理员密钥、长寿命用户凭据、审批绕过 token。它只收到:按会话作用域的 Craft token、会话上传/库文件、物化后的技能 bundle、OpenCode 配置,以及代理/信任配置。

审批执行必须位于 Onyx 可控路径(代理 + 后端编排);Agent prompt 与 OpenCode 工具权限只是引导,不是审批边界。

仓库约定(repo conventions),贯穿所有 Craft 相关工作:

  • OnyxError(而不是HTTPException);FastAPI 端点使用类型化返回,不使用response_model=
  • 所有 DB 操作位于backend/onyx/dbbackend/ee/onyx/db
  • 所有 Celery 任务使用@shared_task,且每次入队都带expires=——既有的直接沙箱文件同步入队应在检索/沙箱工作中被移除或补上过期时间;
  • 超时逻辑写在任务体内(Celery time limits 在线程池下不生效);
  • 任务变更后重启 Celery worker(无热重载)。

已定案的跨项目决策(settled cross-project decisions)共七条:

  1. Docker 沙箱后端采用直接 Docker 控制,不设独立 runner 服务;
  2. Onyx 检索以专用 HTTP 工具暴露给 OpenCode,行为与常规 Onyx 检索工具完全一致;
  3. 每次定时运行创建全新 Craft 会话;
  4. Slack DM 投递只能通过技能实现,不做成自定义 Craft 集成;
  5. 内置技能种子进数据库,内置与自定义共用一条管理/选择路径;
  6. 非密钥类互联网访问默认放行;
  7. 审批执行位于 Onyx 可控的后端/代理路径;审阅/通知位于 Craft 应用。

另外两条处理既有代码的原则:以现有 Craft/Build 代码为基础,集成而非重写backend/onyx/server/features/build/已拥有会话、消息、工件、沙箱初始化、上传与 OpenCode 流式能力);不要求向后兼容——Craft 还是 alpha,简化 V1 实现时可以接受丢失既有会话/工件/沙箱等状态,代价便宜时保留,但不为维持旧数据而扭曲设计或加迁移垫片;同时保留产品名 “Craft” 而不在 V1 重命名后端build/模块。

六、小型改进项与延伸阅读

主计划还单列了三项“较小改进”:测试不同的 Agent harness(Pi 与 OpenCode 的对比)、在保持 harness 灵活性的前提下移除 ACP 层、PowerPoint 生成增强。其中 ACP 的移除方向在 docs/craft/features/streaming 目录下有成体系的文档(如drop-acp-layer.mdopencode-serve-client.md)。

若想沿主计划深入某个子系统,以下仓库路径是最短入口:

主题入口
V0 架构背景docs/craft/legacy/v0_craft_architecture.md
检索实现docs/craft/features/search/craft-search.md
Docker Compose 沙箱docs/craft/docker/docker-compose-overview.md、backend/onyx/server/features/build/sandbox/README.md
拦截层与审批docs/craft/features/egress-proxy-and-approvals/README.md、backend/onyx/sandbox_proxy
外部 App(OAuth/策略)docs/craft/features/external-apps
定时任务docs/craft/features/scheduled-tasks/overview.md
沙箱镜像与网络docs/craft/infra、docs/craft/sandbox

七、小结

Craft V1 主计划的实质,是用三个不变量把已经存在的 Agent 零件拼成企业级产品:密钥与语料永不进沙箱(出向代理 + 权限化检索)、写操作永不绕过 Onyx 可控路径(拦截层即审批执行点)、每次运行永不失去可追溯性(新会话 + 运行审计层)。它同时用 Out-of-Scope 清单和七条已定案决策,把 V1 的边界钉死——不重建运行时、不合并聊天表面、不做事件触发、不在 Craft 里复制管理面板。对贡献者而言,主计划 + 各 feature 细节文档 +backend/onyx/server/features/build/backend/onyx/sandbox_proxy/源码,构成了一个从“产品决策”一路可追踪到“代码执行”的完整阅读路径。

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询