ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

使用 Instructor 与 GPT-4 Vision 从图片中提取表格:MarkdownDataFrame 结构化输出的完整实战指南

使用 Instructor 与 GPT-4 Vision 从图片中提取表格:MarkdownDataFrame 结构化输出的完整实战指南 使用 Instructor 与 GPT-4 Vision 从图片中提取表格MarkdownDataFrame 结构化输出的完整实战指南【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor本文基于 docs/examples/tables_from_vision.md结合 examples/vision/run_table.py 与 instructor/v2/core/multimodal.py 源码完整讲解如何借助 Instructor 的响应模型response model机制让视觉语言模型从图片中直接提取出结构化的 Markdown 表格并转换为可分析的 pandas DataFrame。读完本文你将掌握自定义 Pydantic 类型AnnotatedBeforeValidatorPlainSerializer的编排技巧、多模态消息的构造方式以及 Instructor 中 TOOLS 与 MD_JSON 两种模式的适用场景。为什么需要从图片中提取表格报表、截图、图表和数据看板中的表格信息往往以像素形式存在无法直接被程序读取。传统方案依赖 OCR 后的人工清洗不仅耗时而且面对复杂表格时准确率不稳定。借助 GPT-4 系列视觉模型如gpt-4o我们可以直接向模型发送图片 URL并要求它返回结构化的 Markdown 表格再由 Instructor 在客户端完成校验与反序列化最终得到可以直接用于数据分析的 pandas DataFrame。这一思路的核心难点在于模型输出的是 Markdown 字符串而我们需要的是 DataFrame 对象。Instructor 的响应模型机制允许我们定义自定义类型在模型输出字符串与最终 Python 对象之间架起一座转换桥梁——这正是本文要深入讲解的MarkdownDataFrame类型。环境准备运行本示例前需要安装 Instructor 及其依赖pip install instructor pandas tabulatepandas用于承载解析后的表格数据tabulate提供DataFrame.to_markdown()所需的 Markdown 渲染能力。完整可运行的示例代码位于 examples/vision/run_table.py同一主题的进阶版本见 docs/examples/extracting_tables.md。定义 MarkdownDataFrame 自定义类型图片中的表格经视觉模型识别后会以 Markdown 表格字符串的形式返回。为了把这个字符串直接变成 pandas DataFrame我们定义如下自定义类型from io import StringIO from typing import Annotated, Any, List from pydantic import ( BaseModel, BeforeValidator, PlainSerializer, InstanceOf, WithJsonSchema, ) import instructor import pandas as pd from rich.console import Console console Console() client instructor.from_provider(openai/gpt-4o, modeinstructor.Mode.TOOLS) def md_to_df(data: Any) - Any: if isinstance(data, str): return ( pd.read_csv( StringIO(data), # Get rid of whitespaces sep|, index_col1, ) .dropna(axis1, howall) .iloc[1:] .map(lambda x: x.strip()) ) # type: ignore return data MarkdownDataFrame Annotated[ InstanceOf[pd.DataFrame], BeforeValidator(md_to_df), PlainSerializer(lambda x: x.to_markdown()), WithJsonSchema( { type: string, description: The markdown representation of the table, each one should be tidy, do not try to join tables that should be separate, } ), ]这个类型通过四个 Pydantic 注解组件协同工作每一个都有明确的职责组件作用InstanceOf[pd.DataFrame]声明该字段最终必须是 pandas DataFrame 实例作为校验的最终目标类型BeforeValidator(md_to_df)在校验之前执行转换函数把模型输出的 Markdown 字符串解析成 DataFramePlainSerializer(lambda x: x.to_markdown())反向序列化当把对象编码回 JSON / API 请求时将 DataFrame 重新渲染为 Markdown 字符串WithJsonSchema({...})为模型生成 JSON Schema 提示告诉模型这是一个 Markdown 表格字符串每个表格应保持整洁不要强行合并本应分开的表格从源码看这种校验前转换 序列化的编排正是 Instructor 响应模型处理的核心机制之一Instructor 接收模型返回的原始文本后会依据 Pydantic 模型的定义执行字段级校验与类型转换相关逻辑可见 instructor/processing/response.py 与 instructor/processing/schema.py。BeforeValidator让字符串到 DataFrame 的转换发生在任何严格校验之前因此模型即使输出格式稍有偏差也能被宽容地清洗。md_to_df 解析管线拆解md_to_df是整条管线的关键它对一段典型的 Markdown 表格文本执行如下操作StringIO(data)把字符串包装成文件对象供pd.read_csv读取sep|按竖线分隔符切分 Markdown 表格的列Markdown 表格即管道表index_col1把第二列作为索引——因为首列通常是空的分隔占位列.dropna(axis1, howall)丢弃整列为空的分隔线列如---所在列.iloc[1:]跳过表头下方的分隔行| --- | --- |.map(lambda x: x.strip())去除每个单元格两侧的空白字符。最终得到一份干净、索引正确的 DataFrame。非字符串输入如已经是 DataFrame则原样返回保证类型转换的幂等性。定义 Table 与 MultipleTables 响应模型由于大部分复杂度已被MarkdownDataFrame类型吸收业务模型本身非常简洁class Table(BaseModel): caption: str dataframe: MarkdownDataFrame class MultipleTables(BaseModel): tables: List[Table]Table包含一个标题caption和一个 Markdown 表格数据框dataframeMultipleTables用于承接一张图片中可能包含的多张表格每张表格独立成一条记录避免模型把本应分开的表格强行拼接。这一点与WithJsonSchema中的描述each one should be tidy, do not try to join tables that should be separate相互呼应从提示层面约束模型保持表格边界清晰。我们可以先构造一个本地示例来验证类型的双向转换是否正常example MultipleTables( tables[ Table( captionThis is a caption, dataframepd.DataFrame( { Chart A: [10, 40], Chart B: [20, 50], Chart C: [30, 60], } ), ) ] )由于PlainSerializer的存在这个对象在需要发送给 API 时会把 DataFrame 自动序列化为 Markdown 字符串。构造多模态提取函数接下来定义extract函数把图片 URL 与指令文本一起通过多模态消息发送给视觉模型def extract(url: str) - MultipleTables: return client.create( modelgpt-5.4-mini, max_tokens4000, response_modelMultipleTables, messages[ { role: user, content: [ { type: image_url, image_url: {url: url}, }, { type: text, text: First, analyze the image to determine the most appropriate headers for the tables. Generate a descriptive h1 for the overall image, followed by a brief summary of the data it contains. For each identified table, create an informative h2 title and a concise description of its contents. Finally, output the markdown representation of each table. Make sure to escape the markdown table properly, and make sure to include the caption and the dataframe. including escaping all the newlines and quotes. Only return a markdown table in dataframe, nothing else. , }, ], } ], )关键点说明消息内容为列表content按顺序包含image_url与text两种类型的消息块这是 OpenAI 视觉接口的标准多模态格式提示词引导结构指令明确要求模型先确定表头、生成整体h1摘要再为每张表生成h2标题与说明最后输出 Markdown 表格且只输出表格的 markdown 表示不附带其他内容并提醒转义换行与引号max_tokens4000表格通常较长预留充足 token 防止输出被截断response_modelMultipleTablesInstructor 据此构建工具/模式并将模型原始输出校验并转换为MultipleTables对象。需要注意的是主文档示例使用instructor.from_provider(openai/gpt-4o, modeinstructor.Mode.TOOLS)初始化客户端而 examples/vision/run_table.py 中针对视觉模型使用instructor.from_openai(OpenAI(), modeinstructor.Mode.MD_JSON)MD_JSON 模式。可以推断当视觉模型不支持原生工具调用function calling时MD_JSON 模式是更稳妥的选择——它通过强约束 JSON 格式解析 Markdown 包裹的 JSON 输出来实现结构化而 TOOLS 模式则依赖模型的工具调用能力。实际使用时请根据所选模型的 API 能力在 docs/concepts/mode-migration.md 与 docs/modes-comparison.md 中确认对应模式的支持情况。批量运行与结果展示对多张图片批量调用extract并借助rich的Console美化输出urls [ https://a.storyblok.com/f/47007/2400x1260/f816b031cb/uk-ireland-in-three-charts_chart_a.png/m/2880x0, https://a.storyblok.com/f/47007/2400x2000/bf383abc3c/231031_uk-ireland-in-three-charts_table_v01_b.png/m/2880x0, ] for url in urls: for table in extract(url).tables: console.print(table.caption, \n, table.dataframe)MultipleTables.tables是List[Table]因此可以直接嵌套遍历逐张打印每张表的标题与 DataFrame。examples/vision/run_table.py 中展示了同一思路的完整运行结果示例数据来自公开图片示例非仓库生成数据模型从一张包含 iOS / Android 双平台榜单的截图中识别出两张独立表格并输出如下形式的 DataFrameRankApp NameCategory1Google OneProductivity2DisneyEntertainment3TikTok - Videos, Music LIVEEntertainment.........注意在 examples/vision/run_table.py 中还使用了client.chat.completions.create_iterable(response_modelTable)的迭代形式每次产出单个Table对象——与主文档的MultipleTables批量形式形成两种等价的组织方式读者可按需选择。深入Instructor 的多模态辅助能力主文档直接使用了 OpenAI 原生image_url消息块。若希望代码更简洁、跨提供商OpenAI / Anthropic / Gemini 等可移植Instructor 还提供了统一的多模态对象详见 docs/concepts/multimodal.mdimport instructor from instructor.processing.multimodal import Image from pydantic import BaseModel class ImageDescription(BaseModel): description: str items: list[str] client instructor.from_provider(openai/gpt-4.1-mini) response client.create( response_modelImageDescription, messages[ { role: user, content: [ What is in this image?, Image.from_url(url), ], } ], )Image类支持from_url()、from_gs_url()、from_path()、from_base64()与autodetect()五种构造方式底层会自动把图片转换为 base64 并拼装为提供商要求的消息格式。查看 instructor/v2/core/multimodal.py 的Image实现可以看到from_url()通过 URL 后缀推断 MIME 类型失败时回退到远程探测from_path()读取本地文件并编码为 base64autodetect()依次判断 base64 前缀、http(s)://、gs://、本地路径最终回退到原始 base64 解析实现给什么都能认的智能检测。如果希望把 URL / 路径直接作为普通字符串传入消息无需手动包装可以在create时开启autodetect_imagesTrueInstructor 会自动识别并转换图片、音频与 PDF 等媒体类型对应源码中的autodetect_media函数。这样本文的多模态消息甚至可以简化为client.create( response_modelMultipleTables, autodetect_imagesTrue, messages[ { role: user, content: [ Extract the tables from this image as markdown:, url, ], } ], )这对于从图片列表批量提取表格如报告截图、票据、排行榜的场景尤为实用。完整代码清单将上述片段合并即可得到一个自洽可运行的完整示例与 examples/vision/run_table.py 同源并扩展为多表格版本from io import StringIO from typing import Annotated, Any, List from pydantic import ( BaseModel, BeforeValidator, PlainSerializer, InstanceOf, WithJsonSchema, ) import instructor import pandas as pd from rich.console import Console console Console() client instructor.from_provider(openai/gpt-4o, modeinstructor.Mode.TOOLS) def md_to_df(data: Any) - Any: if isinstance(data, str): return ( pd.read_csv( StringIO(data), # Get rid of whitespaces sep|, index_col1, ) .dropna(axis1, howall) .iloc[1:] .map(lambda x: x.strip()) ) # type: ignore return data MarkdownDataFrame Annotated[ InstanceOf[pd.DataFrame], BeforeValidator(md_to_df), PlainSerializer(lambda x: x.to_markdown()), WithJsonSchema( { type: string, description: The markdown representation of the table, each one should be tidy, do not try to join tables that should be separate, } ), ] class Table(BaseModel): caption: str dataframe: MarkdownDataFrame class MultipleTables(BaseModel): tables: List[Table] def extract(url: str) - MultipleTables: return client.create( modelgpt-5.4-mini, max_tokens4000, response_modelMultipleTables, messages[ { role: user, content: [ {type: image_url, image_url: {url: url}}, { type: text, text: First, analyze the image to determine the most appropriate headers for the tables. Generate a descriptive h1 for the overall image, followed by a brief summary of the data it contains. For each identified table, create an informative h2 title and a concise description of its contents. Finally, output the markdown representation of each table. Make sure to escape the markdown table properly, and make sure to include the caption and the dataframe. including escaping all the newlines and quotes. Only return a markdown table in dataframe, nothing else. , }, ], } ], ) urls [ https://a.storyblok.com/f/47007/2400x1260/f816b031cb/uk-ireland-in-three-charts_chart_a.png/m/2880x0, https://a.storyblok.com/f/47007/2400x2000/bf383abc3c/231031_uk-ireland-in-three-charts_table_v01_b.png/m/2880x0, ] for url in urls: for table in extract(url).tables: console.print(table.caption, \n, table.dataframe)常见问题与调优建议输出被截断导致解析失败表格行数多或 token 不足时模型输出可能不完整。可将max_tokens调大如 4000或拆分为每次只提取一张表格参考 examples/vision/run_table.py 的create_iterable方式。模型返回纯文本而非严格 JSON选择支持的工具调用模式Mode.TOOLS或改用Mode.MD_JSON后者对纯文本模型更宽容。多张表被错误合并在WithJsonSchema描述与系统提示中反复强调不要合并本应分开的表格并尽量为每张表提供独立标题。本地图片image_url的url字段支持data:image/jpeg;base64,...形式的 base64 URI参考 examples/vision/run.py 中encode_image的用法也可借助Image.from_path()统一处理。延伸阅读docs/examples/extracting_tables.md使用Iterable[Table]与 MD_JSON 模式的进阶表格提取方案docs/concepts/multimodal.mdImage/Audio/PDF多模态对象的统一接口docs/examples/multi_modal_gemini.md使用 Gemini 完成视觉任务docs/examples/index.md更多视觉处理与表格提取示例的索引docs/concepts/validation.md 与 docs/concepts/reask_validation.md响应校验与自动重试机制可作为提升提取准确率的进阶手段。【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表