今天,伊伦迪尔(Earendil)与派社区(Pi community)发布了派 1.0(Pi 1.0)。这源于我们的信念,经过无数小时的强化、维护和积极开发,派已成为构建应用的坚实基石,并持续演进。同时,我们正发布实验性新包派持久(Pi Durable)。派持久专为长时间运行、持久且可变的智能体构建,可运行于任何地方。我们邀请你参与,助其成为最佳持久框架。
正文
今天 Earendil 与 Pi 社区发布了 Pi 1.0,我们认为经过无数小时的加固、维护和开发,Pi 已成为坚实的构建基础。Pi 也在持续进化。伴随 Pi 1.0,我们推出一个实验性新包 Pi Durable,专为能在任何地方运行的长期、持久、可塑代理而建,希望你能一起参与把它做成最好的持久框架。
为何做 Pi Durable?
Pi 编码代理设计在你的(远程)机器终端中由单人驱动运行,进程死了你查看情况让它继续。这是 Pi 1.0 专注且擅长之处,不会改变。
在 Earendil,我们想把这项技术以最契合需求的形式带给所有人。为此,我们需要一个能在任何地方运行、从不同界面接入、支持无限长对话、扛得住内外部灾难性故障、并允许多人操控同一代理的 harness。Pi Durable 就是这样的 harness。它不替代 Pi 编码代理,而是构建任何代理应用(包括编码代理)的框架,不仅与 Pi 编码代理共享如 pi-ai 的代码,也共享极简与可塑的原则。
它也让我们能在不干扰 Pi 编码代理的情况下探索此领域设计。在 Pi Durable 上构建代理应用的经验,一旦证明有价值便会回流到 Pi 编码代理。
什么是 harness?
各家对 harness 定义不同,我们之前写过,这里为 Pi Durable 重述:harness 是存储加上并行运行一个或多个大语言模型对话所需的机器,它提供模型调用的工具及工具运行的执行环境。
对话是你与代理的交互,记录为转录文本。代理是大语言模型加其设置(如思考级别和可调工具)。工具通过执行环境(笔记本、远程虚拟机或内存沙箱)工作,具体给代理哪些工具和环境由每个对话决定。
harness 运行的一切,从调模型到执行工具,都叫任务(task)。和 Pi 一切相同,Pi Durable 让你的代理能理解它。不含测试的整个源码约 15000 行,按 GPT 算约 15 万 token,Claude 约 25 万 token,这是最坏情况。基于 Pi Durable 构建时,你的代理很少需要全部;仅存储后端就有 3000 行通常可跳过。
下面带你看一下 Pi Durable,说明我们建了什么及为何。
随处长久运行
我们希望代理能运行很久,且能在任何地方运行(目前指有任何 JavaScript 运行时的地方)。
在 Pi Durable 中,harness 开启于存储后端之上。Pi Durable 提供内存、SQLite 和 JSONL 存储,以及为你自己后端准备的一致性测试套件和基准。SQLite 和 JSONL 存储代码不使用 Node API,所以加个小适配器就能跑在 Bun 或 Cloudflare Durable Object 上。存储接口很小易实现,可架在键值存储或 Postgres 等之上。同一时间一个进程拥有存储,其他客户端连到该进程。
在 SQLite 上,harness 只在内存留工作集:活动转录、活任务、待提交。其余都在磁盘直到需要。活动转录天然受模型上下文窗口限制,因为压缩会在溢出前总结旧消息,所以即便上万条消息的对话也能妥帖放进内存。
需要文件或 shell 的工具从执行环境获取。Pi Durable 提供 Node 执行环境,让工具访问本地文件。像存储一样,执行环境接口小易实现,因此也可给工具暴露远程执行环境,使 harness 在一台机器跑而工具在另一台。你的 env 函数从对话工作目录为每个工具调用构建环境,所以每个对话可在不同地方运行。
示例里用 OpenAI 模型、Node 执行环境和 SQLite 存储打开 Harness,在首次使用时创建指定工作目录的根对话,重启后仍是同一对话。
扛崩溃
我们希望代理能扛住进程死亡(笔记本休眠、容器重部署或内存耗尽),并从中断处捡起继续。
在 Pi Durable 中,运行的每一步都是任务,在继续前存检查点。进程死了,新进程开同个存储,找未完任务从最后检查点继续。被切断的模型请求重发,部分答案留在转录中标为中止。被切断的工具调用若安全则重跑,否则告知模型被中断。Pi Durable 无内置子代理,但几行代码可建。子代理在自己对话跑,所以也能续,安全重跑的子代理工具会找回子代理等答。队列消息仍排队。requestId 让提交精确一次,崩溃后重试的客户端拿回原始提交而非问两次。
示例里进程在工具调用中死掉,新进程开同 SQLite 存储调用 resume,同样的提交已经作答。
多对话并发
我们希望一个 harness 同时跑多个对话,互不阻塞。
在 Pi Durable 中,一个 harness 并发跑所需数量的对话,全带相同保证。对话可从全新开始,或在转录任一点 fork 另一个,看到父历史至该点而不复制。
想一个 Slack 频道,你的代理回答任何人的提及。然后有人开了线程。频道可是一个对话,线程是它回复消息处的 fork。两者同时跑互不阻塞。
示例代码里频道与线程同时提交不同问题并等待,两者同时工作。每个对话还存自己的代理:模型、思考级别、所选扩展及活跃工具、额外指令、执行环境工作目录。主代理旁的审查者可用更便宜模型、只读工具和自己的代码 checkout。
扩展
我们希望代理能做的事都可插拔,且每个插入部分都参与持久性。
在 Pi Durable 中,扩展是具名捆绑(系统提示段、工具、钩子、任务)。应用把扩展装进注册表。每个对话选它用的扩展和工具,只存名字。
系统提示段
系统提示在每次请求前由对话扩展的段重建,所以改动被下次请求拾取。Pi Durable 在转录改动发生处记录改动,使重启或 fork 看到模型当时看的完全一致。支持对话中途改系统提示和工具的模型只发改动,提示缓存保持有效。
定义扩展可读取执行环境的 agents_md 和 skills 段,每次请求渲染最新状态。
工具
每个工具调用作为自己的持久任务运行,意图在跑前存。崩溃后仅当工具标安全才重跑,否则告模型调用中断附迄今输出,由模型决定。每个对话也可得自己工具集,如 Slack 线程可搜不可部署。
示例里 search_issues 标安全重跑,deploy 不重跑,线程配置卸除 deploy;triage 工具建自己拥有的子代理对话、给小模型等答,UI 可在调用下显示。扩展也可改其他扩展工具,同名后盖前,另一示例 timing 扩展包装任意 bash 工具计时。
钩子
钩子让扩展介入任务(含生成模型响应、调工具、压缩的内置任务)。可重写请求、阻/重写工具调用、替结果、保运行、写总结。崩溃后钩子可重跑,故决策存 memo(任务小值首写赢)。
示例 approval 扩展在 deploy 前钩子问 Slack,重启找存储答案而不再问。多扩展可钩同物成链,按对话选序跑。beforeTool 传改写参下行,首阻停;afterTool 传结果;onYield 首保运行停;观察器总跑;抛错报并续(beforeTool 抛则阻调用)。
任务
harness 用内置任务跑对话(每模型请求、每工具调用、压缩各一)。扩展带自己任务得同机器:每步检查点、活重启定时器、等他任务。
例:分卡结账齐扣款,一卡拒其他 abort 退款。示例定义 Payment 和 Checkout 任务及 checkout 工具实现此逻辑。任务和对话成所有权树。abort 任务自底向上 abort 所属,先清自己效,所属工完才完。子代理同模式:对话属起它的工具调用。
任务默认前台:属对话当前工,对话仅当它们完才闲,如用户按 Esc abort 对话则 abort 它们及所属。后台任务属对话不属当前工,对话闲它跑,普通 abort 留它及所属,适合跨轮子代理或明天响的提醒。另一示例建前台与后台任务,前台 Esc 中止,后台普通中止留它。
压缩
我们希望长对话不停下来总结也能继续。
在 Pi Durable 中,压缩是普通任务,对话继续时跑。上下文近模型限,后台压缩总结旧消息放下一轮边界,仅当下请求不符才等摘要。供应商仍拒过长则压重试一次。可随时手动压自己指令。旧消息总留存储。
示例设 reserveTokens 与 backgroundTokens 及手动 compact。reset() 更进:起新上下文(可选 handoff 笔记),工具返 control:{handoff} 同求。因不删,另一工具仍可搜 handoff 前一切。示例 handoff 与 search_history 工具几行建自交接代理稍后查。
持久应用状态
我们希望建在代理上的应用状态同对话一样持久。
在 Pi Durable 中,应用状态(待办、计划、工单、对话跑的沙箱)存文档(documents)。文档是类型化 JSON 存转录旁,在同原子提交中改,故状态永不与产它的转录悖。每文档说 fork 起值:fork 点父值、当前值或新。
示例定义 Todos 文档及增项工具,UI 订阅提交值。
可塑
我们希望不改停跑代理代码就能改它。
在 Pi Durable 中,对话跑时注册表可改。同名装扩展一步替。已在跑工具用原代码完,下调用新码。对话存扩展工具名非码,重启拾新进程装的。
示例扩展文件改后同名重装即替。
多人协作
我们希望多人多客户端同对话:看、晚加、操控。
在 Pi Durable 中,UI 需皆为提交态,故任意客户端连任意对话。客户端先得当前视图(转录、流式答、跑工具及输出、队列消息、代理、用量),后仅得变。晚加/重连从当前视图起。任意客户端可操控运行对话或排后续。
示例第二客户端加线程看状态并 steer 提交;远程客户端 thread.watch() 送每提交精确操作够小过 socket;好编码代理事件可用 watchEvents() 转(线字节多)。
试一试
今天就能试 Pi Durable,它是实验性的,API 可能还会变。把你的代理指向 Pi checkout 里的 packages/durable,让它读 README、三十多个例子、基于 Pi Durable 的小编码代理,或这个漂亮的假期规划代理,然后开建。
假期规划器约 1300 行 TypeScript,多数为 TUI。如果它像编码代理,只因它从 Pi 编码代理借了 TUI 组件。
- 基于 Pi Durable 带 TUI 的假期规划器。
- 子代理并行跑三个搜索,各是持久任务。
- 同时主代理空闲可聊天。
- 进程死。天气和博物馆完,火车没完。
- 重启。search 安全重跑:仅火车重跑。
- 切到子代理操控它。
- 回主:问、压缩、操控,全在它工作时。
- 报告作为消息到;主转成计划。
从 Pi checkout 运行两 demo 需构建后 node 两个 main.ts。自己项目装 @earendil-works/pi-durable 等包。
未来几周我们会多谈 Pi Durable,展示用它能建的小代理工具(如 Slack bot 或 GitHub triage bot)帮我们工作。先不剧透。随我们自己用 Pi Durable 会有更多来,就像我们用 Pi。
FAQ
为何又用 TypeScript?
因为最易启动。但众所周知,移植到 Rust 或汇编很容易。未来不排除,但目前专注 TypeScript。
评论
社区对 Pi 推出持久化代理框架普遍兴奋并交流自建经验,多数人认可分离式持久 harness 的价值,少数人质疑仅用 JSON 文档持久状态的局限或偏好内存数据库方案。
认为持久化代理框架是行业趋势且 Pi 入局令人兴奋
- 多位开发者分享自建类似框架的经验,指出耐久、分离计算、易多人协作是主要优势,并期待用官方方案替代自研(较多人) > 看到 Pi 也构建了持久代理框架很酷,主要玩家都在做,因为它耐久且易扩展协作(@lukebuehler)
希望持久状态不止于 JSON 文档而支持外部存储与数据库
- 有开发者认为仅用 JSON 文档限制灵活性,建议集成发件箱模式同步外部存储,或直接用数据库文件避免 I/O 摩擦(少数人) > 希望持久应用状态不限于 JSON 文档,应有集成方式实现发件箱模式同步外部存储(@vmg12)
多用户协作特性最受青睐
- 分离式 harness 让多玩家场景更易实现,有开发者表示这能简化远程控制工具的构建(较多人) > 最喜欢多用户部分,便于构建远程控制工具而无需绕过限制(@skeledrew)
分布式部署中会话持久化与沙箱策略带来额外复杂度
- 实际部署时需处理 JSON 会话文件在容器中断后的存活,或期待集成策略引擎管理沙箱,目前需自行解决(少数人) > 在 Kubernetes 上跑需应付 JSON 会话文件保活,用额外工具但觉杀鸡用牛刀(@azuanrb)
有价值的补充
- 同一份约 1.5 万行无测试源码,GPT 计为约 15 万 token,Claude 计为约 25 万 token,模型间计数差异显著。
- 基于 Pi SDK 构建 Slack 值班与支持频道框架已验证可行,且默认厂商无关比早期方案更可定制。
- 偏好内存态加直接数据库文件持久化以避免 JSON 读写摩擦,是一种值得注意的实验方向。