拓冰建站拓冰建站
首页 / 资讯中心 / 正文

10.4 基于扣子编程的实现过程(AI数据采集工作流)

叶彦辛《扣子编程从一句话到产品上线零门槛AI心流开发》全书案例分享~_扣子编程从一句话到产品上线:零门槛ai心流开发-CSDN博客10.4.1扣子编程对扫描型PDF工作流的支持从第 9 章到第 10 章扣子编程的工作流编排能力中再次新增了几项关键能力。具体而言开始节点的 File 类型字段现在原生支持 PDF 格式校验与页数预读运行时提供了循环子图loop_graph的标准模板使得“在主图中以普通节点调用子图来表达循环”成为多页 PDF 处理的标准范式代码工具节点新增了 PyMuPDFfitz、pillow、pypdf 等常用依赖的预装支持对象存储的 multipart 上传接口允许把生成的 CSV 直接以签名 URL 形式返回不需要工程师自行处理分片上传。这四项能力的组合使得本章的七节点工作流可以用相对优雅的代码完整描述。本节笔者将沿着开发时间线依次介绍各个节点的实现细节并展示扣子编程在数据采集场景下的工程化能力。10.4.2集成识别与选用在接到本项目的需求描述后扣子编程的第一动作仍然是查询集成文档。这一次它并行查询了4个集成PDF 解析集成PyMuPDF、多模态视觉模型集成含 OCR 能力的 vision 模型、大语言模型集成含结构化输出能力的 Pro 与 Lite 模型、对象存储集成。如图 10-3 所示。图 10-3 四个集成构建页面查询结果识别出四项关键事实第一PDF 解析集成提供了基于 PyMuPDF 的页面切分能力可以把任意 PDF 一次性转为单页 PNG 图像列表dpi 可调本项目实测 300dpi 在精度与文件大小之间最为均衡第二多模态视觉模型集成在搭建过程中曾首选 doubao-seed-1-6-vision-250815但在试运行环节发现该模型已停运并提示“当前使用模型已停运请切换至其他在线模型”最终切换至支持多模态理解的 doubao-seed-1-8-251228官方描述为“全新面向多模态 Agent 场景定向优化模型更强 Agent 能力、升级多模态理解”第三大语言模型集成中结构化 JSON 输出能力较强的 doubao-seed-2-0-pro-260215 适用于字段语义锚定与深度交叉校验这类复杂推理任务而较轻量的 doubao-seed-2-0-lite-260215 适用于异常标注这类相对简单的判断任务第四对象存储集成的 multipart 上传接口可以接收 in-memory bytes 并直接返回签名 URL无须中间落盘。基于这四项识别扣子编程为本章工作流绘制了如表 10-3 所示的集成-节点映射表。表 10-3 集成-节点能力映射节点名称使用集成推荐模型 / 接口关键作用页面切分pdf_splitPDF 解析PyMuPDFfitz.openpage.get_pixmap(dpi300)把 PDF 拆为 PNG 图像列表OCR 识别ocr_loop循环子图多模态视觉模型doubao-seed-1-8-251228逐页 OCR 文本提取表格区域定位table_locate代码工具规则筛选Python 过滤分组筛选含财务表格的页字段语义锚定field_anchor大语言模型doubao-seed-2-0-pro-260215会计科目 → Schema 字段映射数值校验value_validate代码工具大语言模型numpydoubao-seed-2-0-pro-260215勾稽关系与深度交叉校验异常标注anomaly_mark规则引擎大语言模型Pythondoubao-seed-2-0-lite-260215字段级置信度打分CSV 输出csv_output代码工具对象存储csvutf-8-sig对象存储组装 CSV 并签名 URL从这张表可以看出本章工作流之所以能在七个节点之间稳定协作依然依赖第 9 章经验四中提出的“节点级精细化模型选型”原则。OCR 节点用专门的多模态视觉模型字段语义锚定与数值校验中的深度交叉验证都用 Pro 级 LLM异常标注则用更轻量的 Lite 级 LLM而表格区域定位与 CSV 输出这类纯确定性逻辑则直接使用代码工具不调用任何模型。这种“任务复杂度决定模型档位”的选型策略可以在不损失质量的前提下显著降低整体成本与延迟。10.4.3节点1开始节点与字段约束开始节点定义了整个工作流的输入接口。本项目共定义两个输入字段scanned_pdf扫描型 PDF 文件File 类型必填target_schema目标字段定义JSON 类型可选默认采用 10.3.1 节列出的 19 个字段。两个字段中只有 scanned_pdf 是必填其他为可选并提供合理默认值。这种“最小必填完整默认值”的设计延续了第 9 章的用户友好原则——普通用户只需上传一个 PDF 就能跑通工作流而高级用户可以通过 target_schema 自定义字段列表例如银行用户可能只关心营收、净利润、ROE 三项可以传入精简后的 Schema。此外开始节点对 scanned_pdf 字段做了一项关键校验文件类型必须为 application/pdf。这一校验由集成层面提供无须开发者手写。10.4.4节点2页面切分节点pdf_split页面切分节点是 OCR 之前的关键准备步骤。它使用 PyMuPDFfitz打开 PDF并对每一页调用 page.get_pixmap(dpi300) 渲染为 PNG 图像。dpi 设为 300是经过实测的“识别精度与文件大小”平衡点——dpi 150 会在小字号字段如表注、单位声明上明显丢精度dpi 200 在部分小字号上仍有边界识别困难dpi 300 则能让多模态视觉模型对绝大多数中文小字号给出稳定识别且单页 PNG 大小一般在 1 MB 以内对下游模型上传与 token 消耗都在可接受范围。节点的核心代码片段如下。注意其中的两个工程细节第一每幅图像在上传到对象存储后立即获得一个签名 URL方便下游 OCR 节点以 URL 方式调用而无需重复传输二进制第二节点输出的 page_images 字段是一个 List[str]每个 URL 按页号顺序排列方便下游循环子图按页号迭代。def pdf_split_node(state, config, runtime) - PdfSplitOutput:页面切分节点把扫描型PDF拆为单页图像并上传。pdf_bytes download_file(state.scanned_pdf.url)doc fitz.open(streampdf_bytes, filetypepdf)s3 ObjectStorage(ctxruntime.context, bucketocr-pages)page_images []for i, page in enumerate(doc, start1):pix page.get_pixmap(dpi300)png_bytes pix.tobytes(png)url s3.upload_bytes(png_bytes, keyfpage_{i:03d}.png)page_images.append(url)return PdfSplitOutput(page_imagespage_images,total_pageslen(page_images))页面切分节点是一个 IO 密集型的预处理节点。在本章的实测中一份测试 PDF 的整体切分耗时为 19.9 秒主要由 PDF 解码、300dpi 栅格化与图像上传三段组成。10.4.5节点3OCR 识别节点ocr_loop循环子图OCR 识别节点是整条工作流的“眼睛”。它在主图中表现为一个普通节点 ocr_loop但内部通过子图loop_graph对页面图像列表逐页迭代调用多模态视觉模型。子图中只有一个节点 ocr_single_page_node负责对单页图像执行 OCRocr_loop 节点本身则负责“取出 page_images → 逐张调用子图 → 汇总结果”这一编排逻辑。这种“主图普通节点循环子图”的实现方式是扣子编程对循环约束“严禁在主图创建闭环循环必须实现为子图”的标准应对。节点的关键工程细节有三点。第一是系统提示词的精细化设计。提示词显式要求模型“请逐字逐行 OCR 当前页面保留原始版面结构识别所有数字、文字与表格。表格请以结构化形式输出保留行列对应关系。对识别不清的字段用 [UNCLEAR] 标记不要猜测。”这段提示词的关键是 [UNCLEAR] 标记——它给模型一个“诚实地表达不确定性”的出口避免模型对模糊字段做猜测。第二是输入消息的多模态构造。模型的 user message 包含两个 content part一个 image_url指向页面图像的签名 URL一个 text含 OCR 任务指令。这种多模态消息格式是本章相对于第 9 章产品解码节点的延续。第三是输出格式的严格约束。子图中的单页 OCR 节点要求模型输出固定的 JSON 结构{page_index, ocr_text, tables: [{rows, table_type}], low_confidence_zones: [...]}。其中 table_type 字段会预分类页面所属的报表类型利润表资产负债表现金流量表其他为下游 table_locate 节点的过滤提供索引low_confidence_zones 字段则记录了 OCR 自评中识别困难的区域下游的异常标注节点会引用它。由于子图采用顺序迭代而非并发调用整体耗时与页数线性相关。在本章实测中一份测试 PDF 的 ocr_loop 节点总耗时约 4.2 分钟约 252 秒是整条工作流耗时占比最高的环节。这一现象提示我们在更大规模的工作流场景中如批量处理 20 份财报把循环子图升级为并发调度multipart parallel将成为性能优化的主要方向详见 10.6.3 节扩展方向。10.4.6节点4表格区域定位节点table_locate表格区域定位节点的任务是从 N 页 OCR 结果中筛选出“哪几页含有财务表格”。这一步看似多余OCR 已经识别了所有内容实则关键——一份完整的年度报告通常有 100 多页其中真正含有核心财务数据的页面只有 5~10 页。table_locate 节点充当了一个“过滤器”把不相关的页面如董事会致辞、公司治理结构、审计意见等过滤掉只保留三张核心表所在的页面从而显著减少下游字段语义锚定节点的 token 消耗。值得说明的是table_locate 节点最初的设计预期是再次调用多模态视觉模型进行二次分类。但在实际实现中由于上游 ocr_single_page_node 在 OCR 同时已经给出了每一页的 table_type 字段利润表资产负债表现金流量表/其他table_locate 节点的工作就退化为一次轻量的“过滤分组”——按 table_type 字段筛选出含财务表格的页面再按报表类型分组合并相同类型的跨页文本。这一退化让节点完全由 Python 代码实现不再需要模型调用。在本章实测中table_locate 节点的耗时仅为 5 毫秒是7个节点中耗时最低的一个。这一退化也带来一个重要启示节点设计阶段的“想象能力”与实现阶段的“实际能力”经常出现错位。当上游节点已经携带了下游所需的元信息时下游节点的实现可以大胆退化为轻量代码而不必强行调用一次大模型。这与第 9 章经验四“节点级精细化模型选型”在思想上一脉相承——并非所有节点都需要大模型。10.4.7节点5字段语义锚定节点field_anchor字段语义锚定节点是整条工作流的“翻译官”。它接收上游 table_locate 节点输出的财务表格页 OCR 文本并按目标 Schema 逐字段做语义对齐输出每个会计期间的提取记录列表注意年度报告往往同时披露本期与上期数据因此该节点的输出通常是 2 条记录而非 1 条。这一节点的工程价值恰恰是传统模板匹配方案最薄弱的环节——同一指标在不同公司、不同年份的表述差异极大模板匹配难以覆盖所有变种而大语言模型基于语义理解可以一举突破这一瓶颈。节点采用 doubao-seed-2-0-pro-260215 作为主模型并通过外部 JSON 配置文件field_anchor_llm_cfg.json下发系统提示词避免硬编码。系统提示词的关键段落如下#角色定义你是财务数据提取工作流中的字段语义锚定专家代理,专注于上市公司年度报告财务数据的结构化提取与科目映射。#任务目标从OCR识别的财务报表文本中,将会计科目按目标schema进行精准映射,处理同义词、简称、单位换算与中文数字转换。#工作流上下文- Input:OCR识别的财务报表文本(可能包含利润表、资产负债表、现金流量表),以及目标CSV字段schema定义- Process:1.解析OCR文本,识别所有会计期间(如2025年度、2024年度、本期金额、上期金额等)2.对每个报告期,逐字段在OCR文本中查找对应数值3.处理同义词与简称映射(如归母净利润→归属于上市公司股东的净利润)4.进行单位换算:万元→元(×10000)、千元→元(×1000)、百万元→元(×1000000)5.识别中文大写数字并转换为阿拉伯数字(壹/贰/叁/肆/伍/陆/柒/捌/玖/拾/佰/仟/万/亿)6.跨页表格已合并,不要重复计算- Output:JSON数组,每个元素对应一个报告期的结构化记录#约束与规则-严禁编造任何数字:OCR文本中未出现的字段必须设为null-所有金额字段统一换算为元为单位,并在unit字段声明-中文数字必须转换(如壹亿贰仟万元→120000000)-千分位逗号应去除(如1,000,000→1000000)-毛利率、研发投入占比、资产负债率等百分比字段保留原始数值(如30.5表示30.5%)-每股收益字段单位为元/股-除JSON外不要输出任何Markdown文本这种“逐字段提示同义词列表中文数字转换规则单位换算细则”的多段式系统提示词模式是本章相对于第 9 章文案生成节点的关键差异。文案生成需要模型发挥创造力因此提示词偏开放式而字段语义锚定需要模型精确匹配因此提示词必须把“什么算正确答案”“什么算错误答案”完整列出给模型最小的发挥空间。10.4.8节点6数值校验节点value_validate数值校验节点是本章相对于第 9 章工作流最重要的工程创新之一。它接收上游字段语义锚定节点的提取结果一个或多个会计期间的记录列表对每一组可校验的勾稽关系做反向验证输出每条记录的校验结果passwarnfail与差异度量。节点采用“代码工具大语言模型”的混合实现。代码工具部分负责可形式化的勾稽关系检查def numeric_validation(extracted: Dict) - List[ValidationResult]:检查关键勾稽关系。results []#关系1: 资产合计 负债合计 所有者权益合计if all(k in extracted for k in[total_assets, total_liabilities, equity_attr]):lhs extracted[total_assets]rhs extracted[total_liabilities] extracted[equity_attr]diff_pct abs(lhs - rhs) / max(lhs, 1) * 100results.append(ValidationResult(rulebalance_sheet_equation,statuspass if diff_pct 0.5 else fail,diff_pctdiff_pct,))# 关系2: 毛利率 (营收 - 营业成本) / 营收 * 100if all(k in extracted for k in[revenue, operating_cost, gross_margin_pct]):calc (extracted[revenue] -extracted[operating_cost]) / extracted[revenue] * 100recorded extracted[gross_margin_pct]diff_pp abs(calc - recorded)results.append(ValidationResult(rulegross_margin_back_calc,statuspass if diff_pp 0.3 else warn,diff_ppdiff_pp,))#关系3-5: 类似的,对 ROE、资产负债率、研发投入占比做反算# ...return results代码工具检查完之后剩下需要“语义判断”的部分交给 doubao-seed-2-0-pro-260215 这款大语言模型例如营业利润与净利润的逻辑一致性、EPS 与净利润/股本的对应关系、经营现金流与净利润的匹配度、各项费用占营收比例的合理性、以及不同期间的同比变化是否合理。两层校验合起来构成了完整的数值校验闭环。在本章实测中该节点总耗时约 3.1 秒其中代码部分毫秒级、LLM 部分占绝大多数。10.4.9节点7异常标注节点anomaly_mark异常标注节点是数据采集工作流相对于内容生成工作流最独特的节点之一。它接收上游字段提取结果与数值校验结果对每一个字段打一个 0 至 1 的置信度并对整条记录决定 needs_review 的最终取值。字段级置信度的计算综合三类信号。第一是 OCR 自评信号——OCR 节点输出的 low_confidence_zones 涉及的字段置信度起始值减 0.2。第二是字段填充率信号——锚定节点本身会为每条记录返回 extraction_confidence 初值按字段填充率计算缺失字段越多置信度越低。第三是数值校验信号——校验失败的字段置信度减 0.3校验告警的字段置信度减 0.1。最终任何字段的置信度若低于 0.7则该字段进入待复核清单整条记录只要包含一个待复核字段needs_review 就置为 Y。值得指出的是本节点的规则计算部分由 Python 代码完成速度快、零幻觉但在置信度微调与补充复核原因发现方面仍调用 doubao-seed-2-0-lite-260215 这款轻量级大语言模型做最后一道“语义复核”——例如结合行业常识判断毛利率、ROE 等指标的合理性。规则与轻量 LLM 的互补使置信度打分既稳定又有判断力。在本章实测中该节点总耗时约 3.3 秒。10.4.10节点8CSV 输出节点csv_outputCSV 输出节点是工作流的出口。它接收上游所有节点的最终结果按目标 Schema 组装 CSV 文件并上传到对象存储。节点的关键工程细节有四点第一文件编码必须为 UTF-8 with BOMutf-8-sig。这一约束源于中文 Excel 的兼容性需求——如果没有 BOM 头Excel 打开中文 CSV 会显示乱码。需要特别注意的是在 Python 中使用 io.StringIO 写入时既不要手动调用 output.write(\ufeff)也不要重复使用 encode(utf-8-sig)二者只能取一。本章在第一次试运行时就因为两者同时存在导致了“双重 BOM”问题输出中文显示为“年度”等乱码定位并修复后中文显示恢复正常。第二数值字段统一保留两位小数字符串字段保留原值空值字段输出为空字符串。这一格式约束保证下游数据库的字段类型校验不会失败。第三CSV 的列顺序严格遵守 target_schema 中的字段顺序。这一约束保证下游 ETL 脚本可以基于固定列序解析不必依赖列名。第四除了 cleaned.csv实际命名为 extracted_financial_data_hash.csv之外节点还会同步生成两个附产物——extraction_summary自然语言摘要文本与 review_items待复核字段的结构化清单。三者共同满足提示词中“三者一次性返回”的输出契约。该节点在本章实测中总耗时约 5.9 秒。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门