---
name: banyan-content-workflow
description: "榕树 banyan 的自媒体内容流水线：按「宽进窄出」的漏斗走完选题 → 资料 → 评估 → 撰写 → 验收 → 多平台发布。当你要写一篇内容、管理选题池（候选 / 入选 / 已完成）或整理资料库（来源 + 关键事实）时用它；含 Banyan MCP 工具与本地 HTTP API 两条通道的用法与常见坑。"
license: MIT
metadata: {"banyan-id": "banyan-content-workflow", "banyan-mcp": "required"}
---

# 榕树 banyan — 内容流水线（宽进窄出）

把一篇内容从「一个题材」做到「发布到多个平台」，走的是**宽进窄出**的漏斗：入口放宽，允许候选大量堆积、允许死掉；出口收窄，只有评估通过的题才动笔。本技能是可移植的通用版本，不绑定某一位作家的配置。

## 什么时候用

- 用户说「写一篇」「今天写什么」「帮我找几个选题」「把这批资料整理成稿」；
- 需要管理**选题池**（记题 / 评估 / 定优先级 / 领取 / 完成）或**资料库**（信源 + 关键事实）；
- 需要把稿件落成草稿或发布到多平台（公众号 / 头条 / 知乎等）。

**不适合**：与榕树无关的纯问答或代码任务；定时任务排期本身（那是运维层，不在这里）。

## 工具面：先选通道

**通道一（优先）Banyan MCP 工具**，可用工具：

```
list_platforms  list_accounts  create_article  list_articles  get_article
update_article  delete_article  publish_article  upload_media
list_image_templates  generate_image
list_topics  create_topic  assess_topic  list_sources  add_sources
set_topic_priority  claim_topic  complete_topic  release_topic
```

工具是延迟加载的：先搜出工具、再看 schema、再调用；参数按 schema 平铺传（如 `create_article` 的 `{title, content, platforms[], coverImage?, mediaPaths[]}`），不要自造嵌套结构。工具名/参数以运行时拿到的 schema 为准，别照抄示例硬编码。

**通道二（无 MCP 时）榕树本地 HTTP API**：接口地址与认证 token 在客户端「设置 → API 与 MCP」页查看（默认 `http://127.0.0.1:5832`，请求头 `Authorization: Bearer <token>`）。MCP 与 API 都是榕树客户端的本地服务，所以**客户端必须在运行**；报 `login_required` / 「生成草稿需要先登录榕树账号」表示客户端未登录账号，只能由用户在客户端登录，**不要重试**。

## 内容流水线七步

### 1. 划定题材

先定「写什么领域、写给谁、不写什么」。题材范围窄一点比宽一点好：宽泛的题材会让后面每一步都失焦。产出是一句话的题材定义 + 3-5 条边界（明确排除哪些内容）。

### 2. 定题入库（先记为候选，不直接开写）

把题记进选题池，**默认落「候选」**——候选不参与领取、不占额度，允许堆积。用 `create_topic` 时把判断层写具体，别只写个标题：

- `title` 主题（必填）、`outline` 大纲 / 写作要求、`category` 题材、`mode` 创作类型、`priority` 1-9（越小越先写，默认 P5）；
- 判断层：`angle` 切入角度（别人写过的不写）、`audience` 写给谁（具体到人）、`whyNow` 时效锚（为什么是现在）、`differs` 差异（别人写过什么、我写什么没写透）、`payoff` 读完得到什么、`risk` 事实 / 合规风险及处理方式、`evidence` 可核查的事实列表。

**记题 ≠ 开写。** 一轮里先产候选、再统一评估，比「想到一个就写一个」稳得多：候选层是允许死掉的，写稿层不许。

### 3. 搜集资料并落库（来源 + 关键事实，同 URL 复用）

对要评估或要写的题，把资料**落库**，不要只留在上下文里——只在上下文里搜集，下一轮会重复抓同一批源，写稿时也查不到依据。

- `add_sources({ sources: [...], topicId })`：每条给 `title` / `url` / `publisher` / `publishedAt` / `kind` / `credibility` / `keyFacts[]` / `summary` / `status` / `role`；
- **URL 相同则复用既有资料**（不要制造重复条目）；带 `topicId` 时顺带挂到该选题；
- `list_sources` 回看：`?topic=<id>` 看某题的资料，`?status=active|used|stale|dead` 按状态筛。
- 选题评估时用 `evidence` + `sourceId` 指向已入库资料，做到「每句关键断言都能追到一条来源」。

### 4. 选题评估（入选 / 落选 / 搁置 / 观察）

用 `assess_topic({ id, verdict, score?, reason?, parkedUntil? })`，四种结论：

| verdict | 结论 | 语义 |
|---|---|---|
| `shortlist` | 入选 | 真要写；**唯一会被作家领取的状态**，占「在办额度」（入选 + 写作中每作家最多 30 条） |
| `reject` | 落选 | 淘汰；**必须写 `reason`**，理由进同题去重，下一轮不再重复产出同一批题 |
| `park` | 搁置 | 有料但时机未到；**必须写 `reason`**（可带 `parkedUntil`） |
| `watch` | 观察 | 留在候选，只记下这次评估（分数 / 理由），不动状态 |

评估结论要**成组产出**：一批候选一次过完，别只挑一条。落选不写理由是无效评估（数据层会拦），写理由这件事本身就是在给下一轮省事。定优先级用 `set_topic_priority({ id, priority })`（只能调自己产出 / 未绑定的待写题）。

### 5. 撰写并校验（关键数字事实写作当下核验，禁止编造）

- 领取：`claim_topic({ profile })` 原子领取「入选」的题并置为写作中。**池空（404）就说明没有入选题**——此时应该报告并等用户决定，或先回去评估，**不要凭空开写**。
- 中断 / 放弃：`release_topic({ id })` 放回待写。写作中超过 24 小时未更新，会在下次领取时自动退回入选。
- **写作当下的核实纪律**：正文里的关键数字、时间、人名、机构、版本号，落笔这一刻必须能追到可查来源（优先资料库里那条 `keyFacts`）；追不到就降级为定性表述或删掉，**禁止用「大概是」「应该差不多」把数字糊过去，更禁止编造来源**。原文专名核实不出来时，保留原文拼写并注明口径，别脑补品牌归属。
- 引用他人观点 / 数字时标注出处与日期；同一量的两个口径（厂商自测 vs 独立研究）各自署名、不混用，必要时另起一段「编译注」。

### 6. 产出规范验收（字数 / 结构 / 标题 / 排版 / 平台适配）

发布前逐项过一遍，缺项的稿子不进草稿箱：

- **字数**：按目标平台与文体核对（长文有下限，短讯 / 译文不硬凑字数）；统计口径用「总字符（去空白与 Markdown 符号）+ 汉字数」两个数一起看。
- **结构**：标题 → 导语 → 分层小节 → 结尾；小节之间不重复，别用「首先 / 其次」堆砌空话。
- **标题**：能看出写给谁、读完得到什么；不做标题党（正文兑现不了的标题是负分）。
- **排版**：中文标点全角、引号用「」与“”，不残留半角逗号 / 冒号 / 直引号；列表与前后的空行统一。
- **平台适配**：按目标平台的字数上限、图片数量限制、是否支持外链、封面比例逐项对齐（`list_platforms` 看平台能力）。
- **配图**：正文图片用 HTML `<img src="/绝对/本地/路径.png" alt="…" />` 直写真实路径，**不要用 Markdown 图片语法**——发布时资源匹配会把路径里的空格编码成 `%20`，导致「有 N 张正文图片上传失败」而发布仍报成功。封面用 `list_image_templates` 选模板 + `generate_image` 生成，非图片素材走 `upload_media`。

### 7. 发布

- 建稿：`create_article({ title, content, platforms[], coverImage?, mediaPaths[] })`；先要 check 用 `list_articles` / `get_article` 确认稿件真的建出来了，再发。
- 发布：`publish_article({ id, platformIds[], coverImage? })`；`list_accounts` 看有哪些已接入账号。
- **`success=true` ≠ 已发布**：发布结果要看 `publishError` 与每个平台的 `postData[].status`。微信公众号的「成功」形态是「草稿已建、待人工发表」（机制限制，不允许全自动发表）——汇报时如实写，不要报成「已发布」。某个平台失败时其余平台的成败各自独立，逐平台报。
- 发布失败（凭证失效 / 平台拒绝）时**稿件和封面都已存好，不要重写**：修好凭证后对同一 `id` 重发即可。
- 收尾：`complete_topic({ id, articleId })` 把选题置「已完成」并关联稿件；这一条别漏，否则该题会被下一轮重复领取。

## 选题状态语义（记牢这三种）

| 状态 | 含义 | 关键约束 |
|---|---|---|
| 候选 `candidate` | AI 产出或人工记下的题 | **允许大量堆积，不占额度**；不参与领取 |
| 入选 `shortlisted` | 评估通过、真要写 | **唯一能被领取的状态**；受「在办额度」限制（入选 + 写作中每作家 ≤ 30 条，超了不能再入选） |
| 已完成 `done` | 终态，不再流转 | 不能回退；不强制关联文章 |

另外三个状态也要认识：写作中 `writing`（被某位作家领取）、落选 `rejected`（淘汰，必带理由）、搁置 `parked`（有料但时机未到，必带理由）。

读题 / 查题用 `list_topics`：`?status=<状态>` 过滤，`?mine=1` 只看自己创建的候选。

## 常见坑

- **候选再多也不会被写**：领取只查「入选」的题。池里没有入选题时应报告并等决定，而不是拿候选凑数直接开写。
- **额度只算在办**：「入选 + 写作中」合计上限 30 条；写掉或落选清理才能入选新题。候选不占额度，所以「先多记、后收敛」是安全的。
- **落选 / 搁置必须带理由**：理由进同题去重；没有理由的淘汰等于把同一批题原样丢给下一轮。
- **题材不匹配也领不到**：领取除了状态还看题材与创作类型匹配，写「不限领域」才算不限。
- **别在确定失败的调用上反复重试**（如 `login_required`、池空 404）：连续失败会触发 MCP 熔断，把能用的调用一起拖垮。
- **选题状态机不是发布链的前置**：客户端版本较老 / 选题池不可用时，发布链（`generate_image` → `create_article` → `publish_article`）照常能走；此时把关选的题写进汇报，别在选题工具上硬耗。
- **发布链的最终口径只有一个**：稿件字段 `publishError` 与 `postData[].status`。任何「返回 ok / success=true」都要用这两个字段复核一遍。
