新闻详情

新闻详情

首页 / 资讯中心 / 详情

Yuxi 项目 Workdir 与 Sandbox Runtime 基础:从独立存储域到 UserWorkspace 的架构演进

发布时间:2026/9/17 19:25:41来源:尧图网络
Yuxi 项目 Workdir 与 Sandbox Runtime 基础:从独立存储域到 UserWorkspace 的架构演进
Yuxi 项目 Workdir 与 Sandbox Runtime 基础从独立存储域到 UserWorkspace 的架构演进【免费下载链接】Yuxi可私有部署的多租户知识智能体平台统一 RAG、知识图谱、多智能体、MCP/Skills、沙盒与权限管理。Self-hosted knowledge agent platform for RAG, knowledge graphs and multi-agent workflows.项目地址: https://gitcode.com/GitHub_Trending/yu/Yuxi本文以仓库中已归档的技术决策记录 2026-08-18-project-workdir-runtime-foundation.md 为主体骨架结合其后继落地决策与 backend、sandbox provider、sandbox provisioner 等源码实现完整还原 Yuxi 平台Project Workdir 与 Sandbox Runtime 身份解耦这一关键架构演进先提出独立ProjectWorkdir存储域再被Workdir 归属 UserWorkspace的简化方案完全取代。读者将理解 Workdir、runtime scope、Skill 投影三者的职责边界以及沙盒挂载、generation 契约与权限校验的底层实现。一、文档历史定位一项被取代的架构决策该文档在仓库中处于archived已归档状态属于simplification简化类型决策。文档开头明确声明它已被 Workdir 归属 UserWorkspace 并取消独立 Project 存储域完全取代仅保留为历史背景。这意味着阅读本文时需要把握两层信息历史方案本决策记录的主体引入独立的ProjectWorkdirPostgreSQL 模型、runtime_scope_id执行树分组键、Sandbox generation 契约与按 uid 汇总的只读 Skill 投影演进结果后继决策放弃独立 Project 存储域让 Workdir 变成 UserWorkspace 下的一个相对路径Sandbox 挂载收敛为两个逻辑域。同时文档也记录了语义 Owner 的划分原则ProjectWorkdir与 Conversation/AgentRun 绑定由PostgreSQL model、repository 和 schema migration拥有Sandbox identity、generation 和挂载校验由agents/backends/sandbox/provider.py与docker/sandbox_provisioner/app.py拥有用户 Skill 投影由agents/skills/service.py拥有。这套谁拥有什么的划分正是后续所有实现落地的组织原则。二、问题旧 Sandbox identity 的多重耦合决策记录指出的核心问题是旧 Sandbox identity 同时混入了三类来源文件 thread历史文件所属的线程 ID 被当作运行环境标识Skills thread按线程复制出来的 Skill 文件来源每个 Run instance每次运行实例的临时环境。其后果有三文件授权、Agent 选择与运行环境生命周期互相耦合——文件属于哪个线程本应是文件系统的授权问题却被错误地提升为运行环境隔离边界用户 workspace 只有隐式路径没有可供未来多个 Conversation 共享的持久工作目录身份provisioner 缺少 generation 契约——无法防止旧的观察结果误删新创建的实例典型的 ABA 问题。此外Skills 文件按 thread 复制存在双重缺陷既不能表达用户授权全集一个用户的 Skill 权限是全量的而不是某个线程的子集也会在多 worker 同步共享来源时产生竞争与越界风险。三、决策分离文件身份与运行环境身份针对上述问题该决策提出了一套完整的身份模型其核心思想是让文件身份Workdir与运行环境身份runtime scope彻底分离。3.1 ProjectWorkdir持久化的文件身份PostgreSQL 使用ProjectWorkdir保存四类信息opaque ID、所属 uid、存储键storage key与物化状态materialization state。顶层 Conversation 创建时默认创建 Workdir子 Conversation 通过SubagentThread继承根 Conversation 的workdir_id跨用户绑定被拒绝——Project 与 uid 的归属关系是硬约束。这为未来多个 Conversation 共享同一持久工作目录提供了身份基础而不需要再次改变文件协议。3.2 runtime_scope_id执行树的运行环境身份AgentRun.runtime_scope_id持久保存根 Conversation 的 runtime scope。在此之后Sandboxhash、cache key、wire、Docker label、Kubernetes annotation 和工具连接一律不再使用file_thread_id或skills_thread_id当前 identity 由uid runtime thread 可选 instance组成Workdir 作为不可漂移的挂载约束——它约束这个运行环境挂载哪个目录但不参与身份哈希。这一设计直接回应了文件授权被错误提升为环境隔离边界的问题两个顶层 Conversation 即使绑定同一个 Workdir也只是共享文件绝不共享运行环境。3.3 generation 契约防止旧观察误删新实例provisioner 为每次 runtime incarnation运行实体返回 generation。所有涉及实例生命周期的操作——发现discover、缓存、删除、idle reaper、Kubernetes 409 恢复——都复核 identity/generation从而保证旧观察不能删除或接管新的同名实例。这是并发安全的基石。若删除了 generation 复核旧 worker 的延迟删除请求就可能误删新创建的 Sandbox。3.4 挂载契约Project/User/Skills 三个可选挂载Docker 与 Kubernetes 支持可选的 Project/User/Skills mount contractProject Workdir 在 Sandbox 内使用/home/gem/projects/project-opaque-id并作为显式 Workdir fixture 的默认目录Kubernetes contract 要求RWX PVC/subPath文档明确注明当前 shipping 文件主链路尚未切换到该可选 contract该切换属于后续决策的范围。3.5 Skills 授权投影按 uid 汇总的只读全集/home/gem/skills是按 uid 汇总的共享/内置授权全集只读投影个人 Skill 直接保留在 UserWorkspace不进入共享投影Agent 配置只控制 Prompt 和工具激活不改变 Sandbox identity 或文件可见集合——这是权限模型的关键边界投影刷新在 PostgreSQLuid advisory lock内重读最新授权再以共享卷flock 串行替换授权上下文缺失时 fail-closed默认拒绝绝不无授权也放行。3.6 投影的受限安全复制fd-relative O_NOFOLLOW共享 Skill 投影刷新使用从文件系统根逐组件O_NOFOLLOW的 fd-relative 快照只复制普通文件和真实目录。以下特殊项会导致删除旧 slug 投影并阻止本次刷新symlink 竞态Unix socketFIFO设备等特殊项。这套机制杜绝了经典 TOCTOU 攻击路径——symlink 指向文件系统根时任何基于字符串路径的复制都会越权而 fd-relative 打开每级目录都以O_NOFOLLOW打开后持有 fd 再进入下一级让攻击者无法在复制中途替换目录。文档同时指出personal Skill 的持久源与单一路径已由 Skill 持久源与只读投影收敛 接管本决策只保留授权投影的并发与安全基础。四、被拒绝的替代方案决策记录明确列出了四条被拒绝的路线及理由这些理由本身就是理解设计取舍的注脚方案拒绝理由继续让file_thread_id、skills_thread_id参与 Sandbox identity把历史文件 Owner 和 Agent 选择错误地提升为运行环境隔离边界在 4R-A 直接切换 uploads/outputs/Viewer历史数据尚未完成全量物化、缺少维护 fence 和 activation gate局部切换会产生按 Conversation 混跑与空目录假成功用 MinIO 或 s3fs 模拟实时 POSIX Workdir对象存储不拥有 rename、partial write、锁和多进程可见性所需的完整文件系统语义把 personal Skill 复制进共享授权投影个人目录由 UserWorkspace 直接提供投影只承载共享与内置 Skill五、后果与验证记录5.1 后果Project 文件身份与 Sandbox runtime identity 已分离未来 Project 只需让多个顶层 Conversation 指向同一workdir_id无需再次改变文件协议同 uid 的父子 Agent看到相同共享 Skill 投影与 UserWorkspace 个人 Skill但各自Prompt/工具仍保持选择隔离实时文件行为由后续 owning decision 负责本记录只保留 Workdir/runtime identity 与 Skills 投影基础Skills 投影刷新会对共享来源执行受限安全复制并跨 worker 串行化换取授权一致性真实 Kubernetes RWX 行为仍需目标集群 smokeCompose 和 Pod spec 测试不能替代该证据。5.2 验证数据决策当时的测试记录该决策在落地时拥有成体系的测试证据backend non-slow unit1377 passed, 26 skippedSkills 定向 unit60 passed真实 PostgreSQL Workdir/schema/runtime scope 与 advisory-lock 撤权 integration5 passed真实 Docker 双 Sandbox同 Workdir 文件互见且/tmp隔离Skills 跨 Sandbox 共享、跨 uid 隔离、只读写拒绝2 passedoutput revision 旧链路兼容 integration5 passedsymlink 交错、特殊文件、执行位、确定性两进程 flock、缺失授权上下文和 generation/ABA均有负向测试工程契约48 passedRuff check/format、git diff --check与 docs build 通过Darwin Unix socket 负控真实运行通过真实 Kubernetes RWX smokeNot run未执行。决策还明确了旧能力不存在清单Sandbox identity/wire/mount/tool 链路不再接受file_thread_id或skills_thread_idSkills 不再按 thread/Agent 选择创建文件投影personal Skill 投影不再使用会跟随 symlink 的复制路径。同时给出重新引入条件只有新的产品边界明确要求不同文件 thread 或 Skill 选择拥有独立运行环境并提供对应生命周期、授权和真实并发证据时才可重新引入。六、演进Workdir 归属 UserWorkspace 并取消独立 Project 存储域6.1 为什么放弃独立存储域后继决策 Workdir 归属 UserWorkspace 并取消独立 Project 存储域 指出把 Workdir 建模为独立的ProjectWorkdir存储域会为同一用户文件能力引入一整套平行设施单独的数据库表、storage key、物化状态、宿主机目录、容器挂载和 Kubernetes PVC与 UserWorkspace 形成两套根目录。同时新的 Thread 创建需求允许指定 UserWorkspace 内的目录独立 Project 根目录与该需求的真实权限边界不一致——选择一个 workspace 目录不应变成切换一个存储域和挂载域。6.2 新模型Workdir 是 UserWorkspace 下的相对路径最终落地模型是Workdir 保留为对话的逻辑工作目录但不再是独立存储域轻量业务 Project 保存一个相对于当前用户workspace的路径workdir_path projects/opaque-workdir-id宿主机和 Sandbox 的映射由 UserWorkspace Owner 统一完成宿主机user-data/shared/uid/workspace/workdir_path 容器内/home/gem/user-data/workdir_path/home/gem/user-data直接表示当前用户的 UserWorkspace 根不再在容器内重复一层workspace。默认 Workdir 的容器路径是/home/gem/user-data/projects/opaque-workdir-id个人 Skill 的容器路径是/home/gem/user-data/agents/skills/slug。Workdir 在该设计中是Conversation 的 cwd 和 Thread 文件 API 的默认视图不是同一用户不同 Thread 之间的文件授权边界。Sandbox 可以访问当前 uid 的整个 UserWorkspaceuid 挂载负责跨用户隔离Thread 文件 API 仍只暴露绑定的workdir_path。因此Project A 读取 Project B 的文件属于设计范围可用于引用同一用户的其他项目资料。系统 Prompt 向 Agent 提供当前workdir_path并明确默认写入约束来自 Prompt 实现整个 UserWorkspace 对当前 Sandbox 可见。可以读取其他目录作为参考未经用户明确要求 不得在当前 Workdir 之外创建、修改、移动或删除文件。该约束定义的是默认模型行为不构成安全或授权边界后端仍只强制 uid 隔离、路径不越界和具体工具拥有的权限。6.3 runtime_scope_id 与 Workdir 彻底分离在最终实现中runtime_scope_id是持久化在AgentRun上的执行树分组键当前取根 Conversation 的 thread ID根 Conversation 的 Run 使用自己的conversation_thread_idSubAgent Run 拥有自己的conversation_thread_id但继承创建者 Run 的runtime_scope_id同一runtime_scope_id的父子 Run复用一个 Sandbox runtime并共享进程、/tmp、运行时依赖和环境根执行树终态时worker 用该值确认没有仍活跃的子 Run仍在执行的子 Run 先保留cancel_requested与 owner/lease确认停止后再通过同一清理栅栏销毁 Sandbox两个顶层 Conversation 即使显式绑定同一个workdir_path也具有不同的runtime_scope_id因此只共享文件不共享运行环境或生命周期。在源码层面Sandbox provider 的_sandbox_key(uid, runtime_thread_id)返回f{uid}::{runtime_thread_id}作为连接缓存键sandbox_id_for_thread以f{uid}:{thread_id}的 SHA-256 摘要前 12 位作为 Sandbox ID——整个 identity 不包含任何 Workdir 信息。同时_touch_if_needed在每次探活时会复核record.workdir_path ! connection.workdir_path若同一 runtime scope 内 Workdir 发生变化则抛出SandboxIdentityMismatchError这就是Workdir 作为不可漂移的挂载约束的运行时实现。6.4 挂载边界收敛为两个逻辑域Sandbox 的持久文件挂载最终收敛为两个逻辑域当前用户 UserWorkspace - /home/gem/user-data rw 共享 Skill projection - /home/gem/skills roSandbox 的 cwd 设置为/home/gem/user-data/workdir_path。不再存在容器内的/home/gem/user-data/workspace中间层、独立的/home/gem/projects根目录、Project bind mount、DOCKER_PROJECTS_HOST_PATH或PROJECT_DATA_PVC。每个 Thread 只改变 cwd不改变挂载配置。uploads/、outputs/是当前 Workdir 下的目录约定/home/gem/user-data/workdir_path/uploads和/home/gem/user-data/workdir_path/outputs两者都按首次使用创建Sandbox provisioner 只验证挂载与 cwd不预建业务目录也不递归修改整个 UserWorkspace 权限。6.5 旧数据迁移与运行身份storage-migrator收敛为一次性旧布局迁移 Owner升级基线是 v0.7.1每个历史顶层 Conversation 获得 implicit Project 和确定性派生的 canonicalprojects/uuidv0.7.1 threaduploads/outputs导入对应 Workdir持久化的/home/gem/user-data/workspace/...改写为/home/gem/user-data/...未发布的ProjectWorkdir、FileStorageMaterialization与workdir_id中间 schema明确拒绝不执行兼容导入新安装直接使用 UserWorkspace 布局统一运行身份见 统一 Workspace 运行身份并删除权限补丁API、worker 与 Sandbox 数据面统一使用数值身份1000:1000访问同一 UserWorkspace新目录0o700、新文件0o600旧数据由 root storage migrator 在运行时启动前一次性收敛所有权与权限provisioner 不再承担运行时权限修复。七、源码佐证从决策到实现的落地链路7.1 Workdir 授权服务workdir_service.py 是当前 Workdir 语义的 Owner。核心数据结构WorkdirBinding携带conversation_id / thread_id / uid / project_id / workdir_path / directory_mode其中directory_mode仅有managed与linked两个合法值见workdir_binding_from_project的校验materialize_managed属性决定事务提交后是否物化目录。ensure_conversation_workdir_available实现了文档要求的提交后物化顺序managed模式调用ensure_bound_user_workdir物化目录linked模式调用Workdir.open_existing打开已有目录。resolve_authorized_conversation_workdir则对 Conversation 做uid与status deleted的双重校验后返回AuthorizedWorkdir——这与决策中跨用户绑定被拒绝的约束一一对应。7.2 Workspace 路径与 no-follow 安全workspace/paths.py 实现了决策中的路径安全契约normalize_workdir_path拒绝绝对路径、\、://以及空/./..组件ensure_bound_user_workdir通过_open_user_workspace_fd从配置根逐层open_directory_fd打开拒绝中间 symlinkELOOP/ENOTDIR被翻译为包含符号链接或非目录组件workspace_uid_dirname对含:等不安全字符的 OIDC subject 使用 SHA-256 摘要生成uid-hex目录名managed Workdir 命名兼容两种形式projects/uuid与projects/timestamp_project-id前8位[-N]见normalize_managed_workdir_path。workdir.py 中的Workdir类把浏览 scope 固定到持久化目录resolve_path拒绝..、\、://所有文件操作list/read/write/stat/copy/delete都通过Workspace的*_authorized_*方法执行并携带rootself.root_path防止越界。7.3 Sandbox runtime 路径契约agents/backends/paths.py 定义了SANDBOX_VIRTUAL_PATH_PREFIX默认/home/gem/user-data可用环境变量SANDBOX_VIRTUAL_PATH_PREFIX覆盖与/home/gem/skills两个 runtime 根。runtime_workdir_path把持久化 Workdir 标识映射为/home/gem/user-data/workdir_pathworkdir_runtime_paths返回 Workdir 内的outputs/large_tool_results与outputs/conversation_history目录is_runtime_path判断路径是否属于 runtime 命名空间。这些函数构成了宿主机路径、容器虚拟路径、Workdir scope三层转换的闭环。7.4 Provisioner 与挂载实现docker/sandbox_provisioner/app.py 是决策中provisioner 拥有 Sandbox identity、generation 与挂载校验的落地。值得注意的细节PERSISTENT_SANDBOX_MOUNT_ROOTS兼容性保留/home/gem/skills、/home/gem/user-data、/home/gem/projects三个历史挂载根MemoryProvisionerBackend在create时若existing.workdir_path ! normalized_workdir_path直接抛错delete校验expected_generation否则抛SandboxGenerationMismatchError——这就是 generation/ABA 防护的 reference 实现LocalContainerProvisionerBackend使用DOCKER_USER_DATA_HOST_PATH与DOCKER_SKILL_PROJECTIONS_HOST_PATH两个 host bind 路径容器内路径分别为/app/user-data与/app/skill-projectionskubernetes_storage_init_script生成 K8s PVC 子树的一次性身份迁移脚本以O_NOFOLLOW逐级打开、fchown/fchmod归一化到1000:1000并带 marker 目录.v072-runtime-identity防重入SandboxOperationPins让删除等待已开始的 proxy 请求排空SandboxQuiescenceGate在存储迁移停机后拒绝创建新的 Sandbox generation——与维护 fence 和 activation gate的决策一致。docker-compose.yml 中可以看到API/worker/storage-migrator 都 bind 同一YUXI_USER_DATA_DIR: /app/user-dataprovisioner 服务声明USER_DATA_PVC与SKILLS_PVC环境变量SANDBOX_VIRTUAL_PATH_PREFIX默认/home/gem/user-data——与决策中的单根语义完全吻合。7.5 Skills 投影的并发实现agents/skills/service.py 实现了决策中的并发与安全契约refresh_user_skill_projection_async先执行pg_advisory_xact_lockPostgreSQL 事务级 advisory lock重读最新授权再通过fcntl.flock(LOCK_EX)在共享卷的.locks目录上串行替换投影——advisory lock 内重读 flock 串行替换的双重串行化正是文档描述的实现形态。八、总结设计取舍与适用边界回顾整个演进可以提炼出三条贯穿始终的设计原则身份分离文件身份Workdir/Project与运行环境身份runtime_scope_id/Sandbox严格分离。文件属于谁、Agent 选择谁、运行环境是什么——三件事互不干扰单一根目录UserWorkspace 是唯一的 POSIX 字节与 uid 隔离边界Workdir 只是其中的相对路径任何第二个根独立 Project 根、/home/gem/projects挂载、workdir-files-id文件桥接都被删除并发安全显式化generation 契约防止 ABAadvisory lock flock 串行化投影刷新fd-relativeO_NOFOLLOW阻断 symlink 竞态fail-closed 保证授权上下文缺失时默认拒绝。同时要明确其边界同一用户不同 Thread 之间的文件互不可见不属于当前设计范围需要重新引入更窄的挂载或等价的强制访问控制Kubernetes RWX 行为仍需目标集群 smoke 验证Prompt 的默认写入约束不能阻止被注入的 Agent 跨 Project 写文件——这些是文档明示的接受风险而非缺陷。对开发者而言若要为 Yuxi 增加新的文件或运行环境能力应遵循当前 Owner 划分文件视图与授权看 workdir_service.py 与 workspaceSandbox 生命周期看 provider.py 与 provisionerSkill 投影看 service.py。【免费下载链接】Yuxi可私有部署的多租户知识智能体平台统一 RAG、知识图谱、多智能体、MCP/Skills、沙盒与权限管理。Self-hosted knowledge agent platform for RAG, knowledge graphs and multi-agent workflows.项目地址: https://gitcode.com/GitHub_Trending/yu/Yuxi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

DeepSeek证券做市报价与流动性管理:三层衔接与落地实践 2026/9/17 20:10:48

DeepSeek证券做市报价与流动性管理:三层衔接与落地实践

简介:这份530页的PDF方案围绕DeepSeek大模型在证券做市商报价与流动性管理中的实际应用展开,面向量化交易、做市策略研究、金融AI工程化等场景的读者。资源为单个PDF文件,压缩包整体约15.77MB,文档共52个大章节,支持目…

阅读更多 →
Daft on Ray 实战指南:从本地 Ray 集群部署到自动扩缩容(Flotilla 分布式执行深度解析) 2026/9/17 20:10:48

Daft on Ray 实战指南:从本地 Ray 集群部署到自动扩缩容(Flotilla 分布式执行深度解析)

Daft on Ray 实战指南:从本地 Ray 集群部署到自动扩缩容(Flotilla 分布式执行深度解析) 【免费下载链接】Daft High-performance data engine for AI and multimodal workloads. Process images, audio, video, and structured data at any s…

阅读更多 →
Python+pandas+ECharts:京东手机数据清洗与可视化实战 2026/9/17 20:10:48

Python+pandas+ECharts:京东手机数据清洗与可视化实战

简介:一份基于Python与ECharts构建京东手机销售数据分析与可视化系统的完整方案文档,适合电子商务从业者、数据分析人员以及计算机专业学生阅读参考。文档以电商平台真实数据为对象,完整覆盖爬虫采集、Pandas清洗、MySQL存储、Flask后端搭建与…

阅读更多 →
AR-NAR混合Transformer原理与YuE2实战部署指南 2026/9/17 20:10:48

AR-NAR混合Transformer原理与YuE2实战部署指南

1. 项目概述:从“YuE”到可复现的AR–NAR混合Transformer实践最近在Hugging Face上看到一个叫“YuE”的模型仓库,点进去发现它既不是常见的LLM微调项目,也不是单纯的图像生成模型,而是一个明确标注为“AR–NAR Mixture-of-Transfo…

阅读更多 →
基于MATLAB的汽车功率平衡图绘制与最高车速求解 2026/9/17 20:10:48

基于MATLAB的汽车功率平衡图绘制与最高车速求解

简介:一份以MATLAB为工具绘制汽车功率平衡图的讲解文档,面向车辆工程专业学生、汽车工程师以及MATLAB仿真学习者。文档从汽车动力学基本概念出发,详细给出发动机转速、扭矩、驱动力、滚动阻力与空气阻力等关键参数的计算公式,并整…

阅读更多 →
基于 TeamCity 报告端到端修复 IntelliJ 平台测试中的 Project 泄漏:`_LastInSuiteTest.testProjectLeak` 五阶段修复工作流 2026/9/17 20:07:47

基于 TeamCity 报告端到端修复 IntelliJ 平台测试中的 Project 泄漏:`_LastInSuiteTest.testProjectLeak` 五阶段修复工作流

基于 TeamCity 报告端到端修复 IntelliJ 平台测试中的 Project 泄漏:_LastInSuiteTest.testProjectLeak 五阶段修复工作流 【免费下载链接】intellij-community IntelliJ IDEA & IntelliJ Platform 项目地址: https://gitcode.com/GitHub_Trending/in/intelli…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞