Paper

论文速读:DART-SD 让多轮 Tool-Calling Agent 自我蒸馏

5 min read ·

Hugging Face Daily Papers 近期收录的 DART-SD 全名是 Diamond-topology Aware Retrieval Tuning with Self-Distillation for Multi-Turn Tool-Calling Agents。论文讨论一个越来越实际的问题:当 agent 不再只调用一次函数,而是需要多轮检索、调用、观察、修正和汇总时,训练数据从哪里来?参考来源:Hugging Face PapersarXiv 搜索Model Context Protocol

过去两年,tool calling 的工程栈成熟很快。OpenAI、Anthropic、Google、Mistral、Qwen、DeepSeek 等模型都支持结构化工具调用,框架层有 LangGraph、LlamaIndex、CrewAI、Mastra、MCP server 和各类 agent harness。但模型训练侧仍有一个硬问题:单轮函数调用样本相对好造,多轮工具轨迹很难造。

原因很简单。一次函数调用只需要判断“应该调用哪个工具,参数是什么”。多轮 agent 轨迹要同时回答更多问题:第一步应该检索还是直接问用户?工具返回空结果后要不要换查询?两个工具结果冲突时信谁?什么时候停止?最后答案如何引用证据?这些能力不是靠一堆孤立 JSON schema 就能学会的。

DART-SD 的价值在于,它把多轮工具调用训练看成数据拓扑问题,而不是 prompt 问题。

为什么多轮工具调用难

我们先看一个企业知识库 agent 的例子。用户问:“过去 30 天高优先级工单里,哪些客户同时临近续约?”一个弱 agent 可能只搜工单,然后直接回答。一个强 agent 会拆成几步:

1. 查询过去 30 天高优先级工单
2. 按客户聚合并筛掉测试租户
3. 查询这些客户的续约日期和 ARR
4. 交叉过滤未来 90 天续约客户
5. 输出客户、风险原因、证据和下一步动作

这里每一步都依赖上一步观察。训练样本如果只记录最终 SQL 或最终答案,模型学不到中间决策。训练样本如果记录所有细节,又可能太长、太嘈杂、难以泛化。

多轮工具调用的样本质量有三个标准:可执行,能恢复错误,有明确停止条件。很多自动生成数据只满足第一条,看起来像轨迹,但没有真实观察和失败分支。

diamond-topology 的直觉

论文标题里的 diamond-topology 可以用工程语言理解:不要只从“问题到答案”建一条线,而是把任务、工具、轨迹和观察连成菱形结构。

task
  -> similar tasks
  -> relevant tools
  -> candidate traces
  -> execution observations
  -> distilled trace

为什么这比普通检索更好?因为 agent 学工具调用时,真正有用的相似性不只来自文本相似。两个问题表述不同,但都需要先查用户、再查订单、再查工单,它们在工具路径上相似。两个工具名字相似,但权限和返回结构不同,不能混用。一个轨迹看起来合理,但执行观察显示第二步返回空结果,也不能直接当好样本。

所以检索要同时看任务语义、工具 schema、调用历史和执行结果。这就是 DART-SD 对开发者最有启发的地方:训练 agent 不是堆更多 prompt,而是组织更好的经验索引。

自蒸馏为什么适合 agent

自蒸馏在这里的作用,是把复杂轨迹压缩成更干净的训练样本。一个 teacher 模型或强执行器先生成多条候选轨迹,系统执行并观察结果,然后筛选成功轨迹,再把冗余推理、无效尝试和重复调用压缩掉。

一个实用流水线可以这样设计:

type TraceStep = {
  thoughtSummary: string;
  tool?: string;
  args?: Record<string, unknown>;
  observation?: unknown;
};

type AgentTrace = {
  task: string;
  tools: string[];
  steps: TraceStep[];
  finalAnswer: string;
  success: boolean;
};

function keepTrace(trace: AgentTrace) {
  if (!trace.success) return false;
  if (trace.steps.length === 0) return false;
  if (trace.steps.length > 12) return false;
  return trace.steps.some((step) => step.tool);
}

真实系统还要加入结果验证。比如查询类任务可以比对数据库结果,代码类任务可以跑测试,客服类任务可以检查是否引用了允许字段。没有执行验证,自蒸馏就容易把模型幻觉变成训练资产。

从训练数据到轨迹库

不是每个团队都要微调模型。DART-SD 的思路同样适合构建“轨迹 RAG”。也就是说,检索的不只是文档,而是过去成功完成任务的工具调用路径。

type TraceCard = {
  id: string;
  taskEmbeddingText: string;
  toolPath: string[];
  preconditions: string[];
  failureModes: string[];
  compactSteps: string[];
};

当新任务进来时,系统先检索相似 TraceCard,把工具路径和失败模式作为上下文给 agent。这样做比把整段历史对话塞进上下文更稳,因为它保留的是可复用结构,而不是聊天噪声。

例如“查客户续约风险”和“查客户流失风险”文本不同,但工具路径可能相近。轨迹库能教模型:先查客户集合,再查事件,再查财务字段,最后汇总证据。

关键风险:污染和过拟合

自动蒸馏最大风险是污染。模型生成错误轨迹,执行器没有发现,下一轮训练又把错误轨迹强化。长期看,agent 会越来越自信地重复错误。

解决办法不是完全不用自蒸馏,而是把蒸馏当数据生产线管理。至少要做四件事。

第一,所有轨迹必须可重放。保存工具版本、输入、输出摘要和验证结果。

第二,失败轨迹不要全删。保留部分失败样本用于教模型何时停止、何时改查、何时向用户澄清。

第三,轨迹要去重。相同工具路径的大量样本会让模型过度偏好某条路线,遇到新任务不愿探索。

第四,敏感数据要脱敏。工具轨迹里常含客户名、邮箱、订单号和内部字段,不能直接进入训练集。

对 MCP 生态的意义

MCP 让工具暴露更标准,但标准化工具并不等于模型会用工具。未来 agent 的差距,很可能来自两层:工具 schema 是否清楚,历史轨迹是否高质量。

DART-SD 提醒我们,MCP server 最好天然产出训练数据。每次工具调用都记录任务、参数、观察、错误、重试和最终结果。这样运行一段时间后,团队会拥有自己的 agent 行为资产。相比通用公开数据,这类私有轨迹更贴近业务流程。

结论

DART-SD 值得关注,因为它把多轮工具调用的核心矛盾说清楚了:agent 缺的不是更多函数名,而是高质量、可执行、可泛化的工具轨迹。

普通团队可以先做低配版:为 agent harness 加 trace 记录,把成功任务压缩成 TraceCard,上线前用检索轨迹做 few-shot,上线后再筛选新轨迹。等数据规模足够,再考虑微调。训练 agent 的第一步,不是买更大的模型,而是把自己的工具经验组织起来。

Frequently asked questions

DART-SD 主要解决什么问题?
它解决多轮工具调用训练数据难构造的问题。单轮函数调用数据很多,但真实 agent 需要跨步骤检索、规划、调用、观察和修正,轨迹质量更难保证。
diamond-topology 检索是什么意思?
可以理解为不只检索相似问题,而是同时连接任务、工具、示例轨迹和中间观察,形成多边关系,再用这些关系生成更可靠的调用路径。
自蒸馏会不会放大模型错误?
会有这个风险,所以关键是加入执行校验、失败过滤、轨迹压缩和多样性采样。没有校验的自蒸馏很容易把错误步骤包装成训练数据。
它对普通 RAG 项目有什么启发?
RAG 不应只检索文档片段,也可以检索成功工具轨迹。相似任务过去如何查库、调用 API、处理错误,都是 agent 可复用的经验。
生产团队能怎么落地?
先记录真实工具调用 trace,清理成任务、工具、观察和结果四类对象,再用离线执行器筛掉失败轨迹,最后做小规模微调或 few-shot 轨迹库。
// next.txt ›

Some outbound links in this post are affiliate links — see disclosure.