为什么?
在对话系统的设计和实现中,传统的基于 Rasa-like 框架的方法往往需要依赖于多个模块的紧密协作,例如我们在之前的文章中提到的基于大模型(LLM)构建的任务型对话 Agent,Thought Agent,其由自然语言理解(NLU)、对话管理(DM)和对话策略(DP)等模块共同协作组成。这种模块化的设计虽然在理论上具有灵活性,但在实践中却带来了诸多挑战,尤其是在系统集成、错误传播、维护更新以及开发门槛等方面。为了克服这些挑战,构建一个端到端(E2E)的模型显得尤为关键。E2E 的模型通过将对话的各个阶段集成到一个统一的框架中,极大地简化了系统架构,提高了处理效率,并减少了错误传递的可能性。此外,由于其简化的架构,也更易于维护和更新,从而降低了开发和维护的成本。在我们看来,端到端的对话 Agent 不仅在技术上更具优势,而且在实际应用中也展现了其独特的价值和潜力,例如能够快速构建帮助用户查询信息、调度技能的 Agent。
本文将指导读者如何采用蒙特卡洛方法(Monte Carlo)模拟用户行为并结合 LLM 的方法来构建训练数据集;使用 LLaMA Factory 对多种 LLM 进行高效微调构建任务型对话 Agent。该方案允许用户快速创建出能够精准调用外部工具的 Agent。
挑战
任务型对话系统的核心需求包括意图识别、槽位填充、状态管理和策略决策。我们识别了以下几个关键挑战:
- 微调后的 LLM 能够从用户的问题中识别到用户意图和关键信息(槽位)
- 微调后的 LLM 能够对用户的问题有判断边界的能力,容易混淆的内容将触发意图确认,完全无关的内容将触发兜底话术
- 微调后的 LLM 能够根据槽位填充状态判断合适的触发功能调用(Function calling)的时机
- 微调后的 LLM 能够对根据上下文正确的识别到需要用于调用功能的关键信息
构造数据集
为了应对上述挑战,首先我们需要构造能够覆盖大部分场景的对话数据集,我们面临的核心难点是如何模拟真实世界中用户的多样化行为和对话系统的有效响应。但是对于任务型对话 Agent 来说,用户和 Agent 之间的对话域是有限的,因为 Agent 只需要处理业务范围内的用户意图,超出处理范围的内容,只需要返回一些固定的兜底话术即可。因此我们可以采用了状态图对对话的过程进行建模,使用蒙特卡洛方法对真实的对话过程进行模拟,接着使用 LLM 的生成能力来创建符合状态、角色定义的对话内容从而达到构建数据集的目的。
基于图的对话流程图的建模
我们使用有向图(Directed Graph)的数据结构来对通用的任务型对话流程进行建模,这比传统的有限状态机更加灵活和通用。在构建对话流程图时,我们首先定义了一组节点,每个节点代表了对话中的一个关键状态。例如,一个理想的对话过程至少包含以下节点:
- Start: 对话开始
- IntentAcquire: Agent 询问用户意图
- UserInquiry: 用户发起新的提问
- IntentConfirm: Agent 向用户确认意图 (用户意图不明确时)
- UserConfirm: 用户确认意图
- UserDeny: 用户否认意图
- AskSlot: 追问用户关于该意图的关键信息(槽位)
- ProvideSlot: 用户提供或更新关键信息(槽位)
- FunctionCalling: 调用功能,传递槽位信息
- Chitchat: 用户闲聊
- End: 对话结束
在定义了节点之后,我们使用边将可以进行状态转移的节点连接起来,从而构建一个有向图用来表征对话过程中所有可能的转移关系,如下图。在这个图中,主要的变量是用户对话内容,Agent 的回复内容是随着用户的对话意图和槽位状态发生的变化而变化。 对于每个原子对话(Atomic Dialogue)来说,我们认为在用户提供了清晰的意图以及提供了全部的必填槽位信息之后,这个原子对话就算结束了,即可以触发 Function calling 的指令。
图 1. 对话流程转移图示例(可能没有覆盖全部场景)
初始状态随机生成
在对话系统的开始阶段,用户的首次提问可能包含从零到全部所需槽位的不同信息量。为了模拟这种多样性,我们可以使用蒙特卡洛方法来随机决定哪些槽位在用户的首次提问中被提及。具体来说,对于一个意图中的所有槽位,我们可以生成一个由 0 或 1 组成的随机数组,其中 0 表示该槽位不能再首次提问中提及,而 1 表示需要被提及。
例如,考虑一个酒店预订任务,可能的关键信息包括「入住日期」、「退房日期」 和 「房间类型」。利用上述的方法,我们可以为每个槽位生成一个对应的随机值,从而决定用户的首次提问中需要包含哪些信息。这不仅增加了对话样本的多样性,也使得训练数据集更加贴近真实世界的对话情况。
随机游走模拟用户行为
初始状态生成了之后,我们需要生成生成多样化的对话路径,这里采用蒙特卡洛方法使得当前的对话状态在建立好的对话转移状态图中随机游走。在每个状态完成之后,将随机选择下一个状态,各状态的转移概率可以根据经验进行定义,从而模拟用户可能采取的不同行动。例如,用户在首问中没有提供全部的必填槽位, Agent 将发起槽位的追问,对于 Agent 的追问,用户可能认真的回答槽位信息,也有可能发起闲聊,还有可能改变了主意,问了一个新的问题,不同的转移路径我们可以设置不同的概率,例如上面的转移路径我们根据经验分为设置概率为 [0.8, 0.1, 0.1]。通过这种随机游走的方式,可以生成不同的对话状态路径,每条路径都代表了一种可能的用户行为和 Agent 响应。这些路径为我们提供了丰富的训练数据,帮助对话系统学习如何处理各种情况。
对上下文理解能力的增强
在实际对话中,用户通常不会在每个回合都重复提供所有相关信息。相反,他们会根据上下文,利用代词、省略或简化的表述来替代之前已经提及过的内容。为了让对话系统能够正确理解这种上下文依赖的表达方式,我们需要在训练数据中模拟这种用户行为模式。
具体来说,我们将对话分为多个阶段,每个阶段对应不同的任务意图。在后续阶段生成语料时,我们会考虑之前阶段已经提供的槽位信息。如果用户的新问题与之前的问题存在槽位重叠,且该槽位已在先前回合中提供过,那么在生成新问题时,我们将有意识地省略这部分信息,只保留用户需要补充的新信息。
例如,假设用户之前已经询问过「成都市内哪家火锅好吃」,这句话中包含了用户想要了解的位置和餐厅类型两个槽位信息。在后续对话中,如果用户想询问这些餐馆的价格区间,可能会使用「它们的价格大概是多少?」这样的省略式表述,而非重复提供完整的问句。通过模拟这种情况,我们可以增强模型对于上下文依赖的理解能力。
基于 LLM 的对话内容生成
LLM 在这一过程中扮演了至关重要的角色。我们利用 LLM 的强大生成能力来模拟用户的提问和系统的追问,生成接近真实对话的数据。例如,以推荐餐厅这个意图为例, 用于生成首问的 Prompt 可以这样写,
你是一个用户,你现在想要「根据自己的位置、兴趣和预算,让智能客服推荐当地的餐厅」,请向智能客服寻求帮助
你的问题需要满足以下几个条件
1. 在问题中需要提到具体的用户当前的区域或希望探索的区域。
2. 在问题中一定不要提到具体的用户感兴趣的餐厅类型,中餐,日料,西餐等。
3. 在问题中一定不要提到具体的用户的最大预算。
请生成一句满足当前的场景和设定的问题
LLM 广阔的知识面为我们提供了丰富的语言资源,支持我们模拟各种场景的对话。此外,LLM 还能够根据上下文生成连贯且逻辑性强的回复,进一步提高了数据集的质量。
通过 RAG 增强生成对话的质量和多样性, 在任务型对话 Agent 中,尤其是当涉及到特定业务功能开通的意图时,领域知识会显得十分重要。为了在用户问题中融入这些领域知识,同时保持问题的多样性,我们可以利用 RAG 技术将领域知识附加到 LLM 中。首先,我们构建一个包含所有业务功能的槽位列表,这些功能可能包括各种服务、产品特性或用户可能感兴趣的特定操作。接着,通过随机化的方法,从这个槽位列表中选择一个或多个功能,这一步确保了每次生成的问题都可能关注不同的业务点,增加了对话的多样性。然后,我们设计一个 RAG 模板,这个模板预留了位置来插入特定的业务功能信息。接下来,我们将随机选中的业务功能信息填充到模板中,生成具体的用户问题。
易扩展的意图配置
对于任务型 Agent 来说,对话的目标是一致,即收集足够的信息帮助用户执行任务。我们可以通过一个 YAML 文件来对任务的详细内容和槽位信息进行描述,用户意图增加和减少都可以通过编辑一系列 YAML 配置文件来实现,而无需对有状态转移图或生成流程进行复杂的更改。这种设计提高了本文方案的可扩展性。例如想生成一个根据地点,餐厅类型,最大预算推荐餐厅任务相关的数据集,只需要编写如下配置文件即可:
name: recommend_restaurant
description: 根据自己的位置、兴趣和预算,让智能客服推荐当地的餐厅
parameters:
- name: destination
description: 用户当前的区域或希望探索的区域。
type: text
required: True
- name: cuisine_type
description: 用户感兴趣的餐厅类型,中餐,日料,西餐等
type: text
required: True
- name: budget
description: 用户的最大预算
type: float
required: False
目标为任务型对话 Agent 的 LLM 微调
我们选择 LLaMA Factory 作为我们的微调工具,这是一个开源的高效微调框架,专为 LLMs 设计,能够适应各种下游任务,并且兼容大部分主流模型,同时提供一个图形界面 LLaMA Board 帮助用户更友好的执行和管理微调任务。对于本文的任务,对 LLM 按照任务型 Agent 方向进行微调,因为需要学习的知识较少,并且不会对模型整体的回答能力进行大的变化,这里我们采用 LoRA 微调技术对模型进行 SFT。在基础模型的选择上,没有经过指令微调的 Base 模型和有过指令微调后的 Chat 模型(e.g., Qwen 1.5 和 ChatGLM3)都会被纳入选择范围。
图 2. 面向 LLM 微调的 LLaMA Board 系统
LLaMA Factory 支持 Alpaca 和 ShareGPT 两种数据集的格式,这里我们将上面使用蒙卡 + LLM 生成的数据集处理为 ShareGPT 格式。下面就是个 sharegpt 格式包含功能调用内容的数据例子,其中 conversations 中是对话历史,tools 是当前对话中所有可用的工具。
{
"conversations": [
{
"from": "human",
"value": "I saw a dress that I liked. It was originally priced at $200 but it's on sale for 20% off. Can you tell me how much it will cost after the discount?"
},
{
"from": "function_call",
"value": "{\"name\": \"calculate_discount\", \"arguments\": {\"original_price\": 200, \"discount_percentage\": 20}}"
},
{
"from": "observation",
"value": "{\"discounted_price\": 160}"
},
{
"from": "gpt",
"value": "The dress will cost you $160 after the 20% discount."
}
],
"tools": "[{\"name\": \"calculate_discount\", \"description\": \"Calculate the discounted price\", \"parameters\": {\"type\": \"object\", \"properties\": {\"original_price\": {\"type\": \"number\", \"description\": \"The original price of the item\"}, \"discount_percentage\": {\"type\": \"number\", \"description\": \"The percentage of discount\"}}, \"required\": [\"original_price\", \"discount_percentage\"]}}]"
}
为了保证不同的意图和槽位能被相对准确的识别到,根据实践经验我们认为训练数据量需要满足意图数 x 槽位数 x 500 的规模。这里我们构造了 5 个任务,分别是根据实时汇率转换货币金额,了解某个地区的习俗和文化特点,根据用户的位置或兴趣,推荐附近的博物馆,根据自己的位置、兴趣和预算,推荐当地的餐厅以及查询去某个目的地的交通方式。每个意图包含 2 至 3 个槽位,共生成了 6000 条左右的数据,覆盖了 5 个任务大部分用户状态变化路径,接下来将对微调训练的部分进行详细的介绍。
实验结果
本文选择在 A6000 显卡上进行微调,微调精度选择 fp16,LoRA Rank 设置为 4,训练 3 个 Epoch。在不使用 flash attention 加速时整个训练过程耗时 1.5h 左右,对于 6B - 7B 的模型,显存占用在 20 - 22G 左右。实验对象包括目前市面上主流的开源模型,ChatGLM3 6B,Qwen 1.5 7B,Yi 6B 系列的 Chat 模型和 Base 模型。在额外构造了 100 个验证对话集对模型进行评估之后,这里将微调前的 Qwen 1.5 Chat 模型作为基线对比了不同模型微调后的表现,
Model | Size | Intent Accuracy | Intent Recall | Slot Accuracy | Slot Recall |
---|---|---|---|---|---|
ChatGLM3 Chat | 6B | - | - | - | - |
ChatGLM3 | 6B | - | - | - | - |
Qwen 1.5 Chat | 7B | 96.23% | 97.76% | 93.98% | 95.11% |
Qwen 1.5 | 7B | 94.79% | 98.31% | 91.80% | 94.01% |
Yi Chat | 6B | 92.73% | 95.44% | 89.21% | 91.77% |
Yi | 6B | 94.19% | 97.09% | 91.34% | 92.17% |
Qwen 1.5 Chat(微调前), Baseline | 7B | 82.64% | 85.32% | 75.74% | 89.67% |
💡 ChatGLM3 在 LoRA 微调之后幻觉情况特别严重,无法称之为可用,因此 ChatGLM3 系列的模型暂无法计算具体的性能指标。可能是因为 ChatGLM3 的 Prompt 格式比较特殊, LLaMA Factory 官方没有对 ChatGLM3 进行特殊优化。同时,在 ChatGLM3 的 Repo 中发现官方删除了 ChatGLM3 使用 P-tuning 微调 Agent 的代码,给出的理由是效果较差。关于 ChatGLM3 的 Agent 微调至此作罢,接下来会持续跟踪后续进展。
从对比结果可以发现,经过我们微调后的 Qwen 1.5 Chat 模型在整体性能上表现最佳,相对于 Baseline(微调前的 Qwen 1.5 Chat 模型),除了微调不成功的 ChatGLM3 之外,性能上都有比较显著的提升。Qwen 1.5 的意图召回率略高于 Qwen 1.5 Chat 的原因是 Qwen 1.5 出现幻觉的概率较高,在给出 Tools 之后,没有明显调用工具的提问也较容易触发工具调用。
对比一下 Qwen 1.5 Chat 微调前和微调后的表现,下图 3 为 Qwen 1.5 Chat 微调前的对话表现,图 4 为 Qwen 1.5 Chat 经过微调后的对话表现。可以明显发现微调后的模型对于槽位的识别方面提升很大,并且还附加了槽位追问的能力。
图 3. Qwen 1.5 Chat 微调前的对话表现
图 4. Qwen 1.5 Chat 微调后的对话表现
此外,Agent 对于用户在对话中省略主语时也能正确的识别槽位信息,如下图所示,用户在说「5000 人民币可以在当地还多少钱呢」的时候,模型能够智能的将「当地」和上文中提到的「京都」联系起来,在上下文结合和理解上的表现上比传统的 Rasa-like 对话 Agent 表现的更加智能和灵活,达到了我们的预期水平。
图 5. 本文微调的 Agent 模型超越普通 Rasa-like 对话 Agent 的能力
对比经过指令微调的 Chat 模型和没有指令微调过的 Base 模型我们还发现,经过指令微调的 Chat 模型得到的微调反馈最佳,特别是经过 Agent 相关指令微调的 Chat 模型,这主要是这类模型已经使用了大量的 Function Calling 进行训练,我们在此基础上进行微调实际上属于同方向的增量学习,需要 Agent 额外的学习成本更小。
结论
本文提出了一种利用蒙卡方法和 LLM 生成训练数据集,并将其与 LLaMA Factory 框架相结合,高效微调多种语言模型,构建任务型对话 Agent 的新颖方案。该方案不仅保留了大语言模型强大的理解和生成能力,而且显著提高了微调后模型在意图识别、槽位填充等关键任务上的性能表现。
与传统的模块化对话系统相比,本文方法构建的端到端 Agent 架构更加简洁高效,易于部署和维护。实验结果表明,经过微调的语言模型不仅能够准确识别用户意图和关键信息,还能根据上下文理解用户的省略表达,并在必要时主动追问槽位信息,相较于微调前的模型,展现出更强的理解和交互能力,相较于传统的模型,展现出了更多的智能性。
尽管如此,该方案仍然存在一定的缺陷,首先在数据集的构建方面,靠人脑整理的行为状态图很难考虑到所有可能的用户路径,建模的过程十分耗时。在 Agent 微调方面,准确率还有待进一步提高,因为是 E2E 的系统,整体的可控性和可解释性相对较差。未来我们的工作重点将包括,1. 优化数据集生成方法,例如结合蒙特卡罗树搜索(MCTS)和打分模型的方案对对话状态空间进行探索和筛选。 2. 进一步优化微调方法、探索提高模型可解释性的技术路线等,以期在保持语言模型强大能力的同时,进一步增强任务型对话 Agent 的性能和可靠性。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
![](https://img-blog.csdnimg.cn/img_convert/0dc35641cd2d85e39db6e8cb368fa5cb.png)