本白皮书记录一次完全由 WorkBuddy 驱动的官网部署实战:交付物是一个多页面 Web 应用
(昆仑洞天 · 国风创作工坊 Ω⁷,含完整交互版本与七个历史版本归档),
目标是把作品同时发布到 WorkBuddy 应用通道与 自有官网 huodouai.com。
全过程无人工敲命令、无 SSH 交互,全部通过 Agent 调用云 API 完成。
实战最有价值的部分不是成功路径,而是十四个真实踩中的坑——它们全部具备「单元测试通过、 代码逻辑正确,但在真实环境里依然失败」的共同特征。这些坑位已固化为 元法则 META-AXIOM-E2E-VERIFICATION-V1。
「把作品部署到官网」这句话在实操中会分裂成两个诉求,而它们的技术路径完全不同:
| 诉求 | 形态 | 关键约束 |
|---|---|---|
| 可交互、可分享的应用 | WorkBuddy 应用发布 → https://<slug>.app.workbuddy.host/?sharecode=XXXX |
必须带 sharecode;网关对所有路径校验;一个工作区只有一个应用位 |
| 自有官网的正式入口 | 写入 /www/wwwroot/huodouai.com,由 Nginx 直接托管 |
无网关校验(纯静态);但要自己有落盘通道,且不能破坏既有内容 |
调用站点部署能力即可完成,产物与应用卡片一一对应:
deploy(directory, language="static|node", startCmd, domainPrefix, appName)
| 要点 | 实测结论 |
|---|---|
| 链接形态 | https://<slug>.app.workbuddy.host/?sharecode=XXXX(参赛表单要求的就是这种) |
| 应用位数 | 同一工作区仅一个应用位:换一个目录部署会覆盖原应用而非新建 |
| 多版本组织 | 不要指望多个链接,改用站内路径:/archive/v1.html … /archive/v7.html |
| Node 服务端 | startCmd 直接写 node server.js(跳过 npm 包装,启动更快更稳) |
| 静态资源缓存 | 务必 ?v=N 版本化,并在服务端加 Cache-Control: no-cache |
本地无 SSH 配置,官网文件只能通过腾讯云 TAT(远程助手)写入实例:
| 要素 | 值 |
|---|---|
| Endpoint | tat.tencentcloudapi.com(API 版本 2020-10-28,写错会返回 InvalidAction) |
| 实例 | lhins-laotwc5e / ap-shanghai / Username=root |
| 落地路径 | /www/wwwroot/huodouai.com(Nginx 直接托管该目录) |
| 命令长度上限 | 约 64 KB(Content 为 base64 编码后的脚本) |
整站体积 tar.gz 后约 336 KB,base64 膨胀至 454 KB,远超单命令上限,必须分块:
# 本地:打包 → base64 → 每块 40KB
tar -czf site.tar.gz kunlun projects
base64 -w0 site.tar.gz # 454 KB
# 远端:逐块追加(顺序敏感,必须串行)
printf '%s' '<40KB chunk>' >> /tmp/site.b64
# ... 共 12 块 ...
# 远端:解码 → 解压 → 落地
base64 -d /tmp/site.b64 | gunzip | tar -xzf - -C /www/wwwroot/huodouai.com
| 设计要点 | 理由 |
|---|---|
| 块大小 40 KB | base64(shell) 二次膨胀后仍低于 64 KB 上限 |
| 串行追加 | 并发写同一文件会交错,base64 流损坏 |
| 传输后校验 | base64 -d 的 RC、gzip -t 的 RC、tar -tzf 列表,三步全绿才落地 |
| 落地前备份 | 解压会覆盖同名文件,官网既有目录必须先备份 |
以下每一条都是本次实战真实撞上的,现象、根因与解法均可复现。
curl https://host/api/status 校验接口,返回的却是一段 HTML「链接不完整」页面——但状态码是 200。sharecode,缺参数时返回拦截页而非 4xx。?sharecode=;判断「是否拿到真内容」要检查内容特征,不能只看状态码。/、/changelog.html、/archive/vN.html。pip install tencentcloud-sdk-python 在默认源超时无输出,清华源报 No matching distribution found。pip install -i https://mirrors.aliyun.com/pypi/simple/ tencentcloud-sdk-python。AuthFailure.SignatureFailure。DescribeInvocationsRequest.__init__() 不接受关键字参数;响应字段是 InvocationSet 而非 Invocations;轮询 100 秒始终空。$WEBROOT/.../_deploy.log(该路径可被公网 HTTP 读取),
部署完成后用 HTTP 回读日志校验,而不是依赖状态查询。/kunlun/ 的 index.html 变成了新作品,而该目录原本是另一套 workbench 演示的首页。ls 目标目录;② 优先使用新路径(本次改为 /workshop/kunlun-cave-heaven/);
③ 已覆盖则用 *.bak-* 备份恢复;④ 清理本次新增的残留文件。?v=N 版本号 + 服务端返回 Cache-Control: no-cache, must-revalidate。class="examples",JS 取的是 getElementById("examples") → 抛
Cannot set properties of null → 初始化中断,页面结果区空白。getElementById 与 HTML 的 id 求差集,缺失即失败;
② 启动路径改为同步 boot + 多重兜底,不依赖 DOMContentLoaded 与定时器。duration=312.89s——而设计值是 15 秒。stts 的 delta 必须是采样数(timescale=48000),
而编码器给的是微秒时间戳;直接差分填入导致单位错配 1000 倍。aDelta = round(Δμs × sampleRate / 1e6);修复后实测
duration=15.02s / 720×1280 / 11,295,572B。
关键认知:文件「能生成、能播放」不等于「文件是对的」。printf '%s' '…' 传给远端执行器:传输字节数核对正确、
base64 -d 退出码为 0,但解出来的文件「不是 gzip 格式」,解压直接失败。cat > file <<'EOF'),绕开单参数长度;
大文件仍用分块追加,但每块追加后立刻做长度与哈希校验,绝不等到最后才验证。
本次实测:heredoc 直写 26 KB 文件 → 落地字节数与本地完全一致(26308 = 26307 + 1 换行)。base64 -d 退出码为 0、文件字节数与本地完全一致(83807 = 83804 + 3 个换行),
但解出来的不是 gzip(gzip: stdin: not in gzip format)。本地同样的数据解码完全正常。base64 -d 对多行输入的处理与本地 GNU coreutils 不同(疑似只按单行处理后静默截断)。python3 -c "import base64;open('x','wb').write(base64.b64decode(open('y').read()))"。
修复后服务端解出 62852 字节,与本地 gzip 大小逐字节一致。{"error":"0"},异常信息只有一个字符「0」,完全看不出问题在哪。j.get("choices") and j[0].get(...)——把 j(dict)当序列取下标。
上游返回标准 OpenAI 结构时,j.get("choices") 是非空 list(truthy)→ 执行 j[0] → KeyError: 0。
而当上游返回不含 choices 的错误体时短路成功,反而「看起来是 200 但内容为空」。_extract_reply / _extract_image),兼容 list / dict / 缺字段;
② 异常必须带 traceback 落盘——{"error":"0"} 这种「信息量为零的错误」是排查效率杀手,
加上 traceback 后 1 次定位到根因;③ 失败必须把上游原始响应体写进日志(chat empty raw=…)。HTTPServer(单线程)→ 请求排队 → nginx 判定上游不可达 → 前端静默降级为本地规则,
界面显示「云端通道已托管」但实际生成来源是 local-rule。ThreadingHTTPServer(daemon_threads=True);
② 对上游调用加串行锁 + 429/5xx 退避重试,避免触发免费通道并发限流;
③ 验收必须看真实字段:不只看「通道状态提示」,而要断言 source=llm:… 与关键帧来源为云端。本次采用三层验证,每层都用真实环境而非推断:
| 层 | 手段 | 判据 |
|---|---|---|
| L1 路由探针 | HTTP 逐条打点(含 sharecode) | 作品路由 13/13 = 200;既有内容回归 12/12 = 200 |
| L2 浏览器真实打开 | 真实 Chromium 加载公网地址 | 首屏 Demo 真实产出:src=local-rule shots=5 frames=5 |
| L3 产物回读 | <video> 解码 + 字节数读取 | 时长 / 分辨率 / 字节数三项与设计值一致 |
| 类别 | 条目 | 结果 |
|---|---|---|
| 作品路由 | 首页 / index / changelog / archive v1–v7 / 2 张截图 / 介绍页 | 13/13 · 200 |
| 官网回归 | / /product-hub /whitepaper /capabilities /achievements /developer /kunlun/* /gallery/* /projects/* | 12/12 · 200 |
| 应用通道 | 首页 / changelog / archive v1–v7 / 接口 /api/agnes/status | 9/9 · 200 |
| 产物 | MP4 导出 → 解码回读 | 15.02s · 720×1280 · 11.3MB |
def fire(name, script, timeout=120):
req = models.CreateCommandRequest()
req.CommandName = name
req.CommandType = "SHELL"
req.Content = base64.b64encode(script.encode()).decode()
req.Timeout = timeout
cid = client.CreateCommand(req).CommandId
inv = models.InvokeCommandRequest()
inv.CommandId = cid
inv.InstanceIds = [INSTANCE]
inv.Username = "root"
iid = client.InvokeCommand(inv).InvocationId
return iid # 不轮询状态,改由 HTTP 回读日志校验
def deploy(tar_path, remote_root, log_path, chunk=40000):
b64 = base64.b64encode(open(tar_path, "rb").read()).decode()
fire("init", f"rm -f /tmp/site.b64; : > {log_path}")
for i in range(0, len(b64), chunk):
fire(f"c{i}", f"printf '%s' '{b64[i:i+chunk]}' >> /tmp/site.b64")
fire("extract",
f"base64 -d /tmp/site.b64 | gunzip | tar -xzf - -C {remote_root}; "
f"echo EXTRACT_RC=$? >> {log_path}")
curl -s "https://<host>/<path>/_deploy.log" # 远端命令的真实输出
要点:让远端命令把结论写进公网可读的文件,是绕过「无状态轮询」与「异步调度不确定性」的最省事解法, 且校验路径与用户实际访问路径完全一致。
# 单个 ≤ ~30KB 的文件:一条命令搞定,绕开单参数长度与 base64 二次膨胀
cat > /www/wwwroot/huodouai.com/whitepaper/report.html <<'EOF_DOC'
<!DOCTYPE html> ... </html>
EOF_DOC
wc -c < /www/wwwroot/huodouai.com/whitepaper/report.html
注意 heredoc 定界符要用带引号的形式(<<'EOF'),否则内容里的 $、反引号会被 shell 展开。
| 阶段 | 耗时 | 说明 |
|---|---|---|
| 打包 + 分块 | < 1 s | 336 KB gzip → 454 KB base64 → 12 块 |
| 12 块传输 | ≈ 3 min | 每块一次创建+调度,串行 16 s 间隔 |
| 解包落地 | ≈ 20 s | 解码 + gunzip + tar + 校验 |
| 导航注入 + 路径纠正 | ≈ 1 min | sed 插入口 + 迁移到独立目录 + 恢复既有首页 |
| 回归验证 | ≈ 3 min | 25 条 HTTP 探针 + 真实浏览器首屏校验 |
| 合计 | ≈ 8 min | 全链路无人值守 |
可复用资产:site.tar.gz(全站快照)、deploy_to_huodouai.py(分块部署)、e2e/(可复跑的端到端脚本集)。
本次十个坑位共同指向一条规则,已固化为最高位阶元法则并写入本体:
e85bf6689fb8c1e96a930a96enabled、产物字节数是否非零、状态文案是否正常、时长/分辨率是否等于设计值——四者都必须真机点击确认。该法则同时被写入核心公理集(新增第 9 组 E2E-VERIFICATION)与哈希账本,使其可被审计与复算。
ls 一遍,确认不覆盖既有内容;优先选择全新路径。no-cache,否则「已修复」无法被验证。# 一、应用通道部署(Node 服务端)
deploy(directory=..., language="node", startCmd="node server.js",
domainPrefix="<slug>", appName="...") # → https://<slug>.app.workbuddy.host/?sharecode=XXXX
# 二、官网落盘(TAT)
base64 -w0 site.tar.gz | split -b 40000 - # 本地分块
# 远端逐块:
printf '%s' '<chunk>' >> /tmp/site.b64
# 远端落地:
base64 -d /tmp/site.b64 | gunzip | tar -xzf - -C /www/wwwroot/huodouai.com
# 三、校验
curl -s "https://<host>/<path>?sharecode=XXXX" | head -c 200 # 判定内容而非状态码
curl -s "https://<host>/<path>/_deploy.log" # 回读远端命令结论
# 四、回归
for p in / /a.html /b.html; do curl -s -o /dev/null -w "%{http_code} $p\n" "https://<host>$p"; done