大模型接口返回 200,为什么程序还是报错?

做一个客服聊天整理功能,让模型提取订单号和实付金额。

接口返回 200,有内容,耗时也正常。接着把结果交给程序,金额字段里却写着「待确认」。

这个故障值得在上线前主动模拟一次。更麻烦的是另一种情况:金额确实是数字,程序一路执行成功,但多了一个零。

先把输入缩短,方便看清问题:

A1024 这单原价 259.90 元,券后实付 199.90 元。

我们要提取的是实付金额,约定以整数「分」保存。期望结果是:

json 复制代码
{"order_id": "A1024", "amount_cents": 19990}

这里有两层 JSON,容易混在一起。HTTP 响应体能解析,只说明拿到了接口返回的对象;message.content 里面那段模型生成的文字,还得单独检查。

为了把检查逻辑跑一遍,我构造了下面几组返回内容。它们是本地模拟数据,不代表某个模型的实际表现。

返回内容 交给程序后会怎样
这笔订单实付 199.90 元。 人能看懂,JSON 解析失败
{"amount_cents":19990} JSON 合法,但缺少订单号
{"order_id":"A1024","amount_cents":"待确认"} 字段齐了,金额类型不对
{"order_id":"A1024","amount_cents":19990} 结构和这道题的答案都对

只写一句 json.loads(content),只能发现第一种问题。

我给这个小例子加了一段检查。只用 Python 标准库,把它放在读取模型回答之后、写数据库之前:

python 复制代码
import json


def parse_order(content, finish_reason):
    if finish_reason != "stop":
        raise ValueError(f"没有拿到最终文本:{finish_reason}")
    if not isinstance(content, str) or not content.strip():
        raise ValueError("回答为空")

    try:
        data = json.loads(content)
    except json.JSONDecodeError as exc:
        raise ValueError("回答不是合法 JSON") from exc

    if not isinstance(data, dict):
        raise ValueError("需要 JSON 对象")

    order_id = data.get("order_id")
    if not isinstance(order_id, str) or not order_id.strip():
        raise ValueError("order_id 缺失或无效")

    amount = data.get("amount_cents")
    if type(amount) is not int or amount < 0:
        raise ValueError("amount_cents 必须是非负整数")

    return {"order_id": order_id, "amount_cents": amount}

这里用 type(amount) is int,是因为 Python 的 isinstance(True, int) 也会返回 True。金额不应该接受布尔值。

这段代码只处理最终返回 JSON 文本的流程。工具调用有自己的处理路径,tool_calls 不能直接算作模型故障;输出被截断时,也不能把已经收到的半段文字当作完整答案。

拿到非流式 Chat Completions 响应后,调用位置是:

python 复制代码
choice = response["choices"][0]
order = parse_order(
    choice["message"].get("content"),
    choice["finish_reason"],
)

这里的 response 是已解析成字典的接口响应。通过检查,只代表这份数据符合刚才约定的字段和类型。

本地运行,前面三种异常都被拦住了。但再加一个例子:

json 复制代码
{"order_id": "A1024", "amount_cents": 199900}

它会通过上面的检查。

订单号有了,金额是非负整数,JSON 也没有任何问题。可原文实付 199.90 元,这个结果变成了 1999.00 元。

演示脚本中,这两条的输出是:

text 复制代码
正常结果:结构通过;与人工标注答案一致
金额多一个零:结构通过;与人工标注答案不一致

第二步能发现错误,是因为我提前写好了这条样本的参考答案。换成线上新数据,仍然需要核对原文或订单记录。字段校验不会替你判断事实。

这也影响模型怎么选。只比较「有没有返回」或者「能不能解析 JSON」,很容易选出一个格式很整齐、提取结果却不可靠的模型。

接入层可以沿用 moyi API 的 Chat Completions 接口。它在这里的用处是:对支持该接口的候选模型,保留同一套请求和验收代码,换模型后继续跑同一批样本。具体参数能力仍要逐个确认,接口兼容不代表功能完全相同。

样本不用一开始就堆得很大,但要有实付价和原价同时出现、缺少订单号、没写金额、同一段话提到两笔订单这些情况。把预期结果标好,再分别记录格式通过率和字段提取正确率,才知道模型差在哪里。

还有个容易被忽略的处理:原文没写金额,就应该进入待补充或人工确认。为了让程序继续运行,把「待确认」强行补成 0,后面反而更难查。

提示词当然也要约束格式。DeepSeek 的 JSON Output 文档要求配合 JSON 提示和格式示例,并提醒注意输出截断、空内容。即使开启这类功能,业务仍然要核对提取出的值。

对这个例子,我会把日志里的「成功」拆开记:HTTP 请求成功、结构检查通过、字段核对通过。遇到问题,至少能知道该查网络、返回格式,还是模型把原价当成了实付价。

你们接 AI 时,更费时间的是接口报错,还是它正常返回了,但结果不能直接用?

相关推荐
小小张说故事1 小时前
Python 的 __new__ 到底管什么?和 __init__ 的分工一次讲透Python后端python知识整理日新计划
python
青少儿编程课堂2 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会C/C++考级:并查集连通块与朋友圈问题解析
c++·python·算法·bfs·信息学竞赛
外收内放2 小时前
数据分析(数据排序)
python·学习·数据分析
Pniubi2 小时前
agent处理封号怎么解决误封问题
开发语言·python
小羊没烦恼!2 小时前
浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色
前端·数据库·后端·python·web安全·oracle
ss.li2 小时前
rppg阅读笔记 2026.10.15
图像处理·python·计算机视觉
大貔貅喝啤酒3 小时前
Unittest框架使用教程
自动化测试·python
一个简单的TTS开发者3 小时前
中文TTS工具有哪些-8款主流方案横向对比
人工智能·后端·python·indextts
yunfanleo3 小时前
temperature 详解:大模型采样参数原理、三种用法与工程实践
人工智能·python·rpa