字节笔记本
2026年6月25日
当官方文档骗了我:逆向 AnyGen API,用 Go 搭一个能跑的生图站
做个文生图项目,前端只要 HTML。
听起来简单。出图能力用 AnyGen,后端用 EdgeOne Go,前端纯静态页面。架构一目了然,似乎打开文档照着抄就行。
然后我被官方文档骗了三次。
文档里没有一句真话
第一骗,是「文档索引」。AnyGen 文档首页写着「Fetch the complete documentation index at llms.txt」,满怀期待地抓下来,全是营销话术,真正的 API 参考根本不在里面。
第二骗,是「OpenAPI 规范」。我去抓那份标准化的 openapi.json,要么 500 报错,要么返回一个叫 "Plant Store" 的花店示例——这是 Mintlify 文档框架自带的占位假数据,和 AnyGen 没有半毛钱关系。
第三骗,是「Skills 仓库」。公开仓库里的生图 skill,核心逻辑全甩给一个叫 anygen-workflow-generate 的内部 skill,而它压根不在仓库里。
三层文档,三层套娃,最后指向一个黑盒。
不能信文档,那就信运行时。
从 CLI 源码里扒真相
AnyGen 有个命令行工具,装在本地。它是明文 JavaScript,可以直接读。
我钻进 /opt/homebrew/lib/node_modules/@anygen/cli/,逐个文件翻。先是 api/client.js,看清了鉴权方式:Authorization: Bearer <key>。再翻 discovery/client.js,发现一个关键机制——CLI 根本不硬编码端点,而是启动时动态拉一份叫「Discovery Document」的配置,所有 API 地址都从这份文档里来。
更妙的是,这份文档会被缓存到本地:~/.config/anygen/cache/discovery.json。
不用联网,直接读缓存。一解析,真相全出来了:生图端点是 POST /v1/openapi/tasks,查询状态是 GET /v1/openapi/tasks/:id,baseUrl 是 www.anygen.io。连每个字段的含义都写得明明白白。
逆向 CLI,比读十遍文档都管用。
但 schema 不等于现实
拿到 API 结构,离真正能用还差一步:得实跑。
我 curl 了一个真实的生图任务,prompt 是「戴宇航头盔的柴犬,电影感打光」。任务创建成功,拿到 task_id,然后开始轮询——10%、13%、90%……大约 30 秒,状态变成 completed,图片落在 output.files[0].url。
一张 2048×2048 的 PNG,柴犬戴头盔,确实帅。
但我在 URL 里看到一个眼熟的域名:internal-api-drive-stream-sg.feishu.cn。AnyGen 的图,存在飞书云文档的 CDN 上。
这可不是 schema 能告诉我的事。飞书 CDN 对 referer 敏感,浏览器直接 <img src> 加载会失败。如果我只看文档不实跑,等项目上线才发现图显示不出来,那才叫抓瞎。
于是后端多了一个「图片代理」端点——服务端把图取回来再透传给前端,顺便伪装成正常浏览器来源。这一步,是整个项目的胜负手。
最后的架构,干净得像教科书
所有坑踩完,架构反而很简单:
浏览器输入描述,POST 给 Go 后端,后端调 AnyGen 创建任务,秒回一个 task_id。前端拿着 task_id 每 3 秒轮询一次状态,进度条一格一格往前走。出图了,图片走后端代理绕过飞书 CDN,直接显示。
为什么拆成「创建 + 轮询」两步?因为生图要 30 秒,一个 HTTP 请求等 30 秒会超时。拆开后每个请求都是秒级,完美避开 EdgeOne 的 120 秒运行上限。
而那个 API Key 呢?从头到尾没碰过前端。 前端零密钥,所有调用走后端,key 只待在环境变量里。就算前端代码被人扒个底朝天,也偷不走一个字符。
零外部依赖,零前端构建,go build 一次过。整个项目就两个 Go 文件加一个 HTML。
写在最后
这个项目给我最大的启发不是技术,而是一个朴素的道理:
永远相信运行时,别相信文档。
当三方文档可能造假、可能过时、可能套娃的时候,运行中的 CLI、实际的网络请求、真实的返回数据,才是唯一靠得住的真相来源。花两小时逆向 CLI,省下的是上线后两天的故障排查。
至于那个生图站,已经实跑通了。柴犬很帅,图很清晰,代理很稳。下次你想验证一个 API 到底怎么用,记住——别看它说了什么,看它实际做了什么。
项目地址:EdgeOne Go × AnyGen 文生图 · 前端纯 HTML,后端 Go 标准库,经真实验证可用。