让 Agent 定时读取多方数据并向团队推送简报,是常见的自动化场景。它看似只是用模型替代脚本规则,实际却容易状态错位:固定时间窗口会漏读或重复,鉴权故障可能被误判为“没有新内容”,回执不明则可能造成重复发送或漏报。
后台自动运行还会放大安全风险。后台自动运行不能依赖逐次人工批准,Slack 和 GitHub 内容也可能包含恶意指令,因此必须用权限、网络、凭据和预算限制其影响。
近日,Anthropic 公开了一套运行在 Beta 阶段 Claude Managed Agents 上的“每日简报”参考实现:它在每个工作日创建新的 Agent 会话,从 Slack 频道和 GitHub PR 中读取变化,再向指定 Slack 频道发送简报。这个案例的核心不在摘要格式或模型选择,而在后台 Agent 如何确定读取起点、确认外部写入,并决定何时推进跨运行状态。

图 1:后台自动化 Agent 总体架构,展示定时调度、数据源、Agent、投递目标、持久化存储与保护边界。
从固定时间窗口改为可提交的读取进度
定时采集任务最直观的第一版,通常是让 Agent 读取“过去 24 小时”的消息。这种方法把调度时间当成了业务进度。
任务晚启动两个小时,两次读取窗口之间就可能出现空档;提前执行或人工补跑,又可能把上一轮内容重新读一遍。Claude 的定时部署也不承诺任务总在精确时刻启动:官方文档说明,实际执行可能带有调度抖动,暂停期间错过的触发也不会自动补跑。
参考实现因此为每个来源维护独立的读取进度,原文称为 bookmark。它不是“上一次调度时间”,也不只是“最后一次读到数据的时间”,而是该来源上一次已经完成处理并提交的读取位置。状态文件可以采用类似下面的形式:
{
"slack:C0123456789": "2026-09-14T13:02:11Z"
}
下一轮从记录位置之前的十分钟开始读取,主动保留一段重叠窗口;对于已经报告且状态未变的事项,再依据稳定 ID 与已汇报台账跳过。已汇报台账在原文中称为 ledger,用来记录事项来源、稳定 ID、报告时间以及当时的状态。
两类状态解决的问题不同:
读取进度回答“下一轮从哪里继续读取”;
已汇报台账回答“这个事项是否报告过,以及它后来有没有变化”。
它们可以存入同一个状态系统,但语义不能相互替代。只有时间戳,无法判断一个仍未解决的 PR 是新事项,还是昨天事项的延续;只有已汇报列表,又无法知道来源读取到了哪里。
读取进度的推进还需要同时满足两个条件:来源读取成功,以及本轮输出已经确认送达或明确选择静默。如果 Slack 发布失败,即使 GitHub 和 Slack 的数据都读取成功,读取进度也不能向前移动,否则下一轮可能直接越过尚未送达的内容。
后台 Agent 还必须区分“没有新内容”和“本轮没有读到”。MCP 服务器不可用、访问令牌过期或 Slack API 返回业务错误时,会话仍可能继续处理其他来源。如果 Agent 只看到空结果,就可能自然地生成“今日无事发生”。参考实现因此把来源状态分成两类:
来源读取成功,但没有符合条件的新事项;
来源读取失败,系统不知道其中有没有新事项。
第二种情况不能推进相应来源的读取进度。Agent 可以继续使用其他正常来源生成简报,但需要在末尾明确说明本轮无法读取哪些来源。
这里必须区分实现事实和约束强度。“来源失败时保留读取进度”“在简报中报告缺口”都写在 agent.md 中,仍由模型执行,并不是平台状态机强制完成的动作。要获得更强保证,需要把来源健康检查和进度提交放进确定性代码,而不是只写进提示词。

图 2:数据源,展示 Slack、GitHub 等只读来源通过 MCP 或 HTTPS 向 Agent 提供数据。
规则与运行状态的分层持久化
定时部署的每次触发都会创建新的 Agent 会话,每个会话使用独立沙箱。上一轮写在普通工作目录里的读取进度、已汇报台账和运行记录,不会自动成为下一轮的状态。
参考实现为此挂载了两个跨会话的持久化存储:
preferences保存用户指定的频道、仓库、排除项、篇幅限制、目标频道和暂停规则;state保存 Agent 维护的bookmarks.json、ledger.md、来源说明、偏好修改建议和每轮运行记录。
preferences 以只读方式挂载。Agent 每次运行都重新读取,因此用户修改规则以后不需要重新发布 Agent 配置;文件系统会拒绝 Agent 对它的写入。state 则允许读写,因为跨运行进度必须持续更新。
一份已汇报台账可以采用下面这样的示意格式:
2026-10-12 github 481 review blocked, day 2
2026-10-12 slack:C0123 1790000000.001 customer waiting for a decision
Agent 提取到候选事项后,先用稳定 ID 与台账对照。已经报告但仍未解决的事项可以标为延续项;已经关闭的事项不再出现在本轮简报;新的事项才作为本轮变化加入。
只读挂载解决的是“Agent 能不能改写偏好文件”,不保证模型一定正确理解和遵守偏好。规则文件的权限是硬约束,规则的解释与执行仍然是模型行为。把两者混成一句“Agent 无法违背规则”,会高估只读存储能够提供的安全性。

图 3:持久化存储,展示用户维护且 Agent 只读的 preferences,以及 Agent 可读写的 state。
发布前复核与投递确认
Agent 从读取来源到完成筛选,往往会经历多次工具调用。期间外部状态仍在变化:PR 可能已经合并,等待回复的问题可能已经解决,负责人也可能刚刚发生变化。
参考提示词因此要求 Agent 在发布前重新读取每个拟报告事项:
已经解决,直接从简报中删除;
仍未解决但状态改变,更新描述;
无法重新确认,不做推测,从简报中移除并把原因写进运行记录。
这是一个明确的工程取舍:参考实现接受漏掉少量无法复核的事项,以降低向读者发送过期行动项的概率。重新验证仍是模型按提示词执行的软约束;如果某类状态关系到告警、审批或资金操作,验证逻辑应进一步下沉到代码和服务端校验。
读取和筛选都正确,并不代表一次运行已经成功。真正容易造成长期错位的步骤,是向 Slack 产生外部副作用以后,怎样更新内部进度。
如果 Agent 先推进读取进度和台账,再调用 Slack,只要发送失败,这批内容就会在内部被标记成“已经处理”,下一轮可能永久跳过。反过来,如果消息已经成功发送,但 Agent 没有可靠处理回执便重试,读者又会收到重复简报。
参考实现采用下面的顺序:
读取各来源
→ 筛选候选事项
→ 发布前重新验证
→ 检查当天简报是否已经存在
→ 将本轮记录为 posting
→ 调用 Slack chat.postMessage
→ 检查 ok:true 和消息时间戳
→ 确认成功后更新台账、读取进度和运行记录
发布成功的证据不是 HTTP 200。Slack 即使在业务调用失败时也可能返回 HTTP 200,因此参考提示词会继续检查响应体中的 ok: true 和消息时间戳。只有这两个条件成立,才把运行记录改为 posted 并推进状态。
如果响应不明确,本轮记录为 maybe posted,读取进度和台账保持不变。这个状态没有用猜测抹掉不确定性,但也没有自动解决它。如果在同一天重试,Agent 可以按当天标题检查简报是否已经出现;一旦跨到下一日期,标题随日期变化,参考实现没有定义如何自动核对上一轮的未知投递。最终仍可能需要人工检查,或者增加基于消息 ID、幂等键和服务端记录的对账程序。
这套顺序可以理解为一种弱事务式提交协议,但不能称为真正的两阶段提交或恰好一次语义:Slack 和持久化存储之间没有原子事务,多个状态文件也可能只更新一部分;投递前按标题查重还存在并发竞态。它降低了漏报和重复投递的概率,没有消除这两类问题。

图 4:投递目标,展示 Agent 在检查当天简报是否已经存在后,向唯一目标 Slack 频道投递内容。
后台自动执行的权限与环境防线
在 Managed Agents 中,MCP 工具集默认采用 always_ask。有人参与时,工具调用可以暂停等待确认;对于后台自动任务,这会让会话暂停在等待批准的状态。参考配置把 GitHub MCP 工具集改为 always_allow,再用只读的细粒度个人访问令牌,将其权限限制为指定仓库的 Contents: read 和 Pull requests: read。
取消逐次人工审批以后,安全控制被分散到几个更低层的边界中。
真实凭据留在**沙箱**外。 Slack 和 GitHub 凭据保存在凭据库中。对于环境变量类型的凭据,沙箱中只有不含真实凭据的占位符;Agent 发起出站请求时,平台才在允许的主机和位置替换真实值。真实访问令牌不需要出现在提示词、普通文件或模型可读输出中。
凭据库的主机限制决定真实凭据可以注入哪些请求,运行环境的网络配置决定沙箱能连接哪些主机。这是两道不同的检查。它们都按主机控制,不理解一次 Slack 请求是在读消息还是发消息,也不理解 GitHub 请求是在读 PR 还是修改仓库。
网络允许列表不能替代 API 权限。 参考运行环境只允许沙箱访问 slack.com,并允许连接 Agent 配置的 MCP 服务器。网络允许列表能缩小数据外传范围,却不是业务授权系统。GitHub 写操作真正被阻止,依赖的是 GitHub PAT 的只读权限;是否只向目标 Slack 频道发消息,则取决于 Slack 访问令牌、机器人所在频道以及 Agent 是否遵守提示词。
示例使用同一个 Slack 机器人读取来源频道和发布简报。它可以向自己已加入且访问令牌允许写入的频道发消息,所以“只写目标频道”不是硬隔离。官方仓库建议敏感场景拆成两个 Slack 应用:一个只读来源,另一个只加入目标频道并负责写入。
预算上限会暂停运行,不会自动完成善后。 参考定时部署为每次运行设置独立预算。平台按公开价累计本轮实际发生的模型调用、Web 搜索和运行时间等成本;达到阈值后不再发起新的模型请求,并把会话暂停为空闲状态,stop_reason 为 budget_reached。正在执行的请求仍可完成,所以最终公开价成本可能略高于阈值。该参考 Agent 已经关闭 web_search 和 web_fetch,搜索成本并不是其正常运行中的固定支出。
预算是硬约束,但不是错误通知机制。如果预算在发布前耗尽,Slack 频道里看到的仍然只是沉默。修改或移除预算后,会话还可以恢复,因此不能把 budget_reached 写成任务已经失败或终止。
提示词注入仍可能沿可写状态跨运行传播。 凭据库、只读访问令牌和网络允许列表能够限制一次错误判断的破坏范围,却不能阻止外部文本影响模型决策。
Slack 消息或 GitHub 内容可能诱导本轮 Agent 改变筛选标准、向错误频道发送内容,或者把恶意信息写进可写的 state。后续会话再次读取这些持久化状态时,污染就会跨运行延续。官方文档也明确提醒:处理不可信输入的 Agent 如果拥有存储写权限,成功的提示词注入可能把恶意内容留给后续会话。
持久化存储的设计因此不能只讨论“记住什么”,还要讨论谁能写、谁会读取、内容如何审计,以及污染以后怎样恢复。每次修改都会生成版本记录,这有助于审计和在可用版本范围内恢复,但不会自动判断某次写入是不是由提示词注入造成的。

图 5:保护边界,展示围绕 Agent 的权限限制、运行预算与外部监控。
公开参考实现仍然留下了哪些缺口
这套设计处理了不少容易被忽略的故障,但它没有把后台 Agent 变成确定性工作流。
会话创建限流、运行环境或凭据库被归档等错误会留下失败的部署运行记录;根 Agent 被归档时,定时部署会随之归档,却不会生成部署运行记录。两类情况都需要通过部署状态、部署运行记录和相关 Webhook 在 Agent 外部监控。
定时触发与人工运行如果重叠,公开参考实现没有展示显式锁来阻止两个会话同时通过“今天尚未发布”的检查。
公开运行步骤没有定义跨
bookmarks.json、ledger.md和运行记录的原子提交,中断可能留下部分更新。来源只保留有限历史或每次只返回最近若干条时,长时间停机后,旧的读取进度也未必能追回全部数据。
Managed Agents 仍处 Beta。官方文档说明,由于会话会在服务端保存对话历史、沙箱状态和输出,它目前不具备 Zero Data Retention(ZDR)资格,也不在 HIPAA BAA 覆盖范围内。
后台自动运行并不等于无需监控。Agent 负责生成业务输出,另一个确定性链路仍需观察它有没有按时启动、是否达到预算、工具是否缺失,以及状态是否长期停在 posting 或 maybe posted。
后台 Agent 的工程分水岭
这套参考实现最终展示的不是“怎样写一条更长的系统提示词”,而是应该把什么留给模型,什么必须交给平台和代码。

模型适合处理语义判断,权限系统适合限制动作范围,确定性代码适合维护不可含糊的状态转换。三者不能互相替代。
对其他 Agent Runtime 来说,可以直接复用的不是 Anthropic 的配置文件,而是下面这组检查:
每个来源是否有独立、可恢复的已提交读取进度?
系统能否区分“没有新数据”和“本轮没读到数据”?
外部写入取得什么证据以后,内部进度才允许推进?
写入结果未知时,谁负责对账并消除中间状态?
用户规则和 Agent 自己生成的状态是否由不同主体控制?
哪些限制由权限、网络、预算和服务端校验执行,哪些只是提示词要求?
如果 Agent 连会话都没能启动,谁负责发现这次缺席?
后台 Agent 的可靠性不来自模型永远听话。它来自一条能够恢复的执行链:知道从哪里继续,知道哪些步骤已经取得可检查的成功证据,也知道在结果无法确认时不能推进状态;即使模型判断失效,权限和运行环境仍能限制副作用的范围。