首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >AI 数据工程:模型上限由数据决定

AI 数据工程:模型上限由数据决定

原创
作者头像
资源shanxueit.com
发布于 2026-10-19 14:14:26
发布于 2026-10-19 14:14:26
90
举报

一、先纠正一个误区:数据工程不是“清洗一下丢给模型”

很多人对数据准备的理解是:拉数据、去空值、格式化、喂给模型。实际项目里真正出问题的是这些:

  • 同一份数据跑两次管道,结果不一样,无法复现实验;
  • 训练集和测试集有重叠,指标虚高;
  • 线上推理的输入分布和训练时不一致,模型悄悄退化;
  • 标注规则改了,但没有版本记录,旧模型无法复现;
  • 数据里混进 PII 或违规内容,上线后才发现;
  • 坏样本没拦住,训练跑完才知道白跑。

所以正确姿势不是“清洗一次”,而是把数据当软件资产来管:

  1. 定数据契约:字段、类型、取值范围、缺失规则;
  2. 建采集与清洗管道:幂等、可重跑、有日志;
  3. 做质量校验:结构校验 + 业务规则 + 分布检查;
  4. 管版本与血缘:每次数据集有唯一标识,能追到来源;
  5. 划分数据集:去重后再切分,防止泄漏;
  6. 管标注:规则、指南、一致性校验都要版本化;
  7. 做合规:脱敏、保留期限、访问控制。

二、第一步:先把“数据契约”写下来

数据契约是字段级的约定,写清了,管道和校验才有依据。

代码语言:javascript
复制
数据集:客服对话样本 v1
字段:
  sample_id: string, 唯一
  text: string, 1-2000 字, 不含手机号/身份证
  label: enum[退款, 物流, 账号, 其他]
  source: enum[app, web, phone]
  created_at: date, 不晚于今天
规则:
  - sample_id 不可重复
  - text 去首尾空白后非空
  - label 缺失率 < 1%,缺失样本进隔离区而非丢弃
  - 每批次记录行数、来源分布、label 分布

契约里最有价值的两条是缺失率阈值和隔离区。坏数据不要直接删,删了就永远不知道坏在哪;应该隔离并统计。

三、第二步:质量校验要写成代码,不要靠人眼看

数据校验的第一原则:能自动拦住的,绝不留到训练后

代码语言:javascript
复制
from dataclasses import dataclass

@dataclass
class Row:
    sample_id: str
    text: str
    label: str
    source: str

LABELS = {"退款", "物流", "账号", "其他"}
SOURCES = {"app", "web", "phone"}

def validate(rows: list[Row]) -> tuple[list[Row], list[dict]]:
    ok, bad, seen = [], [], set()
    for r in rows:
        errs = []
        if not r.sample_id or r.sample_id in seen:
            errs.append("id缺失或重复")
        if not r.text.strip() or len(r.text) > 2000:
            errs.append("text为空或超长")
        if r.label not in LABELS:
            errs.append("label非法")
        if r.source not in SOURCES:
            errs.append("source非法")
        seen.add(r.sample_id)
        (bad.append({"row": r, "errors": errs}) if errs else ok.append(r))
    return ok, bad

这段代码不长,但它把“什么算合格”从口头约定变成了可执行规则。质量规则应该是版本化的代码,而不是某个人的经验。

四、第三步:去重要在切分之前做

训练集和测试集重叠,是让指标虚高最常见的原因。而重叠往往来自近重复样本:同一段话改了几个字、加了标点、换了空格。

最小可行做法是归一化 + 哈希去重:

代码语言:javascript
复制
import hashlib, re

def normalize(text: str) -> str:
    t = re.sub(r"\s+", "", text.lower())
    t = re.sub(r"[^\w\u4e00-\u9fff]", "", t)
    return t

def dedup(rows: list[Row]) -> list[Row]:
    seen, out = set(), []
    for r in rows:
        h = hashlib.md5(normalize(r.text).encode()).hexdigest()
        if h not in seen:
            seen.add(h)
            out.append(r)
    return out

严格去重之后再切分数据集,顺序不能反。反了就会泄漏:先去重再切分,测试集里就不会有训练集的近重复。

五、第四步:数据版本与血缘

“这个模型是用哪版数据训的”必须能回答。最小方案是给每个数据集生成一个清单文件,记录哈希、行数、来源和生成时间。

代码语言:javascript
复制
import json, hashlib
from datetime import datetime, timezone

def make_manifest(paths: list[str], out: str = "dataset_manifest.json"):
    files = []
    for p in paths:
        with open(p, "rb") as f:
            files.append({"path": p, "sha256": hashlib.sha256(f.read()).hexdigest()})
    manifest = {
        "created_at": datetime.now(timezone.utc).isoformat(),
        "files": files,
        "total_rows": sum(1 for _ in files),  # 示例占位,实际按行统计
    }
    with open(out, "w") as f:
        json.dump(manifest, f, ensure_ascii=False, indent=2)

清单不用复杂,关键是每次训练都绑定一个 manifest。出了问题时,你能回答“当时用的到底是哪批数据、有没有被改过”。

六、第五步:管道要幂等、可重跑

数据管道最常见的运维事故是:中途失败后重跑,数据被写了两遍。

解决原则很朴素:每一步都可重跑,输出由输入决定,重复执行结果不变。

具体做法:

  • 中间结果按批次分区存放,写新分区而不是追加到同一文件;
  • 每步输出带批次 ID,失败从失败那步重跑;
  • 写库时用“先写临时表再原子替换”,或者按主键 upsert;
  • 每步记录输入行数、输出行数、丢弃行数和丢弃原因。

丢弃原因统计是被严重低估的指标。它突然升高,通常意味着上游数据源变了。

七、第六步:标注工程比标注本身更重要

如果是需要人工或模型标注的数据,规则和指南必须版本化:

  1. 标注指南:每个类别的定义、正例反例、边界情况;
  2. 一致性校验:同一批样本双人标注,算一致率,低于阈值就返工;
  3. 仲裁机制:分歧样本由第三人裁决,裁决结果回流成新案例;
  4. 指南版本:指南改了,旧数据要标注“按哪版指南标注”,不能混训。

AI 可以辅助预标注、生成候选,但指南的边界定义必须人定。因为“这句话算不算退款诉求”,是业务判断,不是模型判断。

八、第七步:合规与隐私,越早做越便宜

数据工程的合规不是上线前补的,是采集时就要设计的:

  • 最小必要:只采业务真正需要的字段;
  • 脱敏前置:手机号、身份证、地址在入湖前就脱敏,不留原文;
  • 保留期限:原始数据、中间数据、训练集分别定保留期;
  • 访问控制:按角色分权限,谁看过、导出了什么要有记录;
  • 删除能力:用户要求删除时,能追溯到哪些数据集受影响。

最后一条最容易被忽略。如果数据没有血缘,用户要求删除时你根本找不到它散落在哪。

九、AI 在数据工程里的正确角色

AI 很适合帮你做这些:

  • 生成校验规则和测试用例初稿;
  • 辅助做数据画像和异常模式发现;
  • 写清洗脚本、SQL、管道配置;
  • 预标注和生成标注候选;
  • 审查管道代码里有没有幂等缺陷和数据泄漏。

一个实用的审查提示词:

代码语言:javascript
复制
请审查下面数据管道代码,只输出问题表格:
问题类型 | 位置 | 风险说明 | 修改建议
重点检查:是否幂等、失败重跑是否重复写入、是否有数据泄漏、
是否记录丢弃行数和原因、是否有未脱敏字段。
不要重写代码。

但契约怎么定、缺失率阈值多少、什么算边界样本,这些必须人来做。AI 没有你的业务判断。

十、常见坑

  1. 先切分后去重:测试集泄漏,指标全虚高。
  2. 管道不幂等:失败重跑写两遍,训练数据翻倍。
  3. 坏数据直接删:丢失问题线索,无法定位上游。
  4. 没有数据版本:模型无法复现,实验结论不可信。
  5. 标注指南没版本:新旧标准混训,模型学得四不像。
  6. 脱敏放在最后:原文已在多处落盘,删除成本极高。
  7. 只看总行数不看分布:批次间分布漂移,模型悄悄退化。

结论

AI 数据工程的正确姿势,不是“清洗一下丢给模型”,而是把数据当软件资产:契约先行、校验可执行、去重先于切分、版本与血缘可追、管道幂等可重跑、标注规则版本化、合规前置设计。

代码可以很少,但校验不能省,版本不能丢,幂等不能破。记住一句话:模型决定下限,数据决定上限;没有可复现的数据管道,就没有可信的模型结论。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、先纠正一个误区:数据工程不是“清洗一下丢给模型”
  • 二、第一步:先把“数据契约”写下来
  • 三、第二步:质量校验要写成代码,不要靠人眼看
  • 四、第三步:去重要在切分之前做
  • 五、第四步:数据版本与血缘
  • 六、第五步:管道要幂等、可重跑
  • 七、第六步:标注工程比标注本身更重要
  • 八、第七步:合规与隐私,越早做越便宜
  • 九、AI 在数据工程里的正确角色
  • 十、常见坑
  • 结论
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档