七牛云实训营的题目二。写一篇稿子,自动适配成各平台(公众号/知乎/B站/小红书)各自的调性和格式,省掉手动一遍遍改写。
插件化的 Adapter 架构:加平台就是写个子类
整个适配层用模板方法模式:一个 PlatformAdapter 基类,唯一必须实现的抽象方法是 style_prompt()(平台风格的灵魂),其余 few-shot、输出 schema、格式化、发布意图都可选覆写。目标是”新增一个平台 = 写一个子类 + 注册,约 100 行”,第一个真实 adapter 就验证了——加一个平台只写了 prompt 加身份,零编排代码。多平台适配是并发跑的,单个平台失败返回 error 不拖垮整体。后来的”发布策略 Agent""一键出标题候选”这些功能,也都直接长在这个架构上,新增平台自动进入打分。
AI 起草的成本路由,以及它的一次现实 pivot
加了个”给我个主题,AI 帮你起草”的入口。比赛 API 余额很有限(共享额度只剩个位数元),全程付费模型很快烧光。所以管线按成本分两段:起草用一个免费的中转模型(质量要求不高,只要把骨架铺出来),润色才用付费的 DeepSeek,温度调低做轻量打磨,润色失败就降级返回初稿、绝不抛错。核心思路是按”对质量的敏感度”给每步选模型。
但这条路线后来被现实改了:那个免费中转的额度被跑空了、而且和生产共享。于是我把起草也切回 DeepSeek,提交记录写得很直白——“起草 step 从中转改为 DeepSeek(额度耗尽)“。这是个真实的取舍:理想的成本路由要依赖一个不稳定的免费外部服务,当它不可靠时,工程上更现实的是退回稳定方案,而不是死守一个更”优雅”的架构。
一个流式接口的空 chunk 坑
接那个免费中转模型时,起草冒烟测试直接报错。定位到:它流式返回的最后一个 chunk 的 choices 是空列表,而我的流式解析直接取 chunk.choices[0],触发 IndexError。修法是在流循环里跳过空 choices 的 chunk。这种边界文档里不会写,只有真接了才撞得上——所以涉及外部接口,我习惯先写最小冒烟把真实返回打出来看。
诚实版”真发布”:导出成品包
赛题有”让 AI 替你执行真实操作”的设想,落到发布场景就是”一键真发到各平台”。但我没有各平台的发布 API 凭证,硬做”真发布”要么是假的、要么得让用户交出 token,都不合适。所以做成诚实版:导出一个 ZIP,里面是每个平台已经适配好、可直接粘贴的文件,外加各平台发布入口链接。UI 标语就写”适配 → 预览 → 复制 → 跳转 · 不假装能发”。
这里还踩了个具体的坑:导出文件名最初用了含中文的标题拼,线上 POST /export 直接 500——Content-Disposition 响应头只能用 latin-1,中文触发 UnicodeEncodeError。改成固定英文名解决。
用户账户与历史
前端用 localStorage 存一个 UUID 当 session(匿名、无密码),后端用内置 sqlite3(无 ORM)建 history 表,每个 session 上限 50 条、插入后立刻修剪,删除带 session 双条件(只能删自己的)。轻量、不需要注册流程,适合工具型产品。
写接口限流:零成本就能验证
公开的 POST 接口每个真烧 DeepSeek,余额只剩约 ¥11,怕 Swagger 暴露的调用按钮在演示前被刷爆。加了滑动窗口限流(每 IP 每分钟 30 次)。验证它用了个零成本的法子——连发 35 个空内容请求(限流在”空内容”守卫之前触发,所以根本不调 LLM),精确得到 30 个 400 加 5 个 429。经 Caddy 反代时真实 IP 在 X-Forwarded-For 首段,不能用 request.client.host(那是 127.0.0.1)。
一次必须如实交代的事故:手滑删了线上视频
restyle 部署时,npm run build 因为视频目录是 root 属主而清空失败,我用 sudo rm -rf dist 清理重建,连带把线上的演示视频一起删了。好在找到一个 content-length 完全一致的备份恢复了。根治是把视频移到 dist 之外、部署脚本加 post-build 恢复。但这里还套了第二个坑:部署脚本自己的 git pull 在运行中替换了脚本本身,第一次执行的还是没有恢复块的旧版,重跑才生效——经典的”自更新脚本”陷阱。这件事记进了复盘,也让我对 rm -rf 和 sudo 多了一份敬畏。
小结
按计划的 PR 全部做完,main 全程可运行,最后用 Playwright 录屏 + edge-tts 旁白 + ffmpeg 合成了演示视频(其中一版还因为字幕念错分数、用 Azure TTS 零成本重生成了旁白修正)。这个项目我印象最深的不是哪个功能,是那一连串”理想方案碰上现实”的时刻——免费额度耗尽、流式空 chunk、中文文件名编码、手滑删视频。工程的真实质感,多半就在这些地方。