为什么我放弃了传统方案,改用 GPT-5.1

research进阶7 分钟阅读2026/10/14

为什么我放弃了传统方案,改用 GPT-5.1

起因:一个让我头疼了三周的文本解析需求

先说说我为什么折腾这个。我们公司有个内部系统,每天要处理几百封客户发来的半结构化邮件——订单确认、退换货申请、地址变更之类的。传统方案是我写的一套 Python 解析器,正则表达式加规则引擎,大约 1200 行代码,从客户邮件里抽取订单号、SKU、数量、收货地址这些字段。

这东西维护了两年,我快被它折磨死了。上个月客户邮件里出现了一种新格式:“订单 2024-XXXX 号(总共 3 件商品)”,我的正则 订单\s*\d{4}-\d{4} 直接匹配不上,因为有人用中文括号,有人夹了空格。光是为各种括号、空格、全角半角字符打补丁,我每周就要花好几个小时。

我当时的想法很简单:这种脏活累活,为什么不丢给大模型干?但我一直没换,是担心两点:成本和延迟。每天几百封邮件,每封都调一次 API,账单会不会爆炸?延迟会不会拖垮流水线?

于是我拿 GPT-5.1 做了试点,结果三周后我把那 1200 行解析代码整个删掉了。下面是完整的过程,包括我踩的坑。

第一步:先做基准测试,别急着动手

我的建议是,不管你要替换什么传统方案,先量化老方案的表现。我统计了老解析器过去 30 天的数据:

  • 处理邮件 9,842 封
  • 解析失败需要人工介入的:417 封(失败率 4.2%)
  • 平均处理延迟:8ms
  • 每月维护工时:约 15 小时

有了这个基准,后面才能客观判断新方案到底值不值。

第二步:写第一个提取 Prompt

我的第一版 Prompt 非常朴素:

从下面的客户邮件中提取以下字段,以 JSON 输出:
order_id(订单号), sku_list(商品SKU和数量), address(新收货地址,如有), intent(订单确认/退货/地址变更/其他)

邮件内容:
{email_body}

结果让我惊喜又踩坑。惊喜的是,那些老解析器搞不定的奇葩格式,它几乎全对。坑是第一版跑下来我发现了三个问题:

  1. 它太“热心”了。邮件里没提地址,它有时会编一个出来。
  2. SKU 大小写不稳定。客户写 abc-123,它有时输出 ABC-123。
  3. 中文引号里的订单号偶尔漏掉。

第三步:用结构化输出解决格式问题

针对第一个问题,我在 Prompt 里加了明确约束:

规则:
1. 只提取邮件中明确出现的信息,找不到的字段填 null,禁止推测
2. SKU 保持原样输出,不要改变大小写
3. 输出必须是合法 JSON,不要包含任何解释文字

更关键的一步是我改用了 API 的结构化输出功能,直接定义 JSON Schema 强制输出格式,而不是靠提示词“求”它输出合法 JSON。以 Python SDK 为例:

from openai import OpenAI
client = OpenAI()

response = client.chat.completions.parse(
    model="gpt-5.1",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": email_body},
    ],
    response_format=ExtractionResult,  # Pydantic 模型
)

result = response.choices[0].message.parsed

其中 ExtractionResult 是个 Pydantic 模型:

from pydantic import BaseModel

class SkuItem(BaseModel):
    sku: str
    quantity: int

class ExtractionResult(BaseModel):
    order_id: str | None
    sku_list: list[SkuItem]
    address: str | None
    intent: str

用了这个之后,JSON 解析失败的次数直接归零,代码里那段“容错解析 JSON”的 hack 也删了。

第四步:处理成本和延迟

这是我最担心的部分,实际测下来的数据:

  • 每封邮件平均输入 800 token、输出 150 token
  • 单封调用约 0.15 秒(用 GPT-5.1 的较低推理档位,因为我这个任务不需要深度思考)
  • 每天按 500 封算,月成本大概几十美元——远低于我每月 15 小时维护工时的成本

延迟上我用了个混合策略:先用一个极简正则判断邮件类型,格式标准的邮件仍走老逻辑(快且免费),只有老解析器抛出低置信度或解析失败时,才降级到模型调用。这样大约 70% 的流量根本不花钱,API 只兜底那些“疑难杂症”。后来我发现模型兜底的准确率太高了,索性反过来了——模型为主,正则只做前置过滤垃圾邮件。

第五步:加一层验证,别完全信任输出

我现在仍然保留了一层校验:

def validate(result: ExtractionResult, raw_email: str) -> bool:
    if result.order_id and not re.match(r"\d{4}-\d{4}", result.order_id):
        return False
    if result.sku_list:
        for item in result.sku_list:
            if item.quantity < 1 or item.quantity > 999:
                return False
    return True

校验失败的邮件进人工队列。上线第一个月,人工介入率从老方案的 4.2% 降到了 0.3%,而且剩下那 0.3% 基本是邮件本身写不清楚、人也得打电话问的情况。

实用建议

  1. Prompt 里明确“找不到就填 null”,否则模型会脑补,这在数据提取场景是致命的。
  2. 用结构化输出,别靠正则解析模型返回的 JSON 字符串,省掉一整类 bug。
  3. 保留确定性校验。模型负责理解,规则负责把关,两者结合才是生产级方案。
  4. 控制输出字段数量。我一开始想让模型顺便输出“客户情绪”,结果干扰了主任务的准确率,字段拆开处理更稳。
  5. 先用 50~100 个历史难例做离线评估再上线,我拿那 417 封失败邮件当测试集,新方案一次通过率 96%。

诚实的局限

  • 延迟确实回不去了。8ms 变成 150ms,如果你做的是毫秒级实时系统,传统方案可能仍然更合适。
  • 成本随量线性增长。如果是每天百万级请求,账单要仔细算,可能需要模型+规则的混合架构。
  • 行为不完全稳定。同样的邮件,两次调用可能给出细微不同的结果(比如地址的空格差异),对强一致性场景要加后处理归一化。
  • 调试体验不同了。正则错了你能一眼看出来,模型错了你只能改 Prompt 然后重新跑测试集,需要建立一套回归测试的习惯。

总结一句:如果你的传统方案里堆满了“为千奇百怪的输入打补丁”的代码,那它大概率就是模型该接管的那部分。把确定性的部分留给规则,把理解语言的部分交给模型——这个分工是我这次重构最大的收获。

相关 Agent

D

DeepSeek V4

DeepSeek最新开源MoE大模型,671B参数,推理和编程能力顶尖,成本极低

了解更多 →