既然您已经掌握了使用合成数据进行微调的原理,现在让我们将这些知识付诸实践。本节将指导您创建一个小型、有针对性的合成数据集,用于一个特定的微调任务。我们将侧重于生成指令-响应对,旨在塑造大型语言模型的行为,特别是使其成为一个善解人意的客服代理。这个实践练习将涵盖定义任务、编写生成提示、生成数据,以及将其结构化为微调流程的可用格式。定义您的微调目标明确定义您希望微调后的LLM做什么非常重要,尤其是在生成任何数据之前。一个精确的目标有助于编写有效的提示并评估合成数据的质量。对于本次实践,我们的目标是创建一个数据集,用于微调LLM,使其成为一个善解人意的客服代理。任务: 带着同情心和帮助意愿回复客户提问。LLM的输入(微调后): 客户的陈述或问题。LLM的期望输出: 一个回应,其能识别客户感受、表达理解,并提供具体帮助或后续步骤。目标行为: 耐心、主动倾听(模拟)、解决问题以及始终如一的支持性语气。拥有这个明确的目标将指导我们合成数据生成过程的每一步。选择您的生成方法正如本章前面以及第2章所讨论的,有几种生成合成文本的方法。这些包括基于规则的系统、回译、意译以及使用其他大型语言模型。对于需要特定语言细节、特定角色或复杂指令遵循的任务,使用强大的LLM作为生成器(通常被称为“LLM作为评判者”或简称为基于LLM的生成)是一种非常有效的方法。我们将使用LLM来生成我们的合成数据集。这种方法提供了很大的灵活性,并且在精心设计的提示引导下,能够产生高质量、多样化的示例。编写种子示例(可选但建议)尽管一个足够详细的提示可以指导LLM,但在您的生成提示中提供少量高质量示例(种子示例)可以显著提升输出效果。这些示例充当模板,向LLM展示您想要的指令-响应对的预期结构、风格、语气和复杂程度。以下是用于我们善解人意的客服代理任务的几个种子示例:客户问题(指令部分): “我的订单#ORD12345本应在三天前到达,但追踪信息没有更新。我真的很担心。” 善解人意的回应(输出部分): “I completely understand your concern about order #ORD12345, especially when tracking hasn't updated. That must be frustrating. Let me look into this for you right away. I'll check the latest shipping information and see what we can do to resolve this.”客户问题(指令部分): “我收到了产品,但它不像广告宣传的那样运作。这太令人失望了!” 善解人意的回应(输出部分): “Oh, I'm truly sorry to hear that the product isn't working as expected. I can see how disappointing that would be after anticipating its arrival. We definitely want to make this right for you. Could you please tell me a bit more about what's happening with it?”这些种子示例体现了同理心、积极主动的方法,以及请求更多信息以帮助解决问题。设计生成提示您提供给生成器LLM的提示是这个过程中最重要的部分。它需要清楚地指示LLM要创建什么。对于我们的任务,我们希望LLM生成新的客户问题和相应的善解人意的回应。这里是一个您可以使用的元提示结构示例。这个提示要求LLM以特定的JSON结构生成数据,这可以简化后续的解析。您是一个助手,正在帮助创建一个数据集,用于微调大型语言模型,使其成为一个善解人意的客服代理。您的任务是生成多样化的客户问题和理想的善解人意的回应示例。 请生成一个新的、独特的客户问题以及一个恰当的、善解人意且有帮助的回应。问题应听起来像是来自真实客户,回应应表现出理解、识别感受,并提供明确的后续步骤或帮助。 以下是我们期望的风格和内容的一些示例: 示例 1: 客户问题: "My order #ORD12345 was supposed to arrive three days ago, but the tracking hasn't updated. I'm really worried." 善解人意的回应: "I completely understand your concern about order #ORD12345, especially when tracking hasn't updated. That must be frustrating. Let me look into this for you right away. I'll check the latest shipping information and see what we can do to resolve this." 示例 2: 客户问题: "I received the product, but it's not working as advertised. This is so disappointing!" 善解人意的回应: "Oh, I'm truly sorry to hear that the product isn't working as expected. I can see how disappointing that would be after anticipating its arrival. We definitely want to make this right for you. Could you please tell me a bit more about what's happening with it?" 现在,请生成一个新示例。确保客户问题与提供的示例不同。回应应保持善解人意的语气。 请以JSON对象形式提供您的输出,包含两个键:“customer_query”和“empathetic_response”。 例如: { "customer_query": "一个新的客户问题在此...", "empathetic_response": "一个新的善解人意的回应在此..." }该提示中的主要部分:角色设定: 界定LLM的用途。任务描述: 清楚说明需要生成什么。所需品质: 强调同理心、帮助性、多样性。少量示例: 提供具体例子(我们的种子示例)。输出格式指令: 要求JSON格式,这使得输出易于使用。新颖性指令: 明确要求新的、独特的示例。接下来,您会将此提示发送给您选择的LLM(例如,GPT-4、Claude 3、Gemini Pro或开源模型)。生成合成数据为了生成多个数据点,您通常会编写一个脚本,使用您设计的提示重复调用LLM API。对于每次调用,您可能会稍微修改提示(例如,通过询问有关“账单问题”或“产品功能”等特定主题的问题),或者依赖LLM固有的创造力和温度设置来生成多样化的输出。这是一个Python代码片段,说明了您如何进行此类调用并收集响应。此示例使用一个占位符 call_llm_api 函数。在实际应用中,您会使用 openai、anthropic 或 google-generativeai 等库。import json import time # 避免达到速率限制 # 这是您实际的LLM API调用函数的占位符。 # 它将接收提示并返回LLM的文本响应。 def call_llm_api(prompt_text): """ 模拟对LLM API的调用。 在实际场景中,此函数将使用API客户端(OpenAI、Anthropic等) 将prompt_text发送到LLM并返回其响应。 对于此示例,我们模拟了根据提示要求生成的JSON字符串输出。 """ print("正在模拟LLM调用...") # 根据提示,我们期望得到一个JSON字符串。 # 让我们模拟一个新查询的合理输出。 simulated_json_output = { "customer_query": "I'm trying to use a discount code you sent me, but it says it's invalid. What's wrong?", "empathetic_response": "I'm sorry to hear you're having trouble with the discount code! That's definitely frustrating when you're looking forward to a good deal. I can help with that. Could you please share the discount code with me so I can check its status and details?" } # 在实际API调用中,您可能会得到一个更复杂的响应对象。 # 这里,我们假设核心内容易于提取或已结构化。 return json.dumps(simulated_json_output) generation_prompt_template = """ 您是一个助手,正在帮助创建一个数据集,用于微调大型语言模型,使其成为一个善解人意的客服代理。您的任务是生成多样化的客户问题和理想的善解人意的回应示例。 请生成一个新的、独特的客户问题以及一个恰当的、善解人意且有帮助的回应。问题应听起来像是来自真实客户,回应应表现出理解、识别感受,并提供明确的后续步骤或帮助。 以下是我们期望的风格和内容的一些示例: 示例 1: 客户问题: "My order #ORD12345 was supposed to arrive three days ago, but the tracking hasn't updated. I'm really worried." 善解人意的回应: "I completely understand your concern about order #ORD12345, especially when tracking hasn't updated. That must be frustrating. Let me look into this for you right away. I'll check the latest shipping information and see what we can do to resolve this." 示例 2: 客户问题: "I received the product, but it's not working as advertised. This is so disappointing!" 善解人意的回应: "Oh, I'm truly sorry to hear that the product isn't working as expected. I can see how disappointing that would be after anticipating its arrival. We definitely want to make this right for you. Could you please tell me a bit more about what's happening with it?" 现在,请生成一个新示例。确保客户问题与提供的示例不同。回应应保持善解人意的语气。 请以JSON对象形式提供您的输出,包含两个键:“customer_query”和“empathetic_response”。 """ synthetic_data_points = [] number_of_examples_to_generate = 5 # 对于真实数据集,这个数量会大得多 for i in range(number_of_examples_to_generate): print(f"正在生成示例 {i+1}/{number_of_examples_to_generate}...") # 如果需要,您可以在此处添加对提示的轻微修改, # 例如,通过询问与不同主题相关的查询。 # 为简单起见,我们使用相同的提示。 raw_llm_output = call_llm_api(generation_prompt_template) if raw_llm_output: try: data_point = json.loads(raw_llm_output) if "customer_query" in data_point and "empathetic_response" in data_point: synthetic_data_points.append(data_point) print(f"成功生成: {data_point['customer_query'][:50]}...") else: print("错误:LLM输出未包含预期键。") except json.JSONDecodeError: print(f"错误:无法将LLM输出解码为JSON: {raw_llm_output}") else: print("错误:LLM API调用失败或未返回输出。") time.sleep(1) # 如果使用真实API,请遵守API速率限制 print(f"\n已生成 {len(synthetic_data_points)} 个数据点。") # 此时,synthetic_data_points 包含一个字典列表。这个脚本会多次调用LLM API。每个 raw_llm_output 预计是一个JSON字符串,如 {"customer_query": "...", "empathetic_response": "..."}。脚本随后将此字符串解析为Python字典,并将其添加到我们的列表中。为微调构造数据大多数LLM微调框架要求数据采用特定格式,通常是JSON Lines (JSONL)。在JSONL文件中,每一行都是一个有效的JSON对象。对于指令微调,一个流行的格式是Alpaca所用的格式,它包含 instruction、input 和 output 字段。让我们将我们生成的 customer_query 和 empathetic_response 对转换成这种Alpaca风格的格式。instruction 将是模型的一个通用指令。input 将是具体的客户问题。output 将是期望的善解人意的回应。您可以将 synthetic_data_points 列表转换成JSONL文件的方式如下:# (接续之前的Python脚本) # 定义微调任务的通用指令 general_instruction = "You are an empathetic customer service agent. Provide a helpful and understanding response to the customer's query." fine_tuning_dataset = [] for item in synthetic_data_points: # 确保我们有生成步骤中预期的键 if "customer_query" in item and "empathetic_response" in item: fine_tuning_entry = { "instruction": general_instruction, "input": item["customer_query"], "output": item["empathetic_response"] } fine_tuning_dataset.append(fine_tuning_entry) # 保存到JSONL文件 output_filename = "empathetic_customer_service_dataset.jsonl" with open(output_filename, 'w') as f: for entry in fine_tuning_dataset: json.dump(entry, f) f.write('\n') print(f"\n格式化后的数据集已保存到 {output_filename}")您的 empathetic_customer_service_dataset.jsonl 文件中的一行示例如下:{"instruction": "You are an empathetic customer service agent. Provide a helpful and understanding response to the customer's query.", "input": "I'm trying to use a discount code you sent me, but it says it's invalid. What's wrong?", "output": "I'm sorry to hear you're having trouble with the discount code! That's definitely frustrating when you're looking forward to a good deal. I can help with that. Could you please share the discount code with me so I can check its status and details?"}这个JSONL文件现在可以用于许多流行的微调库和平台。工作流程图我们所遵循的过程可以用以下图表概括:digraph G { rankdir=LR; node [shape=box, style="filled", fillcolor="#e9ecef", fontname="Arial"]; edge [fontname="Arial"]; seed [label="种子示例\n(可选)"]; prompt_eng [label="提示工程\n(定义任务和LLM指令)"]; llm_api [label="LLM调用\n(生成原始数据)", style="filled", fillcolor="#a5d8ff"]; raw_data [label="原始生成对\n(例如,问题/回答)"]; structuring [label="数据结构化\n(转换为JSONL,Alpaca格式)", style="filled", fillcolor="#96f2d7"]; dataset [label="微调数据集\n(.jsonl 文件)", peripheries=2, style="filled", fillcolor="#b2f2bb"]; seed -> prompt_eng; prompt_eng -> llm_api; llm_api -> raw_data; raw_data -> structuring; structuring -> dataset; }此图表展示了从最初的种子示例到提示工程、基于LLM的生成、数据结构化,最终创建即用型微调数据集的工作流程。初步审查和后续步骤您现在已经创建了一个小型合成数据集!在将其用于实际微调之前,最好进行以下操作:手动检查样本: 仔细阅读您生成数据的一部分。它符合您的质量标准吗?多样性是否足够?是否存在重复模式或不理想的输出?检查相关性: 每个指令-响应对是否与预期任务(善解人意的客服)一致?考虑数据增强: 如果您的初始数据集太小或缺乏多样性,您可以优化生成提示、使用更多样化的种子示例,或采用第2章的技术进一步增强数据。这个实践练习说明了用于创建微调的合成数据的一个基本流程。随着规模扩大,您将迭代提示设计、尝试不同的生成策略,并执行更严格的质量检查,这些内容我们将在后续章节中涵盖,特别是关于评估的第6章。目前,您已经打下了坚实的根基,可以生成有针对性的数据集,以满足特定需求来定制LLM。