当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > 多模态模型读取发票图片时如何保留字段证据

多模态模型读取发票图片时如何保留字段证据

来源:17golang原创 2026-09-12 16:12:00 0浏览 收藏

多模态模型能从发票图片中读出发票号码、金额和日期,但如果系统只保存一段模型文本,财务人员很难回答“这个值在原图哪里”“为什么相信它”。更稳妥的做法是把每个字段设计成一个证据对象:值、原图归一化坐标、证据描述、置信说明和复核状态一起保存。

官方地址:https://platform.openai.com/docs/

要点速览
  • 用 JSON Schema 固定每个字段的证据结构,避免模型只返回自由文本。
  • 坐标保存为 0 到 1 的比例值,并与原图宽高、哈希绑定。
  • 置信度只代表抽取判断的把握,缺证据或低置信字段仍要人工复核。

一、先定义字段证据模型

字段证据的核心不是给结果再加一个 confidence,而是让值和它的来源区域成为一条不可拆开的记录。下面的结构以发票号码、价税合计为例;box 使用左上角和右下角的归一化坐标,范围固定在 0 到 1。

# 用同一种结构保存字段值、原图位置和复核状态
FIELD_SCHEMA = {
    "type": "object",
    "properties": {
        "value": {"type": "string"},
        "box": {
            "type": "object",
            "properties": {
                "x1": {"type": "number", "minimum": 0, "maximum": 1},
                "y1": {"type": "number", "minimum": 0, "maximum": 1},
                "x2": {"type": "number", "minimum": 0, "maximum": 1},
                "y2": {"type": "number", "minimum": 0, "maximum": 1}
            },
            "required": ["x1", "y1", "x2", "y2"],
            "additionalProperties": False
        },
        "evidence": {"type": "string"},
        "confidence_note": {"type": "string"},
        "needs_review": {"type": "boolean"}
    },
    "required": ["value", "box", "evidence", "confidence_note", "needs_review"],
    "additionalProperties": False
}

这里的 evidence 应该是“字段出现在发票右上区域的黑色印刷文字”这类可读说明,而不是再次复制整张发票。confidence_note 也要描述不确定性来源,例如“数字 8 的边缘略模糊”,不要把模型置信度写成税务真实性结论。

发票字段证据对象的静态数据结构框图
图1:字段证据对象把 value、box、evidence、confidence_note 和 needs_review 绑定在同一个数据结构中。

二、把发票图片和抽取规则一起提交

图像输入和抽取规则要在一次请求中表达清楚。官方 Responses API 支持把图片作为 input_image 传入;实际项目还应在提示中声明:看不清时返回空值并标记复核,不要猜测号码。

import base64
import json
from openai import OpenAI

# 图片只作为本次请求输入;密钥应从服务端环境变量读取
client = OpenAI()
with open("invoice.jpg", "rb") as image_file:
    image_data = base64.b64encode(image_file.read()).decode("ascii")

prompt = """
# 只抽取发票号码和价税合计,并为每个字段返回原图归一化坐标。
# 无法确认的字段 value 返回空字符串,needs_review 必须为 true;不要猜测。
"""
response = client.responses.create(
    model="gpt-5",
    input=[{
        "role": "user",
        "content": [
            {"type": "input_text", "text": prompt},
            {"type": "input_image", "image_url": f"data:image/jpeg;base64,{image_data}"}
        ]
    }],
    text={
        "format": {
            "type": "json_schema",
            "name": "invoice_evidence",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "invoice_number": FIELD_SCHEMA,
                    "total_amount": FIELD_SCHEMA
                },
                "required": ["invoice_number", "total_amount"],
                "additionalProperties": False
            }
        }
    }
)
result = json.loads(response.output_text)  # 结构固定后再交给业务层处理

Schema 的价值是让缺失字段也有稳定形状,便于后续审计和数据库入库。不要把图片压缩、裁剪后的坐标和原图坐标混在一起;如果为了识别做了裁剪,要同时记录裁剪框。

发票图片、抽取规则与结构化响应的静态模块关系框图
图2:发票图片、抽取提示、JSON Schema 与结构化响应之间的静态模块关系示意。

三、把坐标和原图绑定到审计记录

归一化坐标的计算很简单:原图宽度为 W、高度为 H 时,像素点 (px, py) 保存为 (px / W, py / H)。入库时建议额外保存原图 SHA-256、宽高和处理时间,这样同一张发票被重新识别时仍能对比证据。

import hashlib
from pathlib import Path

# 生成可复核的原图指纹,并把比例坐标恢复为像素框
image_path = Path("invoice.jpg")
image_hash = hashlib.sha256(image_path.read_bytes()).hexdigest()

def to_pixels(box, width, height):
    # 乘回原图尺寸,方便前端在原图上画定位框
    return {
        "x1": round(box["x1"] * width),
        "y1": round(box["y1"] * height),
        "x2": round(box["x2"] * width),
        "y2": round(box["y2"] * height),
    }

audit_record = {
    "image_sha256": image_hash,
    "image_width": 2480,
    "image_height": 3508,
    "fields": result,
}

如果模型返回的框越界、x1 > x2 或没有覆盖字段文字,不要静默修正后当成可信结果;应保留原始响应并把该字段设为待复核。坐标只回答“模型指向哪里”,不能代替发票验真、税率核验或业务规则。

四、用证据完整度决定是否人工复核

自动入账前至少检查四件事:字段值非空、坐标在范围内、证据说明非空、needs_review 为 false。金额还要和业务侧的数值解析、币种及合计规则独立核对。只要一项不满足,就把整张发票送入人工队列,并保留模型原始响应。

检查项通过条件不通过处理
字段值非空且符合字段格式标记缺失字段
图像定位四个坐标在 0 到 1 之间保留原始 JSON,人工查看原图
证据说明能说明文字所在区域或可见特征禁止自动入账
复核标记needs_review=false进入人工复核队列

最后要强调:证据链提升的是可追溯性,不是模型的绝对正确率。发票识别涉及财务和合规场景时,仍应结合原图、业务规则和人工抽查;不要因为 JSON 格式正确,就把抽取结果当作已经验证的事实。

相关问题

为什么不直接保存 OCR 文本?

纯文本缺少字段与原图的对应关系,后续很难复核。把文本、坐标和说明放在同一字段对象里,前端才能点击字段回看原图。

置信度低于多少才需要人工复核?

不要只设一个脱离业务的通用阈值。先按字段风险、金额范围、图像清晰度和历史误差制定规则,并把阈值命中原因写入复核记录。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go race detector 没报错但数据仍不一致该查什么Go race detector 没报错但数据仍不一致该查什么
上一篇
Go race detector 没报错但数据仍不一致该查什么
Go 泛型约束如何同时支持整数别名与自定义方法
下一篇
Go 泛型约束如何同时支持整数别名与自定义方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    102次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    16次使用
  • OpenCompass大模型评测体系详解:功能、使用指南与应用场景
    OpenCompass
    OpenCompass是上海AI实验室推出的开源大模型评测平台,提供CompassKit、CompassHub和CompassRank三大核心组件,支持LLM及多模态模型的一站式标准化评估与排行榜查询。
    29次使用
  • AGI-Eval大模型评测平台:权威榜单、数据集与人机协同评测方案
    AGI-Eval
    AGI-Eval是由上海交大等高校联合发布的大模型评测社区,提供公正透明的LLM能力榜单、多领域评测集及Data Studio数据服务,助力AI模型性能评估与NLP科研开发。
    17次使用
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    257次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码