跳到正文
LangChain:Blog·· 2023-10-16精选AI 评分64

Rubric Labs 团队详解如何用 LangChain 设计生产级 Agent Cal.ai

How to design an Agent for Production

AI 导读

Rubric Labs 团队在 LangChain 博客发布指南,讲解为 Cal.com 构建的 AI 邮件调度助手 Cal.ai 的生产架构。

推荐理由

原文拆解了一个已在生产环境运行的邮件调度 Agent 架构,读者可以借鉴其工具设计与提示词构造方法。

正文 · AI 翻译

编者注:本文由 Dexter Storey、Sarim Malik 和 Ted Spare 撰写,他们来自 Rubric Labs 团队。

重要链接

目标

本指南旨在解释使用 LangChain 在生产环境中部署调度代理 Cal.ai 所依赖的底层技术和逻辑。

背景

最近,我们 Rubric Labs 的团队有机会构建 Cal.com 的 AI 驱动电子邮件助手。作为背景,我们是一支热衷于解决棘手工程问题的构建者团队。

该项目的愿景是简化复杂的日历管理世界。我们设想的一些核心功能包括:

  • 将非正式邮件转化为预订:“想明天下午 2 点见面吗?”
  • 列出和重新安排预订:“取消我的下一个会议”
  • 回答基本问题:“我周二看起来怎么样?”

等等。总之,我们希望构建一个个人化的、由 AI 驱动的调度助手,能够为最终用户提供完整的 CRUD 操作套件,所有这些都在他们的电子邮件客户端内使用自然语言完成。

向 Cal.ai 发送电子邮件

架构

我们决定使用 AI 代理来实现这一点,特别是一个 OpenAI functions agent,它更擅长处理结构化数据,因为 Cal.com 的 API 暴露了一组具有清晰输入的预订操作。底层架构解释如下。

代理架构。暂存器(scratchpad)是一种记忆,AI 尝试在其中自我书写。

输入

Cal.com 用户可能会向 username@cal.ai(例如 ted@cal.ai)发送电子邮件,提出诸如“你能在明天某个时候与 sarim@rubriclabs.com 预订一次会议吗?”之类的请求。

收到的电子邮件会在 receive route 中使用 MailParser 进行清理和路由,地址会通过 DKIM record 进行验证,使其难以被伪造。

在这里我们还会进行额外检查,例如确保电子邮件来自 Cal.com 用户以防止滥用。在电子邮件经过验证和解析后,它会被传递给代理循环。

代理

该代理是一个 LangChain OpenAI functions agent,使用 GPT 模型的微调版本。该代理被传入预定义的函数或工具,并能够检测何时应调用某个函数。这使我们能够指定所需的输入和期望的输出。

该代理记录在 the agent loop 中。

OpenAI functions agent 有两个必需的输入:

  1. 工具——工具只是一个 Javascript 函数,具有名称、描述和输入模式
  2. 聊天模型——聊天模型是 LLM 模型的一种变体,它使用一种接口,其中“聊天消息”是输入和输出

除了工具和聊天模型之外,我们还传入一个前缀提示,为模型添加上下文。让我们逐一查看每个输入。

👉

为了更清晰,我们用一个类比来说明。这个代理是一位名叫 Peer 的电工。Peer 与其他任何电工都不同,Peer 通过多年的训练和学习(模型)获得了深度智能。然而,当面对一个问题(输入)时,Peer 的工作成果(输出)并不总是符合客户的期望。有一天,一位名叫 Bailey 的客户决定雇用 Peer,并给他提供了一套有限的工具——一把焊枪、一块电池、一些电线和一只灯泡。Peer 运用自己的知识和所提供的工具,想出了一个完全符合 Bailey 期望的解决方案。

提示词

提示词是一种通过提供上下文来为模型编程的方式。用户的信息(userId、user.username、user.timezone 等)被用来构建一个提示词,然后传递给代理。

const prompt = `You are Cal.ai - a bleeding edge scheduling assistant that interfaces via email.
Make sure your final answers are definitive, complete and well formatted.
Sometimes, tools return errors. In this case, try to handle the error
intelligently or ask the user for more information.
Tools will always handle times in UTC, but times sent to users should be
formatted per that user's timezone.

The primary user's id is: ${userId}
The primary user's username is: ${user.username}
The current time in the primary user's timezone is: ${now(user.timeZone)}
The primary user's time zone is: ${user.timeZone}
The primary user's event types are: ${user.eventTypes}
The primary user's working hours are: ${user.workingHours}
...
`

在这里找到完整的提示词。

聊天模型

聊天模型是语言模型的一种变体,它将聊天消息作为输入和输出。对于这个项目,我们使用 OpenAI 的 GPT-4 模型,可以通过 OPENAI_API_KEY 访问(阅读此处以生成 API 密钥)。

为了获得更好的采用率,我们知道用户体验必须快如闪电。我们试验了 gpt-3.5-turbo,但有趣的是,它往往会以更绕的方式完成任务,从而导致整体耗时更长。

温度被设置为 0,以生成更一致的输出。更高的温度会导致更具创造性、更不一致的输出。

const model = new ChatOpenAI({
   modelName: "gpt-4",
   openAIApiKey: env.OPENAI_API_KEY,
   temperature: 0,
 });

工具

一个工具由 Javascript 函数、名称、输入模式(使用 Zod)和描述组成,并且被设计为与结构化数据一起工作。

本项目使用的工具类型为 DynamicStructuredTool,它们被设计为与结构化数据一起工作。动态结构化工具是 LangChain 的 StructuredTool 类的扩展,它基本上用所提供的函数覆盖了 _call 方法。请参阅下面的模式以了解 DynamicStructuredTool。

DynamicStructuredTool({
   description: "Creates a booking on the primary user's calendar.", // Description
   func: createBooking(), // Function
   name: "createBooking", // Name
   schema: z.object({ // Schema
     from: z.string().describe("ISO 8601 datetime string"),
...
   }),
 });

DynamicStructuredTool 的输入,完整示例可在此处查看

通过创建一套工具,我们赋予了代理执行预定义操作的额外能力。本项目使用的所有工具都在此处记录,并在下面列出。每个工具都有复杂的逻辑,使其能够理解用户的请求,通过执行 CRUD 任务与 Cal.com API 交互,并处理响应。

const tools = [
   createBooking(apiKey, userId, users),
   deleteBooking(apiKey),
   getAvailability(apiKey),
   getBookings(apiKey, userId),
   sendBookingLink(apiKey, user, users, agentEmail),
 updateBooking(apiKey, userId),
];

上述工具的输入是我们不希望 AI 代理访问的变量,因此它们被注入到工具中,绕过代理循环。

使用动态提示词和聊天模型,工具解析器能够选择最合适的工具来处理用户的请求,然后循环运行,直到能够达到期望的行为。这遵循迭代学习,甚至允许在出现错误时通过选择替代工具来进行回退。

工具架构

执行器

最后,使用工具、聊天模型和提示词来初始化一个代理并运行执行器以生成响应。

const executor = await initializeAgentExecutorWithOptions(tools, model, {
 agentArgs: { prefix: prompt },
 agentType: "openai-functions",
 verbose: true,
});

响应

在代理利用不同工具循环运行、与 LLM 模型聊天并与 Cal.com API 交互之后,它会结束并得出最终响应。然后,该响应会使用电子邮件服务(例如 Sendgrid 或 Resend)通过电子邮件发送给用户。该电子邮件要么是确认,要么是错误。

技术栈

结论

显然,拥有作用域工具的 AI 智能体是一种非常强大的组合。将 LLM 模型的知识与结构化工具相结合,有助于用结构化数据解决自然语言问题,从而提高此类智能体的可靠性。我们对 AI 智能体的未来感到无比兴奋,随着它们不断演进,我们希望与 Cal.com 和 LangChain 合作打造一个生产环境中的开源智能体,能成为未来项目的模板。

💬

如果您对本文有任何反馈,请通过 hello@rubriclab.com 联系我们

来源:LangChain:Blog · langchain.com