返回资讯中心
外部精选
软件工程
#开发者实时流

Restate 为 TypeScript SDK 加入持久协程,单步开销降至毫秒级

来源标题:Durable Coroutines for TypeScript

Restate 在其 TypeScript SDK 中新增持久协程,为多步骤例程提供与工作流相同的持久化和恢复语义,但每个持久操作只增加毫秒级开销,而非工作流方案常见的 50-100 毫秒。在生产环境的 GCP 三可用区同步复制部署中,持久步骤的延迟开销为 P50=2.5ms、P99=9ms,持久操作速率超过每秒 1 万次。该功能与构建持久化 Agent 的用户共同开发,用于支持按细粒度步骤持久化进度的 Agent。

Hacker News 最新calvinfo2026/11/4 · 5 天前30 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

BlogDurable Coroutines for TypeScript:毫秒级开销的容错 Agent 2026 年 11 月 3 日 Igal Shilman, Stephan Ewen, Giselle van Dongen 我们为 Restate 的 TypeScript SDK 加入了 Durable Coroutines:持久化、可并发的多步例程(routine),提供与 workflow 相同的持久化和恢复语义,但每个持久化动作只增加毫秒级开销,而不是 workflow 方案中常见的 50-100 毫秒1。 在生产部署中,对于 GCP 上同步复制的 3-AZ 配置,在超过 10,000 次 durable_actions/秒的速率下,coroutine 中的持久化步骤带来的延迟开销为 P50=2.5ms、P99=9ms。 我们与构建 durable agent 的用户一起开发了 Durable Coroutines。现代 agent harness 会以细粒度步骤持久化并跟踪进度:LLM 结果的各个 chunk、每次 tool 调用中的多个步骤(intent、guardrail、结果 chunk)。这种粒度让 agent 在从故障中恢复时拥有更强的模型。但如果采用为每个持久化步骤都调度并向 worker 分发 activity 的持久化执行模型,这很难做到。 我们构建 durable coroutines 正是为了填补这一空白。这种方法的另一个好处是,代码可以采用类似持久化进程的模型,其中持久化步骤可以依赖局部变量,并高效利用缓存资源。 coroutine 的实现大量使用 TypeScript 的 generator 函数,来实现一个控制执行的确定性调度器。 持久化执行最初以 workflow 和 activity 的形式出现:如果你想要一个持久化步骤,就需要创建一个 activity,它会被调度到某个 worker 上。在 Temporal 这类系统中,这意味着 workflow 任务让出执行(返回 workflow 编排器),activity 被发送到 worker 执行并返回结果,然后 workflow 任务再次执行2。并行工作意味着设置多个 activity,当 workflow 任务让出执行时,所有 activity 开始运行。这种方式适合任务队列 + worker 架构。 1export async function agent(prompt: string) {2 const context: Message[] = [userMessage(prompt)];3 4 while (true) {5 const next = await callModel(context);6 if (next.done) return next.answer;7 8 const calls = next.tools.map((t) =>9 callTool(t));10 const results = await Promise.all(calls);11 context.push(...results);12 }13} Workflow Server保存 workflow 历史和任务队列agent()Worker 1idleWorker 2idleWorker 3idleworkflow 已挂起 —— 没有任务在运行 agent.ts尚未被调用 1export function* agent(prompt: string) {2 const msgs: Message[] = [userMessage(prompt)];3 4 while (true) {5 const next = yield* run(() => callModel(msgs));6 if (next.done) return next.answer;7 8 const calls = next.tools.map((t) =>9 spawn(callTool(t)));10 const results = yield* all(calls);11 msgs.push(...results);12 }13} bidi streamRestate Server推送 invocation · 记录每个步骤journal0 条目Service process长期存活 · 单一事件循环空闲 —— 没有 invocation进程空闲 —— 等待 invocation RestartPause Restate 和其他系统实现的另一种方法通常被称为 Durable Functions。这些函数可以包含持久化步骤(ctx.run(...),再加上持久化 signal、sleep、promise 等),并通过 RPC(调用其他持久化函数)进行组合。持久化步骤比 activity(或调用其他持久化函数)更快,因为需要做的工作更少:Restate 与执行中的函数保持流式连接,在应用程序和 Restate Server 之间发送步骤和 ack。Restate 的整个架构就是为了让步骤提交足够快而设计的。 Durable Functions 让开发者可以在两种模型之间选择:把(应该被持久化的)工作单元放进单独的函数或 activity 中,适合较重的任务,或者需要把工作排队并分发到不同 worker/部署、以特定速率或并发限制运行的情况。 相比之下,用持久化步骤和 coroutine 编写的程序更像是在编写持久化进程。除了实际的故障/恢复情况外,执行是在同一进程中的连续运行,让代码可以复用本地资源,如缓存的文件/结果或已认证的连接。Restate 一直支持持久化步骤,但 Durable Coroutines 的加入修复了该 API 之前对并发支持有限的问题。 两种模型相辅相成:我们经常看到开发者把较大的工作(如对话轮次或长时间运行的工具)放进单独的持久化函数(其 invocation 具有排队和流控),并使用步骤/coroutine 来捕获子步骤的持久性。 Restate 的 Durable Coroutines 库借鉴了 Go、Rust 或 Kotlin 等编程语言中的 coroutine 思想,并实现了一个确定性调度器,使它们与基于 journal 的持久化执行兼容。 让我们深入看一个例子:一个 agent 循环,它将工具作为并发子 workflow 启动,并监听 steering signal。 function* agent(userMessage: string): restate.Operation<string> { const sandbox = yield* connect(); // 跨工具调用可复用的连接 const messages: Message[] = [{role: "user", content: userMessage}]; const tasks = new Map<string, restate.Task<ToolResult>>(); // 进行中的任务 let steer = restate.signal<string>("steer"); // 用于等待用户发来的消息 // Durable agent 循环 while (true) { // 1. 持久化 LLM 调用 const action = yield* restate.run(async () => llm(messages)); if (action.type === "final") { return action.message; messages.push({role: "assistant", calls: action.calls}); // 2. 启动并行工具调用(每个调用可能是一个多步骤序列) for (const call of action.calls) { tasks.set(call.id, restate.spawn(performCall(call, sandbox))); messages.push({ role: "tool", results: action.calls.map(({id}) => ({id, result: "task created"})), });

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →