<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Durable-Object on 奇诺分享 | 重在分享</title>
        <link>https://blog.ccino.org/tags/durable-object/</link>
        <description>Recent content in Durable-Object on 奇诺分享 | 重在分享</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Thu, 06 Aug 2026 08:00:00 +0800</lastBuildDate><atom:link href="https://blog.ccino.org/tags/durable-object/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>每个 Agent 一台“电脑”还不够：Cloudflare Computer 真正要统一的是 Workspace</title>
        <link>https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/</link>
        <pubDate>Thu, 06 Aug 2026 08:00:00 +0800</pubDate>
        
        <guid>https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/</guid>
        <description>&lt;img src="https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/cover.png" alt="Featured image of post 每个 Agent 一台“电脑”还不够：Cloudflare Computer 真正要统一的是 Workspace" /&gt;&lt;p&gt;“给每个 Agent 一台电脑”很容易让人点头。Agent 有 shell，有文件系统，有网络，再给它一个单独的环境，事情似乎就齐了。&lt;/p&gt;
&lt;p&gt;我看完 &lt;a class=&#34;link&#34; href=&#34;https://github.com/cloudflare/computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Cloudflare Computer&lt;/a&gt; 的 README，觉得它有意思的地方在另一处。Agent 跑一次命令不难，难的是它跑到第三步、第五步，甚至换了执行环境以后，前面留下的文件、日志和产物还找不找得到。&lt;/p&gt;
&lt;p&gt;举个 README 里能对应上的场景。一个任务先写好 Markdown，后来要调用 &lt;code&gt;pandoc&lt;/code&gt; 生成 PDF。前半段可能在 Worker 里完成，后半段需要进有完整 Linux 用户空间的容器。文件若跟着前一个执行环境放，后面就要拷贝、同步、挂载。任务再失败一次，系统还得回头确认那份文件最后在哪儿。&lt;/p&gt;
&lt;p&gt;Cloudflare Computer 把这件事单独拎了出来。它先给任务留一个 Workspace（工作区），再让容器、Worker Shell 和 Worker JavaScript 按各自的能力接入。执行环境可以换，工作目录还在原处。&lt;/p&gt;
&lt;p&gt;这篇文章只根据项目的 GitHub README 和公开示例来讲。该项目明确写着 &lt;strong&gt;PREVIEW ONLY&lt;/strong&gt;，目前适合实验和原型，不能直接当作生产方案使用。接口和设计都有变化的可能，下面谈的是它已经公开的做法，不是对安全性或性能的背书。&lt;/p&gt;
&lt;h2 id=&#34;容器停了任务留下什么&#34;&gt;容器停了，任务留下什么
&lt;/h2&gt;&lt;p&gt;容器很适合给 Agent 干活。它能装依赖、跑编译器、执行测试，也能把不同任务隔开。碰到浏览器自动化、原生二进制、复杂语言工具链，容器通常绕不过去。&lt;/p&gt;
&lt;p&gt;可容器对长期任务有个很实际的问题。它擅长承接一次运行，文件和中间产物却常常跟着实例走。实例销毁、迁移或更换时，系统得想办法把现场搬出去。一个任务只跑十分钟时，这些处理看着不重。任务一旦跨越多轮工具调用，还要在不同环境之间切换，问题就会不断冒出来。&lt;/p&gt;
&lt;p&gt;我更愿意把一段 Agent 任务拆成三件事。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;执行环境决定命令在哪里运行，能用哪些进程、网络和系统工具&lt;/li&gt;
&lt;li&gt;Workspace 保存这个任务处理过的文件和产物&lt;/li&gt;
&lt;li&gt;调度程序根据当前步骤选择合适的后端&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这三个东西分开以后，任务从轻量 Worker 转到容器时，换的是执行能力，原来的目录不用搬家。&lt;/p&gt;
&lt;h2 id=&#34;cloudflare-把文件系统放进-durable-object&#34;&gt;Cloudflare 把文件系统放进 Durable Object
&lt;/h2&gt;&lt;p&gt;README 对 Cloudflare Computer 的描述很直接。它是一个运行在 Durable Object（持久对象）中的虚拟文件系统，权威状态放在 SQLite 里。&lt;/p&gt;
&lt;p&gt;Workspace 先提供文件系统。执行后端挂在 &lt;code&gt;workspace.runtime&lt;/code&gt; 上。项目也允许只创建 Workspace 而不注册任何后端，调用方只把它当文件系统用。&lt;/p&gt;
&lt;p&gt;统一的执行入口如下。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;backend&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;调用时传入 &lt;code&gt;backend&lt;/code&gt;。它决定 &lt;code&gt;source&lt;/code&gt; 是 shell 命令，还是 ECMAScript 模块。这个 API 本身并不神奇，真正值得看的是职责分开了。文件在哪儿，由 Workspace 负责。命令怎么跑，交给所选后端。&lt;/p&gt;
&lt;p&gt;README 还提到，一个 Workspace 可以用稳定 ID 注册多个后端，后端会在首次使用时连接。任务不用在创建时就押注某一种运行环境，后面的步骤可以按需要选。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/workspace-architecture.png&#34;
	width=&#34;1672&#34;
	height=&#34;941&#34;
	srcset=&#34;https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/workspace-architecture_hu_a5bd31aec99db740.png 480w, https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/workspace-architecture_hu_d72c3b30806dff7b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;同一份 Workspace 文件状态可交由不同执行后端处理&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/official-architecture.png&#34;
	width=&#34;1612&#34;
	height=&#34;1474&#34;
	srcset=&#34;https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/official-architecture_hu_6d6aef03bed4e20a.png 480w, https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/official-architecture_hu_64c8168a35563c1e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Cloudflare Computer 官方架构图&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;109&#34;
		data-flex-basis=&#34;262px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来源：&lt;a class=&#34;link&#34; href=&#34;https://github.com/cloudflare/computer/blob/main/docs/assets/arch.png&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Cloudflare Computer 官方文档&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;三种后端各做各的事&#34;&gt;三种后端，各做各的事
&lt;/h2&gt;&lt;p&gt;Cloudflare Computer 当前列出三种后端。它们服务的工作并不相同。&lt;/p&gt;
&lt;h3 id=&#34;container-留给真实-linux&#34;&gt;Container 留给真实 Linux
&lt;/h3&gt;&lt;p&gt;Container 后端会把 SQLite 中的状态投射到沙箱容器内的 FUSE 文件系统。容器侧的 &lt;code&gt;computerd&lt;/code&gt; 守护进程负责挂载，并通过 capnweb RPC 与 Durable Object 通信。&lt;/p&gt;
&lt;p&gt;完整 Linux 用户空间、真实二进制和网络访问，都属于这一类需求。README 中的 tutorial 做了一个具体演示。Agent 在 Workspace 里写 Markdown，容器直接对这份文件运行 &lt;code&gt;pandoc&lt;/code&gt;，产出 PDF。文件不需要先从一个临时目录复制到容器里。&lt;/p&gt;
&lt;p&gt;这条路有代价。容器提供了执行环境，却不负责回答 Agent 能不能访问某个域名、读取哪些文件、何时可以把结果发出去。网络出口、资源配额、密钥处理、审计和人工确认，仍得由使用它的系统自己补上。&lt;/p&gt;
&lt;h3 id=&#34;worker-shell-处理轻量脚本&#34;&gt;Worker Shell 处理轻量脚本
&lt;/h3&gt;&lt;p&gt;Worker Shell 在 Dynamic Worker 中运行 &lt;a class=&#34;link&#34; href=&#34;https://github.com/vercel-labs/just-bash&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;just-bash&lt;/a&gt;。它通过 Workers RPC 直接访问 Workspace，不另存一份文件，也不多走一次同步。&lt;/p&gt;
&lt;p&gt;整理目录、读写文本、小型构建步骤，这些任务未必需要完整容器。能在受限 shell 里完成，就没有必要为它启动更重的环境。反过来，任务真需要系统二进制和复杂依赖，硬塞进轻量 shell 只会多出兼容问题。&lt;/p&gt;
&lt;p&gt;这里没有万能后端。任务要什么能力，系统就给到什么能力，通常更省事。&lt;/p&gt;
&lt;h3 id=&#34;worker-javascript-把步骤写成模块&#34;&gt;Worker JavaScript 把步骤写成模块
&lt;/h3&gt;&lt;p&gt;Worker JavaScript 会在新的 Dynamic Worker 中运行 ECMAScript 模块。README 提到结构化输入和结果、持久的相对导入、已配置的库，以及由 Workspace 支持的 &lt;code&gt;node:fs/promises&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;对用 JavaScript 或 TypeScript 调工具的 Agent 来说，这种形式很实用。一个步骤可以读 Workspace 里的文件，算出结构化结果，把新产物再写回去。比起把一长串 shell 字符串交给模型，它通常也更容易约束输入和输出。&lt;/p&gt;
&lt;p&gt;分析、编辑、转换和构建，本来就不要求同一种运行能力。把它们都塞进一个大容器，或都压进一个很轻的 Worker，最后都会碰到不舒服的地方。&lt;/p&gt;
&lt;h2 id=&#34;文件状态比一次执行更难处理&#34;&gt;文件状态比一次执行更难处理
&lt;/h2&gt;&lt;p&gt;Agent 写长任务时，真正麻烦的上下文有不少落在文件系统里。源码、临时脚本、下载内容、测试报告、失败日志、生成的制品，还有一轮轮修改留下的版本，都在里面。&lt;/p&gt;
&lt;p&gt;这些文件没有稳定归属，恢复任务时就容易犯难。日志里写着某个容器失败了，开发者仍要追问，当时输入是什么，改过哪些文件，产物有没有出来，下一次该从哪个目录继续。&lt;/p&gt;
&lt;p&gt;Cloudflare Computer 的做法很朴素。Workspace 保存权威文件状态，容器和 Worker 只负责进去干活。这样能带来一些实际好处。&lt;/p&gt;
&lt;p&gt;轻量 Worker 写下的内容可以交给容器继续处理，容器生成的文件也留在同一个目录。后续加一类后端时，状态保存方式不用一起推倒。出了错以后，排查至少有一个明确地点可以回去看输入、变更和产物。&lt;/p&gt;
&lt;p&gt;持久 Workspace 也不能变成一个无限堆积的目录。谁能访问，多久过期，任务结束后删什么，敏感文件能不能留，产物能不能外发，都要写进生命周期规则。文件留得住只是开始，后面的管理同样重要。&lt;/p&gt;
&lt;h2 id=&#34;先看能力再挑运行环境&#34;&gt;先看能力，再挑运行环境
&lt;/h2&gt;&lt;p&gt;大多数团队不必复刻 Durable Object、FUSE 和 Dynamic Worker 这套实现。真正能拿走的是先问任务需要什么。&lt;/p&gt;
&lt;p&gt;读写文本、生成结构化数据的步骤，可以放进受限的 JavaScript 模块或轻量环境。需要 shell 语义却用不到完整系统工具时，轻量 shell 可能够用。编译器、浏览器、原生依赖和特定网络访问出现后，再进容器或更强隔离环境。&lt;/p&gt;
&lt;p&gt;发送邮件、写业务系统、删文件、外发数据，属于另一类问题。这些动作即使在容器里运行，也仍然要经过权限和审批规则。运行环境解决命令怎么执行，权限策略决定这条命令能不能放行，别把两件事混在一起。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/runtime-selection.png&#34;
	width=&#34;1672&#34;
	height=&#34;941&#34;
	srcset=&#34;https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/runtime-selection_hu_c33fb44a9ce90883.png 480w, https://blog.ccino.org/p/cloudflare-computer-workspace-runtime-2026/imgs/runtime-selection_hu_94283529bf6ebf9d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;按任务能力选择 JavaScript 模块、Worker Shell 或容器&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;任务身份和 Workspace 上下文最好贯穿所有后端。这样排查一个失败任务时，开发者看到的是同一个任务留下的现场，不是一堆彼此无关的短命实例。&lt;/p&gt;
&lt;h2 id=&#34;preview-阶段先别急着上生产&#34;&gt;Preview 阶段先别急着上生产
&lt;/h2&gt;&lt;p&gt;Cloudflare 在 README 中把边界写得很清楚。Cloudflare Computer 目前是预览版，API 不稳定，设计也可能改。&lt;code&gt;docs/&lt;/code&gt; 下的规范偏向未来方向，项目方还特别提醒，不能把它们当成当前代码行为的完整描述。&lt;/p&gt;
&lt;p&gt;这类项目很适合拿来验证自己的问题。比如，一个 Agent 是否真要在几种运行环境之间切换，现有文件状态是否被某个容器绑得太死，轻量任务有没有被不必要地送进重型环境。&lt;/p&gt;
&lt;p&gt;生产环境则得先把任务和数据的边界说清楚。谁可以创建 Workspace，哪个任务可以访问哪份文件，网络怎样出，密钥怎样注入，失败后留什么，多久清理。项目给出了一种文件系统和运行时的组合方式，这些决定仍然在使用者手里。&lt;/p&gt;
&lt;p&gt;Cloudflare Computer 把 Agent 的“电脑”拆成了两部分。容器、shell 和 JavaScript Worker 提供不同的执行能力。Workspace 把文件和产物留在任务身边。&lt;/p&gt;
&lt;p&gt;任务越长、后端越多，这个拆分越有用。下次设计 Agent 运行环境时，可以先问一句，命令换个地方跑以后，前面做过的事还能不能接上。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;参考来源&#34;&gt;参考来源
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/cloudflare/computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;cloudflare/computer GitHub README 与示例&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/cloudflare/computer/tree/main/packages/computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Cloudflare Computer 的 &lt;code&gt;@cloudflare/computer&lt;/code&gt; 包说明&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/cloudflare/computer/tree/main/docs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Cloudflare Computer 文档目录&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.bestblogs.dev/en/article/8fe8f605eb&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;BestBlogs 对 Cloudflare Computer 的收录&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上来源用于说明 Cloudflare Computer 的公开项目定位、README 中列出的架构和示例，以及选题发现背景。它们不构成对稳定性、安全性或性能表现的独立审计。项目 README 已明确标注该软件仅为预览版，生产使用前需要自行验证兼容性、隔离和权限控制。&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
