11.4 基于扣子编程的实现过程(AI 数据质检工作流)

叶彦辛《扣子编程从一句话到产品上线:零门槛AI心流开发》全书案例分享~_扣子编程从一句话到产品上线:零门槛ai心流开发-CSDN博客

11.4.1 扣子编程对多源数据治理的支持

从第 10 章到第 11 章,扣子编程的工作流编排能力中再次新增了几项关键能力。具体而言:开始节点的 File 列表字段(ListFile)现在原生支持文件 schema 一致性预校验(如果多个 CSV 的列名不一致,会在节点入口就报错);代码工具节点新增了 pandas、difflib、numpy 等数据处理常用依赖的预装;运行时为大语言模型节点提供了"批量字段处理"模式(一次调用处理多个字段冲突的判定,显著降低 token 单位成本);对象存储集成新增了 zip 打包接口,可以一次性把多个文件压缩为一个签名 URL。

这四项能力的组合,使得本章的八节点工作流可以用相对优雅的代码完整描述。本节将沿着开发时间线,依次介绍各个节点的实现细节,并展示扣子编程在数据治理场景下的工程化能力。

11.4.2 集成识别与选用

在接到指令后,扣子编程的第一动作仍然是查询集成文档。这一次它并行查询了四个集成:pandas 数据处理集成、Python 标准库 difflib 模糊匹配模块、大语言模型集成、对象存储集成(含 zip 打包能力)。查询结果识别出四项关键事实:第一,pandas 集成提供了 read_csv 工具,可以读入 CSV文件 并通过 dtype 参数显式保留 stock_code 等带前导零字段的字符串语义;第二,Python 标准库的 difflib.SequenceMatcher 接口能够稳健地处理"创联智能"与"创联智能科技股份有限公司"这类公司名变体,无需额外安装第三方包;第三,大语言模型集成推荐使用 doubao-seed-2-0-pro-260215 作为仲裁与异常识别的主模型,doubao-seed-2-0-lite-260215 作为审计报告生成等轻量任务模型;第四,对象存储集成的 zip 上传接口,允许把多个本地文件一次性打包上传并返回签名 URL。

基于这四项识别,扣子编程为本章工作流绘制了如表 11-3 所示的集成-节点映射表。

11-3 集成 - 节点能力映射

|----------|--------------------|-------------------------------------|------------------------------|
| 节点名称 | 使用集成 | 推荐模型 / 接口 | 关键作用 |
| 数据加载 | pandas | read_csv(dtype={'stock_code':str}) | 把多 CSV 合并为单 DataFrame 并保留前导零 |
| 主键对齐 | pandas+difflib+LLM | SequenceMatcher+doubao-seed-2-0-pro | 按主键聚合+公司名归一 |
| 字段级冲突检测 | pandas+numpy | groupby+CV+Jaccard | 计算每个(主键,字段)的离散度 |
| 异常值检测 | 大语言模型 | doubao-seed-2-0-pro-260215 | 识别脏数据模式 |
| 仲裁规则应用 | 代码工具+LLM | Python 规则引擎+LLM 兜底 | 产出可信值 |
| 数值勾稽校验 | 代码工具 | pandas+numpy | 勾稽与范围校验 |
| 审计报告生成 | 大语言模型 | doubao-seed-2-0-lite-260215 | 生成自然语言审计报告 |
| 输出打包 | 对象存储 | zip+签名 URL | 三文件打包并签名 URL |

从这张表可以看出,本章工作流的节点分工延续了第 10 章经验四"节点级精细化模型选型"的原则。代码工具承担确定性逻辑(数据加载、冲突检测、数值勾稽校验),大语言模型承担语义判断(异常值识别、仲裁兜底、审计报告生成)。两类节点合作,构成了高效又稳健的混合流水线。值得一提的是,模糊匹配选用 Python 标准库 difflib 而非更知名的第三方包(如 fuzzywuzzy),背后的考量是工程稳定性------标准库自带,无版本冲突风险,对公司名这类短文本的相似度来说计算精度已足够。

11.4.3 节点 1 :开始节点与字段约束

开始节点定义了整个工作流的输入接口。本项目共定义三个输入字段:source_csvs(ListFile,多个 CSV 文件,至少 2 个);source_metadata(ListJSON,每个源的名称与可信度先验,可选,默认所有源同等权重);arbitration_strategy(仲裁策略名称,可选,默认 hybrid 即五条规则按优先级降级,也支持 majority_only 与 authoritative_only 两种简化策略)。三个字段中只有 source_csvs 是必填,其他为可选并提供合理默认值。

开始节点对 source_csvs 字段做了一项关键校验:所有 CSV 的列名集合必须完全一致,且至少包含 stock_code 这一主键列。若任何一个 CSV 不满足约束,则工作流在入口处直接报错,不进入下游。这种"早失败"设计避免了下游节点收到不规范输入后产生难以诊断的错误。

11.4.4 节点 2 :数据加载节点

数据加载节点是工作流的入口数据准备步骤。它使用 pandas 集成的 read_csv 工具,把多个 CSV 文件读入一个统一的 DataFrame,并自动添加一列 _source_name 记录每行来自哪个源。这一元列是下游所有节点判断"这个值是哪个源给的"的依据。

节点的核心代码片段如下:
def load_data_node(state, config, runtime) -> LoadDataOutput:

"""数据加载节点:把多个CSV读入统一DataFrame。"""

dfs = \[\]

for i, csv_file in enumerate(state.source_csvs):

source_name = state.source_metadatai"name"

df = pd.read_csv(

csv_file.path, encoding="utf-8-sig",

dtype={"stock_code": str}, # 关键:保留000858等前导零

)

df"_source_name" = source_name

dfs.append(df)

merged = pd.concat(dfs, ignore_index=True)

return LoadDataOutput(

merged_df=merged.to_dict("records"),

total_rows=len(merged),

source_count=len(dfs),

)

值得指出的是,节点输出的 merged_df 字段类型是 ListDict,而非 pandas DataFrame。这一选择源自工程现实------扣子编程的节点间数据传递采用 JSON 序列化,DataFrame 无法直接传递。把 DataFrame 序列化为字典列表,是工作流中常见的处理方式。另外,dtype={"stock_code": str} 这一参数看似不起眼,却避免了 pandas 把 000858 这类纯数字字符串自动转为整数 858 的隐性陷阱------这正是扣子编程在调试过程中识别并修复的一个工程细节,后文 11.5 节会再次提到。

11.4.5 节点 3 :主键对齐节点

主键对齐节点的任务是:把多源数据按 stock_code 主键对齐,并为同一公司的不同公司名(如简称与全称)做归一化处理。节点采用"代码工具+大语言模型"的混合实现。代码工具部分负责按 stock_code 聚合(pandas groupby);当聚合时发现同一主键下的公司名不一致(例如"创联智能"与"创联智能科技股份有限公司"),调用 difflib.SequenceMatcher 计算相似度,相似度≥0.85 的视为同一公司、统一归一为"创联智能科技股份有限公司"(采用最长版本作为权威名)。

对于模糊匹配仍然无法判定的边界情形,节点调用大语言模型做最后裁决------例如"宁德时代新能源"与"宁德时代",前者的"新能源"后缀可能是公司全称的一部分,也可能是另一家完全不同的公司。LLM 会基于公司名的语义、所在行业、上下文一致性做综合判断。这种"代码先行+LLM 兜底"的混合策略,既保证了大多数对齐操作的速度(毫秒级),又保留了对长尾边界情况的应对能力。

11.4.6 节点 4 :字段级冲突检测节点

字段级冲突检测节点是仲裁的"侦察兵"。它接收对齐后的数据,对每一个 (主键, 字段) 组合,计算多源值的离散度。具体而言,对数值字段(revenue_2024_yi、net_profit_2024_yi、roe_2024_pct 等)计算变异系数(即 CV=标准差/均值的绝对值);对文本字段(company_name、industry)计算 Jaccard 相似度(字符级 unigram 或 token 级);对日期字段(report_date)计算最大间隔天数。

节点的输出是一个 conflicts 列表,每一项形如:{stock_code, field_name, source_values: List, source_names: List, dispersion_metric, dispersion_value}。这份冲突明细既是下游仲裁节点的输入,也是最终 conflicts.csv 的核心数据来源。

值得强调的是,冲突检测节点并不做任何"决策"------它只是诚实地报告"哪些字段存在多源不一致",把"如何处理这些不一致"的决策权交给下游的仲裁节点。这种"检测与决策分离"的设计是数据治理工程的最佳实践,能让两个节点各自独立测试与迭代。在试运行中,该节点的执行耗时仅 6 毫秒,体现了纯确定性代码逻辑相对于大语言模型调用的速度优势。如图11-3所示。

11-3 冲突检测节点试运行页面

11.4.7 节点 5 :异常值检测节点

异常值检测节点的任务是:在冲突字段中进一步识别"哪些值看起来明显错误",而非仅仅"哪些值不一致"。例如,某公司的"2024 年营业收入"在三个源里都是 3 291.4 亿元,在第四个源里是 32 914 亿元------这不是简单的"不一致",而是明显的"单位错位(万元当亿元)"录入错误。区分"不一致"与"明显错误",是高质量数据治理的关键。

节点采用大语言模型实现,主模型为 doubao-seed-2-0-pro-260215。系统提示词中给出几类常见脏数据模式的识别启发:
请检查以下字段在多源间的差异,识别是否存在脏数据模式:

  1. 负号丢失:若某源值等于其他源值的绝对值,符号相反,

则该源很可能是负号录入丢失

  1. 小数点错位:若某源值=其他源值的10/100/1000倍,

则可能是小数点位置错位

  1. 单位错误:若某源值=其他源值的10000倍,

且字段名含"yi"(亿元)单位,可能是该源用了"万元"单位

  1. 口径差异:若某源值显著高于其他源,

且字段为employees(员工数),可能是该源含临时工

  1. 数据延迟:若某源的report_date明显早于其他源,

且当期值与往期值更接近,则该源数据可能未更新

请对每个冲突字段输出:

{

"stock_code": "xxx",

"field_name": "xxx",

"pattern_detected": "<上述模式之一或 normal_variation>",

"suspect_source": "<疑似出错的源名>",

"explanation": "<自然语言说明>"

}

与传统硬编码规则相比,大语言模型在异常值识别上的优势是显著的:第一,模型可以基于语义判断"为什么这个值看起来错了",而不是机械地比较数字;第二,对于规则覆盖不到的长尾模式(如某些口径差异),模型可以基于会计常识做合理推断;第三,模型的输出本身就带有可解释的自然语言说明,方便审计报告节点直接引用。

在本章测试数据上,节点准确识别出了若干脏数据:财经新闻源对招商银行(600036)的营业收入字段使用了百万元单位(32 914),与其他源(3 291.4 亿元)的数值形成 10 倍差异;卖方一致预期对部分公司归母净利润的负号丢失;某些公司员工数包含临时工的口径差异。

11.4.8 节点 6 :仲裁规则应用节点

仲裁规则应用节点是工作流的"法官"。它接收字段级冲突检测节点的离散度信息与异常值检测节点的脏数据模式识别结果,按照预设的五条规则(majority_vote、authoritative_source、latest_filing、weighted_median、manual_review)依次尝试,为每个冲突字段产出一个可信值与决策依据。节点采用"代码规则引擎+LLM 兜底"的混合实现,主模型为 doubao-seed-2-0-pro-260215。节点的核心代码片段如下:
def arbitrate(conflict, source_metadata,

anomalies) -> ArbitrationResult:

"""对单个字段冲突应用五条规则,按优先级返回可信值。"""

field_name = conflict"field_name"

values = conflict"source_values"

sources = conflict"source_names"

排除已识别的明显错误源

excluded = {a"suspect_source" for a in anomalies

if a"stock_code"==conflict"stock_code"

and a"field_name"==field_name}

candidates = [(s, v) for s, v in zip(sources, values)

if s not in excluded]

规则 A: majority_vote

counter = Counter(v for s, v in candidates)

top, top_n = counter.most_common(1)0

if top_n >= math.ceil(len(candidates) / 2):

return ArbitrationResult(

trusted_value=top, rule="majority_vote",

reason=f"{top_n}/{len(candidates)} 源一致")

规则 B: authoritative_source

auth_src = sorted(source_metadata,

key=lambda s: s"trust", reverse=True)0"name"

auth_val = next((v for s, v in candidates if s==auth_src), None)

if auth_val is not None and field_name in AUTH_FIELDS:

return ArbitrationResult(

trusted_value=auth_val, rule="authoritative_source",

reason=f"该字段为权威源({auth_src})优先字段")

规则 C: latest_filing

规则 D: weighted_median

规则 E: manual_review (CV > 0.1)

...

return ArbitrationResult(

trusted_value=None, rule="manual_review",

reason=f"CV={cv:.2%} 超阈值 10%")

节点的工程亮点有两点。第一是"先排除明显错误,再走规则"的设计------若异常值检测节点已经标记了某个源的某个字段为"单位错误"或"负号丢失",则在仲裁时不会让该源参与多数票,避免错误值污染仲裁结果。第二是"规则按优先级降级"的实现------每条规则都有清晰的"成立条件",前一条不成立则进入下一条;这种线性降级让仲裁逻辑容易调试、容易理解。

对于规则全部不成立、必须升级人工复核的字段,节点会把 trusted_value 设为 None,并在审计报告中明确标注。下游消费者拿到 cleaned.csv 时,可以基于这一空值字段决定是否阻塞下游流程、是否触发告警。在扣子编程的实际生成代码中,仲裁日志的命中规则字段会出现 "llm_assisted+authoritative _source"这种组合标签,表示"LLM 辅助判断+权威源优先"两条规则联合得出结论,体现了代码规则引擎与大语言模型的协同。

11.4.9 节点 7 :数值勾稽校验节点

数值勾稽校验节点延续了第 10 章设计的数值校验闭环思路,但作用对象从"OCR 提取的原始字段"转变为"仲裁后的可信值"。节点检查的勾稽关系包括:净利润/营业收入=净利率,应当在 -50%, 50% 合理区间;总负债 ≤总资产;资产负债率=总负债/总资产,应当在 0%, 100% 之间;ROE、PE、PS 等比率字段应当在各自合理范围内(如 ROE∈-100%, 100%、PE∈ (0, 1 000])。

若校验失败,节点不会"自动修正"------这是与某些粗糙的数据治理系统的核心差异。节点会把校验失败的字段重新标注为 needs_review=Y,并在审计报告中给出"虽然 majority_vote 通过,但勾稽关系不通过,建议人工复核"这样的双重提示。这种"多重护栏"机制,是真正可信数据治理系统的核心特征。该节点的执行耗时仅 4 毫秒,反映了纯代码勾稽校验相对于大语言模型推理的极致速度优势。

11.4.10 节点 8 :审计报告生成节点

审计报告生成节点的任务是:把整条工作流的所有决策过程,转化为一份合规审计员可以一眼看懂的自然语言报告。这一节点是数据治理工作流相对于传统 ETL 工具的核心差异------传统 ETL 工具的日志是程序员的语言(堆栈、SQL、JSON),而 AI 数据质检的审计报告是业务人员的语言(类似"为什么选择了 Wind 的值而不是东方财富的值")。

11-4 审计报告生成节点配置页面

如图11-4所示,节点采用大语言模型实现,模型选用 doubao-seed-2-0-lite-260215。lite 版本在文本组织与自然语言生成上,已能胜任审计报告这类相对程式化的任务,且单位 token 成本更低、生成速度更快------这是节点级精细化模型选型在本章的具体体现。系统提示词中要求模型按照固定的报告模板生成内容:
请基于以下结构生成审计报告:

多源财务数据质检审计报告

一、本次治理概况

  • 数据源数量、记录条数、字段数

  • 检测到的冲突字段数与命中规则分布

  • 升级人工复核字段数

二、典型冲突案例

对每个升级人工复核或仲裁结果异常的字段:

  • 公司名/股票代码

  • 字段名

  • 各源原始值与来源

  • 检测到的脏数据模式(若有)

  • 仲裁命中规则

  • 最终可信值

  • 决策理由

三、源可信度评估

基于本次冲突分布,各源的事后可信度估算:

  • 公司公告: <可信度评估>

  • Wind: <可信度评估>

  • 财经新闻: <可信度评估>

  • 卖方一致预期: <可信度评估>

四、推荐人工复核项

按重要性排序列出待复核字段

约束:

  • 每条决策必须用一句自然中文解释

  • 不允许使用专业JSON或代码语法

  • 报告总长度控制在 800-1500 字

通过模板化的提示词约束,审计报告生成节点的输出在结构上保持一致,便于合规岗位形成"看一眼就能理解"的稳定阅读体验。这种"结构化输出+自然语言解释"的混合形态,是 AI 时代审计文档的典型模板。需要指出的是,由于审计报告涉及对全量冲突明细的逐条解释,输入 token 量较大,节点的实际执行耗时约 1.4 分钟(在本章试运行数据上),是整条工作流耗时占比最高的单一节点。

11.4.11 节点 9 :输出打包节点

输出打包节点是工作流的"出口"。它接收上游所有节点的最终结果------可信值表、冲突明细表、审计报告------把它们组装为对应的三个文件(cleaned.csv、conflicts.csv、audit_report.md),并通过对象存储的 zip 上传接口一次性打包上传,返回一个签名 URL。

节点的关键工程细节有四点:第一,文件编码统一为 UTF-8 with BOM(utf-8-sig),保证 Excel 直接打开中文 CSV 不乱码;第二,写出 cleaned.csv 时显式将 stock_code 列指定为字符串类型,避免 pandas 在序列化阶段把 000858 这类前导零字符串隐式转换为整数 858(这是扣子编程在测试中专门修复的一个 bug,详见 11.5 节);第三,conflicts.csv 的列顺序严格按 (stock_code, field_name, source_name, source_value, dispersion_value, rule_applied, trusted_value, decision_reason) 组织,便于下游做透视分析;第四,audit_report.md 采用标准 Markdown 语法,方便直接渲染到企业知识库或合规系统。

相关推荐
YHL1 小时前
🚀 端侧 AI DEEPSEEK-R1-WEBGPU 项目实战(二):封装进度条组件,看懂 React 事件与组件树
人工智能
皮皮狗工坊1 小时前
贡院计划第一弹:DeepSeek Harness考生翻墙抄了答案,还企图隐藏罪证
人工智能
Dawson Zhu1 小时前
Agent自我纠错死循环:从原理剖析到工程化防御体系构建
人工智能·语言模型·架构·aigc
weixin_471383031 小时前
22 多 Agent 架构
agent
ZJU_统一阿萨姆1 小时前
【算子开发】卷积算子基础实现与优化
人工智能·语言模型
Justin3go1 小时前
DeepSeek Harness 如何做到 99% 缓存命中率(原理详解)
人工智能·开源·agent·deepseek
luckystar513~1 小时前
自己动手写Agent Harness【hooks】:生命周期钩子实现
人工智能
comedate2 小时前
DeepSeek Harness 配置 deepseek-v4-flash-vision-exp 视觉模型
agent·skill·deepseekharness
fightcrap2 小时前
DeepSeek Harness:Cordis 插件树与 Agent 主链路
人工智能·后端·程序员