构建生成式 AI 产品的思考 [译]

作者:Juan Pablo BottaroKarthik Ramgopal

在过去的六个月里,我们在 LinkedIn 的团队一直在努力开发一种新的 AI 驱动体验。我们希望重新定义会员们进行工作搜索和浏览专业内容的方式。

生成式 AI 的爆炸性发展让我们重新审视现在有哪些一年前还不可能实现的东西。我们尝试了许多想法,但都没有真正奏效,最终发现了将每个动态和职位发布转变为跳板的潜力:

  • 更快获取信息,例如,从帖子中快速提取要点或了解公司的最新动态。
  • 连接信息点,例如,评估自己是否适合某个职位。
  • 获得建议,例如,改进个人资料或准备面试。
  • 还有更多……

开发是否顺利?成功与挑战有哪些? 构建在生成式 AI 之上并非一帆风顺,我们在许多地方遇到了瓶颈。我们想揭开背后的“工程”故事,分享哪些方面比较容易,哪些方面遇到了困难,以及接下来会发生什么。

移动屏幕显示高级体验
移动屏幕显示高级体验

概述

让我们通过一个真实场景来展示系统的工作原理。

想象一下,你正在浏览 LinkedIn 动态,偶然看到一篇关于设计中无障碍访问性的有趣帖子。在帖子旁边,你会看到一些引导性问题,帮助你深入了解这个话题。你感兴趣并点击了“无障碍在科技公司中的商业价值的一些例子是什么?”

以下是后台的工作过程:

  1. 选择合适的智能体:你的旅程从这里开始。我们的系统会根据你的问题,决定哪个 AI 智能体最适合处理。在这种情况下,它识别出你对科技公司无障碍访问性的兴趣,并将你的查询引导至一个专门处理一般知识查询的 AI 智能体。
  2. 搜集信息:是时候进行一些基础工作了。AI 智能体调用内部 API 和 Bing,寻找具体的例子和案例研究,展示设计中的无障碍如何为科技公司带来商业价值。我们正在创建一个档案,以便提供有根据的回答。
  3. 生成回复:有了必要的信息后,智能体可以开始撰写回复。它过滤并综合数据,形成连贯且信息丰富的答案,为你提供无障碍举措如何推动科技公司商业价值的明确例子。为了避免生成大量文字并使体验更具互动性,内部 API 被调用以附加文章链接或帖子中提到的人的个人资料等附件。

接下来你可能会问“我该如何转行到这个领域?”,我们会重复这个过程,但现在将你引导到一个职业和求职 AI 智能体。只需点击几下,你就可以深入了解任何话题,获得可行的见解或找到下一个重大机会。

这一切大多是由于大型语言模型(LLMs)的出现才得以实现的,我们认为分享我们在其基础上构建过程中遇到的挑战的幕后故事会很有趣。

轻松实现的部分

整体设计

处理用户查询的简化流程图
处理用户查询的简化流程图

图 1: 处理用户查询的简化流程图。KSA 代表“知识共享智能体”,是能够处理用户查询的多个智能体之一。

从上面的解释中,有些人可能已经注意到,我们的流程采用了检索增强生成 (RAG) 的设计模式,这是一种常见的生成式 AI 系统设计模式。构建这个流程比我们预期的要轻松得多。只用了几天时间,我们就搭建了基本框架:

  • 路由: 确定查询是否在范围内,并决定将其转发给哪个 AI 智能体。智能体的例子有:职位评估、公司理解、帖子总结等。
  • 检索: 这是一个回忆导向的步骤,AI 智能体决定调用哪些服务以及如何调用(例如 LinkedIn 人物搜索,Bing API 等)。
  • 生成: 这是一个精确导向的步骤,通过筛选检索到的噪声数据、过滤它们并生成最终的回答。

调优‘路由’和‘检索’感觉相对自然,因为它们具有分类的性质:我们构建了开发集,并通过提示工程和内部模型对其进行了优化。而生成部分则是另一回事。它遵循 80/20 规则;达到 80% 的效果很快,但最后的 20% 花费了我们大部分的工作。当产品期望 99% 以上的回答都应该是高质量时,即使使用最先进的模型,也需要大量的工作和创造力来提升每一个百分点的质量。

对我们有效的做法

  • 固定的三步处理流程
  • 路由/检索使用小模型,生成使用大模型
  • 基于嵌入的检索(EBR),通过内存数据库作为我们的“简易微调”方法,将响应示例直接嵌入到提示词中
  • 每个步骤的专门评估流程,特别是路由/检索

开发速度与团队协作

我们希望在多个团队之间快速推进,因此决定将任务拆分为由不同人员开发的独立 AI 智能体:通用知识、职位评估、帖子要点等。

然而,这种方法引入了一个重大折中。通过任务并行化,我们在速度上取得了进展,但代价是碎片化。当智能体的后续交互可能由不同的模型、提示词或工具管理时,保持一致的用户体验变得具有挑战性。

为了解决这个问题,我们采用了一个简单的组织结构:

  • 一个小型的“横向”工程小组,负责处理共同组件并专注于整体体验。这包括:
    • 托管产品的服务
    • 评估/测试工具
    • 被所有垂直部门使用的全局提示模板(例如,智能体的全局身份、对话历史、越狱防护等)
    • 为我们的 iOS/Android/Web 客户端共享的用户体验组件
    • 一个由服务器驱动的 UI 框架,用于在不更改客户端代码或发布的情况下发布新的 UI 更改。
  • 几个拥有自主权的“纵向”工程小组,负责各自的智能体,例如:
    • 个性化帖子总结
    • 职位匹配评估
    • 面试技巧

对我们有效的做法

  • 分而治之,同时限制智能体的数量
  • 支持多轮对话的集中评估流程
  • 共享提示模板(例如“身份”定义)、用户体验模板、工具和检测手段

我们遇到的困难

评估

评估我们答案的质量比预期的要困难得多。这些挑战大致可以分为三个方面:制定指南、标注的规模化和自动化评估。

  • 制定指南 是第一个障碍。以职位评估为例:点击“评估我与该职位的匹配度”然后得到“你很不适合”并没有多大用处。我们希望它既真实准确又富有同情心。有些会员可能正在考虑转行到他们目前并不擅长的领域,需要帮助了解差距和下一步该做什么。确保这些细节的一致性对标注员评分的一致性至关重要。
  • 标注的规模化 是第二个步骤。最初,团队中的每个人(产品、工程、设计等)都参与其中,但我们知道需要一个更系统的方法,拥有一致和多样的标注员。我们的内部语言学团队构建了工具和流程,使我们能够评估每天多达 500 个对话,并获得以下方面的指标:整体质量评分、幻觉率、责任 AI 违规、连贯性、风格等。这成为我们了解趋势、迭代提示并确保准备上线的主要标志。
  • 自动化评估 是我们的终极目标,但仍在进行中。没有它,工程师只能肉眼检查结果并在有限的示例集上进行测试,同时需要 1 天以上的延迟才能知道指标。我们正在构建基于模型的评估器,以估算上述指标并允许更快速的实验,并在幻觉检测方面取得了一些成功(但这并不容易!)。

我们执行的评估步骤图
我们执行的评估步骤图

图 2: 我们的评估步骤。工程师们进行快速且粗略的评估,以获取大致的指标。标注员提供更细致的反馈,但需要大约 1 天的时间。最终由团队成员进行评判,这提供了全面的评估,但某些指标的单次更改可能需要超过 3 天的时间。

我们的研究方向: 端到端的自动评估系统,以加快迭代速度。

调用内部 API

LinkedIn 拥有大量关于人、公司、技能、课程等独特且关键的数据,这对于构建具有独特和差异化价值的产品至关重要。然而,LLM(大语言模型)并没有使用这些信息进行训练,因此无法直接利用它们进行推理和生成响应。解决这个问题的标准模式是建立一个检索增强生成(RAG)管道,通过该管道调用内部 API,并将其响应注入到后续的 LLM 提示中,以提供额外的上下文来支撑响应。

很多这种独特的数据是通过各种微服务的 RPC API 在内部暴露的。虽然这对于人类编程调用非常方便,但对 LLM 却不太友好。我们通过在这些 API 周围包装“技能”来解决这个问题。每个技能包含以下组件:

  • 对 API 功能及其使用时机的友好描述,便于人类和 LLM 理解。
  • 调用 RPC API 的配置 (如端点、输入模式、输出模式等)。
  • 适合 LLM 的输入和输出模式
    • 原始类型 (如字符串/布尔值/数字) 的值
    • JSON 风格的输入和输出模式描述
  • 将 LLM 友好模式与实际 RPC 模式映射的业务逻辑。

这些技能使得 LLM 能够执行与我们产品相关的各种任务,如查看个人资料、搜索文章/人/职位/公司,甚至查询内部分析系统。相同的技术也用于调用非 LinkedIn 的 API,如 Bing 搜索和新闻。

系统调用使用技能的内部 API 的示意图
系统调用使用技能的内部 API 的示意图

图 3: 使用技能调用内部 API

我们编写提示词,让 LLM 决定使用哪个技能来完成特定任务(通过计划进行技能选择),然后输出调用技能的参数(函数调用)。由于调用参数必须与输入架构匹配,我们要求 LLM 以结构化的方式输出这些参数。大多数 LLM 在训练中都使用了 YAML 和 JSON 来进行结构化输出。我们选择了 YAML,因为它比 JSON 更简洁,因此消耗的 Token 更少。

我们遇到的挑战之一是,尽管大约 90% 的时间里 LLM 的响应包含了正确格式的参数,但仍有约 10% 的时间 LLM 会出错,常常输出不符合提供的架构,甚至不是有效的 YAML。虽然这些错误对于人类来说很容易发现,但却会导致解析代码出错。10% 的错误率足够高,不能轻易忽视,因此我们着手解决这个问题。

解决这个问题的标准方法是检测错误,然后重新提示 LLM 纠正其错误并提供一些额外的指导。虽然这种技术有效,但会增加非小量的延迟,还会因为额外的 LLM 调用消耗宝贵的 GPU 资源。为了解决这些限制,我们最终编写了一个内部防御性 YAML 解析器。

通过分析各种负载,我们确定了 LLM 常见的错误,并编写代码在解析之前适当地检测和修复这些错误。我们还修改了提示词,在一些常见错误周围注入提示,以提高修复的准确性。最终我们将这些错误的发生率降低到了约 0.01%。

我们正在进行的工作:一个统一的技能注册表,以在我们的生成式 AI 产品中动态发现和调用打包为 LLM 友好技能的 API/智能体。

我们正在进行的工作:一个统一的技能注册表,用于动态发现和调用打包为大语言模型友好技能的 API/智能体,适用于我们的生成式 AI 产品。

一致的高质量

团队在第一个月内实现了我们目标基础体验的 80%,然后又花了四个月的时间试图超过 95% 的完整体验——我们努力优化和改进各个方面。我们低估了识别和减少幻觉的挑战,以及质量分数提高的速度——最初迅速上升,然后趋于平稳。

对于能够容忍这种程度错误的产品体验,使用生成式 AI 构建是令人耳目一新的简单。但这也造成了难以达到的期望,初期的快速进展带来了“几乎完成”的错觉,当每增加 1% 的改进速度显著放缓时,这种错觉变得令人沮丧。

构建助手感觉像是从以原则为基础的机器学习转向了调整专家系统中的规则。因此,尽管我们的评估变得越来越复杂,但我们的“训练”主要是提示工程,这更像是一门艺术而非科学

我们正在进行的工作:微调大型语言模型(LLM)以使我们的流程更具数据驱动性。

容量与延迟

容量和用户体验的延迟始终是我们关注的重点。以下是几个方面:

  • 质量与延迟:诸如思维链(CoT)之类的技术在提高质量和减少幻觉方面非常有效。但它们需要用户看不到的 Token,因此增加了他们感知到的延迟。
  • 吞吐量与延迟:运行大型生成模型时,通常会发现首次 Token 响应时间(TTFT)和 Token 间时间(TBT)随使用率增加而增加。在 TBT 的情况下,有时可能是线性的。如果愿意牺牲这两个指标,我们的每秒 Token 数(TPS)最多可提高 2 到 3 倍,但我们最初不得不对其进行严格限制。
  • 成本:GPU 集群既难以获取又昂贵。在开始时,我们甚至必须设定测试产品的时间表,因为测试会消耗太多 Token,使开发人员无法工作。
  • 端到端流式处理:完整答案可能需要几分钟才能完成,所以我们所有请求都使用流式处理以减少感知延迟。更重要的是,我们实际上在整个流程中都使用流式处理。例如,LLM 响应决定调用哪些 API 时会逐步解析,我们在参数准备好后立即调用 API,而不等待完整的 LLM 响应。最终综合的响应也使用我们的实时消息基础设施流式传输到客户端,同时进行诸如信任/责任 AI 分类的逐步处理。
  • 异步非阻塞管道:由于 LLM 调用可能需要很长时间处理,我们通过构建一个完全异步非阻塞的管道来优化服务吞吐量,从而避免因 I/O 阻塞线程而浪费资源。

这些有时会在它们之间产生有趣的相互影响。例如,我们最初仅限制了 TTFT,因为它直接映射到我们的初始产品的用户延迟。当我们解决幻觉问题并在提示中采用思维链时,忽略了 TBT 对我们的影响更大,因为任何“推理”Token 都会成倍增加用户延迟(例如,对于一个 200 个 Token 的推理步骤,即使 TBT 增加 10 毫秒,也意味着额外的 2 秒延迟)。这导致我们的

一个公共项目突然发出警报,某些任务超时,我们不得不迅速增加容量以缓解问题。

我们正在进行的工作

  • 将更简单的任务转移到内部微调模型。
  • 为 LLM 部署提供更可预测的部署基础设施。
  • 减少每个步骤的 Token 浪费。

收获

总结与收获

说了这么多,何不让产品自己说话呢?

带有 AI 驱动洞察和收获的手机屏幕
带有 AI 驱动洞察和收获的手机屏幕

这还不错!尤其是后续建议,可以让你开始一场探索之旅,就像在维基百科上一样。

随着我们不断优化质量、开发新功能和加速优化流程,很快我们将推广给更多用户。

取得这些成就是一群杰出人士的共同努力,我们将在不断学习中分享更多技术细节。敬请关注!