AutoSynthData:为企业智能体构造可验证的合成训练数据

2026-10-02 27 预计阅读时间: 1 分钟
来源: huggingface.co AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:11 分钟

企业智能体缺的往往不是更多文本,而是更贴近业务流程的高质量样本:用户提出请求,智能体判断权限,选择工具,生成结构化参数,处理异常,并给出可审计的答复。AutoSynthData 这一主题指向一种工程化思路——自动生成这类训练数据,同时用规则、执行结果和人工抽检控制质量。

由于来源摘要没有提供具体接口或实现细节,下面不会假定 AutoSynthData 存在某个固定 SDK,而是给出一套可以直接改造的实现蓝图。

企业智能体的数据不只是“问题—答案”

普通问答数据通常只有输入与输出,但企业智能体还需要学习中间决策。一个适合训练或评测的样本至少可以包含:

  • 用户请求:保留真实业务语言中的省略、歧义和约束。
  • 业务上下文:租户、角色、时区、资源状态等必要信息。
  • 预期动作:调用哪个工具,以及参数应如何组织。
  • 策略约束:哪些操作需要审批,哪些字段不能泄露。
  • 最终答复:工具成功、失败或权限不足时应如何回应。
  • 质量标签:生成器版本、验证结果、难度和失败类型。

例如,“帮我给王敏退款”并不是一个完整训练样本。智能体还应识别订单、确认退款金额、检查操作者权限,并在信息不足时询问,而不是编造订单号。

一种便于落盘和版本管理的数据格式如下:

{
  "id": "refund-0001",
  "task": "refund_order",
  "user_message": "给订单 ORD-1042 退款 99 元",
  "context": {
    "role": "support_agent",
    "currency": "CNY"
  },
  "expected_action": {
    "tool": "create_refund",
    "arguments": {
      "order_id": "ORD-1042",
      "amount": 99,
      "currency": "CNY"
    }
  },
  "expected_behavior": "request_approval",
  "metadata": {
    "generator_version": "demo-v1",
    "synthetic": true
  }
}

这里的关键不是字段名称,而是把“正确答案”从一段自然语言扩展为可验证的行为轨迹。

生成流水线:先定义约束,再扩充表达

可维护的合成数据系统通常不应直接让模型自由生成数万条记录。更稳妥的流水线可以拆成四层:

  1. 任务目录:列出智能体支持的业务动作、工具参数和权限规则。
  2. 场景组合:组合角色、资源状态、语言表达、成功路径和失败路径。
  3. 样本生成:使用模板、规则或大模型产生多样化请求与期望行为。
  4. 自动验证:检查 JSON Schema、业务不变量、权限边界和重复率。

在这一过程中,应刻意生成“难样本”,而不只是顺利完成任务的正例。例如:

  • 缺少订单号,智能体必须追问。
  • 金额超过审批阈值,智能体必须请求授权。
  • 用户试图跨租户访问数据,智能体必须拒绝。
  • 工具返回超时,智能体不能声称操作已经成功。
  • 请求中夹带提示注入,智能体仍需遵守系统策略。

如果训练集只有成功调用,模型很容易学会“遇到请求就执行”,这在企业环境中比答错一句话更危险。

可运行的最小生成器

下面的示例只依赖 Python 标准库。它根据少量业务规则生成退款场景,执行基本验证,然后写入 train.jsonl。运行前可修改审批阈值、角色和订单列表,使其贴近自己的业务。

#!/usr/bin/env python3
import json
import random
from pathlib import Path

random.seed(42)

ORDERS = [
    {"order_id": "ORD-1042", "max_refund": 120},
    {"order_id": "ORD-2098", "max_refund": 500},
]
ROLES = ["support_agent", "finance_admin"]
APPROVAL_THRESHOLD = 100


def expected_behavior(role: str, amount: int, max_refund: int) -> str:
    if amount <= 0 or amount > max_refund:
        return "reject_invalid_amount"
    if role != "finance_admin" and amount > APPROVAL_THRESHOLD:
        return "request_approval"
    return "call_tool"


def build_sample(index: int) -> dict:
    order = random.choice(ORDERS)
    role = random.choice(ROLES)
    amount = random.choice([20, 99, 120, 150, 600])
    behavior = expected_behavior(role, amount, order["max_refund"])

    templates = [
        "请给订单 {order_id} 退款 {amount} 元",
        "客户要求退 {amount} 元,订单号是 {order_id}",
        "处理一下 {order_id},退款金额 {amount} CNY",
    ]
    message = random.choice(templates).format(
        order_id=order["order_id"], amount=amount
    )

    action = None
    if behavior == "call_tool":
        action = {
            "tool": "create_refund",
            "arguments": {
                "order_id": order["order_id"],
                "amount": amount,
                "currency": "CNY",
            },
        }

    return {
        "id": f"refund-{index:04d}",
        "task": "refund_order",
        "user_message": message,
        "context": {"role": role, "max_refund": order["max_refund"]},
        "expected_action": action,
        "expected_behavior": behavior,
        "metadata": {"generator_version": "demo-v1", "synthetic": True},
    }


def validate(sample: dict) -> None:
    required = {
        "id",
        "task",
        "user_message",
        "context",
        "expected_action",
        "expected_behavior",
        "metadata",
    }
    missing = required - sample.keys()
    assert not missing, f"missing fields: {sorted(missing)}"

    behavior = sample["expected_behavior"]
    action = sample["expected_action"]
    assert behavior in {
        "call_tool",
        "request_approval",
        "reject_invalid_amount",
    }
    assert (behavior == "call_tool") == (action is not None)

    if action:
        args = action["arguments"]
        assert action["tool"] == "create_refund"
        assert args["amount"] <= sample["context"]["max_refund"]


def main() -> None:
    samples = [build_sample(i) for i in range(1, 101)]
    for sample in samples:
        validate(sample)

    output = Path("train.jsonl")
    with output.open("w", encoding="utf-8") as f:
        for sample in samples:
            f.write(json.dumps(sample, ensure_ascii=False) + "\n")

    counts = {}
    for sample in samples:
        key = sample["expected_behavior"]
        counts[key] = counts.get(key, 0) + 1

    print(f"wrote {len(samples)} samples to {output}")
    print("behavior distribution:", counts)


if __name__ == "__main__":
    main()

保存为 generate_data.py 后运行:

python3 generate_data.py
head -n 3 train.jsonl

这个例子没有调用大模型,但它展示了自动合成系统的骨架:场景空间、业务规则、期望动作和验证器彼此分离。后续可以让大模型只负责改写 user_message,而由确定性代码计算 expected_behavior,从而减少标签被模型“顺手编造”的风险。

验证质量,而不是只统计数量

生成十万条数据并不等于获得十万条有效数据。数据流水线至少应关注以下指标:

  • 规则通过率:结构、类型和业务不变量是否全部满足。
  • 任务覆盖率:每种工具、角色、异常和权限分支是否都有样本。
  • 重复率:文本不同但语义完全相同的样本是否过多。
  • 执行正确率:预期工具调用能否在沙箱或模拟器中成功运行。
  • 策略一致性:危险操作是否始终触发拒绝或审批。
  • 人工接受率:领域专家抽检时,有多少样本可直接使用。

训练集、验证集和测试集也不能简单随机切分。如果同一模板生成的近似样本落入不同集合,评测结果会被高估。更合适的做法是按模板族、业务实体或场景类型分组切分,并保留一套由人工编写、从未进入生成流程的测试集。

隐私同样是边界条件。即使最终数据是合成的,生成提示中也不应直接塞入未脱敏的客户记录。使用真实数据提取模式时,应先做字段最小化、去标识化和访问审计。

落地时从小闭环开始

不要一开始就试图覆盖整个企业知识库。可以先选择一个高频、边界清楚、可在沙箱执行的动作,例如退款、工单分类或账号解锁,然后完成一个小闭环:

  • 定义工具契约和权限规则。
  • 编写 20~50 个经过专家确认的种子场景。
  • 扩充表达方式、异常条件和对抗输入。
  • 用代码验证结构,用模拟工具验证执行结果。
  • 人工抽检后再进入微调或评测流程。
  • 保存生成器版本、随机种子和规则版本,确保数据可重现。

AutoSynthData 的真正价值不应只是“更便宜地造数据”,而是把企业知识、权限策略和工具行为变成可执行的数据规范。生成速度可以交给自动化,正确性仍需要规则、沙箱和领域专家共同把关。


相关推荐