精品长文一键写作:任务写完了没有?看 task_status 三种状态
精品长文一键写作task_status异步任务轮询 # 精品长文一键写作:任务写完了没有?看 task_status 三种状态
> 接口:精品长文一键写作(apiCode=3206)· 接入点:3206-2 查询任务列表 / 3206-3 查询文章详情
> 计费:计次收费(3206-2 与 3206-3 均为 0 厘/次)· 请求方式:POST/GET · 返回格式:JSON
> 适用人群:接入中的开发者 · 阅读时间:约 6 分钟 · **最后实测核对:2026-09-15**
## 核心要点
- `task_status` 只有三个值:`preparing`(准备执行)、`writing`(执行中)、`success`(执行完成)。
- 想拿正文只能用 `3206-3`,并且它在文章未完成时返回 **HTTP 450**;`3206-2` 只给列表概览。450 的响应体随 `need_md` 变化,且 `ret_code` 会返回 **-1**。
- 长文生成是长耗时任务。2026-09-15 实测两个任务,一个约 7 分钟完成,另一个提交后 87 分钟仍是 `writing`、未出稿。
## task_status 的三种取值
精品长文一键写作(apiCode=3206)用 `task_status` 字段表达任务进度,`3206-1`、`3206-2`、`3206-3` 三个接入点返回的取值集合一致。
| 取值 | 含义 | 这个阶段能拿到什么 |
|------|------|------------------|
| `preparing` | 准备执行 | 只有 `task_id` 和 `topic`,正文与标题都还没有 |
| `writing` | 执行中 | `3206-2` 里 `title` 为空字符串、`content_length` 为 0;`3206-3` 返回 HTTP 450,`ret_code` 为 -1 |
| `success` | 执行完成 | `3206-3` 返回 `title`、`content`、`keywords`、`outline`、`imgs` |
状态是单向推进的,不会从 `writing` 退回 `preparing`。文档没有给出第四种终态,也没有「失败」这个状态值;调用层面失败走的是 `ret_code`(`3206-1`、`3206-2` 为 0 成功 / -1 失败),任务层面没写完就是一直在 `writing`。
2026-09-15 实测两个任务:一个英文主题约 7 分钟内变为 `success`;另一个中文主题提交后 87 分钟仍是 `writing`,`content_length` 一直为 0,始终没出稿。样本只有两次,无法据此推断耗时分布,也不能判断这属于偶发还是常态。结论是:客户端必须按业务容忍度设等待上限,不要写死一个偏大的固定秒数——超时后用 `3206-4` 清掉任务再重提,比无限等下去更可控。
## 两个查询入口怎么分工
`3206-2` 和 `3206-3` 都能看到状态,用途不一样。
| 对比项 | 3206-2 查询任务列表 | 3206-3 查询文章详情 |
|------|------|------|
| 入参 | `page`(页码,可选,默认 1) | `task_id`(必填)、`need_md`(可选) |
| 返回范围 | 近 30 天内的任务,一页最多 20 条 | 单个任务的完整内容 |
| 是否带正文 | 不带,只有 `content_length` 这个长度值 | 带,`content` 是全文 |
| 响应封装 | 有 `showapi_res_body` 一层 | 透传模式,字段在顶层 |
| 未完成时的表现 | 正常返回 JSON,状态为 `writing` | 返回 HTTP 450;`need_md=2` 时为 JSON(`ret_code=-1`),`need_md=1` 时为纯文本 |
| 适合什么时候调 | 做任务总览、批量看进度、翻历史记录 | 盯单个任务直到出稿 |
后台管理界面用 `3206-2` 拉列表,具体取稿的那一步用 `3206-3`,这是最省的组合:列表页一次拿 20 条状态,只有需要正文的那几条才去调详情。
`3206-2` 的列表里 `topic` 会截断。2026-09-15 实测,提交时传入 25 个字符的 `topic`,列表里返回的是前 20 个字符加 6 个点:
```json
"topic": "写一篇介绍昆明气候特点的短文,300字左......"
```
在列表页展示时按这个长度预留版面,需要完整 `topic` 就去调 `3206-3`。
## 轮询怎么写
最省事的做法是按固定间隔查,查到就停。生成中的响应不是 JSON,所以判断顺序是「先看状态码,再看字段」。
```python
import time
import requests
def poll_article(task_id, appkey, interval=15, max_wait=900):
"""轮询 3206-3 直到出稿。返回详情 dict,超时抛异常。"""
base = "https://route.showapi.com"
deadline = time.time() + max_wait
while time.time() < deadline:
time.sleep(interval)
r = requests.post(
f"{base}/3206-3",
params={"appKey": appkey},
data={"task_id": task_id, "need_md": "2"}, # 2 返回 JSON;传 1 会直接返回 Markdown 原文
timeout=60,
)
if r.status_code == 450:
continue # 生成中,等下一轮
if r.status_code != 200:
r.raise_for_status() # 其它异常交给上层
detail = r.json()
if detail.get("task_status") == "success":
return detail
if detail.get("ret_code") not in (0, None):
raise RuntimeError(f"取稿失败:{detail.get('remark')}")
raise TimeoutError(f"任务 {task_id} 超时未完成")
```
`interval` 别设太小。接口并发量是 2 次/秒,单个任务 15 秒一查已经足够密;一篇长文生成按分钟计,每秒都在查只是白占配额。
任务多的时候,把轮询改成「先问列表,再问详情」更划算:
```python
def poll_batch(task_ids, appkey, interval=20):
"""先用 3206-2 扫全量状态,只对写好的任务调 3206-3 取稿。"""
base = "https://route.showapi.com"
pending = set(task_ids)
done = {}
while pending:
time.sleep(interval)
page, pages = 1, 1
while page <= pages:
r = requests.post(f"{base}/3206-2", params={"appKey": appkey},
data={"page": page}, timeout=60).json()["showapi_res_body"]
pages = r.get("allPages", 1) or 1
for item in r["contentlist"]:
if item["task_status"] == "success" and item["task_id"] in pending:
pending.discard(item["task_id"])
done[item["task_id"]] = item
page += 1
return done
```
注意空列表时 `allPages` 会是 0,上面用 `or 1` 兜住,否则分页循环会直接跳过。
## 超时与重试
`3206-3` 的读写超时按 OpenAPI 文档声明是 60 秒。生成阶段返回的 450 属于中间状态,不属于超时,重试是正常路径而不是异常处理。
真正需要重试的是网络层错误和 5xx。给这类错误加指数退避,别把 450 也当成失败去重试,那样会堆无意义的请求。
任务提交本身不需要幂等保护:`3206-1` 每次调用都会新建一个任务,返回新的 `task_id`。重复提交的后果是产生两篇稿子和两次计费,所以客户端要自己防重复点击。
## 计费与调用方式
`3206-2` 与 `3206-3` 的单次费率都是 0 厘,也就是轮询这两个接入点不额外产生费用;真正计费的是 `3206-1`(300 厘/次)和 `3206-5`(260 厘/次)。调用成功才计费,失败不扣费。档位与其余费率见接口详情页的「产品价格」标签。
## FAQ
**Q1:多久轮询一次比较合适?**
15 到 30 秒一次。2026-09-15 实测两个任务:一个英文主题约 7 分钟完成,另一个中文主题提交后 87 分钟仍是 `writing`。间隔太短拿到的都是同一个状态,还占用 2 次/秒的并发额度。
**Q2:`3206-3` 返回 HTTP 450 是出错了吗?**
不是出错,是任务还在生成中。2026-09-15 实测:`need_md=2` 时响应体是 `{"ret_code":-1,"task_status":"writing","remark":"文章正在生成中,请稍后!"}`,`need_md=1` 时是一行纯文本。注意生成中的 `ret_code` 就是 -1,所以判断逻辑要先看状态码 450,再看 `task_status`,不能只看 `ret_code`。
**Q3:为什么 `3206-2` 里 `title` 是空的?**
任务还在 `writing` 阶段,标题和正文都还没生成,所以 `title` 为空字符串、`content_length` 为 0。等状态变 `success` 再读这两个字段。
**Q4:任务一直停在 `writing` 怎么办?**
先确认提交后已经过了多久,长文生成按分钟计。若超过业务容忍时间仍未完成,用 `3206-4` 删除失败任务,再重新提交一次;删除接口需要传 `task_id`。
**Q5:有回调推送吗?**
文档没有提供回调地址参数,任务完成不会主动通知。取稿靠主动轮询,这也是 `3206-2` 和 `3206-3` 存在的意义。
## 下一步阅读
- 返回字段逐个说明:[精品长文一键写作返回字段与 ret_code 说明](https://www.showapi.com/guides/longform-writing-response-fields-3206)
- 批量任务的调度设计:[把批量写作任务排成队列的几种做法](https://www.showapi.com/guides/longform-writing-batch-queue-3206)
- 最小可用流程:[用 Python 提交第一个写作任务并取回成稿](https://www.showapi.com/guides/longform-writing-quickstart-3206)
- **本系列共 9 篇**:查看[精品长文一键写作指南总目录](https://www.showapi.com/guides/longform-writing-guides-3206)