Om

奥马尔·迪亚布

添加于

使用 Grok 构建统一的聊天体验

xAI 文档概述了与 Grok 交互的几种方式:多轮聊天对话、实时令牌流式传输函数调用图像理解结构化响应。虽然每个功能本身都很强大,但将它们组合成一个连贯的应用程序可能会感觉不清楚。本指南演示了如何将这些功能集成到一个单一的、实用的客户支持聊天机器人中,展示了实现无缝聊天体验的模式和代码。实际上,一个真实的聊天机器人会通过公司政策、常见问题解答和语气指南进行增强,但在这里我们专注于技术基础,而不是生产级的实现。

目录

代码设置

注意: 如果您想运行 notebook,请确保导出名为 XAI_API_KEY 的环境变量,或者在此外层存储库的根目录下的 .env 文件中进行设置。如果您还没有 API 密钥,请前往我们的控制台获取。

带流式传输的基本多轮聊天

Grok 聊天 API 是无状态的,这意味着除了您在 messages 数组中提供的内容之外,它没有之前交互的记忆。每个请求都是一个全新的开始,模型完全依赖于您发送的对话历史记录。为了构建一个功能性的多轮聊天,您必须在每个 API 调用中,将所有相关的轮次(用户输入、助手响应和工具调用)包含在 messages 数组中。

作为开发人员,管理对话状态取决于您。这涉及到跟踪完整的历史记录并确保将其正确地传递给 Grok 以保持上下文。

下面的示例演示了一个简单的聊天应用程序,它处理了这个问题,并结合了实时流式传输以实现即时逐令牌响应。

在此设置中,ChatApp 类使用 API 密钥和可选的系统提示初始化,并将对话存储在 messages 列表中。converse 方法捕获用户输入,将其附加到历史记录中,并流式传输 Grok 的响应,同时用每次助手回复更新状态。这种方法确保了流畅、交互式的体验,同时尊重 API 的无状态性质。

添加函数调用

函数调用将 Grok 的功能扩展到对话之外,使其能够根据用户输入触发外部操作。通过此功能,您可以定义 Grok 可以调用的函数,通过生成结构化调用(包括函数名称和参数),这些调用嵌入在其响应中。API 在 tool_calls 字段中返回这些调用,您的应用程序会解析并执行这些调用,从而将实际功能集成到聊天流程中。

在此示例中,我们将添加函数调用以创建客户支持票证。当用户描述问题时,Grok 会识别意图并生成对预定义 create_customer_ticket 函数的调用。为简单起见,模拟实现返回一个确认字符串,但实际上,这可以与 CRM 系统或数据库交互。对话状态继续通过 messages 数组进行管理,现在包括工具调用请求及其结果。

让我们分解一下上面发生的事情

  1. 用户输入触发聊天循环:用户输入一条消息(例如,“我无法登录”),该消息作为 "user" 角色条目附加到 messages
  2. 流式响应开始:应用程序将 messages 数组与 tools 列表一起发送给 Grok,请求流式响应。Grok 处理输入并开始发送数据块。
  3. 文本和工具调用检测:当数据块到达时,Grok 可能会通过 chunk.choices[0].delta.content 流式传输文本内容(例如,“我将为 Omar 创建一张客户票证,问题是‘无法登录’”),并实时显示。同时,它可能在 chunk.choices[0].delta.tool_calls 中包含一个或多个 tool_calls。一个 for 循环收集所有工具调用(例如,create_support_ticket),因为 Grok 可以从一条消息中请求多个操作。
  4. 响应完成:一旦流结束,助手的完整消息(文本内容和任何工具调用)将附加到 messages 中。
  5. 工具执行:每个工具调用都由 _handle_tool_call 处理。此函数使用 self.executables(将工具名称映射到可调用函数的字典,例如 {"create_customer_ticket": create_customer_ticket})和 self.arguments(Pydantic 模式的字典,例如 {"create_customer_ticket": CreateCustomerTicketRequest})来验证和解析 JSON 参数。模拟的 create_customer_ticket 函数可能会为每个相关的调用返回“已为 Omar 创建票证,问题:无法登录”。
  6. 附加工具结果:每个工具执行的结果(例如,“已为 Omar 创建票证……”)将作为 "tool" 角色条目附加到 messages 中,并链接到各自的 tool_call_id
  7. 向 Grok 发送后续调用:工具调用执行完成后,更新的 messages 数组(现在包含工具结果)将通过新的流式请求发送回 Grok。Grok 处理此请求并流式传输最终响应(例如,“我已成功创建客户票证”或“如果发生错误,我无法创建票证”),该响应将附加到 messages 中。

此过程确保函数调用无缝集成到对话中,并通过流式传输保持响应能力。ChatAppWithTools 类管理此流程,利用 self.executables 进行执行,self.arguments 进行验证,同时循环返回 Grok,根据工具结果获得最终的用户可见响应。

为了检查对话状态,我们可以查看消息数组,以确切了解发生的一系列事件。

通过结构化输出添加图像理解

我们可以通过添加图像理解支持来增强我们的聊天应用程序,允许用户共享图像(例如通过 URL 的收据),并让 Grok 分析它们。Grok 的图像处理功能从这些图像中提取细节,通过结构化响应功能,我们可以将输出格式化为 JSON 或 Pydantic 对象。这使得数据易于处理,适用于下游任务,例如保存到数据库或触发进一步的操作。

为此,我们将定义一个新函数 analyze_receipt_image,它处理收据图像并返回一个包含提取内容(例如项目、总计)的结构化 Pydantic 响应。下面的示例演示了这是一个独立的功能。

由于我们的 ChatAppWithTools 已经处理了工具调用,因此集成此新行为非常简单。我们只需使用 analyze_receipt_image 定义更新工具列表,将其可执行文件添加到 EXECUTABLES,并将其 Pydantic 参数模式包含在 ARGUMENTS 中。无需其他代码更改——Grok 现在可以调用此工具以及现有工具,处理用户提供的图像 URL 并在对话流程中返回结构化数据。结果将附加到消息中并传递回 Grok,从而能够根据收据内容进行无缝的后续响应。

在对话中,两个工具都无缝使用。Grok 正确识别并调用了适当的工具——例如使用收据工具解析图像 URL——尽管没有明确的关键词如“收据”,这表明了其上下文理解能力。

结论

本指南介绍了如何使用 Grok 构建一个客户支持聊天机器人,集成了多轮对话、流式传输、函数调用和带结构化输出的图像理解。以下是主要经验教训:

  • 无状态 API 管理:聊天完成端点的无状态特性要求开发人员维护 messages 数组,附加用户输入、助手响应和工具结果,以在多轮对话中保留上下文。
  • 实时流式传输:逐令牌流式传输响应通过提供即时反馈来增强用户体验,并无缝集成到聊天循环中。
  • 函数调用灵活性:工具调用可实现可操作的结果(例如,创建支持票证),Grok 生成结构化请求,应用程序执行这些请求并循环返回最终响应。
  • 图像理解集成:添加图像分析(例如,收据解析)扩展了功能,利用结构化输出进行下游任务,并轻松融入现有工具调用框架。
  • 状态检查messages 数组用作对话状态的日志,允许您逐步跟踪每次交互。

后续步骤

读者可以在此基础上进行以下构建:

  • 使用公司特定的数据(例如,常见问题解答、政策)增强系统提示,以获得更定制的聊天机器人。
  • 实现真实的工具集成,例如将 create_support_ticket 连接到 CRM 或将 analyze_receipt_image 连接到数据库。
  • 为网络故障或无效输入等边缘情况添加错误处理。