一、背景:ChatGPT 从”聊天框”变成”工作区”
2026 年 8 月底,Simon Willison 在实测后写下《Understanding ChatGPT Work》,揭示 OpenAI 正在把 ChatGPT 从问答机器人改造成可执行、可编排、可留存的”工作环境”,这个模式被命名为 Work。与过去”问一句、答一段、用完即走”的用法不同,Work 模式给了模型五样新武器:联网的代码执行环境、无头浏览器(Headless Chrome)、跨会话持久文件系统、可调用的子 Agent,以及能生成站点与定时任务的 Sites 能力。组合起来,ChatGPT 第一次能独立完成”调研—写代码—跑起来—留档—定时复查”的完整工作闭环。
国内读者即使暂时用不上完整版 Work 功能,这套思想也完全可以平替复刻:任何”沙箱执行 + 浏览器自动化 + 文件沉淀 + 定时任务”的组合都是它的影子。本文先讲透 Work 的五大机制原理,再给出一套本地可跑的平替实战,最后谈落地时的坑与合规边界。
二、原理:Work 模式的五大机制
2.1 联网的代码执行环境
传统 ChatGPT 的代码解释器是离线沙箱:能算数、画图,但不能 pip install,不能 curl 外网,装不了新库、拉不到真实数据。Work 模式的代码执行是联网的,模型可以在沙箱里安装依赖、请求公开 API、下载数据集、跑爬虫。这意味着”数据分析”从演示变成生产:模型能直接拉取真实 CSV、调真实接口、返回基于真实数据的结论,而不是基于想象编数字。代价是安全边界必须重建——联网执行意味着提示注入的杀伤力从”说错话”升级为”发请求、写文件”,权限管控成为必修课。
2.2 无头 Chrome:模型长出了”眼睛和手”
无头浏览器让模型能像人一样打开网页、填表单、点按钮、截图确认。过去模型只能”读”你粘贴的文本,现在它能自己去目标网站翻页、验证信息、做端到端冒烟测试。Willison 的实测显示,模型会主动”打开页面→截图→发现按钮没点上→换选择器重试”,具备了初级的自我纠错循环。这对两类工作是质变:竞品调研(自动翻页抓取公开信息)与 Web 验收(自动跑一遍关键路径并截图留证)。
2.3 持久文件系统:跨会话的工作台
过去每次新开会话都要重新上传文件、重新讲背景。Work 模式的文件系统在会话间持久存在:模型上次写的脚本、下载的数据、生成的报告,下次还在。文件成为”人机共享的工作台”:人把原始材料丢进去,模型在里面加工,产出留在里面沉淀。这带来一个新习惯——用文件而非对话做 state 传递:把约定写进 CONTEXT.md,把半成品留在草稿目录,新会话第一句就是”先读工作区里的 CONTEXT.md”。
2.4 子 Agent:任务分而治之
复杂任务可以拆给多个子 Agent 并行执行:一个负责拉数据,一个负责写分析脚本,一个负责整理报告,主 Agent 负责汇总。这本质上是”MapReduce 式协作”:并行分支互不干扰,最后归约。子 Agent 模式成立的前提是任务可分解、接口可定义(输入输出格式提前约定),否则并行只会制造合并灾难。
2.5 Sites 与定时任务:从一次性问答到持续服务
Sites 能力让模型把成果发布成可访问的站点(报告页、仪表盘、文档站),定时任务让它按周期自动执行(每天早 8 点拉数据、每周一出周报)。两者叠加,ChatGPT 从”用完即走的工具”变成”持续值班的员工”。这是 Work 模式最具想象力的部分,也是风险最高的部分——自动运行的 Agent 必须有完善的日志、告警与熔断,否则一个坏掉的定时任务可以连续错一个月才被发现。
三、环境准备:本地平替方案
Work 完整功能需要特定订阅与灰度资格,但其思想可用开源栈平替。推荐一套”两件套 + 两习惯”:
# 件套1:联网代码执行 —— Docker 沙箱 + Python 数据栈
docker run -it --rm --network bridge -v $(pwd)/work:/work python:3.11 bash
pip install requests pandas beautifulsoup4 playwright pytest -q
# 件套2:无头浏览器 —— Playwright 自带 Chromium
playwright install chromium
python -c "from playwright.sync_api import sync_playwright; print('ok')"
两习惯:一是所有协作状态落文件(work/CONTEXT.md 记录目标与约定,work/log.md 记录每次运行结论);二是周期任务交给 cron/systemd timer,而不是靠人每天手动唤起。下面实战全部基于这套平替,可直接运行。
四、分步实战:复刻 Work 的完整闭环
贯穿例子:做一个”竞品价格日报”——每天抓取 3 个公开电商页面的标价,生成 Markdown 报告并归档。
步骤 1:建工作区与上下文文件
mkdir -p work/{data,reports,scripts} && cat > work/CONTEXT.md <<'EOF'
# 竞品价格日报
- 目标:每日跟踪 A/B/C 三款公开商品页标价,输出 reports/YYYY-MM-DD.md
- 规则:只抓公开页面,不登录;每次抓取间隔 ≥3 秒;失败重试 2 次后记"缺失"不崩
- 口径:价格取页面主标价(不含券);货币统一 CNY;时间统一 Asia/Shanghai
EOF
把这份文件作为每次唤起模型(或脚本)的第一输入,就是平替版”持久上下文”。
步骤 2:联网代码执行——写抓取脚本并真实运行
# work/scripts/fetch.py
"""联网抓取:对应 Work 的联网代码执行环境。"""
import re, time, datetime, json
from zoneinfo import ZoneInfo
import requests
TARGETS = {
"A": "https://example.com/product-a",
"B": "https://example.com/product-b",
"C": "https://example.com/product-c",
}
HEADERS = {"User-Agent": "price-watch/1.0 (research; contact: you@example.com)"}
def fetch_price(url: str) -> float | None:
for attempt in range(3):
try:
r = requests.get(url, headers=HEADERS, timeout=15)
r.raise_for_status()
m = re.search(r"[¥¥]\s?([\d,]+\.?\d*)", r.text)
if m:
return float(m.group(1).replace(",", ""))
except Exception as e:
print(f"尝试 {attempt+1} 失败 {url}: {e}")
time.sleep(3)
return None
def main():
today = datetime.datetime.now(ZoneInfo("Asia/Shanghai")).date().isoformat()
rows = {"date": today, "prices": {}}
for name, url in TARGETS.items():
rows["prices"][name] = fetch_price(url)
time.sleep(3)
with open(f"work/data/{today}.json", "w") as f:
json.dump(rows, f, ensure_ascii=False, indent=2)
print("已落盘", today, rows)
if __name__ == "__main__":
main()
python work/scripts/fetch.py && cat work/data/$(date +%F).json
要点:真实请求、真实落盘、失败记缺失不崩——这正是”联网执行”与演示版问答的本质区别。
步骤 3:无头 Chrome——对付需要渲染的页面
静态请求抓不到 JS 渲染的价格时,上无头浏览器(对应 Work 的 Headless Chrome):
# work/scripts/fetch_rendered.py
from playwright.sync_api import sync_playwright
def fetch_rendered(url: str, selector: str = ".price") -> str | None:
with sync_playwright() as p:
b = p.chromium.launch(headless=True)
pg = b.new_page(user_agent="price-watch/1.0 (research)")
try:
pg.goto(url, wait_until="networkidle", timeout=30000)
pg.wait_for_selector(selector, timeout=10000)
text = pg.inner_text(selector)
pg.screenshot(path="work/data/last_view.png") # 截图留证
return text
except Exception as e:
print("渲染抓取失败:", e)
pg.screenshot(path="work/data/error_view.png")
return None
finally:
b.close()
if __name__ == "__main__":
print(fetch_rendered("https://example.com/product-a"))
截图留证是关键习惯:每次抓取留一张 last_view.png,价格异常时先看截图是”真涨价”还是”页面改版抓错了”,排障效率差数倍。
步骤 4:子 Agent 式并行——三路抓取同时跑
# work/scripts/parallel.py(平替版"子Agent":多进程分治)
"""三个商品各一个 worker,主进程归约,对应 Work 的子 Agent 编排。"""
from concurrent.futures import ThreadPoolExecutor
from fetch import fetch_price, TARGETS
import time
def worker(item):
name, url = item
time.sleep(1)
return name, fetch_price(url)
with ThreadPoolExecutor(max_workers=3) as ex:
result = dict(ex.map(worker, TARGETS.items()))
print(result)
子任务并行的铁律:每个 worker 输入输出格式一致((name, price|None)),失败只污染自己那一路,主进程归约时对 None 记缺失。这是从”能并行”到”敢并行”的分界线。
步骤 5:生成报告站(平替 Sites)
# work/scripts/report.py
import json, glob, datetime
from zoneinfo import ZoneInfo
files = sorted(glob.glob("work/data/2*.json"))[-7:]
lines = ["# 竞品价格周报", ""]
lines.append("| 日期 | A | B | C |")
lines.append("|---|---|---|---|")
for f in files:
d = json.load(open(f))
p = d["prices"]
lines.append(f"| {d['date']} | {p.get('A')} | {p.get('B')} | {p.get('C')} |")
lines += ["", f"> 生成时间:{datetime.datetime.now(ZoneInfo('Asia/Shanghai'))}"]
open("work/reports/weekly.md", "w").write("\n".join(lines))
print("报告已生成")
python work/scripts/report.py
# 发布成站点:任意静态托管即可(对应 Work 的 Sites 一键发布)
cd work/reports && python -m http.server 8000
步骤 6:定时任务(平替 Work scheduled tasks)
# 每天 08:00 自动执行(对应 Work 的定时任务)
(crontab -l 2>/dev/null; echo "0 8 * * * cd $(pwd) && python work/scripts/fetch.py && python work/scripts/report.py >> work/log.md 2>&1") | crontab -
crontab -l | tail -2
定时任务三件套缺一不可:日志追加(>> work/log.md)、失败不静默(脚本异常时非零退出 + 告警)、幂等输出(同一天重跑覆盖而非追加重复)。
步骤 7:验收与巡检脚本
# work/scripts/check.py(定时任务的"监工")
import json, glob, datetime
files = sorted(glob.glob("work/data/2*.json"))[-3:]
assert len(files) == 3, f"最近3天数据缺失:仅 {len(files)} 份"
for f in files:
d = json.load(open(f))
missing = [k for k, v in d["prices"].items() if v is None]
print(f, "缺失:", missing or "无")
print("巡检通过")
五、常见坑与合规边界
- 联网执行放大提示注入:网页里的隐藏文本可能诱导模型执行恶意指令。对策:抓取与解析分离——抓取脚本只取文本,绝不把网页原文拼进可执行指令;高权限操作(发请求、删文件)必须白名单。
- 无头浏览器被反爬:高频访问触发封禁。对策:间隔 ≥3 秒、带可联系的 UA、失败退避重试;只访问公开页面,不绕登录、不破验证码,这是法律红线。
- 持久文件变成垃圾场:工作区文件越堆越多,新会话读到过期约定。对策:
CONTEXT.md置顶”最后更新日期 + 当前有效口径”,过期内容归档到archive/;每次会话结束花 2 分钟更新上下文。 - 子任务接口不统一导致合并灾难:三个 worker 返回三种格式,主进程归约崩溃。对策:先定义 JSON Schema 再开并行,归约前做 schema 校验。
- 定时任务静默失败:连续错两周才发现。对策:check.py 巡检 + 缺失告警(如邮件/群机器人);报告页顶部显示”数据新鲜度”(最近成功抓取时间),一眼可见异常。
- 把 Sites 当正式产品:模型生成的站点缺鉴权、缺审计,直接对外有泄露风险。对策:Sites 只做内部分享,涉客数据走正式发布流程。
- 成本失控:无头浏览器 + 长时间执行烧 token/烧机器。对策:给定时任务设超时(如 10 分钟熔断)与月度预算告警;抓取频率按需而定,日级别多数场景足够。
六、总结
ChatGPT Work 的真正含义不是五个功能点,而是工作范式的迁移:从”一次问答”到”持续经营”——联网执行让结论基于真实数据,无头浏览器让验证眼见为实,持久文件让知识跨会话累积,子 Agent 让复杂任务分治并行,Sites 与定时任务让产出持续服务。即使没有官方 Work 入口,用”Docker 沙箱 + Playwright + 文件工作区 + cron”也能复刻八成功力。落地的关键不在工具多时髦,而在纪律:白名单权限、截图留证、schema 先行、巡检告警。把这套纪律跑顺,你的 AI 就从”聊天搭子”升级为”值班同事”。 点击阅读原文
参考资料:Simon Willison《Understanding ChatGPT Work》(1行)。 点击阅读原文
七、附录:从日报到值班体系的升级路线
价格日报跑稳一个月后,可以按三步升级为值班体系。第一步加异常告警:当某商品单日涨跌幅超过阈值,或抓取连续两天缺失,自动发告警消息到群机器人,阈值按品类单独配置,告警信息必须附带截图路径与原始数据链接,方便值班人一分钟定位是真涨价还是抓取故障。第二步加周报月报:将日报数据自动聚合为趋势图与涨跌榜,每月初生成月度复盘,沉淀为可检索的档案库,支持按商品与时间范围回查任意一天的原始快照。第三步加自愈:对已知故障模式编写自动恢复逻辑,如页面改版导致选择器失效时自动尝试备用选择器并标记待人工确认,恢复动作全部记日志。从单次任务到定时任务再到值班体系,每一步都以前一步的日志与快照为基础,持久文件工作区的价值在这里真正释放。升级过程中权限 review 必须同步进行,自动化的权力越大,白名单就要收得越紧,这是 Work 范式下不变的安全铁律。
八、附录二:成本与安全运营手册
成本方面给三个硬性配额:单次无头浏览器任务超时十分钟熔断,每日抓取总请求数设上限并告警,每月对账统计沙箱与模型调用费用,超预算自动降频。很多团队第一次跑自动化抓取就被反爬封禁或账单吓到,根源都是没有配额意识。安全方面坚持四条:抓取目标白名单制,新增域名需审批;所有外部文本先入库再分析,绝不直接拼进执行指令;定时任务以最小权限账号运行,权重目录与密钥目录只读挂载;每月做一次权限复核,清理过期任务与无用文件。把这份手册贴在工作区首页,新人接手第一天就知道红线在哪里。自动化走得越远,护栏就要修得越高,这是运营铁律。