GPT‑6 Astra 如何让劳动力市场研究智能体的时间与成本同时减半

2026-09-22 20 预计阅读时间: 1 分钟
来源: openai.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:11 分钟

Parallel 报告称,在使用 GPT‑6 Astra 处理劳动力市场数据的研究与综合任务后,其智能体的执行时间和成本都降到了此前模型的一半。这不是单纯比较一次模型调用的响应速度,而是在提醒团队:评估智能体模型时,应关注完成整个研究任务所付出的时间、Token、工具调用和重试成本。

“减半”应该放到完整任务链路中理解

劳动力市场研究通常不只是生成一段文字。一个可落地的智能体工作流往往包含:

  1. 检索职位、薪资、地区和时间范围等数据;
  2. 从多个来源提取结构化指标;
  3. 识别数据口径、时间窗口和样本差异;
  4. 汇总趋势并生成带证据引用的结论;
  5. 在格式错误、证据不足或工具失败时重试。

因此,模型升级可能从多个位置降低总成本:更少的推理轮次、更准确的工具参数、更短但信息密度更高的输出,以及更低的格式错误率。反过来,即使单次调用价格较低,只要智能体频繁重试或产生需要人工返工的结论,端到端成本仍然可能更高。

Parallel 公布的是其自身工作负载上的结果。摘要没有给出任务集规模、价格口径、质量评分方法或模型参数,因此不能直接推导出所有智能体都能获得相同的 50% 改善。更可靠的做法是用自己的任务轨迹进行复测。

用固定证据包复测速度、成本和格式成功率

下面是一个可以直接改造的基准脚本。它假设服务提供 OpenAI 兼容的 chat/completions 接口,使用同一批模拟劳动力市场证据分别调用旧模型和 GPT‑6 Astra,并记录延迟、Token 成本与 JSON 输出成功率。

示例数据是虚构的,只用于验证基准流程。运行前需要替换接口地址、模型 ID和实际价格。

# benchmark.py
import csv
import json
import os
import statistics
import time
import urllib.request

BASE_URL = os.environ["LLM_BASE_URL"].rstrip("/")
API_KEY = os.environ["LLM_API_KEY"]
ROUNDS = int(os.getenv("ROUNDS", "2"))

MODELS = {
    "old": {
        "id": os.getenv("OLD_MODEL", "replace-with-prior-model"),
        "input_price": float(os.getenv("OLD_INPUT_USD_PER_MTOK", "0")),
        "output_price": float(os.getenv("OLD_OUTPUT_USD_PER_MTOK", "0")),
    },
    "astra": {
        "id": os.getenv("NEW_MODEL", "gpt-6-astra"),
        "input_price": float(os.getenv("NEW_INPUT_USD_PER_MTOK", "0")),
        "output_price": float(os.getenv("NEW_OUTPUT_USD_PER_MTOK", "0")),
    },
}

# 以下数据均为虚构示例,不代表真实劳动力市场。
CASES = [
    {
        "case_id": "postings-trend",
        "question": "比较两个季度的软件工程职位发布量,并说明变化率。",
        "evidence": [
            {"source_id": "s1", "period": "2025-Q1", "postings": 1200},
            {"source_id": "s2", "period": "2025-Q2", "postings": 1020},
        ],
    },
    {
        "case_id": "salary-regions",
        "question": "比较两个地区的数据分析师薪资中位数,不要推断未提供的原因。",
        "evidence": [
            {"source_id": "s3", "region": "Region-A", "median_salary": 98000},
            {"source_id": "s4", "region": "Region-B", "median_salary": 91000},
        ],
    },
]

SYSTEM_PROMPT = """你是劳动力市场研究智能体。
只能使用用户提供的证据,不得补充外部事实。
每项关键结论都要引用 source_id。
证据不足时必须明确写出 unknown。
仅返回 JSON,字段为 summary、findings、citations、limitations。
"""


def call_model(model_id, case):
    payload = {
        "model": model_id,
        "temperature": 0,
        "messages": [
            {"role": "system", "content": SYSTEM_PROMPT},
            {
                "role": "user",
                "content": "分析以下证据包:\n" + json.dumps(case, ensure_ascii=False),
            },
        ],
    }

    request = urllib.request.Request(
        BASE_URL + "/chat/completions",
        data=json.dumps(payload).encode("utf-8"),
        headers={
            "Authorization": "Bearer " + API_KEY,
            "Content-Type": "application/json",
        },
        method="POST",
    )

    started = time.perf_counter()
    with urllib.request.urlopen(request, timeout=120) as response:
        data = json.loads(response.read().decode("utf-8"))
    latency = time.perf_counter() - started

    content = data["choices"][0]["message"]["content"]
    usage = data.get("usage", {})
    input_tokens = usage.get("prompt_tokens", 0)
    output_tokens = usage.get("completion_tokens", 0)

    try:
        parsed = json.loads(content)
        valid_json = all(
            key in parsed
            for key in ("summary", "findings", "citations", "limitations")
        )
    except json.JSONDecodeError:
        valid_json = False

    return latency, input_tokens, output_tokens, valid_json, content


def token_cost(config, input_tokens, output_tokens):
    return (
        input_tokens * config["input_price"]
        + output_tokens * config["output_price"]
    ) / 1_000_000


rows = []
for label, config in MODELS.items():
    for round_number in range(1, ROUNDS + 1):
        for case in CASES:
            latency, input_tokens, output_tokens, valid_json, content = call_model(
                config["id"], case
            )
            rows.append(
                {
                    "model": label,
                    "model_id": config["id"],
                    "round": round_number,
                    "case_id": case["case_id"],
                    "latency_seconds": round(latency, 3),
                    "input_tokens": input_tokens,
                    "output_tokens": output_tokens,
                    "estimated_cost_usd": round(
                        token_cost(config, input_tokens, output_tokens), 8
                    ),
                    "valid_json": valid_json,
                    "answer": content,
                }
            )

with open("benchmark_results.csv", "w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=rows[0].keys())
    writer.writeheader()
    writer.writerows(rows)

for label in MODELS:
    selected = [row for row in rows if row["model"] == label]
    print(
        json.dumps(
            {
                "model": label,
                "runs": len(selected),
                "p50_latency_seconds": round(
                    statistics.median(row["latency_seconds"] for row in selected), 3
                ),
                "total_estimated_cost_usd": round(
                    sum(row["estimated_cost_usd"] for row in selected), 6
                ),
                "json_success_rate": round(
                    sum(row["valid_json"] for row in selected) / len(selected), 3
                ),
            },
            ensure_ascii=False,
        )
    )

运行方式如下。价格单位是每百万 Token 的美元价格;如果供应商使用不同计费方式,需要相应修改脚本。

export LLM_BASE_URL="https://your-provider.example/v1"
export LLM_API_KEY="replace-me"
export OLD_MODEL="your-prior-model-id"
export NEW_MODEL="your-gpt-6-astra-model-id"

export OLD_INPUT_USD_PER_MTOK="0"
export OLD_OUTPUT_USD_PER_MTOK="0"
export NEW_INPUT_USD_PER_MTOK="0"
export NEW_OUTPUT_USD_PER_MTOK="0"

export ROUNDS="5"
python benchmark.py

benchmark_results.csv 保留了每次调用的完整输出,便于后续人工评分。正式测试时,应把模拟证据替换为经过脱敏的真实任务样本,并至少覆盖简单汇总、跨来源冲突、证据缺失和长上下文四类场景。

不要让低延迟掩盖研究质量问题

劳动力市场数据尤其容易受到口径变化影响。例如,“职位发布量”可能包含重复职位,“薪资”可能是区间中点、基本工资或总薪酬,“地区”也可能按城市、都会区或远程岗位划分。更快地产生一个忽略口径差异的答案,并不构成有效优化。

除了延迟和模型账单,建议同步记录这些指标:

指标 为什么重要
任务完成率 判断智能体是否无需人工干预即可结束任务
引用覆盖率 检查关键结论是否能追溯到证据
数值准确率 捕获百分比、单位和时间窗口错误
工具调用次数 识别模型是否进行了多余搜索或重复读取
重试率 揭示格式失败和不稳定行为带来的隐性成本
人工复核时间 衡量自动化是否真的减少了总工作量

还应把搜索、抓取、模型推理和人工审核分别计时。这样才能判断改善究竟来自模型本身,还是缓存、并发、提示词缩短或数据管道调整。

从影子流量开始,而不是直接替换生产模型

可以按下面的顺序采用新模型:

  • 固定任务集、提示词、工具权限和超时配置,只替换模型;
  • 使用影子流量运行新旧模型,不让新模型结果直接影响用户;
  • 对高风险结论设置规则校验,例如百分比重算、时间范围检查和引用存在性检查;
  • 分别统计成功任务成本与失败任务成本,避免平均值掩盖重试;
  • 当质量不下降且端到端成本、P50/P95 延迟都改善后,再逐步扩大流量;
  • 为数据漂移、供应商故障和输出格式变化保留回滚开关。

Parallel 的结果说明,强模型可能同时改善智能体的速度和经济性,但“时间与成本减半”应被视为一个值得复现的工作负载结果,而不是通用承诺。真正稳妥的升级标准是:在自己的数据、工具和质量门槛下,用更少资源稳定完成同一项研究任务。


相关推荐