Transcription
我马上会做自我介绍,但我希望先了解一下你们。所以,你们可以看到屏幕上有两个品牌。特别是 OpenAI Agents SDK,以及 Temporal。我在 Temporal 工作。我马上会告诉你们更多关于我自己的信息。嗯,我很好奇,今天有多少人正在使用 OpenAI Agents SDK?好的,大约有四分之一的人。嗯,还有其他什么嗯,代理框架吗?好的,大约是同一批人。所以,看起来有相当一部分人还没有使用代理框架。所以,我会教你们一些关于这方面的内容。好的,下一个问题。有多少人正在使用 Temporal?不多。太棒了。我要教你们一些东西。嗯,好的,太棒了。所以,我们今天将要讨论这两种技术。我将分别讨论它们,但我会在它们结合起来的时候花很多时间。剧透一下,我们实际上在 Temporal 和 OpenAI 共同开发的产品之间有一个集成。嗯,所以,你们会看到它真的很棒。所以,让我非常简短地介绍一下我自己。我叫 Cornelia Davis。我是 Temporal 的开发者倡导者。嗯,我想我职业生涯的大部分时间都花在了分布式系统领域。所以我非常幸运能在 Pivotal 工作,从 2010 年初开始就从事 Cloud Foundry 的工作。所以我确实经历了向微服务架构、分布式系统等方向发展的运动。房间里有 Cloud Foundry 的人吗?哦,只有几个。嗯,所以,对于那些不知道 Cloud Foundry 的人来说,Cloud Foundry 是市场上最早的容器技术。它最初是在 VMware 中孵化的一个开源项目,并且在 Docker 出现之前很久,在 Kubernetes 出现之前很久,它就使用了容器镜像、Linux 容器、容器编排、最终一致性等等。所以我非常非常幸运,我能参与到那个支持更敏捷的分布式系统方法的平台运动的开端。因为我在微服务领域花费了大量时间,所以我还写了这本书。
好的。所以,我们今天将要讨论的是 OpenAI Agents SDK。然后,我将给你们一个 Temporal 的概述。我将进行大量的演示,并且我会向你们展示代码库。如果你想跟着做,你可以直接去获取代码库。我今天所有的演示都改成了分支而不是主分支,但我会非常清楚地说明这一点。我将在那里进行大量的演示,然后我会转向 OpenAI Agents SDK 和 Temporal 的结合,我们也会在那里进行更多的演示。然后,我将谈论一些关于通用代理的编排。所以,这里有一个笔记本,我今天不会使用它。所以,我决定我本周早些时候刚做完这个研讨会,我决定对于 AI 人群来说,它太基础了。话虽如此,如果你有兴趣,你可以去那里。它会引导你完成。它配备了 Jupyter 笔记本。你可以在 GitHub 的代码空间中运行它,你可以运行你的第一个 OpenAI Agents SDK 代理。然后,你可以运行你的第一个 101 Temporal 代理,而不是 Temporal 应用程序。然后,你可以一直按照这个议程进行。但它相当基础,我决定对于这个人群,我想要做一些更高级的事情。所以,我们今天不会使用它。嗯,我刚刚在今早制作了一些演示。
好的。所以,废话不多说,这是演示中最短的部分,我将介绍 OpenAI Agents SDK。我想它是在五月份左右发布的。嗯,我不会给你们读这些幻灯片,哦,只是让你们知道我们要去哪里。我将使用一些幻灯片,因为我是那种认为图片真的有帮助的人。我这里有很多图表,但我们也会花很多时间逐步讲解代码。我认为我不需要定义什么是代理。我个人认为,我区分生成式 AI 应用和代理的区别在于,当我们赋予 LLM 代理权,当 LLM 是决定应用程序流程的人时。对我来说,这就是代理的定义。而像 OpenAI Agents SDK 这样的框架就是为了让你更容易地开始使用它们。事实上,我们将看到今天我要展示的两个主要演示之间的对比。它支持 Python 和 Typescript。这是最基本的应用程序。所以,你们在这里看到的是,我们定义了一个代理。我们给它起了一个名字,并给它下达了指令,其余的都使用了默认值。其他默认的东西包括模型本身。我不知道现在默认是什么。然后,你只需要做的就是运行它。任何时候你看到 runner.run,它就对应着一个代理循环。我们将在整个演示中多次讨论代理循环。每一次你看到 runner.run,它都是一个独立的代理循环。当我们稍后讨论编排时,你就会明白为什么我做出这个区分。正如我所说,这里非常简单,但它还有很多其他选项可以放在代理配置中,这些配置会驱动代理循环的工作方式。你可以进行交接。我们稍后会讨论这些。但你可以设置护栏。你可以添加工具。我们将看到我的两个例子都非常依赖于 LLM 的代理权以及它决定使用哪些工具。所以,我将向你们展示工具。所以,还有很多事情可以做,我将在接下来的过程中向你们展示例子。而这实际上是我所说的图景,即每一个 runner.run 都基本上有一个循环,它不断地回到 LLM。在 LLM 调用之后,它会决定做事情。如果 LLM,例如,说,我想让你调用一些工具,它就会去调用那些工具。然后,它会获取工具的输出,并将其路由回 LLM,然后继续进行。LLM 可以决定何时完成遵循系统指令,我们将看到这一点。
好的。所以,这就是基本的嗯,你知道的代理框架概述,而且有很多代理框架。好的。由于你们很少有人了解 Temporal,我将放慢速度,告诉你们更多关于 Temporal 的信息。所以,Temporal 是一个开源项目。它已经存在了大约五到六年了。所以,是的,它远远早于我们现在所处的生成式 AI 热潮。它专为分布式系统而设计,而 AI 应用如果不是分布式系统又是什么呢?所以,事实证明,Temporal 非常适合这些 AI 用例。现在,它被用于许多非 AI 用例。所以,例如,每一个 Snapchat 都通过 Temporal。每一次 Airbnb 预订都通过 Temporal。必胜客、塔可钟的订单都通过 Temporal。嗯,还有很多我记不清的其他。OpenAI Codeex 在 Temporal 上运行。所以,现在我们开始进入 AI 用例。Codeex 在 Temporal 上运行。OpenAI 的图像生成在 Temporal 上运行。这是我能告诉你们的两个。这是公开的两个。嗯,所以,我们还有很多其他的,Lovable 在 Temporal 上运行。所以,我们肯定在 AI 领域取得了进展,获得了大量的使用。所以,我告诉了你们谁在使用它,但让我告诉你们它是什么。它是一种分布式系统作为后端服务。所以,我认为每个人都熟悉 Redis 作为后端服务,或者 Kafka 作为后端服务,或者数据库作为后端服务。所以,我运行着我的应用程序,我使用这些后端服务来提供,你知道的,作为我应用程序的一部分。Temporal 是一种后端服务。它提供的是分布式系统的持久性。我将在演示过程中进一步说明这一点。这意味着你作为开发者可以编程快乐路径。你可以编程你的业务逻辑。而我们今天将要编程的业务逻辑是 AI 代理。所以,你可以说,“你知道吗,我想做的是调用一个 LLM。然后,我想获取 LLM 的输出,然后我可能想调用一些其他 API,然后我想循环回到 LLM。”你不需要构建其中的逻辑,说明如果 LLM 被速率限制了会发生什么。如果我的下游 API 暂时宕机了会发生什么。如果我的应用程序崩溃了会发生什么。你不需要编程任何这些。我们为你完成。我马上会给你看一些图片说明这是如何工作的。所以,有一个 Temporal 服务,它是后端服务。而你连接到后端服务的方式是通过 SDK。所以,SDK 位于你的业务逻辑旁边。所以,你可以编程你的业务逻辑。而你构建业务逻辑的方式是,你在某些函数周围加上包装器。这使得 SDK 可以说,“哦,等等。你正在进行下游 API 调用。我将介入并为你提供一些服务。所以我将为你提供重试。如果那个下游服务成功了,我将为你记录下来。我将为你记录答案,以便在发生某些事情并且我们需要再次经历这个流程时,我可以获取你之前调用的结果。这意味着,例如,如果你使用 Temporal 为你的代理提供持久性,当你与 LLM 进行第 1350 次交互时,你的应用程序崩溃了,没问题。我们已经记录了每一次 LLM 调用和返回,你不会重新燃烧那些 token。这就是这个领域的持久性。我们正式支持七种不同的编程语言,但苹果公司几周前也发布了一个 Swift SDK。所以,几乎任何语言都有支持。还有一些实验性的东西,比如 Clojure 等等。我说这是一个开源项目。绝大多数是 MIT 许可的。嗯,Java SDK 中还有一些 Apache 2 的遗留。所以,非常非常宽松的许可证,嗯,那些不知道历史的人,Temporal 是 Uber 创建的一个名为 Cadence 的项目的分支。有人知道 Cadence 吗?是的。好的。所以,有几个人知道 Cadence。所以,Cadence 几乎 Uber 上运行的每一个应用程序都运行在 Cadence 上,这是因为他们可以编程快乐路径,而所有的持久性都得到了处理。所以,这就是 Temporal 的概述。所以,我将讨论两个基础抽象。还有一些其他的,但作为开发者你需要知道的两个基础抽象是,你需要知道活动。而活动只是一块工作。这是将要进行外部调用的工作。所以,这是可能失败的工作。这就像很多可能失败的工作。或者,如果你正在做很多你不希望在出现问题时重新做的工作,你也可以把它放在活动中。所以,就像从账户提款、存款一样。我们稍后会讨论 AI 用例。所以,这些就是活动,你把它们包装起来。哦,我没提,但 SDK 不仅仅是覆盖在 REST API 之上的薄包装器。这些 SDK,正如你所能想象的,在分布式系统中提供持久性意味着所有你认为你需要实现的算法,比如担心并发和和嗯,法定人数等等,这些都在 Temporal 中实现了,所以我们的 SDK 中有很多这样的逻辑。服务主要是持久性。所以,SDK 中有很多智能。所以,这些活动,如果你说,“看,这是我的工作。这是一项繁重的工作,或者是一项外部工作。让我们给它加上活动装饰器。”那么 SDK 就会说,“哦,好的,我将给你一些特殊行为。”然后,你将这些活动编排到你的业务逻辑中。而我们称之为编排的是工作流。好的。所以,你将看到,当你把活动和工作流放在一起时,魔法就真正发生了。活动中存在一定程度的魔法,事实上,我们刚刚开始发布所谓的独立活动。所以,你可以在没有工作流的情况下使用活动,并获得一些持久性优势。所以,各种各样的演变正在发生。但当我嗯,将工作流和活动结合在一起时,我所说的魔法是,我叠加了一堆图标。所以我叠加了这些小的重试图标。所以,你所做的是,你在工作流逻辑中指定重试配置。所以,你可以决定是进行指数退避,还是进行无限重试。你是最多重试五次。你是否会在重试之间有一个最大窗口。你可以配置所有这些。一旦你这样做了,并将这些东西编排在一起,现在你就可以进行重试了。你将在代码中看到,只需调用这些活动,我无需实现重试逻辑。我无需实现任何其他逻辑。它只是为我发生的。所以,我得到重试。我还得到这些小队列。所以,在你看来,这是一个单一的进程应用程序,我调用这个,然后我调用这个,然后我调用这个,每一次你调用一个活动,每一次你从活动返回到主工作流,所有这些都通过队列进行促进,所以,看起来像一个单一的单体应用程序,已经变成了分布式系统。所以,你可以部署很多实例,并且你可以通过部署更多实例来扩展。你无需管理,你无需管理 Kafka 队列等等。所有这些都内置了。本周我在这里的 AI Engineers 与一个人交谈过,他是一位开源用户,实际上是我们的客户,我问他,他是一家相对较小的初创公司,我说,“你为什么选择 Temporal?”他说,“因为我们试图用 Kafka 队列来构建所有这些,结果我们花了所有的时间在 Kafka 的运维上,花了 25% 的时间在业务逻辑上。当我们切换到 Temporal 时,我们花了 75% 的时间在业务逻辑上,他们正在使用 Temporal Cloud。”我没有提到我们的商业模式,我们提供这项服务作为 SaaS。所以,他们正在使用 Temporal Cloud。所以,他们基本上从 2575 转移到了 7525。不再需要管理 Kafka 队列或 Redis 或任何类似的东西。说到 Redis,你看到右上角的状态管理。所以,我们做的另一件事是,我们跟踪你的应用程序执行的进度。我们通过记录状态来做到这一点。同样,每一次你调用活动并返回时,我们都会记录下来。这基本上是事件溯源。这就是我们所做的。它不仅是事件驱动的架构,而且我们提供事件溯源服务。所以,你可以做到这一点。所以,我们存储了所有这些状态,以便在出现问题时,我将演示这一点,我们将看到问题出现,它将从中断的地方继续,因为我们将通过事件历史记录来恢复并从中断的地方继续。所以,我叠加在逻辑图上的那些小图标,我稍后会回答你的问题。实际上,所有这些服务都生活在这里的服务中。所以,它们都是持久的。所以,它们不是生活在进程中,而是生活在这个服务中。你有一个问题?>> 不确定是否相关。所以,我的很多代理都处理流式数据。所以,我想看看是否能在这方面提供帮助。>> 哦,好问题。所以,是的,问题是我的很多代理都在处理流式数据。你们能处理流式数据吗?答案是目前非常简单的否,我们不能。但这是我们正在做的事情之一。我的同事在后面,Johan,他是 AI 工程的负责人。所以,和他聊聊,和我们任何一个人聊聊。这是我们目前正在处理的两个首要任务之一。另一个是大型载荷存储。如果我在这里的研讨会中没有机会谈论它,请找我们中的任何一个人。我们可以告诉你。你可以想象大型载荷存储是什么。就是你在做 LLM,你会传递大量数据。与其按值传递,不如按引用传递。这就是大型载荷存储。那是 Johan。>> 我只想说,有很多人在使用变通方法。>> 是的。>> 今天大规模生产中的流式处理。所以,很高兴能谈论这一点,但将会有更集成的解决方案。>> 是的。所以我只是重复 Johan 所说的,以防你们听不清。所以,我们确实有一些客户在 Temporal 之上构建了流式处理支持,但我们正在将其内置。所以,是的。所以,你今天就可以做到。只是工作量有点大。这不是快乐路径。所以,好的。嗯,说到这里,我想给你们做一个演示。所以,这是我要移到这里的第一个演示。让我看看我能不能把屏幕弄回来。好的。所以,如果你想跟着做,我将做的第一件事是,我将来到这里,然后我将,让我放大字体。嗯,所以,我将指向两个代码库。这实际上是第二个代码库,但现在屏幕上显示的是,如果你想开始使用 Temporal,非常简单,你不需要使用 Temporal Cloud。你可以运行一个 Temporal 服务。所以,后端服务,你可以在本地机器上运行它。所以,你可以通过 curl 这个来完成。你也可以通过 Homebrew 安装。嗯,然后运行那个本地服务器,你只需要说 temporal server start dev。现在,你就有了一个在本地运行的 Temporal 服务。我所有的应用程序都只是连接到我的 localhost。嗯,我们稍后会看到 UI。嗯,我稍后会回到这个代码库。我将要演示给你们的代码库是这个。嗯,抱歉,我不知道如何放大字体,但你们可以看到组织和代码库在这里,组织是 temporal io。在那里你也可以找到 Temporal 的所有开源代码。嗯,然后我们有一个叫做 AI Cookbook 的东西,这是一个例子。我实际上在今早扩展了这个例子,但是嗯,你们会发现,我们今天将要演示的分支叫做 agentic loop de branch。所以,如果你想,你知道的,以后自己回顾一下,这就是我们要看的。
好的。所以,说到这里,让我进入我的正确终端。嗯,所以,我将在这里运行它,但我想先给你们看代码。好的。所以我在这里吗?OpenAI。不。这是错误的。我的另一个光标。好了。所以,这是代理循环。所以我今天要做两个演示。所以,你们在这里看到的左边,让我再放大一点:还记得我谈到的活动和工作流吗?所以,这是我要做的第一件事,我将向你们展示活动。还记得我们有提款和存款,你知道的,那种东西。这里,当然,我们正在做一个代理循环。所以,我的活动将是调用 OpenAI API,还不是 Agents SDK,只是 OpenAI 的 API,并调用一些工具。所以,这是我的两个活动。所以,让我们看看第一个,你们会看到它有多简单。我向你们保证了快乐路径。它确实是这样。所以,这是我对 OpenAI 响应 API 的调用。好的,它和你期望的一样。我传入了模型。我传入了一些指令。嗯,用户输入将来自我的工具,我稍后会展示。然后,我可以配置一些超时。那是针对 OpenAI 的。我所做的是,我将它包装在一个函数中。它接收那个请求。所以,所有这些参数都来自我传递的请求。我稍后会展示如何调用它。这是那个注解。现在,不同的 SDK 有不同的方法。例如,TypeScript 不需要很多注解。它会自动识别。它知道活动在哪里。Java 有注解。等等。但这是 Python。所以,你们可以看到,我们只有一个活动装饰器。所以,你们可以看到它一点也不复杂。你作为开发者只需要做的是说,“这里有一堆我想做的工作,我想把它封装成一个步骤。”然后,你把它放在一个函数里。你给它加上活动装饰器。所以,我稍后会回到工具调用器,因为这里有一些有趣的事情在发生。所以,现在如果我们去看工作流,工作流也相当直接。所以,我这里有我的工作流定义。你们可以看到它是一个类。它是类的原因是,当你创建一个工作流时,你创建应用程序的主体,我称之为应用程序主体,它上面有 workflow.run。但这个工作流,我今天不会涵盖这些抽象,但我们还有一些其他的抽象,比如信号。所以,对于一个正在运行的工作流,你可以向它发送信号,我们还有一个叫做更新的抽象。它是一种特殊的信号。我们还有对应的查询。所以,这些东西被添加到了这个工作流类中,作为带有信号、更新或查询注解的函数。所以,这就是为什么我们有一个工作流类。如果我们看看这里的逻辑,你们可以看到我有一个 while true。所以,这个简单的应用程序就是我之前展示的那个图,我说我们只是在 LLM 上循环。如果 LLM 决定这样做,我们将调用工具。这就是整个应用程序。但你们会看到我在这里用 Temporal 做了一些有趣的事情。所以,为了调用 LLM,我执行了那个活动。所以,你们可以看到我传递了我的模型。嗯,这里的指令,我不会给你们看,但你们可以在代码库中看到所有内容。有用的代理系统指令基本上只是说你是一个有用的代理。如果你,如果用户说了什么,你认为你应该使用工具,请告诉我。你知道的,选择一个工具。否则,就用俳句回应。你们稍后会看到。比如俳句是 AI 世界的 fooar,对吧?我们都会写代理。这是代理领域的“Hello World”。所以,我们将用俳句回应。嗯,就是这样。所以,我们一直在做这个 while true。我还有几个打印语句。你们稍后会看到这个如何运行。这里我做了一个简化的假设,我假设它一次只调用一个工具。所以,我获取了那个输出。然后,我只是看了一下,说,它是一个函数调用吗?如果是函数调用,那么我将处理那个函数调用。我稍后会给你们看那个代码。然后,我将把那个函数调用的输出添加到对话历史中。所以,我没有做任何花哨的上下文工程。什么都没有。我只是基本上把它添加到对话历史的末尾。好的。现在,处理函数调用也非常直接。所以,我做的第一件事是,我添加了 LLM 的响应。所以,到我们完成这个函数调用时,我们将向对话历史中添加两样东西。我们将添加 LLM 的响应,它说请进行函数调用,然后我们将进行函数调用,然后我们将添加结果。我刚刚向你们展示了我们添加函数调用结果的地方。所以,这里,我只是把它添加到嗯,这是我的一些杂乱的东西。我让这个应用程序也运行在 Gemini API 上。而所有这些东西中最麻烦的是格式不同。所以,我必须重写,因为不同模型之间的对话历史的 JSON 格式是不同的。是的,我知道有 Light LLM,但我不喜欢最小公分母。而且我也喜欢了解这些格式的样子。所以,嗯,但你们可以看到我只是做了一些丑陋的解析,然后我执行了,记住我在这里处理工具调用。我执行了那个工具调用的活动。所以,我从 LLM 的响应中提取了工具调用,然后我调用了那个活动,也就是 execute activity,项目名称是 tool。现在,我非常在意的一件事是,我不想构建一个执行一组工具的代理循环应用程序,然后当我有了另一组工具时,不得不重建一个全新的应用程序。代理本身,我们听到了,我不记得是谁说的了,但本周有人在舞台上说,他们说,“看,代理模式是相当标准的,现在我们正在将东西插入到这个标准化的代理循环中。”而这正是这些嗯,AI 框架,这些代理框架正在做的事情,我也想在这里的 Temporal 代码中这样做。酷的是,Temporal 有一个叫做动态活动的东西。动态活动允许你按名称调用活动,但该活动是在运行时动态找到的。所以,这里的活动处理程序,我稍后会给你们看代码,基本上会接收那个名称,然后说,“哦,好的,我,记住这是事件驱动的。我们有一个活动在队列上等待东西。所以,你可以配置一个活动。你可以配置我们的一个工作器,说,“嘿,这是一个将从活动队列中获取任何东西的工作器。名字是什么并不重要。”所以,你不需要紧密绑定到特定的主题名称,例如。是的。问题。>> 我需要提前映射哪些工具可供代理使用,基于活动。>> 嗯,那是分开的,我将向你们展示那个模块。这里有一个叫做 tools 的模块。如果你看到 tools 目录,我在这里运行的方式是,它在加载应用程序时加载那些东西。所以,我没有进行任何动态加载,但我可以交换那个 tools 模块,而代理代码完全不变。所以,我还没有实现一个注册表并进行动态调用。你可以做到,但这个简单的例子基本上只是把它放在一个单独的模块中。你们会看到那个模块如何被切换进出,因为我在运行时加载它。所以,嗯,简化一下,但是的,你可以做到。好的。所以,我只是调用一个活动。所以,让我们看看那个活动是什么样的。它是这个 tool invoker。所以,你们可以看到它有一个活动装饰器,就像我之前展示的一样,但现在它说 dynamic = true。所以,这意味着这个活动处理程序将获取任何出现在队列中但没有被其他活动拾取的任何东西。所以,它会拾取 get weather。它会拾取 get random number。它会拾取任何出现的东西。你必须注册。嗯,你必须注册。不,你不需要注册所有这些。这些东西可以动态完成。你不需要将它们注册到工作器中。你们可以看到,我们基本上获取了那个,我们得到了工具名称。然后,你们可以看到,我实际上是在查找函数。你们可以看到这里根本没有工具名称。它基本上是从一个字典中查找工具名称。它,它是一个比喻上的字典。我将向你们展示那些嗯,函数稍后。所以,我有一个函数叫做 get tools 函数,顺便说一句,让我回到那个。所以,在 OpenAI 响应中,不,抱歉,它在工作流中,当我调用 LLM 在这里。请注意,我调用了 get tools。我稍后会给你们看那个 get tools 调用。它完全超出了工作流和活动的范围。它在自己的模块中。我稍后会给你们看那个函数。好的。所以,回到 tool invoker。它基本上现在接收名称,然后它进行 get handler。所以, somewhere here is a get handler call. Here's the handler. >> You just passed it. >> I just passed it. Sorry. >> 17. >> 17. Thank you. I appreciate it. So here's the get handler and I'll show you that function in just a second. So great question on the like how tightly bound are these things. Let me show you where that binding is right now. So I have a tools module here and I have in the init is where I've got those two functions defined. So, I've got the get tools and the get tools are basically just taking the list of functions and I'll show you those functions and those functions what we're passing in here is we are passing in the JSON blobs that are passed to the LLM as the tool descriptions. So, these are the tool descriptions. So, for example, let me show you the get weather one. So, if we go over here to get weather, you can see that the um the JSON blob is right here. And it's interesting because OpenAI um in in the completions API, they had a public API that allowed you to take any function that has dock strings on it and generate the JSON for the completions API for the tools. The responses API has no no such public API. So there's a warning in here that says this API that I'm using um which is in this tool helper. I'll show you the tool helper. Where is my tool helper? Uh helpers. Here we go. I guess I could put that in tools. Is that there's a thing in there that says warning. There is currently no public API to generate the JSON blob of tools for the responses API. So I'm using an internal one. There is an open issue on this. So there's just a warning in there that I'm using an internal one. So if we go back there, I've used an internal API to just take my get weather alerts um request which is the uh it's a pyantic model that has the the functions in there and has some you know additional metadata around it and it generates the JSON blob. So again, that's what you see when we go into the agent is we that's what you're getting with get tools is you're getting the the the array of JSON blobs for each of the tools. And then as I said the get handler basically has it it's it's basically a dictionary that I've implemented as as a set of ifns. So it's a takes the tool name and then it picks up what the actual function is completely independent. And so this particular example has a set of and I'm going to demo those for you in just a second. It has a set of tools here. Um and you can just switch those things out. You do have to restart your Python pro process at the moment just because of the way that I've implemented it. Okay. Make basic sense. All right. Let me show you this in action. Um and so what I've got here is I'm running uh the worker. I'm not spending a lot of time here talking about workers, but you remember that I said that this is all event driven. Um, and so there's something that is picking up work off of event cues and then executing the right workflows and activities based on what it's pulled off of the event cues. The the um the thing in temporal that does that is what we call a worker. So a worker is a process that you run. With that worker, you register the activities and the workflows that that worker is going to be responsible for. So it's going to be looking for things on the queue to pull off of those. That worker itself is multi-threaded. So it is not one worker one process. Um in general people run it depends you can do worker tuning but in general people run several hundred threads. So you run one worker and it's already a a a you know concurrent multi-threaded architecture. Okay. So this is some solid stuff. Temporal is just the coolest stuff. It's really truly is distributed systems designed. Okay. So I'm running the worker up here, which is effectively where you're going to see the outputs coming from the activities and the workflows. And I'm going to go ahead and run um run a workflow. And so, let's say are there any weather alerts in California? That's where I'm from. And I think a lot of you are from and hopefully where I will be headed back to tonight. And so we're going to start. And what you can see here is the way that this application is written is basically I I um say whether or not I'm calling a tool. And so you can see here that it said, oh, I made a call to get weather alerts. Um and that is what's happening. So there's a tool call that's happening. And in just a moment, I happen to know that as soon as we get a few drops of rain in California, you know, there's alerts all over the place. So, here we go. Here's a whole bunch of weather alerts in California. You'll see why I'm I'm pointing that out. It's kind of fun. Um, okay. Now, let me show you what this looks like in the temporal UI. So, over here I have the temporal UI, and you can see that I've run a bunch of workflows this morning. And so, let me refresh refresh this. And this is the one that I just ran. And what we see here is, yep, there's all of that dense fog advisory. That's that's about as as extreme as we get in California. A little bit of fog, a little bit of wind, high surf, beach hazards. But here is what happened. So you can see in the temporal UI, you can see each one of those activities that I called. You can see that I made a call to an LLM. That's the create line that you see on the bottom. So we're working from bottom to top. Then you can see that I did a dynamic activity, but the dynamic activity that I did in particular, it doesn't say generic dynamic activity. It says I did a get weather alerts. And then as we do with agentic loops, we take the output of the tool and we send it back into the LLM and we get this. Now I want to show you something here. I'm gonna show you a different example. So, I'm going to ask the question, are there any weather alerts where I'm at? So, does it know where I'm at? And I'm going to start this. And I'm very going to quickly going to come over here and we'll see this one running. And you can see Oh, I'm going to be too slow it looks like, but I'll I'll come back and I'll redo this demo. But you can see how it just it's, you know, brought those things in. So, the other So, I have three tools registered right now. I have a tool that takes in a state. I have a tool that takes in um an IP address and returns a state. And I have a tool that gives me an IP address for the currently running computer. And so I didn't I didn't wire that up that the LLM made those decisions just based on the tools. So all I did was I provided those tools. But you can get that visibility across this in temporal. So, you can see that we started with get IP address, then we got the location info from that IP address, then we got the weather alerts. And here's the ironic thing is there are no weather alerts in New York. So, I think of New York as a place that has much more weather, but maybe today is cal. You have fog, but there's no fog advisories. So, y'all are a lot more resilient than than the rest of us Californians. Okay. So, I want to show you one other thing, which is I'm gonna come back over here. I'm gonna run this again, and I'm going to try to be I I can be a lot quicker. So, I'm going to hit okay. And now I'm going to come up here and I'm going to control C. No workers running. My agent is not running. It's not running at all. And so if we come over here and we take a look at what this looks like in temporal and this is going to give you the clearest picture of what I mean by durability and durable agents is that I have this agent running and you can see that it made the first LLM call. Then it got the made the tool call to the IP address and now it's it's stuck. It started to call the LLM but hang on it something went wrong. the agent itself is not running. And by the way, I could have also done a demo. And I don't have the time to do all of those today, but I could have done a demo where I cut the the network. So I could have cut the network. And what you would have seen here in this little red bar is you would have seen it. Create attempt one, create attempt two, create attempt three. I could have brought the network back and then it would have gotten through. But for brevity here, because I still want to I still have more stuff to cover. I'm just showing you one of the failure scenarios. There's tons of failure scenarios that are covered. So, I'm going to come back over here and I'm going to restart the worker. And what we should see happen is, oh, sure enough, it keeps going. So, it picked up where it left off. Now, when I say it picked up where it left off, of course, I killed the process. There was nothing running in memory anymore. So, when I brought the worker back, it had to reconstitute the state of the application. It did that through event sourcing. So that's the way temporal works fundamentally. Any questions on that? Yes. >> Can we delegate one agent to another agent? >> Can you delegate one agent to another agent? Absolutely. Now we do not yet have native support for A to A if you're thinking about that protocol in particular. But one of the things that you can certainly do is that you can have an agent act as a tool. And so there are a number of different ways to do that. You can either have an activity invoke another agent or you can use some other mechanisms. We have child workflows and those types of things. I'm not going to cover that more advanced use case. But yeah, absolutely. >> A couple of questions. One thing is the way you are coding it. It seemed the functions very itemed. There was like one single line essentially. uh how to make sure that the developers are you know creating function so that the retries are posing a lot so >> second question is the latency just added through because of the framework >> okay I'll so first question is about around item potence so you have recognized that um the activity activities themselves should be item potent um we don't require it we don't check on it because We really don't get into the inner workings of the activities. We leave that up to the developers. Um but that is the the guidance is that if they're not item potent because remember that when we do retries on your behalf, we don't know wh why we never heard back from the first invocation. So we are going to keep retrying until we get back a response. Of course it could be that the request never made it to the activity. It could be that it made it and it invoked the downstream function could have gone wrong in a number of places. So how do you make sure that your developers are doing uh creating your activities to be item potent education. So we don't have any silver bullets there. The second question was around latency because yes I am going up to the server here um with every one of those activity calls and so when we when we think about agents um we the type of latency and Johan I don't remember the exact numbers do you remember what the numbers are I mean it's tiny the latency to go up to the server around activities >> u so it's going to depend a bit where the server is but it's tens of milliseconds >> tens of millc seconds. So it's pretty small. Um so whether I I I think I have heard of several customers who are using this in quite realtime applications. But in the case of agents, especially agents where they're long running and they're running over minutes, hours, days, or they have user interaction, tens of milliseconds is is is tolerable. So there might be use cases where it's not applicable because of that latency, but it's pretty small. It's applicable in most cases. Okay. All right. So, that is the temporal overview. Now, I want to switch back over to the agents SDK now and show you the differences and the similarities. So, let's come back over here. I'm going to go through a few more pictures. Okay. So the OpenAI agents SDK the combination of these two things at a very high level looks like this. At the foundation we have the OpenAI models and the OpenAI API not the SDK but the OpenAI API. So you might have noticed that I've already been using the OpenAI API and we're now going to start using the agents SDK. And then we also have temporal as a foundational element. And now that's what the agents SDK is layered over the top. So those are two foundational components. So it isn't that we're making that temporal sitting on the side or open AI models are sitting on the
边。我们实际上已经集成了这些东西,当我们在代码中遇到集成时,我会做一些评论,并且我完全邀请 Johan 也对此进行补充,因为他在这里领导了集成工程。所以现在你有了代理 SDK,然后你将使用代理 SDK 来构建你的代理,添加防护栏。我将向你展示一些跟踪。所以我向你展示了 temporal UI,但代理 SDK 也有一些非常酷的跟踪功能。你将看到我们已经将这些东西整合在一起。你将看到它们结合在一起。当然还有工具。所以我一直在谈论这些 temporal 活动,我们已经看到了。我将跳过它。呃,跳过它。嗯,所以现在,呃,我们,我将使用我们刚刚完成的完全相同的例子。我将有三个工具。一个是天气 API,另外两个是位置 API。我们要做什么?嗯,我们将在它们周围放置活动装饰器。我将在稍后在另一个代码库中向你展示它是什么样的。我们将确保我们在那里有文档字符串,因为我向你展示了 OpenAI API 如何拥有那个嗯,那个嗯,内部辅助函数,它允许我们生成 JSON 块来描述工具。嗯,代理 SDK 实际上为我们做了更多。所以,你将看到我的一些代码消失了。嗯,然后,呃,是的,然后我们将从那里继续。然后,这将是我们的循环。当我看到代码时,我将向你展示,我们创建那个 JSON 块的方式是集成的一部分。所以你可以接受一个活动,我们为你提供了一个名为 activity as tool 的函数,它将接受活动本身。所以你不必自己担心序列化它。没有内部 API。这是一个公共 API。它是集成的一部分。你将调用 activity as tool,它将生成嗯,JSON 块,然后你也可以设置超时。还有另一个非常重要的部分,那就是你必须配置集成。所以你必须单独的代理 SDK 不使用 temporal,如果你想使用 temporal,你需要确保你包含一个插件,我将在稍后向你展示代码。当然,我们将运行它,并且我们将以相同的方式运行它。好的。所以,让我们演示一下。所以我们将花费更多时间在代码和演示上。请让我回到光标。好的。所以我这里有四个文件要给你看。我将再次从活动开始。所以这是获取天气活动,你将看到它实际上变得更简单了。它只是在获取天气警报上有一个活动装饰器,然后这是它实际调用美国国家气象局 API 的函数。所以那里还有一些代码,它在进行一些格式化,它调用了那个 API 来生成 JSON 块,而那个 JSON 块消失了,因为我们有一个支持该功能的函数。位置活动同样简单。所以字面上就是整个文件。所以我有了这两个带有活动装饰器和我的文档字符串的函数。所以文档字符串描述了参数等等。好的。那么关于代理本身呢?所以请记住,活动只是代理正在使用的工具。我之前展示的是一个用 Python 编写的代理循环,它协调了 LLM 调用和工具调用。所以现在如果我转到工作流,我的工作流看起来是什么样的?就是这样。所以我有一个抱歉,就是这样。这是工作流。好的。而且它基本上是,让我增加字体大小,因为我有足够的空间。请注意,我正在使用代理 SDK。所以我在第 18 行定义了一个代理。我给它一个名字,你的有用的代理,我给它一组工具。这些工具被实现为活动。在那里你可以看到我调用了 activity as tool 函数,它生成了 JSON 块。就是这样。就是这么简单。这就是我实现它的方式。现在请注意,我仍然在工作流中这样做,因为请记住,我之前说过我们有活动,我们有工作流。当你将它们放在一起时,那就是魔法发生的地方。所以将这个代理放入工作流中,这就是添加所有这些持久性功能的原因。我现在不会演示这个非持久性版本,因为今天我们的时间有限。但如果我只用代理 SDK,也就是一个 Python 库来实现它,我将有一个单一的进程。如果我关闭那个进程,一切都会随之消失。我无法扩展那个进程。而且请记住,我有一个 runner.run 在这里,对吧?所以每一个 runner,它只是一个整体代理,对吧?它只是一个 Python 进程。通过这样做,你可以看到,如果我运行多个工作程序,我可以通过运行多个工作程序来扩展它,这些工作程序只是从队列中拉取其他东西。>> 是的。>> 代理之间的交接有效吗?>> 代理之间的交接有效吗?是的。我将在最后一节回来讨论这一点,届时我们将讨论编排。嗯,是的,它们有效。绝对。嗯,好的。所以,现在让我去,呃,我需要,我确实需要从这里拿出另一件事。我需要我的工作程序。嗯,我的工作程序在哪里?这是我的工作程序。因为它在工作程序中,嗯,在哪里是插件?Johan,帮帮我。>> 我刚刚把它传过去了。哦,找到了。OpenAI 代理插件。好的,所以它在工作程序中。请记住,工作程序是所有执行发生的地方。把它想象成一个逻辑上的隐喻容器。而且你经常在容器中运行工作程序。这是你需要放在那里的配置。就是那些,请注意,它正在做一些事情,比如它正在配置 LLM 的一些重试行为。你会注意到,你注意到我没有给你一个调用 LLM 的活动,那是作为代理的一部分完成的,但我们仍然希望它具有持久性。这就是我们实现的一个功能。所以你正在为 LLM 做一些重试策略,你基本上是在说,嘿,OpenAI 代理 SDK,使用 temporal 的这些部分。所以让我告诉你一些关于我们作为集成一部分所做的事情。如果我们回到并查看 OpenAI 代理 SDK 的提交历史,你会发现一个提交,上面写着“使 runner 类抽象”。他们为我们做了这件事,因为那是我们实现,那是我们如何使 LLM 调用与你刚才看到的所有工具一样持久。所以我们有自己的抽象 runner 类实现。所以这就是它的工作方式。好的。所以我们看了活动,我们看了工作流,然后我们运行了工具工作流。所以,我认为那里没有什么更多要看的了。所以,让我们来看看这个。嗯,让我找到我的正确窗口。就是这个窗口。好的。所以,在这个窗口里我正在做的事情,让我稍微增加一下字体大小。就是在上面的窗口里。我将退出这些,因为我只需要两个。好的。所以,在上面的窗口里,我再次运行我的工作程序。你之前看到过。所以,我在那里运行我的工作程序。所以,它有一些日志消息会出来。然后在这里我正在启动工作流。我在这里与代理进行交互。所以,我将,我刚刚推送了一些东西。哦,我稍后会给你看仓库。所以,加州有天气警报吗?请记住代码。代码就是那个代理,对吧?我们仍然实现了我们的活动,但代码就是那个代理,我们正在检查,你可以看到那里滚动的那些东西。所以,你可以看到实际上是嗯,LLM 的 API 调用。你可以看到美国国家气象局的 API 调用。所以,如果我们回到 temporal UI,它是一个不同的,它叫做工具工作流。在这里你可以看到它看起来完全一样,对吧?这就是为什么我想花时间用 temporal 向你展示它,因为 temporal,如果你正在构建这些 temporal 原生的应用程序,你就会获得所有这些持久性。你获得了这种可见性。它看起来完全一样,但你正在使用代理 SDK 来实现你的代理,我认为这非常酷。所以,让我们运行第二个。嗯,我稍后会给你看仓库。我们将运行第二个例子,也就是我这里有天气警报吗?我们将在这里看。我们将看着它进行中。所以,它正在运行。它正在以完全相同的方式运行。我将在它回来时再运行一次。它说,“不,你在纽约没事。”我再运行一次。我让它开始。进行到一半。Ctrl C 退出。我们回到这里,我们看到和之前一样的东西,对吧?代理 SDK 持久,这太棒了。我,我抱歉,我经常这样做,但我仍然对此感到非常兴奋。嗯,它来了。我将与你分享,嗯,嗯,一种直观地思考我们在这里做什么的方式。我写软件已经超过 30 年了。是的,我有灰头发证明这一点,对吧?我写过软件,当我写软件时,我正在考虑它运行的进程。我正在考虑这样一个事实,哦,我这里有一个进程,如果那个进程发生什么事怎么办,或者当我扩展事物时,事物可能不会在相同的进程中运行,我总是在考虑使用 temporal 的进程,你可以做到的是,你可以编写你的程序,将进程视为一个逻辑实体,然后让 temporal 将其映射到实际的物理进程。这尤其,当你在做像“人机协作”这样的事情时,看起来非常酷。所以,本周早些时候我做了另一个,我做了另一个,我做的另一个演讲是关于“人机协作”与代理,而“人机协作”的一个大痛点是,当你考虑构建这些东西时,你正在考虑进程,你就像,好的,我需要运行一段时间,然后我将等待“人机协作”,这可能需要一秒钟,可能需要一分钟,很可能需要几个小时或几天才能让这个人回来。我该如何处理那个等待响应的进程?就像你作为开发者必须弄清楚这一点。使用 temporal,你不需要。你只需要像那个进程一样编写它。顺便说一句,工作程序架构的工作方式是,如果它在等待像人工输入这样的东西,它会在内存中保留一段时间,几秒钟,然后它会将其从活动内存中移除,但它仍然在缓存中。再过一段时间,它就会从缓存中移除,就像你刚刚关闭了那个进程一样。所以,当它在几天或几周后回来时,当用户回来给你输入时,它就会像等待用户时一样重新构建内存并继续进行。所以请记住,我说过它可能崩溃,也可能是其他事情,运营方面的事情,所有这些类型的事情。所以,一旦你开始真正深入 temporal,它就非常自由。意识到我不再需要考虑物理进程,这非常自由。对我来说,进程只是逻辑的。Temporal 会为我处理其余的事情。超级酷的东西。好的,我们还有大约 20 分钟。我将再看几张幻灯片来回答一个关于交接的问题。嗯,并向你展示更多内容,然后我们将有一些时间在最后,我不知道,也许 10 分钟,你知道 10 或 15 分钟,我很乐意回答更多问题,Johan 我相信也很乐意加入。好的。所以,让我,所以,嗯,使用 OpenAI 代理 SDK。我在这里谈论的内容在某种程度上特定于代理 SDK,但这确实可以泛化到代理,也就是使用 OpenAI 代理 SDK。他们使用的范例是构建许多小型代理,这些代理有自己独立的代理循环,然后将它们编排在一起。在代理 SDK 中,有两种方法可以将它们编排在一起。我将在稍后向你展示这两种方法。所以,我们在屏幕上看到的只是几个图表,比如,我有一个分类代理。我有一个澄清代理。然后我有一个“人机协作”。那不是代理。虽然你可能认为人类是这个应用程序中的代理,对吧?然后我有一个指令代理,它将构建一些东西。然后我有一个规划代理。然后你可以看到我们正在并行地做事情。我没有谈论过这个,但 temporal 拥有所有这些抽象。你可以用任何你能在普通编程语言中写出来的东西,你想做多线程,有很多不同的线程,并行地做事情,然后等待它们重新汇合。你可以做到。你想有一种等待,说,“你知道吗,当它们开始进来时,我将开始处理它们。”没问题。你可以做到。任何你能在代码中做的事情,你都能用 temporal 做,因为你只是在编码。所以,这就是代理 SDK 的工作方式。嗯,我也会再次向你展示这些东西。所以你可以并行,你可以长时间等待。嗯,你也可以有循环。所以我已经向你展示了我不需要在 Python 中编写我的逻辑。逻辑,LLM 决定了那个应用程序的流程将如何发生。对吧?所以我只是有一个循环,循环本身是固定的,但循环中发生的事情完全由 LLM 决定。所以这些都是你可以做的事情。所以,有两种方法可以使用代理 SDK 来编排这些微代理。顺便说一下,我必须说我喜欢“微代理”这个词。正如我早些时候提到的,嗯,我,嗯,我在微服务领域花了很多时间,哦,天哪,我们从中获得了多少收益,对吧?这就是我们能够一天部署多次软件的原因。这就是我们能够按我们能扩展的方式扩展的原因。微服务已被证明非常有价值。我们,我认为我们将看到一个非常相似的范例,非常相似的成功,当涉及到构建人工智能代理,MCP 工具,以及所有这些东西时。所以,我喜欢“微代理”的概念,它们只做一件事,并且做得很好。我在 Unix 世界里也待了足够长的时间,这让我心旷神怡。所以,只是代码和交接。只是代码非常简单。这是我之前描述的。所以,你可以看到我有一个 runner.run。我正在执行一个代理。我从那个代理那里得到一个结果,然后我将那个结果传递给下一个代理。我可以并行化,我可以循环,我可以做任何我想做的事情。第二种方式,哦,是的,我已经展示了所有这些。嗯,所以,是的。是的,我之前已经提到了所有这些。嗯,第二种,嗯,嗯,方式是 OpenAI,你是在问 OpenAI 特别是关于交接的时候吗?是的。所以,对于你们不知道的人来说,OpenAI 有第二种编排方式,称为交接。所以,你在这里看到的是,在我定义一个代理时,我可以定义交接。那些交接是其他代理。它们已经被定义了。我可能应该把它放在幻灯片上,但我有一个天气代理,它的定义非常相似。它使用代理,有一个名字,有指令,可能有工具。所以这两个是代理。嗯,所有这些都与嗯,嗯,与 temporal 的集成一起工作,但有趣的是,这些微代理在交接给代理时,它并没有进行单独的代理循环。它有效地,这是我试图描述正在发生的事情的古怪尝试,那就是当你进行交接时,你实际上所做的只是改变代理循环的上下文。所以,有一个单一的代理循环,你有一个分类代理,例如,它决定它将进入交付。我在 Alexa 工作过一段时间,所以你问了 Costco 几点关门,还是问了现在的温度是多少?对吧?所以,这是两个不同的代理,天气和本地信息代理。而你实际上所做的就是,你就是那个代理循环承担了不同的角色。你只是切换了上下文。而且我们本周听了很多关于上下文工程的演讲,因为 LLM 健忘的美妙之处在于,你可以完全控制你想要什么,进入它们的上下文是什么。所以,这完全有效。所以 temporal 完全是交接。我没有现场演示。嗯,所以,就是这样。好的。所以,有了这些,我们将剩下几分钟时间提问。我想给你留下一些资源。所以,你在左边看到的这个是 temporal Python SDK 的二维码。你会发现关于我们的 Python SDK 的很多很棒的信息,但你也会发现一个 contrib 目录,那里有所有与 OpenAI 代理 SDK 的集成代码。你会在那里找到很多示例。在右边,我没有它的二维码,因为我的营销人员不在周六早上工作。对他们来说很好。嗯,是 URL。所以,如果你去我们的文档,docs.temper temporal.io。在顶部的横幅中,你会找到 AI 食谱。我们有一个 AI 食谱,它实现了许多模式。我今天向你展示的那个,代理循环,目前在一个分支上。它已准备好合并。它已经过审查,但我的审查员实际上没有给它批准审查。他们只是审查了它并说,“看起来不错,但我需要批准,所以我今天早上无法合并它。”嗯,但那个食谱将在那里。还有一些其他的。那里有一个关于 OpenAI 代理 SDK 的食谱。所以你会在那里找到它。嗯,所以,总结一下,我不,我不会详细说明。我认为我们也已经讲过了。我想留给你另外两个资源是左边,你会发现我们的博客,我们在其中描述了 OpenAI 代理 SDK 和 Temporal 的集成。所以,左边的那个是博客。你还会注意到,我有一个 paidantic 博客。所以,这种将持久性带入这些否则非持久性的嗯,你知道的代理框架的想法非常受欢迎。所以,在我们做了 OpenAI 代理 SDK 之后,pyantic 本身将 temporal 集成到了他们的代理框架中,Johan 你,我不知道哪些我们可以谈论。我们还有很多正在进行中的。这就是今天的所有内容,还是你想谈论其中任何一个?这就是今天的所有内容,但还有更多即将到来。>> 是的,我认为我们现在有两个、三个或四个正在进行中,它们将从我们或一些其他代理框架中出现。所以,这种将持久性带入否则只是一个概念验证工具的想法正在变得非常强大。最后,如果你愿意,这里有一个二维码和一个 URL。如果你想给我们提供关于这次研讨会的反馈,我们将非常感激。嗯,并在反馈中包含。有一些自由格式的内容。在反馈中包含你希望看到更多什么。比如,嘿,这个很酷,但它没有深入,或者你提到了这个。我真的很想看到更多关于“人机协作”的内容。顺便说一下,如果你去我们的 YouTube 频道,你会找到很多不同的演示。所以,“人机协作”,我三周前做了一个关于它的网络研讨会。我们做了一些 MCP 模块,MCP 的东西,甚至高级的。所以,我们做了一个高级的,我们向你展示了如何使用 temporal 来实现一个 MCP 服务器,它是持久的,并且以比其他方式更持久的方式支持采样和引诱。嗯,有了这些,我们现在还有大约八分钟。嗯,哦,我还要特别提到,尤其是如果你在湾区,但即使你不在,我们的会议,我们的重播会议,temporal 会议,嗯,在五月,将在 Moscone 举行。所以,我们很想在那里见到你。哦,我,你知道这个二维码是为我周二做的研讨会准备的,但嘿,在这里用也无妨。75% 的折扣。是的,75% 的注册折扣,嗯,用于重播。所以,邀请你来参加。你会找到我,你会找到 Johan,你会找到我们更多的人。而且你可以看到我们有各种很酷的人,比如 Samuel Coven 来了,我们有来自 Replet 和 Nvidia 的人,还有更多人来了。所以,我会把反馈留在这里。所以,我们还有几分钟时间提问。>> 是的。>> 嗯,temporal 如何保存状态?>> 状态是如何保存的?>> 你关闭了服务器,它就失去了所有工作程序的内存。>> 是的。好的。所以,你说的是我向你展示的 temporal 服务器,你可以本地运行它。所以,当你本地运行时,你可以打开一个开关,说,“嘿,把它存储在像 SQL light 这样的东西里。”所以,你可以,它有支持它的状态。我通常不那样运行,因为我总是想扔掉东西。嗯,所以 Temporal 是开源的,我们有很多用户会自己托管它。因为它是开源的,我们真的,在这样的活动中,我们总是遇到人们。我昨天或者什么的遇到了一个人,他说,“哦,是的,我们正在使用 Temporal。”我说,然后他们只是在使用开源的。嗯,所以,它确实是开源的。嗯,所以我们确实有人自己托管它,我们支持关系数据库和 Cassandra 作为 temporal cloud 的后端存储。人们之所以选择 cloud 的原因之一是,首先,我们在 15 个不同的 Amazon 区域运行 cloud。嗯,我不知道,四个、五个、六个 Google 区域。我们有跨区域命名空间。所有这些持久性。然后我们在持久性方面也有一些特殊的技巧,可以让我们更有效地做事。嗯,嗯,但我们有很多人成功地使用 Cassandra 或数据库选项来托管它。所以,是的,还有其他问题吗?是的。>> 启动和停止代理。>> 当我启动和停止实例时,代理,你的意思是?我的意思是,如果用户想停止它,我们该如何停止它?>> 工作程序所以>> 工作流>> 是的,嗯,所以有几种不同的方式可以启动工作流,你可以启动一个工作流,期望它是,你知道,同步的,它就结束了,你必须有一种方式来终止它,但更常见的是,你将以异步模式启动它,你将得到一个句柄,然后你可以对那个句柄执行操作来停止工作流。嗯,但总的来说,最常见的事情是,你将在你的逻辑中定义完成代理体验或以某种方式完成工作流的含义。所以,你将决定,“哦,我现在完成了”,然后你就会返回。所以,这就像从它返回一样简单。这是一个好问题,因为我们正在谈论这些异步的事情。我在这节课中没有谈论它,但其中一个非常强大的功能是,这些工作流可以运行数小时、数分钟、数天、数周、数月、数年,而且效率非常高。而且我们,很多用户使用的模式是,他们将工作流用作某种事物的数字孪生。我们也称之为实体工作流。例如,你可能有一个对应于忠诚客户的工作流,每次该忠诚客户在结账时扫描其二维码时,它都会向工作流发送一个信号,而工作流否则不消耗任何资源,它就会弹出,接收信号,处理它需要的东西,然后再次消失。所以,这是一个非常非常常见的模式,就是这种数字工作流作为其他处理器或其他实体的数字孪生的概念。超级超级强大。很多人使用它。>> 是的。>> 另一个。>> 是的。>> 嗯,所以如果工作停止了,你把它放在那个块状状态,它就一直坐着,>> 你们有没有什么与事件管理之类的东西集成,可以触发警报,让工程师进来工作程序?是的。所以,据我所知,我们没有这些集成,但我们的客户构建了这些集成。>> 是的。是的。他们绝对在上面构建。我们是否在 cloud 中有一些我不确定,但我们没有像原生的 Slack 连接器或那些类型的东西。而且其中一些当然不一定是 temporal 的东西。比如,如果你在 Kubernetes 上运行你的工作程序,你可能已经设置了你的 Kubernetes 配置,这样当嗯,当容器关闭时,你会收到警报,或者当你看到 Kubernetes 仪表板中的某些内容时,哦,天哪,比如我的自动扩展器,当然你可以有这些工作程序,你可以在 Kubernetes 上运行它们,并带有自动扩展器。所以,很多这些,或者你知道,像编排的东西可能来自你的运营环境。嗯,你,这实际上是一个非常好的观点,我们托管服务器,但我们不为你托管工作负载。所以,你自己在托管工作负载。大多数人喜欢这样,因为他们想要完全控制。我们正在考虑在某些情况下未来托管工作程序,但目前还没有在路线图上。所以,是的。>> 有没有人用 temporal 构建语音代理的例子?>> 有没有人用 temporal 构建语音代理的例子。我手头没有。我>> 我不知道有任何已部署的。嗯,人们正在尝试。我们正在尝试语音代理。嗯,这绝对是有意义的。这是我们期望代理未来发展的一个方向。>> 是的。是的。后面的问题。>> 所以,我还没有在 keep an eye on the cookbook 中设置 Claude。我还没有 Claude 的例子。嗯,我几乎完成了 Gemini。嗯,是的,我们想在食谱中添加 Claude。我们也乐意接受 PR。所以,如果你想将这个例子映射到 Claude,我们很乐意在上面接受 PR。所以,是的,这个食谱是完全开源的。它都在我们的主存储库,我们的主组织中,采用 MIT 许可。>> 是的。>> 有从 Excel、PDF 中提取信息的示例代理吗?>> 从 Excel 或 PDF 中提取信息的示例代理?我个人没有。嗯,你知道,我还会提到我们有一个代码交换。我们有一个食谱,这是我们的,我们非常,我们非常小心地确保它演示了最佳实践,并且我们对它们进行了严格的审查,因为我们不想误导你。我们还有一个代码交换,我们有大约 20、30 或 40 个例子。那里可能有一些东西。我,我老实说不确定。嗯,是的。>> 就像 GitHub 一样吗?>> 是的。所以,你会在我们的网站上找到代码交换,以及所有,我相信代码交换中的所有条目都有 GitHub URL。我们不拥有它们中的大多数,因为它们来自社区,但它们在别人的存储库中。所以,是的,你会找到它。>> 好的。嗯,这已经……哦,还有另一个问题吗?不,我只是想评论一下,我们已经提到了几次即将到来或会非常非常酷的事情,而且,你知道,我的团队正在招聘,嗯,关于这些 temporal 的 AI 应用。>> 招聘插播>> 好的。既然他这么说了,我是一名开发者倡导者。我们也正在寻找开发者倡导者。所以,如果你符合工程师的画像,请与 Johan 交谈。如果你符合开发者倡导者的画像,请与我交谈。所以,好的。非常感谢。