返回博客

长时程任务预算|几千美元里只有 100 美元在算

人工智能6511
长时程任务预算|几千美元里只有 100 美元在算

短任务按 token 单价核算成本就够用;长时程无人值守任务不行,因为它的开销结构与短任务完全不同。

一个具体案例能说明差距:某次无人值守连续运行数天的任务,算出平面 N=4 超杨-米尔斯理论六粒子振幅的九圈结果,超越了 Lance Dixon 团队 2023 年的八圈纪录。它的总成本约几千美元,而其中直接自举路线的 Python 运行成本仅约 100 美元——真正产出结果的那部分计算,是全部开销里很小的一块。

我在 4sapi(https://4sapi.com)上做长任务预算设计时,这组数字是最好的说明材料。

一、成本结构:试错才是大头

把长任务的开销摊开,大致是三块:

开销项占比特征是否随任务成功与否变化
探索与试错最大的一块强相关:失败任务同样消耗
最终产出计算很小只在收敛后产生
验证与复算中等随验证严格度上升

第一行的性质最关键:探索成本与任务是否成功无关。任务失败时这部分照样花掉,只是没有产出。所以长任务的成本不可预测性来自探索段,而不是产出段。

这也解释了为什么"按最终产出的规模估算成本"会系统性偏低——估算的往往只是第二行。

二、执行链与检查点

长任务的执行链需要显式的结构,否则中途失败只能整段重来:

text
任务定义(目标 + 验收标准 + 预算上限)
    |
    v
探索分支 1 ──┐
探索分支 2 ──┼─> 中间检查点(快照:进度、已花费、当前最优)
探索分支 3 ──┘         |
    |                  +-- 可恢复:从最近检查点继续
    v                  +-- 可归因:每个分支的独立开销
收敛判定
    |
    v
产出 + 验证(复算 / 交叉检查)

三个要素缺一不可:中间检查点让中断可恢复,分支级开销记录让事后能归因,验收标准前置让收敛判定有依据。

检查点的粒度需要权衡。太粗,中断后要重做的部分多,恢复成本高;太细,快照本身的写入开销会累积成可观的比例,而且会打断执行节奏。一个可用的经验是按"分支推进"而不是按"轮次"设检查点——每当一条分支产生实质进展(得到更好的中间结果、排除一条路径、确认一个不变量)时保存一次。这样检查点的数量与任务的实质进展成正比,而不是与运行时长成正比,长任务不会因为跑得久而把开销耗在快照上。

分支级开销记录也应当按同样的粒度累加,让每个检查点都带有"到目前为止这条分支花了多少"的信息。恢复时这份记录直接就是继续判断的依据。

三、为什么总额预算不够

给长任务只设一个总额上限,会得到两种失败模式:

一种是提前撞线。任务还在有效探索中,预算耗尽被迫中止,前面投入全部沉没。

另一种是长期挂空。任务早已进入收益递减区间,但因为还没到总额上限,继续消耗到上限为止。

问题的根源是总额预算只有一个维度。长任务需要的是分层预算:给不同性质的消耗分别设限,让任一层超标都能单独触发处置。

四、分层预算怎么分

我的分法是四层:

  1. 探索预算——所有探索分支的合计上限。这是最大的一层,也是最需要监控的一层。
  2. 单分支预算——任一分支的上限,防止一个分支吃掉全部探索预算。
  3. 收敛预算——进入收敛阶段后允许的开销,通常远小于探索预算。
  4. 验证预算——复算与交叉检查的开销,应按验证严格度预留。

配套一条纪律:任一层触顶都触发处置,而不是只停下总额。单分支触顶时应当终止该分支并把资源让给其他分支,而不是整体中止。

五、四类终止条件

预算是被动约束,终止条件才是主动判断。我固定用四类:

终止条件判据处置
收敛达到验收标准进入产出与验证
收益递减连续若干轮无实质改进停止该方向,或整体收敛
连续无进展连续若干轮无有效中间结果换策略或终止
硬上限任一层预算触顶停止并保存检查点

其中收益递减与连续无进展要分开。前者是"在进步但边际变小",可能值得继续;后者是"完全没有产出",继续只是在烧预算。把两者合成一个指标,会导致该停的没停、该继续的停了。

两类判据的阈值也需要按任务类型标定,而不是沿用默认值。探索空间大的任务(比如搜索类、开放式推理)本来就会有较长的无进展期,阈值设得太紧会过早终止;而结构化程度高的任务,无进展通常意味着路径已经错了,阈值可以设得紧一些。标定方法很简单:在缩小版任务上跑一遍,记录正常推进时无进展轮数的分布,把阈值设在分布的尾部而不是中位数附近——阈值的作用是识别异常,不是识别常态。

六、验收标准必须前置

长任务最容易出的问题不是失败,而是产出一个看起来合理、实际不成立的结果。跑了几天的任务,人会倾向于接受它的结论。

所以验收标准必须在任务启动前写定,而不是结束后再判断。对可形式化验证的任务,标准就是复算;对不可复算的任务,至少要定义可检查的中间断言——比如"每一步的关键中间量满足某组不变量"。没有这些,几天的运行时间会变成一种压力,让验收退化成确认。

七、验证与"看起来合理"的区分

验证预算存在的理由就是这一条:产出的表述质量与产出的正确性是两件事。一个长任务的结果可以逻辑顺畅、术语准确、结构完整,同时在关键数值上是错的。

我的做法是把验证拆成两层:一层是确定性复算(能重算的部分全部重算,比对数值),一层是交叉检查(换一种方法或换一个路径再算一遍,比对结论)。两层都不通过就不接受产出,无论它的表述多么完整。

验证的独立性同样要设计。如果复算用的是与产出阶段相同的代码路径、相同的中间假设、甚至同一个模型,那它复现的只是同一个错误,不构成验证。真正的验证需要一条在关键环节上与产出路径不同的链路——不同的实现、不同的算法族、或者不同的推理顺序。这也是验证预算必须单独预留的原因:它不能复用产出阶段的资源与流程,否则等于没有验证。

八、小规模标定先于规模化

长任务最大的成本风险是"第一次就跑大"。正确顺序是:先用缩小的同类任务跑通流程,测出探索成本与产出的比例关系,再按比例放大并设预算。

标定要测三件事:探索段占总开销的比例、收敛所需的轮次分布、失败任务的平均消耗。第三项最容易被漏掉——失败任务的消耗决定了预算的安全边际,只按成功案例估预算,会在失败率上升时集体超支。

标定还有一个附带收益:它会暴露"这个任务是否适合做成长时程"。如果缩小版任务里探索段占了绝大部分开销、且收敛轮次的分布极其分散,那么放大之后预算的可预测性会很差。这类任务更适合改成"人机交替"的形式——让 agent 跑一段、人看一次中间结果再决定是否继续,用人的判断把长任务切成若干短任务。这比追求完全无人值守更现实,也更容易控制成本。

最后一个容易被忽略的项:成本归因的保留期限。长任务的分支开销记录是下一轮优化的唯一依据,但它常常随着运行结束被清理掉。建议把每次长任务的预算报告与检查点一起归档——记录这一轮各分支的花费分布、最先触发的是哪条终止条件、验证阶段消耗了多少。跑过几次之后,这些报告会直接变成下一轮的预算参数来源,比凭经验调数值可靠得多。这也是长任务从"一次性尝试"变成"可复用能力"的关键一步。

把这套约束合起来看,长任务治理的落点其实只有两个数字:探索段占总开销的比例,以及失败任务的平均消耗。前者决定预算怎么分层,后者决定安全边际留多少。其余的分层设计、终止条件、检查点粒度,都是围绕这两个数字展开的具体手段。先把这两个数字测准,后面的设计就不会跑偏。

九、分层预算实现

下面这段脚本实现了分支级预算、收益递减判定与检查点保存。入口与 Key 从环境变量读取。

python
import os, json, time
from dataclasses import dataclass, field, asdict

BASE_URL = os.getenv("MODEL_BASE_URL", "https://4sapi.com/v1")
API_KEY = os.getenv("FOURSAPI_API_KEY", "")
CKPT_DIR = os.getenv("CKPT_DIR", "./checkpoints")

TOTAL_EXPLORE = float(os.getenv("BUDGET_EXPLORE", "50.0"))   # 探索总预算
PER_BRANCH = float(os.getenv("BUDGET_BRANCH", "8.0"))        # 单分支上限
NO_PROGRESS_LIMIT = int(os.getenv("NO_PROGRESS", "5"))        # 连续无进展轮数
PLATEAU_LIMIT = int(os.getenv("PLATEAU", "8"))               # 连续无改进轮数


@dataclass
class Branch:
    name: str
    spent: float = 0.0
    best: float = float("-inf")
    no_progress: int = 0
    plateau: int = 0
    stopped: str = ""

    def record(self, cost, score, improved: bool):
        self.spent += cost
        if score > self.best:
            self.best, self.plateau = score, 0
        else:
            self.plateau += 1
        self.no_progress = 0 if improved else self.no_progress + 1


@dataclass
class Runner:
    goal: str = ""
    branches: dict = field(default_factory=dict)
    explore_spent: float = 0.0

    def check(self, b: Branch):
        """按四类终止条件判定;返回停止原因或空串。"""
        if b.spent >= PER_BRANCH:
            return "单分支预算触顶"
        if self.explore_spent >= TOTAL_EXPLORE:
            return "探索预算触顶"
        if b.no_progress >= NO_PROGRESS_LIMIT:
            return "连续无进展"
        if b.plateau >= PLATEAU_LIMIT:
            return "收益递减"
        return ""

    def snapshot(self):
        os.makedirs(CKPT_DIR, exist_ok=True)
        path = os.path.join(CKPT_DIR, f"ckpt-{int(time.time())}.json")
        with open(path, "w", encoding="utf-8") as f:
            json.dump({"goal": self.goal, "explore_spent": self.explore_spent,
                       "branches": {k: asdict(v) for k, v in self.branches.items()}},
                      f, ensure_ascii=False, indent=1)
        return path

    def resume(self, path):
        with open(path, encoding="utf-8") as f:
            data = json.load(f)
        self.goal = data["goal"]
        self.explore_spent = data["explore_spent"]
        for k, v in data["branches"].items():
            self.branches[k] = Branch(**v)
        return self

    def report(self):
        print(f"探索已花费 {self.explore_spent:.2f} / 上限 {TOTAL_EXPLORE:.2f}")
        for k, b in sorted(self.branches.items(),
                           key=lambda kv: kv[1].best, reverse=True):
            tag = b.stopped or "运行中"
            print(f"  {k:>12}: 花费={b.spent:.2f} 最优={b.best:.4f} "
                  f"无进展={b.no_progress} 无改进={b.plateau} [{tag}]")

使用顺序是:每个分支每轮结束后调用 check(),返回非空即终止该分支并写入 stopped;explore_spent 累加到探索总预算时,一次性保存检查点并整体停止。report() 输出的分支排行就是事后归因的依据——哪条分支消耗最多、哪条最先进入递减,一眼可见。

十、成本与风险提示

结论

长时程任务的价格表与短任务不是一回事:几千美元的总开销里,真正产出结果的计算可能只有约 100 美元,其余都在探索与试错上。理解这一点之后,预算设计的目标就变了——不是压低产出成本,而是给探索段设好边界。具体做法是分层预算、四类终止条件、可恢复的中间检查点、以及前置的验收标准;在上生产之前,先用缩小的同类任务标定探索占比与失败消耗。这四件事做完,长任务才从"不设上限的等待"变成可排期、可预算、可验收的工程动作。我在 4sapi.com 上把这些约束落到 harness 之后,最直接的改善不是省钱,而是任务变得可以承诺——能提前说出"这个任务大概花多少、多久、什么条件下会停",这比事后解释为什么超支有价值得多。

欢迎在评论区聊聊各自给长时程任务设预算的方式,以及哪些终止条件在实际运行中最先触发。

标签:长时程任务Agent预算成本治理分层预算终止条件

推荐阅读

探索更多前沿洞察与行业干货。