跳到正文
Anthropic:Claude.dev 开发者博客· Lance Martin and CJ Avilla·· 6 小时前精选AI 评分68

Anthropic 用 Claude Managed Agents 构建定时智能体自动化的实践指南

Building effective agent automations

AI 导读

Anthropic 发布基于 Claude Managed Agents(beta)的每日简报参考实现,按计划读取 Slack 和 GitHub 来源并向 Slack 发布简报。

推荐理由

文章把定时智能体自动化拆成可复用的六个组件,并给出书签、台账和权限等可直接迁移的防错规则。

正文 · AI 翻译

随着 AI 加速我们的工作,跟上进度变得越来越难。在 Anthropic,简单的智能体自动化经常被用来提供帮助。它们通常按计划运行,在后台收集上下文,并主动告诉我们需要知道的信息。但构建有效的智能体自动化并不容易:它们可能会在无人察觉的情况下失去对某个来源的访问权限,或者无法遵循我们的偏好。

使用 Claude Managed Agents(beta),我们构建了一个参考实现,它按计划读取自定义来源(例如 Slack 和 GitHub 仓库),跟踪自上次运行以来的变化,并发布你需要知道的信息(例如发布到 Slack)。在本文中,我们将逐步讲解每个步骤,分享一个参考实现,并提供一条可在 Claude Code 中运行的命令,为你配置好该智能体。

获取代码

参考实现在这里。如需交互式演练,请在 Claude Code 中运行以下命令。claude-api 技能可以按照本文的指导帮助设置该智能体:

PROMPT

/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/

对于这个参考实现,你需要一个 Slack 应用(从 manifest 创建它)和一个 GitHub token。所提供的文件(如下所示)是 Claude API 资源的配置,包括智能体、其环境、记忆存储、vault 和部署。

CODEText

daily-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 的基础设施上按计划运行,因此你的机器上无需保持任何进程运行。

概述

我们将构建的智能体有六个组件,按以下顺序介绍:

  • 来源 - 一个命名的读取位置列表
  • 目标 - 智能体可以写入的一个位置
  • 智能体 - agent.md 中的模型、工具和运行步骤
  • 计划 - 一个 cron 计划
  • 记忆 - 你的偏好以及智能体自身的记忆
  • 护栏 - 在智能体只读取的地方使用只读访问,以及每次运行的支出上限
Architecture of the agent: a schedule wakes the agent, which reads from its sources and posts a brief to one destination for the reader. Memory holds the agent's state and the reader's preferences, and guardrails surround the agent.

来源

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

The architecture diagram with Sources highlighted. The sources are read-only, reached through MCP or HTTPS with credentials from a vault, and feed the agent.

为智能体提供其专属的、限定范围的凭证

使用 Managed Agents 时,凭证存放在 vault 中。智能体可以引用这些凭证,但真实值保留在 vault 中,位于 Claude 代码运行的沙箱之外(参见此处和此处):

  • MCP 服务器(GitHub)。 智能体通过一个在沙箱外运行的代理调用 MCP 工具。该代理会找到 URL 与该服务器匹配的 vault 凭证。

  • Shell(Slack)。 智能体在沙箱内使用 bash 工具通过 curl 调用 Slack API。沙箱中只保存一个不透明的占位符 $SLACK_BOT_TOKEN。当请求离开沙箱时,平台会为你允许的主机替换为真实 token。

使用 ant CLI 和仓库中的模板文件创建 vault:

CODEShell

ant apply vault.yaml

这会在你的 Claude API 工作区(平台存储它的地方)中创建 vault,并将其 ID 记录到 claude-lock.json 中。然后使用 TypeScript SDK 将每个凭证添加到 vault 中。以下示例展示了添加 Slack 凭证的过程:

CODETypeScript

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 附加到部署。将 claude-lock.json 中的 vault ID 复制到部署文件 deployment.md 中的 vault_ids。

从上次中断的地方继续读取

一个常见的错误是让 agent 读取固定的时间窗口,比如“过去 24 小时”。运行时间偏晚会留下空档,运行时间偏早则会重复条目。相反,应为每个来源给 agent 一个书签。每次运行结束时,agent 将每个来源中读取到的最新条目的时间戳写入一个文件 bookmarks.json,每个来源一条记录:"slack": "2026-09-14T13:02:11Z"。

下一次运行从这些书签开始,因此其窗口会伸缩以覆盖自上次运行以来的所有内容。书签存放在名为 state 的 memory store 中:这是一个文本文件文件夹,平台会将其挂载到每次运行的沙箱中的 /mnt/memory/ 下,并在运行之间保留。agent 使用其普通文件工具读写它,agent.md 中的说明会告诉它如何操作。

不要把读取失败误认为风平浪静

如果某个 MCP 服务器宕机或其令牌已过期,运行仍会启动,只是没有该服务器的工具。会话会记录一个错误,但 agent 从该来源看不到任何内容,并报告“没有新内容”。

agent.md 中的三条规则有助于解决此问题。当某个来源失败时,agent 将:保持该来源的书签不变,用其他来源撰写简报,并在简报末尾用一行说明它无法读取的内容(“本次运行无法获取 pull requests”),以便让读者知晓。

目标

我们的模板会发布到一个 Slack 频道,每次运行时发布一条带日期的帖子。

The architecture diagram with Destination highlighted. After a check that today's brief isn't already posted, the agent posts to one destination, which delivers the brief to the reader.

agent 使用其沙箱中的 bash 工具发布到 Slack,使用与读取时相同的 bot token。

帖子无需任何批准。agent 通过 bash 命令发送它,而内置的 bash 工具默认无需请求批准即可运行。slack.com 也在 agent 的 environment(其运行的沙箱)的允许列表中。该帖子是一个请求:

CODEShell

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 就会更新其已报告条目的账本及其书签。如果这些记录与实际发布的内容不匹配,可能会出两种问题。如果 agent 记录了从未发布的帖子,书签会继续前进,那些条目就永远不会被报告。如果它因为不确定第一个帖子是否发布而再次发布,读者会收到两次相同的简报。

agent.md 中的三条规则可以防止这种情况。首先,agent 会在频道的最近消息中查找今天的标题,如果该期已经存在,则不会发布。其次,只有当 Slack 返回 "ok": true 和消息 ts 时,帖子才被视为已发送。第三,agent 仅在该确认之后才更新账本和书签。如果结果不明确,它会将该次运行标记为“可能已发布”,并且不更改其他任何内容,因此不会丢失任何信息。

agent 在其 memory store(runs/<date>.md)中保留运行记录。它在发布前将运行标记为“发布中”,然后标记为“已发布”并附上消息 ID,或标记为“可能已发布”。

AGENT

在 Claude Managed Agents 中,agent 是一种版本化配置:一个模型、一个系统提示和工具。每次运行都遵循其运行步骤并停止。

The architecture diagram with the Agent highlighted: a model plus a prompt that holds the run loop and the judgement rules.

在我们的参考实现中,agent 配置是 agent.md:

CODEMarkdown

---
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 提供 agent 名称、模型、工具和 MCP 服务器。正文提供 agent 指令。MCP 工具默认请求批准,而没有人可以给予批准,因此 GitHub 工具集设置为 always_allow,GitHub token 为 read-only。

保持简报简短

agent.md 引导 Claude 保持简洁:

CODEText

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 读取来源到发布之间可能发生变化。就在发布前,agent.md 会指示 agent 重新检查每个条目的实时状态:

CODEText

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 时,agent 只是一个配置文件;由 deployment 来运行它。deployment 指定 agent、环境和每次运行的第一条消息。它还持有 schedule、vault、memory stores 和 budget。每次 schedule 触发时,平台都会启动一个全新的 agent session。

The architecture diagram with Schedule highlighted: a scheduled deployment that wakes the agent for each run.

在我们的模板中,deployment 被记录在 deployment.md 中,第一条消息作为其 body:

CODEMarkdown

---
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>".

这会创建 deployment,并带上它按路径指定的 agent、环境和 memory stores。

CODEShell

ant apply deployment.md

若不想等待 schedule 就进行测试,可用 ant beta:deployments run --deployment-id <id> 手动启动一次运行,使用来自 claude-lock.json 的 ID。

按你的时区计算日期

一个常见的 bug 是 agent 把今天早上称为“昨天”,因为它按服务器的时区计算日期。在 deployment.md 中,timezone 字段设置运行触发的时间,而 body 的第二行告诉 agent 用哪个时区来计算日期。

MEMORY

每次运行都从一个全新的沙箱开始,对上一次运行毫无记忆。没有记忆,反馈就无法留存。然而,过时的记忆也会让 agent 困惑:它会把已解决的条目报告为仍在等待,或者因为“已经报告过”而漏掉一个仍未关闭的条目。

The architecture diagram with Memory highlighted. State is what the agent reads and writes, and Preferences is what the reader writes and the agent only reads.

我们的模板保留两个 memory stores,即挂载在 /mnt/memory/ 下的文件夹(见 Sources):

  • preferences(你的,对 agent 只读):读取哪些频道和仓库、要排除什么、长度上限、目标位置,以及何时停止。

  • state(agent 的,可读写):书签、它报告过内容的台账、每次运行一条记录、它对你 preferences 提出的修改,以及关于每个来源行为的备注(“只返回最新的 50 个条目”)。

ant apply deployment.md 会创建 preferences store,但不会创建其中的文件。首次运行前,用仓库的 scripts/seed-preferences.sh 把你的 preferences.md 写进去。

每次运行开始时重新读取你的 preferences

一个常见问题是把 preferences 的副本固化进 prompt,这会持续应用你已经修改过的规则。让 agent 每次运行都重新读取该文件。如果它无法读取该文件,应当停止并说明,而不是按默认值运行。

保留一份你已经报告过内容的台账,并报告变化

agent 会保留一份台账 ledger.md,记录它报告过的每个条目,这样简报就不会重复自己。每一行记录该条目被报告的时间、来源、一个不变的 ID(Slack 消息时间戳或 pull request 编号),以及它最后已知的状态:

CODEText

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

GUARDRAILS

因为我们的自动化是按 schedule 在“后台”运行的,所以我们为 agent 能做什么、能花多少设定了限制。

The architecture diagram with Guardrails highlighted: a boundary around the agent with caps on turns, time and spend, and a heartbeat that someone watches.

对它可做之事的限制

agent 会读取其他人写的消息和 issue,而这些文本可能被解读为指令。要限制 agent 若听从它们可能做出的事。在我们的示例中,GitHub token 和 preferences store 是只读的,环境只能访问其 allowlist 上的主机。植入的指令仍可能改变简报的内容,包括通过 agent 在运行之间保留的备注。但它无法写入 GitHub 或编辑你的规则。

Slack 是例外:同一个 token 负责发帖,所以只在机器人需要读取或发帖的地方邀请它。

根据真实运行情况设置支出上限

支出上限可以保护你免受失控成本的影响。先从正常一次运行成本的三到五倍开始,等你看到真实数字后再收紧。达到上限的运行会暂停而不是失败,所以上限设得太低看起来就像简报突然没了动静。上限就是 deployment.md 中的 budget。每次运行都会获得全额额度,而达到上限的运行会以 budget_reached 停止原因暂停:

CODEYAML

budget:
  type: limit
  max_list_cost:
    amount: "500" # a string, in cents: "500" is $5.00
    currency: USD

入门指南

我们的参考实现归结为六条规则:

  • 从书签读取每个来源,而不是固定的时间窗口。
  • 将读取失败报告为不可读,绝不要报告为平静无事的一天。
  • 在发帖前重新检查每一个条目。
  • 只有当 Slack 确认后才将帖子计为已发送,然后更新书签和账本。
  • 每次运行都重新读取你的偏好设置,从 agent 无法编辑的存储中读取。
  • 在 agent 只读取的地方授予只读访问权限,并限制每次运行可以花费的额度。

Claude Code 可以带你了解本文提供的指导。首先,更新:

CODEShell

claude update

然后,使用 claude-api 技能:

PROMPT

/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/

claude-api 技能会阅读这篇文章,提出一套配置方案,将文件写入你项目中的 agents/ 文件夹,并使用 ant apply 创建资源。把这当作起点,并根据你的来源、目标或记忆偏好来自定义 agent。

来源:Anthropic:Claude.dev 开发者博客 · claude.dev