随着 AI 加速我们的工作,跟上节奏变得越来越难。在 Anthropic,我们经常使用简单的智能体自动化来提供帮助。它们通常按计划运行,在后台收集上下文,并主动告诉我们需要了解的内容。但构建高效的智能体自动化并不容易:它们可能在无人察觉的情况下失去对某个信息源的访问权限,或者无法遵循我们的偏好。
使用 Claude Managed Agents (测试版),我们构建了一个参考实现,它会按计划读取自定义信息源(例如 Slack 和 GitHub 仓库),跟踪自上次运行以来的变更,并将你需要了解的内容发布出去(例如发布到 Slack)。在本文中,我们将逐步讲解每个步骤,分享一个参考实现,并提供一个可在 Claude Code 中运行的命令,它会为你配置好智能体。
获取代码
参考实现位于 这里。如需交互式讲解,请在 Claude Code 中运行以下命令。该 claude-api 技能可以按照本文中的指导帮助设置智能体:
/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/
要使用此参考实现,你需要一个 Slack 应用(从清单创建它)和一个 GitHub token。提供的文件(如下所示)是 Claude API 资源的配置,包括智能体、其环境、记忆存储、保险库和部署。
CODETextdaily-brief/ ├── agent.md model, tools, instructions ├── deployment.md schedule, time zone, budget, input message ├── environment.yaml network allowlist ├── memory_store_preferences.yaml user preferences ├── memory_store_state.yaml the agent's bookmarks, ledger, notes, and run records ├── vault.yaml the vault that holds the credentials ├── claude-lock.json resource IDs, written by ant apply └── slack/manifest.yaml one bot app
ant apply是 ant CLI 中的一个命令,它读取这些文件,在你的 Claude API 工作区(平台在其中存储并运行这些资源)中创建资源,并将 ID 记录到 claude-lock.json.
我们将在下面的章节中使用此命令。配置完成后,该自动化将在 Anthropic 的基础设施上按计划运行,因此你的机器上无需保持任何程序运行。
概览
我们要构建的智能体有六个组件,按以下顺序介绍:
- 信息源(Sources)- 一个用于读取位置的命名列表
- 目标(Destination)- 智能体可以写入的一个位置
- 智能体(Agent)- agent.md 中的模型、工具和运行步骤
- 计划(Schedule)- 一个 cron 计划
- 记忆(Memory)- 你的偏好以及智能体自身的记忆
- 防护措施(Guardrails)- 在智能体只读取的地方提供只读访问权限,以及每次运行的花费上限

信息源
该智能体读取两个默认信息源:Slack 频道和 GitHub 拉取请求。频道和仓库列在你的 preferences 文件中。该模板可以扩展以使用其他信息源。

给代理分配其专属的、范围受限的凭证
通过 Managed Agents,凭证存储于 vaults中。代理可以引用这些凭证,但真实值保存在 vault 中,位于 Claude 代码运行的沙箱之外(参见 here 和 here):
-
MCP 服务器(GitHub)。 代理通过运行在沙箱之外的代理(proxy)调用 MCP 工具。该 proxy 会查找 URL 与服务器匹配的 vault 凭证。
-
Shell(Slack)。 代理在沙箱内使用 bash 工具通过 curl 调用 Slack API。沙箱中只保存一个不透明的占位符,
$SLACK_BOT_TOKEN。当请求离开沙箱时,平台会为你允许的主机替换为真实令牌。
使用 ant CLI 和仓库中的模板文件创建 vault:
ant apply vault.yaml
这会在你的 Claude API 工作区中创建 vault,由平台存储,并将其 ID 记录在 claude-lock.json中。然后使用 TypeScript SDK将每个凭证添加到 vault 中。以下示例展示了添加 Slack 凭证的过程:
const vaultId = process.env.VAULT_ID!; // the vault's ID, from claude-lock.json
await client.beta.vaults.credentials.create(vaultId, {
display_name: "SLACK_BOT_TOKEN",
auth: {
type: "environment_variable",
secret_name: "SLACK_BOT_TOKEN",
secret_value: process.env.SLACK_BOT_TOKEN!,
networking: { type: "limited", allowed_hosts: ["slack.com"] },
injection_location: { header: true },
},
});
创建 vault 并添加每个凭证后,将该 vault 附加到部署。将 vault ID 从 claude-lock.json 复制到部署文件中的 vault_ids 里, deployment.md.
从上次中断的地方继续
一个常见的错误是让代理读取固定窗口,比如“过去24小时。 late运行会留下空缺,early运行会重复条目。因此,应为每个来源给智能体提供一个书签。在每次运行的结束时,智能体将其从每个来源读取到的最新条目的时间戳写入一个文件, bookmarks.json,每个来源对应一个条目: "slack": "2026-09-14T13:02:11Z".
下一次运行会从这些书签开始,因此其时间窗口会拉伸或收缩,以覆盖自上次运行以来的所有内容。这些书签保存在 内存存储 中,称为 state:这是平台挂载到每次运行的沙箱中的一个文本文件文件夹,路径为 /mnt/memory/ ,并在多次运行之间保留。代理用它的普通文件工具读写该文件夹, agent.md 中的指令告诉它如何操作。
不要把读取失败误认为是安静的一天
如果某个 MCP 服务器宕机或其令牌已过期,运行仍会启动,只是没有该服务器的工具。会话会记录一个错误,但代理看不到来自该来源的任何内容,并报告“没有新内容”。
中的三条规则 agent.md 有助于解决这个问题。当某个来源失败时,代理将:保持该来源的书签不动,根据其他来源撰写简报,并在简报末尾用一行文字说明它无法读取的内容(“本次运行无法获取拉取请求”),从而让读者知情。
DESTINATION
我们的模板发布到一个 Slack 频道,每次运行都会发布一篇带有日期的帖子。

代理在沙箱中使用 bash 工具发布到 Slack,使用的 bot 令牌与它读取时所用的一致。
帖子无需任何审批。代理用一条 bash 命令发送它,内置的 bash 工具默认无需请求批准即可运行。 slack.com 也在代理的 环境(即它运行所在的沙箱)的允许列表中。发布只需一个请求:
curl -s https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d '{"channel": "C0123456789", "text": "Daily brief, Tue Sep 15 ..."}'
在记录之前确认帖子已成功发布
一旦帖子得到确认,代理会更新其已报告条目的账本和书签。如果这些记录与实际发布的内容不符,可能出现两个问题。如果代理记录了一篇从未成功发布的帖子,书签会继续前移,那些条目将永远不会被报告。如果它因为不确定第一篇帖子是否成功而再次发布,读者会收到两次相同的简报。
中的三条规则 agent.md 可以防止这种情况。第一,代理会在频道最近的消息中查找今天的标题,如果该期已经存在就不再发布。第二,只有当 Slack 返回 "ok": true 以及一个 message ts 时,帖子才算发送成功。第三,代理只有在该确认之后才更新账本和书签。如果结果不明确,它将此次运行标记为“可能已发布”,不做其他任何更改,因此不会丢失任何内容。
代理在其内存存储中保留一条运行记录(runs/<date>.md)。它在发布之前将运行标记为“posting”,然后标记为“posted”并附上消息 ID,或标记为“maybe posted”。
AGENT
在 Claude Managed Agents 中,一个 agent 是一个版本化的配置:一个模型、一个系统提示词和一组工具。每次运行都遵循其运行步骤并停止。

在我们的参考实现中,智能体配置是 agent.md:
---
name: Daily brief
model: claude-sonnet-5-5
mcp_servers:
- type: url
name: github
url: https://api.githubcopilot.com/mcp/
tools:
- type: agent_toolset_20260401
configs:
- name: web_search
enabled: false
- name: web_fetch
enabled: false
- type: mcp_toolset
mcp_server_name: github
default_config:
permission_policy:
type: always_allow
---
[Eight numbered run steps; the full text is in agent.md in the repo.]
frontmatter 提供智能体名称、模型、工具和 MCP 服务器。正文提供智能体指令。MCP 工具默认需要审批,但没有人来批准,因此 GitHub 工具集被设置为 always_allow ,而 GitHub token 是 read-only.
Keep the brief short
agent.md 引导 Claude 保持简洁:
4. Decide. An item earns a line when the reader would act on it today, or it changes a decision they are about to make. When unsure, leave it out. Most days that is a few items, sometimes none. A count ("12 open reviews") is not an item; link the ones that are blocked. An item already in the ledger and still open is carried as one marked line ("still waiting, day 3"), not re-reported; a closed item is dropped without comment. Do not bring back a topic the preferences file has retired.
在发布前重新检查所有仍未解决的事项
在智能体读取来源和发布之间,条目可能会发生变化。就在发布之前, agent.md 指示智能体重新检查每个条目的实时状态:
5. Verify. The world moved while you read. For every item you will report, re-check its live source just before posting: resolved since you read it, drop it; still open but changed, fix the line; cannot confirm, drop it and list it in the run record's cuts. One stale "still waiting on you" costs more trust than ten missing items, so never hedge an item's status: assert it or drop it. Every link is copied from the source's own link field (a pull request's html_url, a Slack permalink), never assembled by hand.
SCHEDULE
使用 Claude Managed Agents,智能体只是一个配置文件;由一个 部署 来运行它。部署命名了智能体、环境和每次运行的第一条消息。它还保存了调度、保险库、记忆存储和预算。每次调度触发时,平台都会启动一个全新的智能体 会话.

在我们的模板中,部署被记录在 deployment.md中,第一条消息作为其正文:
---
name: Daily brief
agent: ./agent.md
environment_id: ./environment.yaml
schedule:
type: cron
expression: "32 7 * * 1-5"
timezone: America/New_York
vault_ids: [vlt_...] # the vault you create under Sources
resources:
- path: ./memory_store_preferences.yaml
access: read_only
instructions: The reader's preferences. Re-read them every run. Never write here.
- path: ./memory_store_state.yaml
access: read_write
instructions: Your state. Bookmarks, ledger, notes, proposals, and run records.
---
Write today's brief.
The reader's time zone is America/New_York. Work out every date in that zone.
Follow your run steps in order. Today's edition is titled "Daily brief, <weekday> <month> <day>".
这会创建部署,以及它按路径命名的智能体、环境和记忆存储。
CODEShellant apply deployment.md
为了不必等待调度即可测试,可以手动启动一次运行,使用 ant beta:deployments run --deployment-id <id>,并使用来自以下位置的 ID: claude-lock.json.
在你的时区中计算日期
一个常见的 bug 是 agent 把今天早上称为"昨天",因为它是在服务器的时区中计算日期。在 deployment.md中, timezone 字段设定运行触发的时间,而正文第二行告诉 agent 使用哪个时区来计算日期。
记忆
每次运行都在一个全新的沙箱中启动,对上一次运行毫无记忆。没有记忆,反馈就不会留存。然而,过时的记忆会让 agent 混乱:它会把一个条目报告为仍在等待,尽管它已被解决;或者因为"已报告过"而漏掉一个仍然未决的条目。

我们的模板保留两个 记忆存储,即挂载在 /mnt/memory/ 下的文件夹(参见 Sources):
-
preferences (你的,对 agent 只读):要读取哪些频道和仓库、要排除什么、长度上限、目的地以及何时停止。
-
state (agent 的,可读写):书签、已报告内容的台账、每次运行的记录、它对你的偏好提出的修改建议,以及关于每个信息源行为方式的备注("只返回最新的 50 条")。
ant apply deployment.md 会创建 preferences 存储,但不创建其中的文件。在首次运行之前,请使用仓库的 scripts/seed-preferences.sh.
在每次运行开始时重新读取你的偏好
一个常见问题是偏好的一份副本被硬编码进提示词中,从而持续应用你已经修改过的规则。让 agent 在每次运行时都重新读取该文件。如果它无法读取该文件,它应该停止并说明情况,而不是按默认设置继续运行。
记录你已报告内容的台账,并报告变化
agent 会维护一个台账,即 ledger.md,记录它已报告的每一个条目,这样简报就不会重复自己。每一行记录该条目何时被报告、来源、一个不会改变的 ID(Slack 消息时间戳或 pull request 编号),以及其最后已知状态:
2026-09-09 slack:C0123456789 1788963600.000100 refund thread: customer waiting on a decision 2026-09-11 github 481 review blocked, day 2 (still waiting) 2026-09-11 slack:C0234567891 1789117333.000300 enterprise escalation: owner named, in progress
防护措施
由于我们的自动化是按计划在"后台"运行的,我们对该 agent 能做什么、能花费多少都设定了限制。

对其能做什么的限制
agent 会读取其他人撰写的消息和 issue,这些文本可能被解释为指令。要限制 agent 如果遵循这些指令可能做的事情。在我们的例子中,GitHub token 和 preferences 存储是只读的,环境只能访问其允许列表中的主机。一条植入的指令仍然可以改变简报的内容,包括通过 agent 在运行之间保存的笔记。但它无法写入 GitHub 或编辑你的规则。
Slack 是例外:同一个 token 会发帖,所以只把 bot 邀请到它需要读取或发帖的地方。
根据真实运行设置支出上限
支出上限可以保护你免受失控成本的影响。从正常运行成本的三到五倍开始,然后随着你看到真实数字再收紧。达到上限的运行会暂停而不是失败,因此设置过低的上限看起来像一份悄然停止的简报。上限就是 budget 中的 deployment.md。每次运行都获得完整的额度,达到额度的运行会以一个 budget_reached stop reason 暂停:
budget:
type: limit
max_list_cost:
amount: "500" # a string, in cents: "500" is $5.00
currency: USD
入门指南
我们的参考实现归结为六条规则:
- 从书签读取每个数据源,而不是从固定时间窗口读取。
- 将失败的读取报告为不可读,绝不报告为平静的一天。
- 在发布之前重新检查每个条目。
- 只有当 Slack 确认后,才将一条帖子计为已发送,然后更新书签和账本。
- 每次运行时,都从一个代理无法编辑的存储中重新读取你的偏好设置。
- 在代理只需要读取的地方,给它只读访问权限,并限制每次运行可花费的额度。
Claude Code 可以引导你完成本文提供的指导。首先,更新:
CODEShellclaude update
然后,使用 claude-api 技能:
提示词/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/
claude-api 技能会阅读这篇文章,提出一个配置方案,将文件写入你项目中的 agents/ 文件夹,并使用 ant apply 创建资源。请将其视为一个起点,并根据你的来源、目标或记忆偏好自定义该智能体。
