欢迎访问晨星博客!
一个很常见的场景:站点上装了个 AI 写作插件,定时任务每天生成三篇草稿,某天有篇文章把过期的价格写进了正文并自动发布。你想回溯——是哪次运行、用了什么提示词、模型返回了什么、谁点了发布——结果只能翻到一行 cron 日志和一条 post_modified 时间戳。这不是模型能力问题,是流程没有留下可核对的痕迹。
Buzz 有意思的地方正好在这里。它是 Block 开源的自托管协作平台(仓库 block/buzz,Apache-2.0),在它的设想里,人和 AI agent 待在同一批频道里,而每个参与者持有属于自己的密钥对——不是借用某个人的登录态。对做内容自动化的站长来说,这句话翻译过来就是:agent 的每一次动作有独立的行为主体,而不是「管理员账号又干了点什么」。

官方在 VISION 文档里把定位说得很直白:relay 就是工作区,Buzz 是管道——事件存储、搜索索引、订阅、投递——不是大脑。智能由人和 agent 带进来。
这句定位决定了整套集成的边界。指望 Buzz 内置一个「WordPress 发布模块」是想错了方向;它提供的是一个可自托管、有身份体系、消息可检索的共享空间。内容怎么生成、按什么标准审、什么时候允许发布,得由你在这个空间之上定义。仓库里带有容器编排配置,自建 relay 是设计中的常规用法,这也是我愿意把内容流水线接到它上面的主要原因:数据和身份都在自己的域里。
所以整条链路实际分成三段职责。Buzz 负责承载对话、事件与 agent 身份;你的 WordPress 站点负责暴露一组受控的操作能力;中间那层流程定义负责规定这些能力按什么顺序、在什么条件下被调用。三段分开,出问题时才知道该看哪儿。
已经有实现走通过这条路。VayuPress 做的 Buzz 连接器(随其 v3.15.86 提供)就是让 Buzz 频道里的 agent 通过站点已有的 MCP 接口来调用工具,比如发布文章、更新页面、读取分析数据。作者特别强调它是 inbound only:agent 进来用你的工具,站点不为此新增依赖、新增密钥或新增出站路径。
这个取舍值得抄。入站单向的好处是攻击面和审计面都收窄了——所有动作都从你自己的接口进来,权限校验、参数校验、记录都由你控制。如果你不打算直接用现成插件,最小可用的做法是自己注册一组窄接口,每个接口只做一件事:
add_action( 'rest_api_init', function () {
register_rest_route( 'agent-flow/v1', '/draft', array(
'methods' => 'POST',
'callback' => 'agent_flow_create_draft',
'permission_callback' => function ( WP_REST_Request $request ) {
// 只允许被授权的机器身份,且只给「写草稿」这一项能力
return current_user_can( 'agent_flow_write_draft' );
},
'args' => array(
'run_id' => array( 'required' => true, 'type' => 'string' ),
'title' => array( 'required' => true, 'type' => 'string' ),
'body' => array( 'required' => true, 'type' => 'string' ),
),
) );
} );
function agent_flow_create_draft( WP_REST_Request $request ) {
$post_id = wp_insert_post( array(
'post_title' => sanitize_text_field( $request['title'] ),
'post_content' => wp_kses_post( $request['body'] ),
'post_status' => 'draft', // 生成阶段永远只落草稿
), true );
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
update_post_meta( $post_id, '_agent_run_id', sanitize_key( $request['run_id'] ) );
update_post_meta( $post_id, '_agent_stage', 'generated' );
return array( 'post_id' => $post_id, 'status' => 'draft' );
}
关键在 post_status 和那个 run_id。生成接口不给发布能力,发布是另一个接口、另一项 capability;run_id 则是后面所有审计动作的串联键,缺了它,多个 agent 并发写稿时你分不清哪篇属于哪次运行。
按 Buzz 的身份思路做延伸:给 agent 单独建 WordPress 用户,配一个只含必要 capability 的自定义角色,认证凭据独立签发和轮换。这样做不只是安全洁癖——审计的前提是行为可归属。共用管理员账号的自动化,事后所有记录都指向同一个人,等于没有记录。

到这里能力面已经就绪,但「什么时候调哪个」还散落在代码和定时任务里。我的做法是把流程本身抽出来写成 YAML 文件,跟主题或插件代码一起进版本库。声明式描述带来两个直接收益:改流程会产生 diff,出事故能 checkout 到当时的版本重放。
需要说明的是,下面这份结构是我为自己的编排层定的约定,不是 Buzz 的内置格式——你完全可以按团队习惯改字段名,重点是把阶段、条件和人工关卡显式写出来:
name: post-editing-pipeline
version: 3
identity: agent-editor # 对应站点里那个专用机器身份
stages:
- id: draft
tool: agent-flow/v1/draft # 只允许写草稿的接口
inputs:
topic_source: editorial-queue
on_error: stop
- id: review
tool: agent-flow/v1/review
checks:
- factual_claims_have_source
- no_external_links_without_allowlist
- length_within_range
on_fail: return_to: draft
max_retries: 1
- id: human_gate
type: manual # 人工确认,不可被 agent 跳过
notify_channel: editorial
timeout_action: keep_draft
- id: publish
tool: agent-flow/v1/publish
requires: human_gate.approved
human_gate 这一段是整份文件里最不该省的。把人工确认写成流程里的一个显式阶段,而不是「记得去后台看一眼」,才能让 publish 接口有资格拒绝任何没带审批标记的请求。发布端的校验大致是这个意思:
function agent_flow_publish( WP_REST_Request $request ) {
$post_id = absint( $request['post_id'] );
if ( 'approved' !== get_post_meta( $post_id, '_agent_stage', true ) ) {
return new WP_Error( 'agent_flow_not_approved', '该草稿尚未通过人工确认', array( 'status' => 409 ) );
}
wp_update_post( array( 'ID' => $post_id, 'post_status' => 'publish' ) );
// 把这次运行的关键动作追加进可查询的审计记录
add_post_meta( $post_id, '_agent_audit', wp_json_encode( array(
'stage' => 'publish',
'run_id' => get_post_meta( $post_id, '_agent_run_id', true ),
'time' => current_time( 'mysql', true ),
) ) );
return array( 'post_id' => $post_id, 'status' => 'publish' );
}
服务端做这层判断,而不是信任调用方声称「已审过」,是可审计流水线和「看起来有审核」的分界线。
审稿阶段的检查项也建议尽量写成能机械判定的规则。像「是否有无来源的具体数字」「外链是否在白名单内」「篇幅是否越界」这类,agent 能给出稳定结论;而「语气对不对」「这个判断站不站得住」交回人工,命中率更高,也省得为了让流程全自动而降低标准。
这两种做法都能把文章发出去,区别在事后能不能说清发生了什么,以及流程长大之后改不改得动。
| 维度 | 传统插件触发器 | Buzz + YAML 工作流 |
|---|---|---|
| 触发方式 | 定时任务或后台钩子,条件写死在代码里 | 频道内的对话事件或显式调用,条件写在流程文件里 |
| 行为归属 | 通常复用管理员账号 | agent 持有独立身份,动作可归属到具体主体 |
| 流程变更追溯 | 改设置项,历史版本一般不留痕 | 流程文件进版本库,改动产生 diff |
| 人工关卡 | 靠人记得去后台审 | 作为显式阶段存在,发布端可强制校验 |
| 失败恢复 | 多为重跑整个任务 | 可按阶段和 run_id 定位后重入 |
| 扩展新步骤 | 往回调里继续加分支 | 在流程文件中新增阶段,能力面单独授权 |
代价也得说清楚。插件触发器装完就能跑,而这套方案要你自己维护 relay、机器身份、接口和流程文件,初期投入明显更高。站点每天出一两篇稿、只有你一个人管,用现成插件更划算;一旦有多人协作、有对外署名的内容要负责、或者需要向别人解释某篇文章是怎么来的,可审计性才开始值这个钱。

真正把 agent 接到生产站点之前,这几项我会逐条确认,顺序大致就是风险从高到低:
run_id、阶段轨迹和审批人最后一点补充:先从一条最短的链路开始,只做「生成草稿 + 人工确认」,把审计记录跑通了再往里加自动审稿、多 agent 分工。流程文件的价值恰恰在于加东西的时候有 diff 可看,不必一开始就把全部阶段设计完整。想看 Buzz 这套身份和工作区模型的具体表述,仓库里的 VISION 文档比二手解读清楚得多;而 MCP 侧的落地形态,VayuPress 那篇连接器说明提供了一个可对照的实现思路。
声明:原创文章请勿转载,如需转载请注明出处!