论坛开放 API,你可以让脚本或 agent 代表你读写内容。这篇讲怎么做,以及哪些该做、哪些不该做。
先说结论:不要把密码给 agent
Discourse 有专门的 User API Key 机制,走的是 OAuth 2.0 Device Authorization Grant —— 就是 gh auth login 那套:终端显示一个码,你去网页确认,脚本拿到一把带 scope 的密钥。
比交密码好在三点:scope 可限制(只读还是可写)、随时可撤销、密码从不离开你的脑子。
鉴权:完整可跑的代码
第一步,申请授权码。 需要一对 RSA 密钥,Discourse 会用你的公钥加密返回的 API key。
import json, secrets, subprocess, urllib.request
BASE = "https://reer.dev"
NONCE = secrets.token_hex(16) # 后面要用它校验,别丢
subprocess.run(["openssl","genrsa","-out","agent_priv.pem","2048"], check=True)
pub = subprocess.run(["openssl","rsa","-in","agent_priv.pem","-pubout"],
capture_output=True, text=True, check=True).stdout
def post(path, payload):
r = urllib.request.Request(BASE + path, data=json.dumps(payload).encode(), method="POST")
r.add_header("Content-Type", "application/json")
r.add_header("Accept", "application/json")
with urllib.request.urlopen(r, timeout=30) as f:
return json.load(f)
d = post("/user-api-key/device", {
"nonce": NONCE,
"client_id": "my-reer-agent", # 自己起个稳定的标识
"application_name": "My REER Agent", # 授权页会显示给你看
"scopes": "read", # 先只要读权限
"public_key": pub,
})
print("打开:", d["verification_uri"])
print("输入:", d["user_code"])
跑完会得到类似:
打开: https://reer.dev/user-api-key/activate
输入: VEGK-YMWK
第二步,轮询等授权。 有效期 600 秒,轮询间隔 5 秒(服务端会告诉你,别写死)。
import time, base64
while True:
r = post("/user-api-key/device/poll", {"device_code": d["device_code"]})
if r.get("status") == "authorization_pending":
time.sleep(d["interval"]); continue
break
第三步,解密。 返回的是用你公钥加密过的 base64,用私钥解开:
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
priv = serialization.load_pem_private_key(open("agent_priv.pem","rb").read(), password=None)
raw = priv.decrypt(base64.b64decode(r["payload"]), padding.PKCS1v15())
data = json.loads(raw)
assert data["nonce"] == NONCE, "nonce 不匹配,可能被中间人掉包了"
api_key = data["key"]
nonce 那行断言别省。 它是防重放/防掉包的,服务端把你发的 nonce 原样加密回来,对不上就说明这把 key 不是你申请的那次。
第四步,用起来。
req = urllib.request.Request(f"{BASE}/latest.json")
req.add_header("User-Api-Key", api_key)
请求头是 User-Api-Key,不是 Api-Key(后者是管理员全局密钥,两码事)。
值得做的:读为主的自动化
这些是我觉得真正有价值、也最适合 agent 的:
监控与提醒
盯住你关心的分区或标签,有新帖就推到你的 Telegram / 飞书 / 终端。/c/{slug}/{id}.json 和 /tag/{name}.json 都能直接拿 JSON。
个人摘要
每天把新帖拉下来,让模型按你的兴趣筛一遍,只把相关的推给你。论坛的 digest 邮件是按热度排的,你自己做能按你的方向排。
对论坛做检索
把帖子灌进向量库,在自己的工作流里检索。逆向的时候想起"这个问题好像有人讨论过",本地一查就出来,比翻网页快得多。
同步你自己的内容
博客写完的 writeup,脚本同步一份过来。这属于写入,但内容是你自己的,没有稀释问题。
批量打标签 / 整理草稿
自己的帖子自己整理,随便自动化。
写入:可以做,但请想清楚责任
scopes 填 read,write 就能发帖和回复。技术上没有任何阻碍。
但有两件事要说在前面:
第一,账号所有者对内容负责。 不管是你敲的还是 agent 生成的,出现在你账号下的东西就是你的。"是 AI 写的"不是免责理由。
第二,版规的第一条「技术优先」同样适用于机器写的帖子。 我们没有为 AI 内容单独加规则,因为不需要 —— 一个没有信息量的帖子该清理,跟作者是碳基还是硅基无关。反过来说,一篇 agent 辅助整理出来的、真的有干货的帖子,没人会因为它用了 AI 就反对。
社区规范:如果你的账号会自动发帖,请在个人简介里写明。这不是技术强制,是为了让读者知道对面是什么。别人看到"这是自动同步的 RSS"和以为"这是某人手打的经验",判断是不一样的。
速率限制
会撞到的几条:
| 限制 | 值 |
|---|---|
| 发帖间隔 | 5 秒 |
| 建主题间隔 | 15 秒 |
| 每日主题上限 | 20 |
| 新用户首日回复上限 | 10 |
碰到 429 就退避重试,别硬冲。写循环的时候先设一个总量上限,跑飞了的脚本比没写的脚本更糟。
scope 怎么选
| scope | 能干什么 |
|---|---|
read |
读帖子、分区、标签、通知。大部分自动化只需要这个 |
write |
发帖、回复、编辑、打标签 |
notifications |
读通知、标记已读 |
message_bus |
实时推送,做即时监控用 |
默认只申请 read。 需要写的时候再单独申请一把,别图省事一次要全。密钥泄露时,只读的那把造成的损失小得多。
撤销
在 /my/preferences/security 可以看到所有授权过的应用并随时撤销。脚本行为不对劲、或者你不用了,就去撤掉。
有人拿这个做出什么有意思的东西,欢迎回帖说说。特别想看监控和检索那两类 —— 那才是 agent 真正省时间的地方。