实战经验:在 GoDaddy 运营 LLM 中学到的 10 个教训 [译]
自从 ChatGPT 于 2022 年 12 月发布以来,GoDaddy 在 AI 方面进行了大量投资。在此期间,我们在众多项目中利用大语言模型(LLM)帮助客户创建网站内容、社交营销活动、设计标志,甚至为他们的项目找到最佳域名。我的团队——数字关怀团队,利用 LLM 在我们的消息渠道(短信、WhatsApp 和网络)中提供卓越的客户体验。
GoDaddy 每天在我们的消息渠道中收到超过 60,000 个客户联系。许多对话开始于与我们某个机器人进行互动。我们对 LLM 技术在客户支持中的应用充满了期待和兴奋。早期实验表明,LLM 的表现优于旧的自然语言处理单元;然而,运营 LLM 并非易事。我们在运营这些模型的过程中学到了很多经验教训,这篇文章讨论了这些发现。
1. 有时候一段提示词不够用
Digital Care 首次尝试大语言模型技术是我们的 AI 助理。这个助理会与客户沟通,直到能够将对话归类到我们用于分类支持请求的二十个支持主题之一。当主题确定后,助理会提出一系列特定于该主题的问题,帮助我们的 Guides(人工支持代理)加快支持过程。一旦收集到反馈,助理会利用这些信息将对话分配到合适的支持队列。
最初的实验效果相当不错,但随着我们添加更多的主题和问题,我们的实现开始出现问题。用于驱动对话的提示词不断增加,而大语言模型有时会问与目标主题无关的问题(从其他主题借用问题)。我们的第二次实验尝试为常见的支持问题提供自助服务。助理不再是问问题并路由到支持队列,而是引导用户解决问题的过程。
到我们启动第二次实验时,新提示词膨胀到超过 1500 个 token,导致高运营成本,有时在长对话中超过 token 限制。随着我们整合新指令和上下文,提示词的准确性也下降了。引入检索增强生成(Retrieval Augmented Generation, RAG)并将相关文章和内容整合到提示词中后,内存管理变得越来越重要。本质上,我们采用了 mega-prompt 方法——创建一个单一提示词来满足所有用户交互。
我们很快意识到,使用任务导向的提示词可以更高效地处理复杂的对话流程。任务导向的提示词专注于单一任务,例如“收集咖啡订单”,使作者能够用更少的 token 给出简明的指令,提高准确性。作者也能更好地控制输出(为特定响应进行微调),因为可行的答案范围更小。然而,任务导向的提示词的具体性意味着它们不适用于一般的、开放式的对话。我们需要在这两种策略之间找到平衡。
在我们尝试融合这两种方法的实验中,我们在聊天流程的关键转换点使用了任务导向的提示词。例如,当用户需要转接到人工客服时,我们会执行一个任务来提取关键信息,为人工客服提供摘要。在其他情况下,我们会进行搜索,将结果作为提示词的上下文注入对话中。
我们最早尝试将这两种策略结合时,方法有些僵化,严重依赖确定性代码来决定何时引导对话到特定提示词。随着我们的方法逐渐成熟化,我们从 Salesforce 的多智能体工作中(特别是BOLAA 论文)获得了灵感。团队转向构建使用控制器 - 委托模式的多提示词架构,其中大提示词作为控制器,将对话传递给任务导向的提示词(委托)。
我们的多智能体实验的初步结果是令人鼓舞的。允许控制器提示词决定何时将任务委托给其他提示词,简化了我们的代码库,同时增强了聊天机器人的能力。尽管我们的实现处于早期阶段,这种提示词架构将会普及,直到模型变得更加精确且大上下文模型的成本降低。
2. 小心结构化输出
AI 机器人生成的纯文本响应非常适合聊天对话场景,但对于基于 AI 分析构建的系统可能不太高效。需要时应该请求 AI 模型生成结构化响应,如 JSON 或代码。一些模型,包括 ChatGPT 功能,已经具备生成结构化输出的能力。
然而,验证输出的响应非常重要。在引入功能之前,我们最初使用 ChatGPT 3.5 Turbo 进行的试验表现出显著的可靠性挑战。我们构建了一个自定义解析器,从我们在模型中检测到的典型四到五种错误模式中提取有用信息。幸运的是,ChatGPT 功能的实现提高了准确性,尽管它们并不完美(我们在 1% 的 ChatGPT 3.5 请求和 0.25% 的 ChatGPT 4 请求中遇到了无效输出)。
我们发现了几种增强结构化输出可靠性的策略:
- 最小化 prompt 温度以获取结构化结果。这样可以通过减少随机性来提高 token 的可预测性。
- 考虑为涉及结构化内容的任务采用更高级(且更昂贵)的模型。
- 设计用于响应用户查询的模型,如 ChatGPT,在生成结构化响应时会遇到更多问题。例如,收到的输出通常由纯文本和结构化格式组成:
I'm sorry, I can't assist with this issue. I will transfer you to acustomer support agent for further help.{"transfer": true,"intent": "email","message": "I will connect you with customer support."}
- 如果您使用的是没有原生结构化响应的模型或使用更经济的模型,建议在聊天周期中部署两个并行提示词——一个用于生成结构化响应,另一个用于与用户互动。
3. 提示词无法在不同模型间通用
一个常见的误解是,一组提示词(本质上是文本指令)可以在不同的模型(例如 Titan、LLaMa 和 ChatGPT)之间普遍适用,并保持一致的效果。我们的研究结果表明,这不仅是不真实的,即使是同一模型的不同版本(例如 ChatGPT 3.5 0603 和 ChatGPT 3.5 1106)也会表现出明显的性能差异。
为了证明这一点,GoDaddy 对其 AI 助手进行了实验,比较了 ChatGPT 3.5 Turbo(0603)和 ChatGPT 4.0 在处理支持问题上的效果。起初,我们假设 ChatGPT 4.0 的表现会优于 3.5 Turbo。然而,我们仍在测定两者的性能差异和总体运营成本。
在实验的第一阶段,我们对两个版本(3.5 和 4.0)使用了相同的提示词。由于 ChatGPT 3.5 的性能低于预期,有时在处理支持案例时适得其反,例如未能适当地转接客户和错误地诊断问题,我们在三天后停止了实验。
在随后的尝试中,我们为每个模型调整了提示词。结果,我们注意到 ChatGPT 3.5 组的性能有所改善,问题减少。此外,在随后的实验中,我们将两个版本(gpt-3.5-turbo-1106 和 4.0)升级到了 11 月发布的版本。令人惊讶的是,即使在没有修改提示词的情况下,3.5 和 4.0 版本之间的性能差距也显著缩小。
我们得出结论,团队必须不断微调和测试提示词,以验证其性能是否如预期。
4. AI“安全措施”是必要的
使用大语言模型 (LLM) 存在一个固有风险,那就是它们的输出具有概率性。我们见过在数千次测试中表现良好的提示词在部署给用户时未能提供预期结果。我们在早期实验中犯的一个关键错误是允许模型决定何时转交给人类而没有为用户提供应急措施。用户有时会被拒绝转交的 LLM 卡住。
这些失败警示我们,有些操作不能由模型决定。例如,我们不应该允许 LLM 在没有用户审查过程的情况下进行股票交易。简而言之,我们需要为我们的 AI 应用程序设置“安全措施”。在 GoDaddy,我们实施了几项安全措施,以尽量减少次优 AI 决策的不利影响。首先,我们的聊天系统(和其他工具)使用控件来检查 AI 响应、用户消息和提示词指令中的个人身份信息和冒犯性内容。
我们在聊天系统中使用确定性方法来决定何时将对话转交给人类。例如,我们依赖通过代码识别的终止词语,而不是模型的判断。我们还限制了机器人 - 客户聊天交互的次数,以防止客户无限期地被卡住。我们确保可能对客户产生负面影响的敏感操作通过 LLM 外部的渠道获得批准。这种做法减少了模型独立采取可能混淆或伤害用户的行动的可能性。
最后,当情况不确定时,我们默认为人工干预,因为鉴于当前 AI 的能力,某些行动存在不值得冒的风险。
5. 模型可能会很慢且不可靠
我们在模型运营过程中学到的一个重要教训是,模型可能会很慢且不可靠。我们曾遇到过大约 1% 的聊天在模型提供商(例如 OpenAI)处失败。虽然公司可能会改进其系统的可靠性,但尚不清楚他们将如何解决延迟问题。我们的使用发现,像 ChatGPT 4.0 这样具有更大上下文容量(更强大)的模型,平均响应时间在 1000 个 token 以内为 3-5 秒。当 token 数量增加时,性能显著下降(我们曾看到调用持续长达 30 秒——当我们让客户端超时时)。虽然 ChatGPT 3.5 Turbo 的延迟要低得多,但新一代模型比以前的版本更慢的趋势并不令人鼓舞。
幸运的是,行业内对处理缓慢、不可靠的系统有丰富经验。在调用大语言模型时实施基本的重试逻辑可以减轻大多数可靠性问题。然而,这通常会带来因大语言模型调用本身固有的延迟而产生的成本。例如,我们应该等待 ChatGPT 4 请求多长时间后再重试,如果我们重试,调用者是否会接受额外的延迟?另一种策略是以花费更多钱为代价,进行冗余、并行调用模型。
聊天系统对延迟和可靠性问题非常敏感。客户带着问题来到这些系统,我们最不想做的就是通过糟糕的体验来加重他们的问题。我们的系统特别容易受到延迟的影响,因为我们的上游通信服务提供商对我们的集成调用有 30 秒的超时。大语言模型正在迫使我们走向异步响应(即,确认来自提供商的请求并使用 API 向客户发送消息)。我们建议,特别是如果你不受现有架构的限制,采用大语言模型提供的流 API。虽然实现流 API 更复杂,但它有可能提供更好的用户体验。
6. 内存管理的难题
从我们的角度来看,开发对话式 AI 助手最具挑战性的任务之一是管理 LLM 的上下文。虽然行业中有提供大上下文大小的模型变体(例如 OpenAI GPT 提供最多 32,000 个 token,Anthropic Claude 提供最多 100,000 个 token),但在大规模使用时成本可能会很高。更多的上下文并不总是更好(如关于 mega 和任务导向提示词的第一点所述),因为这可能导致模型在预测中固守重复的概念或优先考虑最新的 token。
AI 社区提出了许多内存管理策略。LangChain 库包括多种技术,如缓冲区(保留最后的 N 条消息或 token)、摘要、实体识别、知识图谱、通过相关性动态检索(通过向量存储)以及前述技术的组合。
对于简短的对话,最好保留整个对话内容。过早总结用户和助手的消息可能会降低 LLM 随后响应的准确性。对于较长的对话,总结对话的早期部分、跟踪命名实体并尽可能保留后期对话内容对我们非常有效。对于 ChatGPT,我们了解到,在模型有机会响应之后,有时移除工具使用后的结果(例如函数消息)是有益的。保留这些消息会导致模型的不可预测性,包括对结果的固守。
最后,在我们深入研究多智能体架构的过程中,我们正在考虑使用“堆栈”来实现内存。核心思想是为委托提示词提供临时工作内存,但在对话焦点回到控制器时收获(并总结)结果。
7. 自适应模型选择将是未来的发展方向
我们在 LLM 项目的早期阶段学到的另一个教训是需要动态更改模型,以解决可靠性和成本问题。一个令人痛心的例子是 ChatGPT 多小时的停机,导致我们的聊天机器人无法运行。在理想情况下,我们应该能够更换供应商并继续我们的运营(即使是降级能力)。
一个不那么戏剧化的场景是当对话接近记忆限制时切换到更高上下文模型(例如,从具有 4k 上下文的 ChatGPT 3.5 Turbo 切换到 32K 上下文)。我们正在探索这种方法,以应对 AI 智能体工具使用可能带回的过多数据。我们可以应用相同的概念,在产品停机期间支持联系激增时最小化支持成本,或者在处理不满意的客户时利用更准确(和更昂贵)的模型。
虽然我们还没有实现自适应模型选择,但我们已经看到了对这一方法的兴趣。我们怀疑,随着 LLM 实施的成熟以及公司寻求提高技术的有效性和经济性,动态选择模型的需求将变得越来越重要和普遍。
8. 有效使用 RAG
RAG 的工作原理是从外部源检索信息,将内容添加到提示词中,然后调用大语言模型 (LLM)。其目标是提供模型可能没有的参数化上下文背景中的信息。我们最初的 RAG 实现涉及根据用户消息在每次提示词调用时执行查询。结果令人失望。根据我们的经验,通常需要三到四条用户消息才能理解客户的问题,因为大多数前几条消息都是寒暄。当我们过早检索文档时,由于将模型的注意力集中在错误的内容上,生成的准确性降低了。
后续实现涉及在确定对话意图后切换到专门的 RAG 提示词。虽然这种方法有效,但缺乏灵活性。我们需要多个提示词和一个状态机来进行对话建模。我们无意中发现了一种已经成熟的模式,称为 LLM 智能体 (with Tools)。LLM 智能体是与一组操作(工具)配对的提示词。在对话过程中,提示词可以返回一个响应,指示应使用一组参数调用某个操作(例如,getWeatherFor('90210')
)。管理智能体的软件执行操作(“调用 weather.com”)并将结果作为新消息提供给提示词。提示词利用这些结果继续与用户对话。
然而,我们发现有些情况下在工具使用之外利用 RAG 是有意义的。例如,我们的对话设计师团队维护的“语音和语调”指令,我们希望包含在每个提示词中。另一个用例是动态提供一组特定提示词可用的标准支持问题,但可以由我们的运营部门动态更新。
我们得出结论,有两种实施 RAG 的基本模式。第一种模式涉及包括动态内容,以帮助自定义提示词的行为。第二种模式是提供与个别对话相关的内容。这种模式还涉及允许模型决定何时收集了足够的信息来生成自己的搜索词(作为 LLM 智能体实现)。使用模型生成搜索查询,使知识库搜索的相关性得到了提高,从而提升了 AI 助手推荐的质量。
9. 调整你的数据以适应 RAG
我们在实施 RAG 时学到的另一个教训是将我们的数据集转换为对模型更有用的格式。大多数文档(文章、网站等)包含华丽的语言和冗余信息。如果模型经常阅读这些信息,额外的内容将导致模型使用更多的 tokens,并可能损害模型预测的性能。
我们不使用原始内容,而是使用Sparse Priming Representations (SPRs,稀疏初始表示)来提炼我们的内容。其基本思路是让 LLM 将文档内容总结为对模型优化的表示。我们将文档的 SPR 版本存储在向量库中,并使用该索引进行 RAG。虽然我们尚未将这种技术投入运营,但早期测试很有前景。平均而言,我们看到 tokens 使用量减少了 50% 以上(但我们需要进行更多实验以确定性能是否有所提高)。
以下是将一篇来自 GoDaddy 帮助中心的文章压缩为 SPR 的示例:
示例:
然而,即使是 SPR 也没有解决实施 RAG 的常见问题。我们的知识库中有很多相似的内容。模型执行查询时,可能会返回数百个涵盖相同主题的文件。由于模型的上下文较短,无法使用多个文件,而这几个文件可能会非常相似(任意缩小知识空间)。除了 SPR,我们还在尝试使用文件聚类来将内容分类,并应用 SPR 将分类内容简化为单个文件。我们认为这种方法通过减少重复和扩展知识空间来提高性能。
10. 测试!测试!测试
最后也是最重要的一课是,测试往往比构建一个大语言模型(LLM)集成更加困难且费力。对提示词的微小改动可能会对其性能产生重大影响。由于自然语言输入的范围是无限的,因此在前几次用户交互之后,创建自动化测试是不可能的。相反,最合逻辑的自动化测试方法是利用 LLM 来测试其他 LLM。然而,即使这种策略也显得成本高昂,尤其是在你可以每天从 CI 管道中多次运行数千次测试时。
LLM 无法捕捉到人类思维的创造力,因此人类需要不断地测试、审查和监控 AI 系统。我们建议建立必要的报告系统,以便 QA 团队审查 LLM 的输出。我们还发现,在重大发布后的最初几天,团队(开发人员、作家、产品经理、业务分析师和 QA)一起审查记录具有极大价值。拥有一个多领域的审查团队可以让我们快速检测和修复问题。
结论
LLM 是一种改善用户体验的令人兴奋的新工具,但它们也带来了挑战。从理解需要多个提示词到意识到 AI 护栏的重要性,仔细的实施和持续的微调是关键。开发人员必须学习如何高效地管理内存和有效地使用 RAG。此外,我们了解到模型可能会很慢且不可靠,提示词并非普遍适用,结构化输出需要小心处理。随着实现变得越来越复杂,团队应考虑在运行时选择模型以优化性能和成本的策略。最后,彻底的测试和持续的监控对于确保最佳性能至关重要。我们希望这些来自 GoDaddy 的经验教训能为其他踏上 LLM 探索之旅的人提供价值。