Agent 进生产前,先把这八段 spec 写清楚
一份给 AI agent 的 spec 模板:身份、任务边界、循环上限、工具契约、决策树、停机条件、输出契约和护栏,每一段都对应一种常见翻车方式。
多数 agent 项目在会议里只有一句话。从这句话到能碰生产,中间差一份短文档。原帖作者 Virtual_Hair_1987 在 r/PromptEngineering 把它拆成八段,每段都对着一种具体失败。
GitHub 的 Spec Kit 和 AWS 的 Kiro 已经在推 spec-first,只是都偏向代码功能。Spec Kit 让编码 agent 在聊天里调用 /speckit-constitution、/speckit-specify、/speckit-plan 等命令,让 spec、plan 和任务列表先于实现出现。Kiro 的文档把 spec 定义成结构化产物,工作流会生成 requirements.md、design.md、tasks.md。Anthropic 对 agent 的定义更接近开放问题:模型自己决定流程和工具调用,步数很难提前写死。给 agent 写 spec,重点在围出边界,不在写死每一步。
示例句子:
我们需要一个 agent,读取新客服工单,把它放进正确队列。

1. 身份写到具体级别
给 agent 一个具体角色,还要标出级别,免得模型退回自己的默认设定。
你是一家 B2B 计费产品的高级支持运营专员。你能分清支付失败、开通 bug 和功能请求,也知道各自该进哪个队列。
这段防的是模型退回默认行为。Arize AI 的现场分析把预训练偏好压过检索上下文列为生产 agent 常见失败之一。训练里学到的行为经常赢过 prompt 里给的上下文。
2. 任务目标,加上不做什么
任务段写清目标、成功条件,以及 agent 不做什么。
GOAL 给过去一小时打开的每张工单分配且只分配一个队列,
并在工单上记录一行理由。
SUCCESS 窗口内每张工单都有队列和非空理由,或者被标记为 escalated。
DOES NOT 回复客户。发退款或信用额度。关闭或合并工单。
修改人工已经设置过的队列。
这段防的是边缘慢慢扩张。没人会在 prompt 里写顺便回复客户。模型觉得回复有帮助,边界就松了。最后一行通常是出事第二天补上的。
3. 推理循环和上限
写清 agent 跟什么模式走,最多迭代几次,撞到上限后做什么。
PATTERN 观察工单,判断信息是否足够路由,最多调用一个工具,
观察结果,重复。
MAX_ITERATIONS 5
AT_CEILING 停止,升级,把目前收集到的内容全部附上。
这段防的是永不结束的循环。Arize 的分类里有递归循环和低效轨迹,还造了 Polling Tax 这个词,指 agent 反复查状态,不去等 webhook。它能看到一串 200 OK。最坏情况,一个任务几百次 API 调用,答案还对,路径已经让成本不可用。只写 MAX_ITERATIONS 不够,还要写撞墙后做什么,否则 agent 会安静地停在半路。
4. 每个工具一份契约,失败路径也要写
每个工具都写同样五段。
TOOL get_customer_plan
WHAT 返回一个账户的计费计划和合同层级。
WHEN 仅当工单提到价格、发票、席位或计划名,并且工单带 account_id 时调用。不要试探性调用。
RETURNS { account_id: string, plan: starter|team|enterprise,
seats: int, contract_end: ISO-8601 date }
ON FAILURE 超时:重试一次。第二次失败,或结果为空:路由到 billing_general,
在工单上记下 plan lookup unavailable。不要从工单文本猜计划。
EXAMPLE get_customer_plan(account_id: acc_8812)
这段防的是不报错的失败。Arize 的第二个失败模式是工具调用参数幻觉。例子很具体:agent 以为字段叫 user_id,真实 schema 要 customer_uuid。数据库返回零行,没有报错,agent 说没查到数据。Arize 把这叫中间工具逻辑里的静默幻觉。所以 RETURNS 要带真实字段名,空结果要进失败路径。Anthropic 在 Building Effective AI Agents 的附录 Prompt engineering your tools 里说,agent 和工具的接口,值得像给人写的 prompt 一样认真。
5. 决策树
每个分支都测 agent 能看见的东西,每个分支都落到一个动作。
IF 工单文本匹配 card decline / payment failed
THEN queue = billing_urgent
ELSE IF 工单提到发票、席位或计划变更
AND get_customer_plan 返回 plan = enterprise
THEN queue = billing_enterprise
ELSE IF 工单包含 stack trace 或错误码
THEN queue = engineering_triage
ELSE queue = triage_human, reason = no matching rule
这段防的是你没写的那条分支。没有最后 ELSE,没匹配上的工单会落到模型判断里,等有人审计队列才发现。
6. 机器能检查的停机条件
工单处理完就停,这是愿望。停机条件要能直接写进代码,不需要模型解释。
STOP WHEN queue 已设置 AND reason 非空
STOP WHEN escalated == true
STOP WHEN iterations == 5
STOP WHEN ticket.status != new
每一条都是布尔值。这是门槛。
7. 输出契约
输出契约固定 agent 返回的记录:工单 id、一个队列、最多 20 个词的理由、升级标记、调用过的工具列表。
{ ticket_id: string,
queue: billing_urgent | billing_enterprise | billing_general
| engineering_triage | triage_human,
reason: string, max 20 words,
escalated: boolean,
tools_called: [string] }
这段防的是下游代码因为结构变化挂掉,也让评估变得可能。输出固定成记录,才能拿一周路由结果和人工结果做 diff,得到一个数。没有契约,只能读 transcript。
8. 护栏,每条带理由
每条护栏都写规则和理由,至少覆盖四类:数据处理、范围、冒名、不可逆操作。
不要把完整工单正文写进路由日志,因为工单包含客户支付信息,受保留期限约束。
不要以某个同事的名义签注,因为这会误导谁处理了工单。
不要发信用额度或退款,因为这会动钱,而且无法从这个 agent 内部撤销。
不要关闭或合并工单,因为合并会销毁原始会话。
理由不是装饰。模型碰到没列出的情况时,需要从理由里泛化。下一个工程师也能判断这条规则还成不成立。这里要清楚:spec 是给 reviewer 看,告诉他在代码里强制什么。Arize 说得很直接:提示词只是建议,缺少代码的刚性。安全不能只靠模型,要有确定性层检查 payload,独立于 agent 的推理去拦截。Anthropic 也提醒,agent 的自主性带来更高成本和错误累积,建议在沙箱里大量测试,再加合适护栏。
最容易被跳过的两段
不做什么,和机器可检查的停机条件。这两段写起来最不痛快,出问题后也最常被想起。它们管的是 agent 遇到你没预料的情况。其他段落更多在描述顺利路径。如果只写两段,写这两段。
等 agent 真跑起来,还有两段值得加:两次运行之间记住什么,每接一个外部接口怎么恢复。Arize 的清单里有外部 API schema 变化和长会话里的指令漂移,这两个更偏记忆和恢复,不偏推理。小分流 agent 的第一版可以先不写。
帖子下面有人补了一个建议:在输出里加 evidence 和 unknown 字段,让 reviewer 看出哪条路由来自工单,哪条是模型推断。不然一段自信的摘要很容易被当成证据。另一个跟帖提醒,brief 要有清楚优先级,否则 agent 像一个很锋利的外包团队,认真把错的东西做出来。流程怎么走,数据怎么显示,布局对不对,要不要再改一版,这些最后还是人的责任。
Sources:
- GitHub Spec Kit: https://github.com/github/spec-kit
- AWS Kiro docs: https://kiro.dev/docs/specs/
- Anthropic, Building Effective AI Agents: https://www.anthropic.com/engineering/building-effective-agents
- Arize AI, Why AI Agents Break: https://arize.com/blog/common-ai-agent-failures/
发布时间: 2026-11-15 03:59