重新训练管道和强大的函数调用器

社区文章 发布于2025年4月28日
Cover Image
如果您已经熟悉函数调用在智能代理系统中的作用,并且了解LoRa适配器,您可能想直接跳到TL;DR

随着越来越强大的模型出现,人们倾向于广泛使用超大模型来处理他们想要委派给它们的所有任务。

最近,“共鸣”(又称*测试时计算* - https://openai.com/index/learning-to-reason-with-llms/)模型的趋势已经占据了新闻头条,并达到了*炒作*浪潮的顶峰。这些是通用且无所不能的模型,它们在生成和暴露实际响应之前,在内部推理循环中消耗和产生大量token。*思考中……,等等,也许……,思考中……,重新表述……,考虑一个不同的角度……等等*。

与此同步,需要按顺序执行一系列细分任务的智能代理系统的出现和普及是一个领域,在此类系统处理的每个请求中,对LLM的调用通常是链式且数量众多的。在这些条件下,这些超强模型在效率方面的相关性可能会受到质疑。

在这种背景下,能够使用一个较小的模型,并使其适应智能代理系统的每个不同任务,这很有吸引力。针对特定任务对“基础”(预训练)模型进行专业化通常通过有监督微调来实现。此步骤涉及完善一个已学习语言模式和规则的现有模型。这种额外的训练通过“请求”和“预期结果”的示例转化为对特定任务的专业化。
一个“基础”模型通过微调成为任务专家。一个常见的例子是“指令”版本,它专门用于聊天/讨论,遵循指令,并以自由文本形式响应用户请求:*“你好”=>“你好,我能为您提供什么帮助?”*。

得益于arXiv论文2106.09685《LoRA:大型语言模型的低秩适应》(2021年6月)中介绍的方法,通过LoRa适配器进行有监督微调,可以以较低的成本和相对较快的速度完成“基础”模型的任务专业化。通过LoRa适配器进行有监督微调的其他优点包括:

  • 它们是可插拔的,即“基础”模型的权重没有被修改。
  • 因此,可以为同一个“基础”模型创建多个LoRa适配器:每个需要专业化的任务一个。
  • 因此,可以部署多个专家模型,而不会急剧增加服务器的硬件容量需求(主要是不增加可用的GPU vRAM的限制,而只是略微增加)。

智能代理函数调用的现状

通常,智能代理系统的一个或多个组件按以下方式工作:
  • “用户查询”=>
  • “用户查询”+一套可访问工具的定义作为上下文(通常是六个或更少)=>
  • LLM + 受限生成(例如通过 pydantic typing 或 grammar)=>
  • 一套可执行的工具调用命令 =>
  • 代码解释器(可以是 Python)=>
  • 工具调用(可以是第三方服务或贵公司技术团队的 API 调用)=>
  • 用户查询 + 工具调用响应作为上下文 =>
  • LLM =>
  • 对用户的响应

注意 :
LLM用户圈中模型上下文协议(MCPs)(anthropic.com/news/model-context-protocol)的繁荣并未改变这种状况,因为这些MCP服务器是LLM和工具之间的抽象层。对于每个它“连接”的MCP服务器(通过协调器,但我们在这里不赘述),LLM仍然接收一组工具定义和一个它必须通过可执行函数调用响应的查询。这是一种零样本提示,随着LLM可用的MCP(及其各自的许多工具)的数量增加,上下文会迅速膨胀。

在实践中,函数调用总是使用非常有限的工具集进行,通常少于十个,很少达到一百个。它们将在处理此任务时传递给LLM。以下是 Chip Huyen(Hub 上的 @chiphuyen)在今年 1 月的代理人博客文章中对此的描述:agents

一个带有工具记忆的函数调用 LoRa 适配器

在预训练阶段向LLM引入大量工具定义,以便它以后可以利用这些定义,这提供了一种替代当前函数调用状态的方法。一旦获得这种“知识”,就很容易灌输将查询转换为一组必须触发才能解决问题的严格可执行函数调用的能力。这样,函数调用中的“专家”模型就“天生”精通大量工具并生成适应它们的可执行函数调用。

在生产系统的专业环境中,重新训练这种“函数调用专家适配器”的原因可能是由于一套工具变得不可用而报废,或者某些工具的更新导致其定义发生变化。在重新训练之间,仍有可能以目前常见的扩展上下文的“经典”方式向LLM提供新工具。

本文的其余部分将介绍模型的再训练,以赋予其函数调用的即插即用专业化能力(来自知识,而非传递的工具上下文),以及多 LoRa 推理服务器的交付,该服务器允许在单个“基础”模型在 vRAM 中的专业化之间切换。

可以在此多适配器推理服务器中部署的其他“经典”LoRa适配器例如是“指令”、“查询路由器”、“响应质量评估器”、“响应聚合器”等类型(@请参阅该博客文章以获取更多灵感:anthropic.com/engineering/building-effective-agents)。它们将共同组成一个专家团队,在节俭的基础设施上为同一智能代理系统的不同功能提供服务。如果“基础”模型也“小”,就像我们这里的例子一样,那么这种代理星座可以部署在“边缘”,用于自托管的本地运行系统。

retrain-pipelines/func_calls_ds 训练数据集

retrain-pipelines 框架附带 [UnslothFuncCallFlow] 示例管道。它是 Hub 上 retrain-pipelines/function_caller_lora 模型仓库的再训练管道实现。第一步包括从 2 个*源数据集*创建*双配置数据集*:
  • 2个源数据集
    • 函数调用:可以是任何通用的函数调用数据集。
    • 通用用户查询:可以是任何用户问答数据集,任何与函数调用完全无关的数据集。
  • 生成的训练数据集(及其2个配置)
    • 持续预训练
    • supervised_finetuning(包含用于*训练*和*评估*的拆分)

目标确实是双重的:

  • 通过工具库扩展“基础”模型的知识。我们通过*持续预训练*来完成此操作,特别是将`embed_tokens`和`lm_head`这两个所谓的*保存模块*与LoRa适配器耦合(有关更多信息,请参见下一节)。
  • 训练一个专门用于可执行工具调用的LoRa适配器,该适配器不会产生幻觉。因此,我们不仅训练实际的“查询 => 工具调用”对,还训练精心设计的“查询 => 无工具调用”对。

function-calling CPT & SFT training dataset 函数调用 CPT & SFT 训练数据集

在本文中,我们使用 `Salesforce/xlam-function-calling-60k` (26d14eb) 作为函数调用源数据集,并使用 `lighteval/natural_questions_clean` (a72f7fa) 作为通用用户查询源数据集。这产生了 `retrain-pipelines/func_calls_ds` v0.28,拥有一个包含 4,200 多个工具的知识库。

retrain-pipelines/func_caller_lora 模型适配器

现在,您可能已经明白,我们依靠 Unsloth Python 包(它本身基于 PEFT)来完成 CPTSFT 适配器训练任务。
由此产生的训练适配器版本同时具有 `saved_modules`(在 `embed_tokens` 和 `lm_head` 层上)和 `LoRas`(在 `q_proj`、`k_proj`、`v_proj`、`o_proj`、`gate_proj`、`up_proj` 和 `down_proj` 层上)。
LLM pluggable adapter (saved_modules & LoRa) 基础 LLM + 可插拔的知识增强型任务专家适配器

正如上面提到的,这个适配器可以插在基础模型上,为后者带来任务特定的专业知识。在我们的案例中:从大量的固有工具知识库中进行函数调用。

然后,我们根据 Jaccard 指数(也称为 IoU,交并比)评估适配器对每个评估记录的性能。因此,对于给定的用户查询,同时惩罚任何“漏掉的工具调用”和任何“不合法(或格式不正确)的工具调用”。请注意,我们故意不依赖任何第三方提供的额外输出限制机制,因为它们对于当今即使是小型模型提供的性能来说也显得多余。

让我们看看 `retrain-pipelines/function_caller_lora` 的 v0.29 示例,它以 `unsloth/Qwen2.5-1.5B` 作为基础模型。下图是此基础模型 + 我们额外知识专家函数调用适配器的性能概述。它以两种不同的分组方式呈现了相同的数据:

Evaluation performance chart 评估性能图表

从图中可以看出,当用户查询不需要任何工具调用时,我们的模型适配器在不调用任何工具方面几乎取得了完美的得分。当只需要进行一次工具调用时,它也表现得相当好,评估集中约 5,700 条记录中有 75% 属于这一类别。对于一个查询最多 9 次工具调用,它表现得相对均匀良好。这相当了不起。

需要注意的是,为了使工具调用在上述性能计算中被认为是有效的,目前我们只采用基本的朴素方法,因此评估的性能度量肯定具有相当大的误导性(点击箭头展开项):

  • 例如,我们不会检查推断函数调用中命名参数的有效但不同顺序的出现
    查询 获取三个评分为1500的国际象棋谜题,侧重于“王翼攻击”主题,并确保它们来自“王翼弃兵开局”家族。此外,请指定谜题应恰好有5步。
    答案 [{"name": "advanced", "arguments": {"number_of_puzzles": 3, "themes": "kingsideAttack", "rating": "1500", "opening_family": "Kings_Gambit_Accepted", "number_of_moves": 5}}]
    完成 [{"name": "advanced", "arguments": {"number_of_puzzles": 3, "rating": "1500", "themes": "kingsideAttack", "number_of_moves": 5, "opening_family": "Kings_Gambit_Accepted"}}]
  • 当参数为数值时,我们不使用算术评估器来检查两个写法是否表示相同的值
    查询 预测一项投资在10年内的增长,初始投资1000美元,每年追加500美元,年回报率7%,前5年通货膨胀率2%,后5年通货膨胀率3%。
    答案 [{"name": "project_investment_growth", "arguments": {"principal": 1000, "annual_addition": 500, "years": 10, "return_rate": 0.07, "inflation": [0.02, 0.02, 0.02, 0.02, 0.02, 0.03, 0.03, 0.03, 0.03, 0.03]}}]
    完成 [{"name": "project_investment_growth", "arguments": {"principal": 1000, "annual_addition": 500, "years": 10, "return_rate": 0.07, "inflation": "[0.02] * 5 + [0.03] * 5"}}]
  • 我们不承认推理中明确提及但实际未提及的默认参数(反之亦然)
    查询 获取ID为“nm0000243”的演员的奖项摘要,并获取美国科技类别的英文头条新闻。
    答案 [{"name": "actors_get_awards_summary", "arguments": {"nconst": "nm0000243"}}, {"name": "top_headlines", "arguments": {"category": "technology", "country": "US"}}]
    完成 [{"name": "actors_get_awards_summary", "arguments": {"nconst": "nm0000243"}}, {"name": "top_headlines", "arguments": {"language": "en", "category": "technology", "country": "US"}}]
  • 有些记录的两个值不同,但都完全有效
    查询 我正计划在悉尼皇家植物园野餐。公园周围有学校吗?
    答案 [{"name": "schools_list", "arguments": {"lat": -33.864108, "lon": 151.217824}}]
    完成 [{"name": "schools_list", "arguments": {"lat": -33.8688, "lon": 151.2093}}]
  • 也有一些记录,在已学习的知识库中存在不止一个工具可以完成这项工作
    查询 为“苹果”获取英文自动完成建议,适用于股票和期货。
    答案 [{"name": "auto_complete_deprecated", "arguments": {"text": "Apple", "type": "stock,futures"}}]
    完成 [{"name": "v2_auto_complete", "arguments": {"text": "Apple", "search_type": "stocks_futures"}}]
  • 有时只是因为缺乏可推导的信息而无法得到正确的答案,即当真实答案包含查询中不存在的信息时
    查询 为Queen乐队的歌曲《Bohemian Rhapsody》创建电台播放列表。
    答案 [{"name": "get_radio_playlist", "arguments": {"uri": "spotify:track:4u7DsyG53mBfR9WP25O6uG"}}]
    完成 [{"name": "get_radio_playlist", "arguments": {"uri": "spotify:track:3wZkxCWeKu0J5tJ5tJ5tJ5tJ5tJ5tJ5tJ5t
  • 模型有时表现优于验证记录,后者有时只是一个不正确的真实值
    查询 显示产品ID为“def456”的产品在“AU”地区使用“en”语言的前50条产品评论,不带任何评分筛选。
    答案 [{"name": "product_reviews", "arguments": {"product_id": "def456", "country": "AU", "language": "en", "limit": "50"}}]
    完成 [{"name": "product_reviews", "arguments": {"product_id": "def456", "country": "AU", "language": "en", "limit": 50}}]

    查询 搜索与“披头士”相关的音乐,并提供“艾玛·沃森”Instagram 短视频的下载链接。
    答案 [{"name": "music_search", "arguments": {"query": "The Beatles"}}, {"name": "get_media_download_link", "arguments": {"link": "https://www.instagram.com/reel/Bxxxxx/"}}]
    完成 [{"name": "music_search", "arguments": {"query": "The Beatles"}}, {"name": "get_media_download_link", "arguments": {"link": "https://www.instagram.com/reel/Emma Watson"}}]
  • 清单还在继续。
……所有这些显然对报告的性能产生了不可忽视的扭曲性负面影响。

回想一下,我们只提交用户查询,模型从其包含 4,200 多个可用工具的内在知识库中选择并生成可操作的工具调用,而无需使用通常的扩展上下文工具。这与当前的函数调用状态截然不同。然而,它却创造了奇迹!
想象一下,你的本地代理系统连接了大量的 MCP 服务器,而且上下文窗口永远不会过载。在企业界,这样的设置感觉就像打了类固醇的魔法,简直就是作弊码。

注意 :
如果您好奇,可以点击 Hub 上的这里查看 retrain-pipelines 在训练此特定模型适配器版本时生成的*管道卡*。

多适配器单端点服务器

我们已经看到,用`transformers`库实例化的LLM可以托管与`PEFT`库兼容的即插即用适配器。
我们之前没有提到但非常重要的一点是,在 SFT 训练阶段,当模型提供“查询”/“响应”对时,为了使学习最有效,这些对都预先添加了一个精心设计的系统提示。它在帮助引导基础模型正确集成任务特定专业知识方面起着重要作用。
这意味着,对于推理来说,在适配器之间切换时,切换 `prompt_template` 至关重要。

注意 :
您可以通过此GitHub永久链接找到与本文描述的`retrain-pipelines/function_caller_lora`适配器配套的精确*prompt_template*。
在您查看此内容时,值得注意的是,我们特别注意了在给定查询合法地不需要任何工具调用时,不返回任何工具调用。

我们使用的多适配器推理服务器是 Litghning AIretrain-pipelinesLitServe 的定制实现。您可以在此处找到完整代码。只需一个超级简单轻量级的 yaml 配置文件,即可告知基础模型和要加载的适配器列表(可从 Hub 或磁盘加载,示例请参阅此处),然后就大功告成了。

推理服务的消费者可以通过 `adapters` 端点查询服务器上正在服务的适配器版本,并从那里构建其推理请求。查询的响应可以批量请求:

func_caller_lora
适配器
curl -X 'POST' \
'http://:8765/predict' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "adapter_name": "func_caller_lora",
    "queries": [
      "Hello there.",
      "Is 48 a perfect square?"
    ]
  }'
`func_caller_lora` adapter activated, inference server response `func_caller_lora` 适配器已激活,推理服务器响应
无适配器
原始基础模型
curl -X 'POST' \
'http://:8765/predict' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "adapter_name": "",
    "queries": [
      "Hello there.",
      "Is 48 a perfect square?"
    ]
  }'
no adapter, base-model inference server response 无适配器,基础模型推理服务器响应

很容易看出这种设置的价值。一支专业的士兵军队,触手可及,没有上下文窗口开销,没有硬件需求爆炸。

前瞻声明

扩展或改进此训练管道的一些方向:
  • 迭代数据清洗,确保只有有效的SFT记录通过
  • 使用 PPO 通过与真实值比较来从 SFT 错误中学习
  • 如有需要,按领域或部门制作适配器,并将其插入同一服务器
  • 监控工具定义漂移并定期重新训练
  • 在多适配器设置下,对推理延迟进行基准测试

这些与 retrain-pipelines Apache 2 库一起提供的“示例管道”旨在:

  • 启发人们看到自动化再训练在规模化场景中是多么有用,
  • 对一些人来说是教育工具,对许多人来说是快速开启他们旅程的起点,无论他们走向何方。
它们可重复且易于参数化,可将其视为实际系统的即插即用组件。例如,可以比较不同基础模型的性能。

本文涵盖的用例旨在促使人们提前思考大规模适应性企业代理系统,这些系统拥有庞大的工具库(很快将被称为“*日常生活所需*”),模型随着工具的变化而适应,而再训练不再是奢侈品,而是基础设施。
在不久的将来,工具(可能是 MCP 服务器或其继任者)将一直进行版本控制、弃用、升级……。很快,就会有像今天在世界各地组织内部部署的 API 开发人员一样,出现专门的 MCP 开发人员。

这不仅仅关乎智能模型。它关乎为智能公司构建适应性基础设施。

让我们向前发展。

另外,现实世界的场景浪潮很快就会追上你,除非你很早开始你的激情项目。
冲向月球和超越的时代已死。万岁:尽情疯狂吧,伙计们!


社区

注册登录 发表评论