编者按:以下是一篇来自 Dosu 首席执行官 Devin Stein 的客座博客文章Dosu。 Dosu 是一位工程队友,帮助你开发、维护和支持软件。

如今众所周知,构建生产级 LLM 产品非常困难。可靠性对任何产品的成功都至关重要,但当你的产品建立在一系列概率函数之上时,确保可靠性绝非易事。

在Dosu,我们持续迭代我们的产品。对于我们做出的每一次改动,我们都需要了解它对最终用户的影响。评估驱动开发(EDD)让我们能够自信地发布。在过去几个月里,LangSmith 让我们能够轻松监控和搜索 Dosu 的活动,从而规模化地实践 EDD。

什么是 Dosu?

如果你曾在 LangChain GitHub 仓库上花过一些时间,你可能已经见过Dosu,一位帮助开发、维护和支持软件项目的 AI 队友。

Dosu 诞生于我做开源软件维护者的经历,这是一个有回报但出了名耗时的角色。随着我的 OSS 项目越来越受欢迎,我发现自己花在提供支持上的时间远远多于开发新功能。

对于维护者来说,这份责任经常导致倦怠,并促使一些人宣布 issue 破产,这一过程就是简单地关闭所有未解决的 issue 和 PR。OSS 社区也深受这种情况之苦,因为人们常常要等上几天、几周甚至几个月,才能等到维护者回复他们的 issue。

这种现象并非开源独有。在行业内,高达85% 的开发者的时间花在非编码任务上,比如回答临时问题、分诊 issue 和处理开销性事务。

Dosu 把这些任务从开发者的待办清单上拿走,让他们能做自己热爱的事:保持心流、写代码、发布出色的功能。同时,Dosu 也是 OSS 社区的资源,每当社区成员遇到意想不到的问题,或是有只有代码才能回答的新奇问题时,Dosu 都能给他们即时的反馈。

早期

Dosu 于 2023 年 6 月下旬上线。那时,我们的量还足够小,可以逐一检查每一条回复。每天,仅凭grep和print声明,我们仔细梳理了日志,以找出需要改进的地方。

这项工作很辛苦,但对于设计和开发 Dosu 的架构很重要。它帮助我们的团队深入理解人们试图如何使用 Dosu、它擅长处理哪些类型的请求,以及它在哪些方面存在不足。

一旦我们知道需要改进什么,问题就变成了如何改进。与传统代码更新不同,更改 LLM 逻辑并不简单。很难知道一个小改动会如何影响整体性能。很多时候我们看到,对提示词做一点微调会在某个领域带来更好的结果,却在另一个领域造成退化。

我们需要一种方法来衡量改动带来的影响。对于每一次改动,我们都想确保自己是在:

  1. 在表现良好的领域保持性能
  2. 在表现挣扎的领域提升性能

正是在这些早期日子里,我们转向了评估驱动开发,以此来衡量我们的进展。

评估驱动开发

评估驱动开发(EDD),就像测试驱动开发一样,为我们提供了开发所依据的最终目标。评估——或称“evals”——是我们理解更新和新功能的基线。EDD 帮助我们理解对 Dosu 的核心逻辑、模型或提示词所做的任何改动会带来什么影响。

借助 EDD,我们有一套定义明确的流程来改进 Dosu:

  1. 用少量初始评估创建一个新行为
  2. 向用户发布该新行为
  3. 在生产环境中监控结果并识别失败模式
  4. 为每种失败模式向我们的离线评估中添加示例
  5. 基于更新后的评估进行迭代以提升性能
  6. 重新发布并重复

在 Dosu 起步时,这套开发工作流对我们很有效,但随着使用量增长,跟上 Dosu 的活动变得困难。

在规模化下保持高质量标准

如今,Dosu 已安装在数千个代码仓库上,全天候生成响应。我们构建了数十个子模块来智能处理不同类型的场景,并且随着模型和该领域研究的发展,我们不断迭代解决问题的方法。

虽然 Dosu 的增长令人兴奋,但也带来了挑战。Dosu 活动量的增加使得几乎无法监控响应并识别生产环境中的失败模式,而这对于我们的 EDD 工作流至关重要。

我们决定是时候升级我们的 LLM 监控技术栈了。我们寻找一款工具,它不仅能帮助我们监控 Dosu 的活动,还要足够灵活以融入我们现有的工作流。我们的一些标准包括:

  • 提示词必须存放在 Git 中——秉承 EDD 的理念,我们将提示词视为代码。对提示词的任何更改都必须以与代码更改相同的标准来对待。
  • 代码级追踪——Dosu 不仅仅是一系列 LLM 请求。我们希望在单个 trace 内追踪 LLM 请求之间的元数据。
  • 易于导出数据——我们已有现成的评估数据集和工具,希望保留它们。
  • 可定制且可扩展——LLM 领域发展迅速,构建 LLM 应用没有标准方式。我们希望能够控制追踪哪些元数据,并能够定制工具以满足我们的需求。

我们探索了LLM 监控与评估领域,试图找到一款满足我们需求的产品。在与我们的早期合作伙伴之一 LangChain 团队通话后,我们很高兴地得知 LangSmith 似乎满足了所有条件。

通过 SDK 实现 LangSmith

最让我们对 LangSmith 感到兴奋的,不是它简洁的 UI 或丰富的功能集,而是它的 SDK。LangSmith SDK 提供了我们所追求的细粒度控制和可定制性。

为了试用 LangSmith,我们只需给我们的一些 LLM 相关函数添加一个@traceable装饰器。我们只花了几分钟就完成了埋点,而且一将这些更改推送到生产环境,我们就看到 trace 涌入 LangSmith UI。

这个@traceable装饰器一个意想不到的绝佳特性是,它可以将函数的和LLM 调用 trace 发送到 LangSmith。这让我们能够在 LangSmith UI 的单个 trace 中看到原始函数输入、渲染后的提示词模板以及 LLM 输出。

开箱即用,LangSmith 让我们对 Dosu 的所有活动都有了可见性。下一步是利用 LangSmith 识别失败模式,并将其集成到我们的 EDD 工作流中。

发现失败

Dosu 会收到用户的大量请求——从关于代码库的简单问题,到升级到新库版本时的错误堆栈,再到询问某个功能的进展。Dosu 可能的输入越多,可能的失败模式就越多。

在尝试识别失败模式或 Dosu 处理不佳的请求时,我们有多种信号可供观察,例如:

  • 显式反馈:由 ChatGPT 普及的经典点赞/点踩反馈。
  • 用户情绪:当用户在 GitHub issue 上与 Dosu 交互时,他们的回复通常能表明是否Dosu 提供了帮助
  • 内部错误:LLM 可能因多种原因失败。输入或输出是否过大?生成的响应是否符合期望的 schema?
  • 响应时间:在 Dosu,我们优先考虑质量而非速度;然而,理解响应为何缓慢很重要。有些请求需要快速响应,而另一些则需要较慢但更精确的响应。

LangSmith 的高级搜索功能让识别异常行为变得容易。我们可以使用一系列条件进行搜索,包括:显式用户反馈、最近的错误事件、响应时间延迟或负面情绪。LangSmith 还允许我们为每个 trace 附加额外的元数据,以进一步扩展其搜索能力。

我们已经识别出许多未曾预见的失败模式。例如,我们发现当用户分享数千行日志或 OpenAI embedding 的原始浮点值时,会出现响应极其缓慢的模式。

我们团队最喜欢的失败案例之一发生在 Dosu 被要求给一个 pull request 打标签时。Dosu 没有给 pull request 打标签,而是决定告诉用户它当晚要去看的演唱会,它对此很兴奋。Dosu 是不是 Swiftie 尚无定论。

一旦发现失败模式,EDD 工作流程与之前相同。

  1. 我们在 LangSmith 中搜索更多示例
  2. 将它们添加到我们的评估数据集
  3. 针对评估进行迭代
  4. 推送新版本的 Dosu,然后重复。

自动化评估数据集收集

在 Dosu,评估驱动开发的未来一片光明。我们团队正在进一步定制 LangSmith,以便能够从生产流量中自动构建评估数据集。我们希望让 Dosu 的工程师尽可能简单地根据对话主题、用户群体、请求类别等来整理数据集。

Dosu 与 LangChain 的合作中存在一种有趣的飞轮效应。LangSmith 帮助我们更快迭代,以提升 Dosu 的性能。Dosu 的改进直接转化为减轻 LangChain 团队的维护和支持负担,让他们能花更多时间交付 LangSmith 的功能,这反过来又加速了 Dosu 的开发。如此循环往复!

PS:Dosu 正在招聘!请联系 jobs*@dosu.dev*