<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Forkd on Huoke.Me - 跨境生活，从理财开始！</title><link>https://blog.huoke.me/tags/forkd/</link><description>Recent content in Forkd on Huoke.Me - 跨境生活，从理财开始！</description><generator>Hugo</generator><language>cn</language><lastBuildDate>Sun, 30 Aug 2026 00:08:00 +0800</lastBuildDate><atom:link href="https://blog.huoke.me/tags/forkd/index.xml" rel="self" type="application/rss+xml"/><item><title>forkd:100个Agent沙箱</title><link>https://blog.huoke.me/posts/forkd/</link><pubDate>Sun, 30 Aug 2026 00:08:00 +0800</pubDate><guid>https://blog.huoke.me/posts/forkd/</guid><description>&lt;blockquote>
&lt;p>🎯 一句话总结：forkd把一个已经启动并预热的Firecracker microVM保存成快照，再用写时复制快速生成大量隔离子机。它适合代码解释器、并行评测和多Agent执行，当前仍处于Alpha阶段，需要Linux、KVM和严格的网络权限配置。&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h2 id="-forkd是什么">📌 forkd是什么&lt;/h2>
&lt;p>&lt;img src="https://blog.huoke.me/img/posts/forkd/hero.webp" alt="forkd AI Agent microVM沙箱" title="forkd Agent沙箱运行时" width="1200" height="630" loading="lazy" decoding="async">
&lt;/p>
&lt;p>forkd是一个面向AI Agent并行任务的microVM沙箱运行时。父虚拟机只启动一次，提前加载Python依赖、JIT运行时、模型权重或浏览器；子虚拟机从父快照恢复，共享尚未发生变化的内存页。&lt;/p>
&lt;p>每个子机都是独立的Firecracker进程，由KVM提供虚拟化隔离。子机修改内存时，Linux内核通过&lt;code>MAP_PRIVATE&lt;/code>执行写时复制，变化后的页面才形成独立副本。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>能力&lt;/th>
 &lt;th>实现方式&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>隔离&lt;/td>
 &lt;td>每个子机独立Firecracker + KVM&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>快速启动&lt;/td>
 &lt;td>从预热父快照恢复&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>内存复用&lt;/td>
 &lt;td>Copy-on-Write页面共享&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>运行环境&lt;/td>
 &lt;td>完整Linux、TCP网络、apt与HTTPS&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>资源限制&lt;/td>
 &lt;td>cgroup v2，目前重点支持&lt;code>memory.max&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>接口&lt;/td>
 &lt;td>CLI、REST、Python、TypeScript、MCP&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>运维&lt;/td>
 &lt;td>systemd、Prometheus指标、JSON审计日志&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>许可证&lt;/td>
 &lt;td>Apache 2.0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>项目当前README标记为Alpha。磁盘格式和API在1.0之前仍可能变化，生产系统应固定版本并保留迁移方案。&lt;/p>
&lt;hr>
&lt;h2 id="-为什么能快速分叉">⚙️ 为什么能快速分叉&lt;/h2>
&lt;p>&lt;img src="https://blog.huoke.me/img/posts/forkd/branch-demo.webp" alt="forkd分叉运行中Agent的官方演示" title="forkd Branch与Agent fan-out演示" width="1200" height="796" loading="lazy" decoding="async">
&lt;/p>
&lt;p>传统虚拟机要重复启动内核、挂载磁盘、加载解释器并导入依赖。forkd把这些工作放在父机阶段完成：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>启动父microVM
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>加载Python、依赖、模型或浏览器
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>暂停并保存内存、磁盘和设备状态
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>多个子Firecracker进程映射同一快照
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>子机只复制自己修改的页面
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>BRANCH&lt;/code>允许对正在运行的沙箱制作分支。Agent可以在执行高风险命令前保存状态，再让多个子机分别尝试不同方案。&lt;/p>
&lt;p>v0.4的Live Branch要求父沙箱以&lt;code>live_fork=True&lt;/code>启动。它使用memfd共享内存，并通过&lt;code>UFFD_WP&lt;/code>跟踪写入页面。官方基准在1.5 GiB源虚拟机上记录了56ms p50、64ms p90的暂停窗口；内存复制在父机恢复后继续进行。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">from&lt;/span> &lt;span style="color:#000">forkd&lt;/span> &lt;span style="color:#204a87;font-weight:bold">import&lt;/span> &lt;span style="color:#000">Controller&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">c&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">Controller&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">parent&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">c&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#000">spawn_sandboxes&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#34;pyagent&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">n&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">per_child_netns&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#204a87;font-weight:bold">True&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">live_fork&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#204a87;font-weight:bold">True&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">)[&lt;/span>&lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">branch&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">c&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#000">branch_sandbox&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">parent&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">tag&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;checkpoint-1&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">mode&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;live&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">wait&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#204a87;font-weight:bold">False&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"># wait=False返回时，快照可能仍处于writing状态&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"># 确认status=ready后再从该tag创建子机&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">grandchildren&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">c&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#000">spawn_sandboxes&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">branch&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;tag&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">],&lt;/span> &lt;span style="color:#000">n&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#0000cf;font-weight:bold">5&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>wait=False&lt;/code>用于缩短调用等待时间，并不代表后台快照已经完成。程序需要轮询快照状态，避免从尚未就绪的分支继续启动。&lt;/p></description></item></channel></rss>