精品长文一键写作:用 Python 提交第一个写作任务并取回成稿
精品长文一键写作Python示例快速接入AI长文生成 # 精品长文一键写作:用 Python 提交第一个写作任务并取回成稿
> 接口:精品长文一键写作(apiCode=3206)· 接入点:3206-1 提交写作任务 / 3206-3 查询文章详情
> 计费:计次收费(3206-1 为 300 厘/次,3206-3 为 0 厘/次)· 请求方式:POST/GET · 返回格式:JSON(3206-3 生成中为纯文本)
> 适用人群:第一次接入的新用户、初级开发者 · 阅读时间:约 8 分钟 · **最后实测核对:2026-09-15**
## 核心要点
- 精品长文一键写作(apiCode=3206)是异步接口:`3206-1` 提交后只拿到 `task_id`,正文要再用 `3206-3` 轮询取回。
- `3206-1` 的 `topic` 是唯一必填参数,写清主题和要求即可,示例值就是「帮我写一篇关于DeepSeek的介绍」这种自然语言。
- 文章没写完时,`3206-3` 返回 **HTTP 450**,响应体形态随 `need_md` 变化:传 `1` 是一句纯文本,传 `2` 或不传是 `{"ret_code":-1,"task_status":"writing",…}` 的 JSON。**生成中 `ret_code` 是 -1**,只判断 `ret_code` 会把还在生成的任务当成失败。
- `need_md` 决定响应体形态:传 `2` 或不传拿到 JSON,传 `1` 拿到的直接就是 Markdown 原文。
## 为什么值得用一次接口换一篇成稿
要自己从零写一篇结构化长文,得先找资料、再列提纲、再逐段写,中间还要反复调结构。这套流程里最耗时的部分不是写字,是前期检索和搭骨架。
精品长文一键写作把这两步合到一次调用里。你给一句主题,接口返回的是「摘要 + 关键词 + 章节大纲 + 完整正文」这样一份带层次的结果,拿到之后直接二次编辑或发布。它适合那些需要稳定、批量产出长文的场景:内容矩阵、专题页初稿、行业综述、产品文档的开头几版。
需要说清一点,**这个接口不返回全文**。提交任务时只回一个任务标识,正文要另外查询。下面按这个流程走一遍。
## 接口速览
| 项目 | 说明 |
|------|------|
| 提交写作任务 | `https://route.showapi.com/3206-1` |
| 查询文章详情 | `https://route.showapi.com/3206-3` |
| 鉴权 | URL query 参数 `appKey` |
| 请求方式 | POST / GET,文档给出的是 POST |
| 返回格式 | JSON(`3206-3` 生成中时为纯文本,见下文) |
| 3206-1 必填参数 | `topic`(写作要求) |
| 3206-3 必填参数 | `task_id`(任务 id,具有唯一性) |
| 超时(OpenAPI 声明) | 两个接入点读写超时均为 60s |
| 并发量 | 2 次/秒 |
## 第一步:拿到 AppKey
登录后到 https://www.showapi.com/console#/myApp 复制 AppKey。下面代码里的 `YOUR_APPKEY` 就是它的位置。
## 第二步:提交写作任务
`3206-1` 的 content-type 是 `multipart/form-data`,`topic` 必填,`reference_list`、`lang`、`file` 都可选。
**Python(requests)**
```python
import requests
APPKEY = "YOUR_APPKEY"
BASE = "https://route.showapi.com"
resp = requests.post(
f"{BASE}/3206-1",
params={"appKey": APPKEY},
data={
"topic": "帮我写一篇关于DeepSeek的介绍", # 必填:写作要求
"lang": "zh", # 可选:zh 中文 / en 英文
},
timeout=60, # OpenAPI 声明 3206-1 读写超时 60s
)
resp.raise_for_status()
body = resp.json()["showapi_res_body"]
if body["ret_code"] != 0:
raise RuntimeError(f"提交失败:{body['remark']}")
task_id = body["task_id"]
print("任务已提交:", task_id, "状态:", body["task_status"])
```
**cURL**
```bash
curl -X POST "https://route.showapi.com/3206-1?appKey=YOUR_APPKEY" \
-H "content-type: multipart/form-data" \
-d "topic=%E5%B8%AE%E6%88%91%E5%86%99%E4%B8%80%E7%AF%87%E5%85%B3%E4%BA%8EDeepSeek%E7%9A%84%E4%BB%8B%E7%BB%8D&lang=zh"
```
**Node.js(fetch)**
```javascript
const APPKEY = "YOUR_APPKEY";
const BASE = "https://route.showapi.com";
const resp = await fetch(`${BASE}/3206-1?appKey=${APPKEY}`, {
method: "POST",
headers: { "content-type": "multipart/form-data" },
body: new URLSearchParams({ topic: "帮我写一篇关于DeepSeek的介绍", lang: "zh" }),
signal: AbortSignal.timeout(60000),
});
const body = (await resp.json()).showapi_res_body;
if (body.ret_code !== 0) throw new Error(`提交失败:${body.remark}`);
const taskId = body.task_id;
```
提交成功后,实际拿到的返回长这样(2026-09-15 实测):
```json
{
"showapi_res_error": "",
"showapi_res_id": "6aa8c4bbfb638c2f69edc8ba",
"showapi_res_code": 0,
"showapi_fee_num": 1,
"showapi_res_body": {
"topic": "写一篇介绍昆明气候特点的短文,300字左右",
"task_status": "preparing",
"remark": "文章正在生成中,请稍后!",
"task_id": "1ef05f9fa412444aa77c99fae4db1358",
"ret_code": 0
}
}
```
两点实测观察值得记一下。`remark` 实际返回的是「文章正在生成中,请稍后!」,文档示例里写的是「提交成功」,判断成败请认 `ret_code`,别拿 `remark` 做字符串比对。`showapi_fee_num` 为 1,表示这次调用计入一次计费。
## 第三步:轮询取回正文
`3206-3` 是透传模式,它**不用 `showapi_res_body` 包一层**,`title` / `content` / `keywords` / `outline` 都是顶层字段。
文章还没写完时它返回 HTTP 450,响应体跟着 `need_md` 走:传 `2` 是 JSON(`ret_code` 为 `-1`、`task_status` 为 `writing`),传 `1` 是一句纯文本。所以轮询代码要先看状态码,再看状态字段。
```python
import time
import requests
def wait_for_article(task_id, appkey, base="https://route.showapi.com",
interval=15, max_tries=60):
"""轮询文章详情,直到 task_status 变成 success。need_md=2 走 JSON 响应。"""
for _ in range(max_tries):
time.sleep(interval)
r = requests.post(
f"{base}/3206-3",
params={"appKey": appkey},
data={"task_id": task_id, "need_md": "2"}, # need_md=2 返回 JSON
timeout=60,
)
if r.status_code != 200:
# 生成中:HTTP 450。need_md=2 时是 JSON(ret_code=-1),need_md=1 时是纯文本
print("生成中:", r.text.strip())
continue
detail = r.json()
if detail.get("task_status") == "success":
return detail
print("当前状态:", detail.get("task_status"))
raise TimeoutError("等待超时,可稍后用同一个 task_id 再查")
detail = wait_for_article(task_id, APPKEY)
print("标题:", detail["title"])
print("正文长度:", len(detail["content"]))
print("章节数:", len(detail["outline"]))
```
## need_md 传 1 还是 2
`need_md` 决定的是**整个响应体的形态**,不只是正文格式。这是最容易写错的一处。
| `need_md` | 响应体 | 客户端怎么解析 |
|------|------|------|
| `1` | 纯 Markdown 文本,以 `# 文章标题` 起头 | 直接读响应文本,**不要调 `json()`** |
| `2` | JSON,正文在 `content` 字段 | `json()` 之后取字段 |
| 不传 | 与传 `2` 相同,返回 JSON | 同上 |
2026-09-15 实测同一个 `task_id`:`need_md=1` 返回 11780 字节的 Markdown 原文,`need_md=2` 与不传都返回 12788 字节的 JSON。GET 方式同样可用,响应形态一致。
**任务未完成时也分两种形态。** 同样在 2026-09-15 实测:`need_md=1` 时拿到的是一行纯文本「文章正在生成中,请稍后!」;`need_md=2` 时拿到的是 JSON:
```json
{ "ret_code": -1,
"task_status": "writing",
"remark": "文章正在生成中,请稍后!" }
```
这里的 `ret_code` 是 **-1**。如果取稿逻辑只判断 `ret_code == 0` 就当成失败,会把还在生成中的正常任务按失败处理。判断顺序必须是「先看 HTTP 状态码是不是 450,再看 `task_status`」。
想要 `title`、`keywords`、`outline`、`imgs` 这些结构化字段就用 `2`;只想把成稿整段拿走、自己再解析标题层级就用 `1`。在 `need_md=1` 上调用 `json()` 会直接抛解析异常。
生成完成后,`3206-3`(`need_md=2`)返回的结构如下,取自 2026-09-15 的真实返回,`content` 为节选:
```json
{
"ret_code": 0,
"task_status": "success",
"task_id": "26d32f71742b40c2b7a91504e438c060",
"title": "Exploring the ShowAPI Open API Marketplace: A Comprehensive Guide",
"topic": "Write a brief introduction to the ShowAPI open API marketplace",
"remark": "文章生成完成",
"imgs": [],
"keywords": [
{ "is_ai": true, "keyword": "ShowAPI" },
{ "is_ai": true, "keyword": "开放接口" },
{ "is_ai": true, "keyword": "API市场" },
{ "is_ai": true, "keyword": "开发者平台" },
{ "is_ai": true, "keyword": "云服务" }
],
"outline": [
{
"name": "1. Introduction to ShowAPI and Its Significance",
"child_list": [
"1.1 Understanding the Concept of an Open API Marketplace",
"1.2 The Evolution of API Markets in the Digital Era",
"1.3 ShowAPI's Position in the Cloud Service Ecosystem"
]
},
{
"name": "2. Key Features and Capabilities of ShowAPI",
"child_list": ["2.1 ……", "2.2 ……", "2.3 ……", "2.4 ……"]
}
],
"content": "> ### 摘要 \n> ShowAPI is a leading aggregated open API marketplace, ……"
}
```
这次实测里有三处值得记下的细节:
- `keywords` 的 `is_ai` 全部为 `true`;正文是英文,关键词仍返回**中文**(`开放接口`、`API市场` 这类)。要英文关键词得自己在调用侧映射。
- `imgs` 在未生成配图时是空数组,配图要单独调 `3206-5`。
- `outline` 实测返回 2 个章节,而 `content` 里实际出现了 3 个 `##` 章节外加一个 `## References` 参考文献小节。做目录时以 `outline` 为准,但不要假设它覆盖正文的全部标题。
`content` 以 `> ### 摘要` 起头,这个「摘要」小标题保持中文,即使正文是英文。整段是 Markdown 原文,交给常见 Markdown 渲染器即可。
## 计费与调用方式
`3206-1` 每次 300 厘,`3206-3` 每次 0 厘。调用成功才计费,失败不扣费。同一接口的费率同时用于通用资源包计费。专用资源包 ¥9.90 起,有效期一年,具体档位与其余接入点费率见 https://www.showapi.com/apiGateway/view/3206 的「产品价格」标签。
接口并发量为 2 次/秒。写批量提交时按这个上限做节流,第 6 篇[批量任务队列](https://www.showapi.com/guides/longform-writing-batch-queue-3206)给了具体做法。
## FAQ
**Q1:提交任务后多久能拿到正文?**
长文生成属于长耗时任务,耗时因内容而异。2026-09-15 实测两次:一次 12:17 提交的英文主题约 7 分钟内变为 `success`;另一次 12:08 提交的中文主题到当日 13:35(87 分钟)仍是 `writing`、`content_length` 一直为 0,始终没出稿。样本只有两次,无法据此判断这属于偶发还是常态。建议轮询间隔设在 15 秒以上,并给等待设一个按业务容忍度定的上限——超时后用 `3206-4` 清掉任务再重提。
**Q2:`3206-1` 返回成功,但 `3206-3` 报错怎么办?**
先看 HTTP 状态码。450 表示还在生成,等下一轮再查;如果 `task_status` 变成 `success` 之外的终态,用 `3206-2` 查询任务列表看 `remark` 与 `content_length`,再用 `3206-4` 删除失败任务。
**Q3:正文为什么带 `>` 和 `###`?**
`3206-3` 返回的正文是 Markdown 原文,摘要用引用块包裹,章节标题用 `##` / `###`。交给 Markdown 渲染器即可;想要纯文本,自己做一次 Markdown 到文本的转换。
**Q4:`need_md` 传 1 还是 2?**
传 2(或不传)返回 JSON,正文在 `content` 字段;传 1 的响应体本身就是 Markdown 原文,不能再调 `json()`。需要 `title`、`keywords`、`outline` 这些字段就用 2。
**Q5:`remark` 写着「提交成功」,我可以拿它判断成功吗?**
不建议。实测提交成功时 `remark` 返回的是「文章正在生成中,请稍后!」,与文档示例不一致。判断成败统一看 `ret_code`,`3206-1` 和 `3206-2` 都是 0 成功、-1 失败。
**Q6:可以一次提交多篇吗?**
`3206-1` 每次只接受一个 `topic`,没有批量参数。多篇要循环提交,注意 2 次/秒的并发限制。
## 下一步阅读
- 状态流转与轮询节奏:[精品长文一键写作:任务写完了没有?看 task_status 三种状态](https://www.showapi.com/guides/longform-writing-task-status-3206)
- 全部返回字段与 `ret_code`:[精品长文一键写作返回字段与 ret_code 说明](https://www.showapi.com/guides/longform-writing-response-fields-3206)
- 引用链接、引用文件怎么传:[reference_list、file、lang 三个参数怎么传](https://www.showapi.com/guides/longform-writing-reference-params-3206)
- **本系列共 9 篇**:查看[精品长文一键写作指南总目录](https://www.showapi.com/guides/longform-writing-guides-3206)