@dzhng: 你应该试试 duet agent 的 /relay:
摘要
duet-agent 是一个用于持久化 AI 代理任务的框架,这些任务可以跨越单个聊天会话,实现长时间运行、可恢复的任务,具有跨会话记忆和通过 relay 轮次观察到的状态。
查看缓存全文
缓存时间: 2026/05/16 09:15
@nikunj 你应该试试 duet agent 的 /relay:https://t.co/qXmneitymt — # dzhng/duet-agent 来源:https://github.com/dzhng/duet-agent duet-agent # duet-agent 在线访问 duet.so (https://duet.so) npm 版本 (https://www.npmjs.com/package/@duetso/agent) 许可证 CI (https://github.com/dzhng/duet-agent/actions/workflows/ci.yml) 基于 Bun 原生 (https://bun.sh) 用于那些比聊天更持久工作的代理框架。
如何让一个代理坚持工作直到任务完成?大多数框架没有答案——聊天结束,进程终止,上下文随之消失。duet-agent 提供了三种方式。一个会话可以暂停几分钟或几个月,并在一个全新的沙箱中恢复,不会丢失线索。
npm install -g @duetso/agent
duet login
duet "挖掘 Acme 的 VP 工程负责人,发送一封初次接触邮件,如果对方回复则预定会议"
一次 duet login 会在 ~/.duet/.env 中写入 DUET_API_KEY,并通过 Duet AI 网关解锁前沿语言模型(Claude、GPT、Gemini)、图像和视频模型,以及由 Firecrawl 驱动的网页技能。无需单独的提供商计费。(如果你更愿意自带密钥,请参见 CLI 环境设置。)
不适合单次聊天的工作
- 长期的推广和生命周期工作。 挖掘 → 发送邮件 → 等待 14 天 → 预定 → 交接。中继在
wait_for_reply中驻留一周,无需进程保持活跃。 - 不会遗忘的编码会话。 一个月后恢复重构任务,代理仍然记得它尝试过什么、什么有效、以及你告诉过它永远不要做什么。
- 带有收据的多步骤研究。 每个步骤都是一个可观察的状态——代理、脚本、轮询——而不是黑盒链。你可以从中途开始:“我已经做了研究,只需起草邮件。”
- 无服务器和沙箱化轮次。
TurnState是轮次之间唯一需要存活的东西。Cron 唤醒它,运行一个轮次,持久化,退出。 - 缓慢、定时、重复的工作。 冷启动外联、每周摘要、审核周期、定时重试、长期迁移——任何下一步在几小时或几天之后的任务。
如果工作适合单次聊天,你可能不需要这个。如果不适合,大多数框架会要求你自带记忆层、自己的队列、自己的恢复逻辑。这就是差距所在。
为什么还需要另一个框架?
大多数代理框架擅长于单次轮次。它们不是为整个工作而设计的。记忆是插件,持久化进程是“对接 Temporal”,从磁盘恢复是事后硬塞的,最终让人后悔。有趣的工作——跨轮次记忆、从中断处继续、知道何时提问 vs. 何时继续——都留给了你。
Claude Code 和 Codex 都非常擅长单次轮次的工作:编辑这个文件、运行这个命令、回答这个问题。duet-agent 是为更上层而构建的——那些需要记忆、等待、在不同进程中恢复并自主路由的工作。
| Claude Code | Codex CLI | duet-agent | |
|---|---|---|---|
| 跨会话记忆 | CLAUDE.md(你编写)+ 自动记忆(Claude 编写,每个仓库,每会话最多加载前 200 行 / 25 KB) | AGENTS.md(你编写;子目录中可分层覆盖 AGENTS.override.md) | 基于 PGlite 的观测性记忆,采用混合检索(pgvector + tsvector,通过 RRF 融合)。代理观察自身记录,并在会话间回忆它们。 |
| 图像记忆 | 图像仅保留在活动记录中 | 图像仅保留在活动记录中 | 视觉能力模型将截图和 UI 捕获观测为文本,代理可在后续轮次回忆。 |
| 跨新进程恢复 | claude --resume <session> / --bg 后台会话——回放保存的记录 | codex resume <session>——从 ~/.codex/sessions/ 回放保存的记录 | TurnState 快照保存在磁盘上;任何新进程——新沙箱、无服务器调用、不同机器——均可通过 runner.start({ state }) 恢复。 |
| 长期、多步骤工作流 | 后台会话;无原生轮询/等待/状态机原语 | 记录驱动;无原生轮询/等待/状态机原语 | 中继:代理路由的状态机,具有五种状态类型——agent、script、poll、timer、terminal。轮次间等待回复数天。 |
| 可使用的模型 | Anthropic | OpenAI(使用 ChatGPT 登录或 API 密钥) | Anthropic、OpenAI、OpenRouter、Vercel AI Gateway、Duet Gateway |
| 许可证 | 专有(闭源 CLI) | Apache-2.0 | Apache-2.0 |
这并不意味着 Claude Code 或 Codex 在其领域内更差。它意味着当任务对于单次聊天来说太长时——当记忆必须在会话之外存活、当进程必须等待外部信号、当轮次必须在一个开始工作时不存在的容器中恢复时——duet-agent 是正确的选择。
下面没有单独章节,但源自同一结构的两件事:
- 一次登录,所有前沿模型。
duet login就是全部设置。Claude、GPT、Gemini、图像、视频、网页——全部通过同一个密钥,默认技能自动同步并保持最新。 - 开源。 不是黑盒。如果我们关于记忆排序或中继路由做出了错误决定,你可以阅读代码并告诉我们错了。
我们的不同之处
记忆,融入其中
记忆和压缩是同一原语:观测性记忆就是上下文在轮次间存活的方式。运行器观察自身记录,在观测增长时进行反思,并将持久行写入 PGlite——针对消息和图像都生成文本观测,因此截图和 UI 捕获可在后续轮次中回忆,无需重新附加字节。
每个轮次的提示前缀是一个冻结的两层包(长期跨会话记忆 + 本轮次的压缩摘要),仅在压缩事件时重建,以便提供商的提示缓存在轮次间保持。未包含在包中的任何内容都可通过 recall_memory 访问——基于 pgvector 余弦相似度和 tsvector 关键词搜索的混合检索,通过倒数排名融合(RRF)合并,并可选地包含释义查询扩展。嵌入在后台工作线程中运行,因此前台轮次永远不会阻塞。
中继:让代理持续工作直到任务完成
中继是 duet-agent 如何在数小时、数天或数月内专注于任务的方式。底层是一个状态机——但运行代理(而不是配置文件)每轮选择下一个转换。足够的结构来路由长期工作,又不会让代理锁定在一条路径上。
每种状态属于五种类型之一:
- agent —— 具有提示、可选的系统提示和可选技能允许列表的子代理。
- script —— 执行
bash、curl、CLI 等。任何有 API 的东西都是脚本状态。 - poll —— 对外部信号(收件箱、构建状态、webhook)的定期检查。
- timer —— 纯粹的延迟,直到挂钟时间,不附加脚本。
- terminal —— 记录业务结果:
completed、cancelled、failed。
flowchart LR
A([agent]) --> S([script]) --> P([poll]) --> Tm([timer]) --> T([terminal])
这就是全部词汇。Email、GitHub、Calendly、CRM——都不需要头等引擎概念;它们就是 shell 脚本。
中继可以从中间开始(“我已经发过邮件了,只需等待回复”),因为运行代理读取的是上下文,而不是工作流 ID。
这不是 Temporal。不是确定性 DAG,不是精确一次运行时,不是工作流服务。它只是为代理提供足够的结构来做出良好的流程决策,并在必要时将操作保证交给外部系统。
磁盘上的状态,默认无服务器
一个轮次是 TurnState 的纯函数。运行器在轮次运行期间在进程内拥有它;持久化在轮次之间保持其在磁盘上。任何进程——明天的相同 shell、新的沙箱、无服务器调用、不同机器——都可以通过调用 runner.start({ state }) 从上一轮结束的地方继续。
没有粘性工作线程、没有温池、没有会丢失的会话亲和性。Cron 唤醒容器,传递快照,运行一个轮次,持久化,退出。这就是你想要的整个部署模型。
三种模式:agent、relay、auto
同一个运行器处理两种工作形式。agent 模式将提示视为正常会话——编码、研究、审查、一次性任务。state_machine 模式(在 UI 中显示为中继)将提示路由到具有持久等待和终端结果的代理路由业务流程。auto 模式让运行器分类提示并选择。
一个 CLI,一个 SDK;长期工作和短期工作使用相同的代码路径。
架构
一个实际的代理路由中继:会议推广外联。用户提示进入 TurnRunner,运行代理从提示 + 历史 + 可用状态中选择下一个状态,中继驱动业务流程直到达到终端状态。
同一个定义可以从中间开始——例如,如果用户说“我已经发过邮件了”,运行器可以直接跳到 wait_for_reply。
完整架构图(点击展开)
stateDiagram-v2
direction TB
[*] --> Classify : user prompt
Classify --> AgentMode : one-off task
Classify --> Outreach : matches a relay
AgentMode --> [*] : answer / edits
state Outreach {
direction TB
[*] --> research_prospect
research_prospect : research_prospect (agent)\nweb + notes lookup
draft_email : draft_email (agent)\nwrite first-touch email
send_email : send_email (script)\nbash: gmail send
wait_for_reply : wait_for_reply (poll)\nevery 6h: check inbox
schedule_meeting : schedule_meeting (script)\nbash: calendly create
meeting_booked : meeting_booked (terminal: completed)
not_interested : not_interested (terminal: completed)
no_response : no_response (terminal: cancelled)
research_prospect --> draft_email : enough signal
research_prospect --> not_interested : disqualified
draft_email --> send_email
send_email --> wait_for_reply
wait_for_reply --> schedule_meeting : positive reply
wait_for_reply --> not_interested : declined
wait_for_reply --> no_response : 14d timeout
schedule_meeting --> meeting_booked
}
Outreach --> [*]
观测性记忆、PI 编码工具和护栏位于每个状态转换之下;它们本身不是状态。
Duet 演示
一个提示,一个可以运行数周、数月甚至数年的工作。状态机(即 duet 中的中继)的力量。
其他功能
可选的护栏
基于模式(快速,正则表达式)和语义(LLM 评估)的护栏可组合成防火墙。每次 bash 命令和文件写入都可以在执行前检查。
const turnRunner = new TurnRunner({
guardrails: [
{
kind: "pattern",
rules: [
{ pattern: /production-db/i, action: "warn", reason: "提到生产数据库" },
],
},
{
kind: "semantic",
model: getModel("anthropic", "claude-haiku-4-5"),
policy: "切勿删除生产数据。切勿在输出中暴露密钥。",
},
],
});
远程 MCP 工具
TurnRunner 可以通过可流式 HTTP 传输连接到远程模型上下文协议 (https://modelcontextprotocol.io) 服务器。在 start 中传递 mcpServers,运行器会连接、列出每个服务器的工具,并将其暴露给父代理和状态代理,以及内置的编码工具。工具名称以 {server}__{tool} 命名空间,因此多个服务器可以共存而无冲突。
await turnRunner.start({
mcpServers: {
docs: {
type: "http",
url: "https://mcp.example.com/docs",
headers: { "x-api-key": process.env.DOCS_KEY! },
},
},
});
目前仅支持 HTTP MCP;认证有意不在范围内,因此服务器期望的任何凭据都必须通过 headers 传输。连接失败会被记录并跳过,因此单个服务器故障不会阻塞会话设置。
原生中断
中断行为来自底层的 pi 代理运行时。用户可以在 pi 会话运行时发送消息,运行时可以将其处理为中断或后续消息。duet-agent 不会在上层添加第二个中断总线。
PI 编码工具
子代理使用来自 @earendil-works/pi-coding-agent 的默认工具:read、bash、edit、write。运行代理提供工作目录,并可以限制哪些技能被注入到状态机代理状态中;它不会将这些工具包装在第二个沙箱抽象中。
安装
# CLI — npm
npm install -g @duetso/agent
# CLI — Bun(CLI 基于 Bun 原生)
curl -fsSL https://bun.sh/install | bash
bun add --global @duetso/agent
# SDK
npm install @duetso/agent
其他包管理器和升级路径
npm install --global @duetso/agent
pnpm add --global @duetso/agent
yarn global add @duetso/agent
# 升级现有的全局安装
duet upgrade
CLI 运行在 Bun 上,因为 OpenTUI 是 Bun 原生的。
开发环境设置
本仓库使用 Bun 进行包管理,Husky 进行预提交检查,Docker 进行功能测试。
bun install
bun run setup # 在 macOS 或 Linux 上安装/启动 Docker(如果需要)
bun run check-types
bun run lint
bun run eval # 在 Docker 内运行实时评估
bun run test # 在 Docker 内运行测试套件
使用 bun run test 和 bun run eval,而不是原生的 bun test,作为可信来源。写入文件的测试和评估在 Docker 中运行,因此集中的主机运行不会在 checkout 中创建 .duet、PGlite 数据库或主目录技能工件。预提交钩子运行 format、check-types 和 lint。
CLI 快速入门
推荐的路径是 duet login。一次登录会在 ~/.duet/.env 中写入 DUET_API_KEY,同步默认技能,并让你通过 Duet AI 网关访问所有前沿语言、图像和视频模型,以及捆绑的网页抓取技能——无需其他 API 密钥。
duet login
duet "挖掘 Acme 的 VP 工程负责人,发送一封关于我们会议演讲的初次接触邮件,等待最多 14 天回复,如果他们感兴趣则在 Calendly 上预定会议"
提供商、模型和 CLI 标志
如果你更愿意自己管理提供商 API 密钥,请使用 duet env(参见下面的 CLI 环境设置)或在环境变量、/.env 或 ~/.duet/.env 中设置提供商 API 密钥。
当省略 --model 时,CLI 会从已配置的提供商推断默认值:Duet、Anthropic、AI Gateway 和 OpenRouter 使用 Opus 4.7(记忆:Haiku 4.5);OpenAI 使用 GPT-5.5(记忆:GPT-5.4-mini)。使用 --provider <name> 固定提供商而不选择模型:
duet --provider duet "构建一个待办事项应用" # duet-gateway: Opus 4.7 + Haiku 4.5
duet --provider openai "解释这个代码库" # openai: GPT-5.5 + GPT-5.4-mini
duet --provider anthropic "重构认证" # anthropic: Opus 4.7 + Haiku 4.5
duet --provider vercel "总结" # vercel-ai-gateway 对应模型
--provider 与 --model / --memory-model 互斥。接受的简写:duet、vercel(别名 ai-gateway)、openrouter、anthropic(别名 claude)、openai(别名 gpt)。
export ANTHROPIC_API_KEY=sk-...
duet "用 Express 构建一个 REST API"
duet # 交互式 TUI
duet -m opus-4.7 --workdir ./my-project "重构 auth 模块"
duet --memory-model sonnet-4.6 "总结这个仓库"
duet --system-prompt "优先给出简洁答案。" "审查这个仓库"
duet --system-prompt-file TEAM.md "审查这个仓库"
duet --no-system-prompt-files "审查这个仓库"
duet --resume session_abc123 --workdir ./my-project
duet skills # 列出已安装的技能
duet memory # 浏览持久记忆
# 通过 Vercel AI Gateway
export AI_GATEWAY_API_KEY=...
duet -m opus-4.7 "审查这个仓库"
模型名称可以使用完整的 provider:modelId 语法或简写名称,如 opus-4.7、sonnet-4.6、haiku-4.5 和 gpt-5.5。简写重新
相似文章
@dzhng: 推出: Duet Agent — 我们正在 @duetchat 上构建的一种新型工具,适合无法在单个聊天中完成的任务:…
Duetchat 推出 Duet Agent,一种用于运行长时间AI代理任务的新型工具,具备状态机中继、内存压缩以及用于沙盒的无状态运行器。
@dzhng: 一旦你开始运行大量监听事件并永远循环的代理,聊天用户界面就会崩溃。我们正在试验一种…
Duetchat 推出了一种基于看板的界面,用于管理多个监听事件并永远循环的AI代理,由父协调器控制。
Relay:基于账本的中间件,用于可靠的智能体交接(零依赖)
Relay 是一个基于账本的中间件,用于多智能体系统中安全且可审计的智能体交接,具备仅追加上下文、快照恢复和硬上限预算功能,以防止上下文损坏和数据泄露。
Show HN: 轻量级多AI代理对话方案,无需API付费
一种轻量级模式,用于编排多个AI代理(Claude、Codex、Gemini)之间的对话,通过CLI实现,无需API付费,利用会话恢复来维持跨代理交互的上下文。
用于长时间运行代理的有效工具
Anthropic 推出了一种由两部分组成的解决方案,使用初始化代理和编码代理,使 Claude Agent SDK 能够有效处理跨多个上下文窗口的长时间运行任务,并通过保持干净、增量的状态来实现。