FIELD NOTES 首页 / AI Engineer
AI Engineer播出 2026.11.0552:3623 章约 22 分钟读完整理于 2026.11.06

别再给你的 AI 智能体 API 密钥——Kim Maida(Keycard)与 Mason Egger(Temporal)

Kim Maida 演示如何用 OAuth 令牌交换替代智能体共享 API 密钥:用户先登录并授权,智能体再以自身身份代表用户请求访问,每次工具调用只获得短时、限定范围的令牌。Keycard 的演示展示了智能体身份、用户身份、审批额度和审计日志如何共同工作,让系统区分谁提交、谁批准,以及智能体是在代表谁行动。Mason Egger 随后介绍 Temporal 的持久执行能力,通过强制停止并重启 worker,展示工作流如何从故障点恢复而不重复调用模型或执行已完成的活动。最后,他说明如何通过拦截器和载荷加密避免把敏感凭据写进事件历史。

01 0:16 229 字

开场介绍

Kim Maida

我叫 Kim Maida,在 Keycard 工作。Keycard 为智能体提供运行时身份与访问管理。

Mason Egger

大家好,我叫 Mason Egger,是 Temporal 的解决方案架构师。Temporal 为软件应用提供持久执行能力,智能体也包括在内;其实几乎整个技术栈都适用。

Kim Maida

今天工作坊需要的所有材料都在屏幕上的链接里。你不必提前注册 Keycard,课程里会带你完成注册。如果想在课后自己使用 Keycard,可以打开页面底部的链接,输入注册代码,创建个人账户。

02 1:17 162 字

给智能体 API 密钥的问题

Kim Maida

好,这张幻灯片我们稍后再回来。我先聊聊智能体的访问权限。现在我们经常把 API 密钥交给智能体,让它们访问资源,这么做有好几个问题。首先,凭据无法归属到某个用户身份或智能体身份。其次,智能体会拿到该密钥所包含的全部权限,访问不受限制。最后,我们也不能事事都让人在环路中把关,因为人也会犯错,而且很多智能体本来就是自主运行的。

03 2:01 295 字

什么是令牌交换

Kim Maida

Keycard 用一种叫令牌交换的开放标准来解决这个问题。这个标准从 2020 年就有了,它扩展了 OAuth 2。今天我会演示整个流程。

要给智能体以及它背后的用户建立身份链,首先得知道用户是谁。授权服务器会验证身份并签发令牌。Google、Okta、Auth0 等身份提供商都提供授权服务器。要在智能体的执行路径中保留完整的身份链,用户就得先登录。

登录后,授权服务器会征求用户同意,把一部分资源访问权限委托出去。那部分权限叫 scope(作用域)。这是第一次收窄访问范围:我们只把用户全部权限中的一部分委托给智能体。之后授权服务器会签发令牌 I,用来标识用户,并包含用户所拥有的访问级别。

04 3:12 720 字信息密度高

跟踪提示词如何经过智能体循环

Kim Maida

看看智能体的执行路径。现在有一位身份已验证、身份信息明确的用户,想用大语言模型与资源交互。智能体是一个会调用大语言模型的控制循环。今天工作坊里,我们会用一个费用报销智能体:它会调用费用 MCP 服务器,服务器位于智能体与账本 API 之间,为智能体提供一组明确的工具,并连接下游资源。

MCP 客户端接收智能体提出的工具调用,再把它们派发给 MCP 服务器。运行时是和智能体循环一起运行、负责执行调用的进程;今天这个运行时就是 Expense Desk 应用。我们会用这个定制 Expense Desk 应用里实现的 LangChain 智能体。

顺着一条提示词看完整条执行路径:用户把提示词提交给运行时,运行时调用模型并把提示词发给大语言模型。模型提出工具调用后,MCP 客户端把它派发给 MCP 服务器;服务器执行工具,再调用资源 API。API 把响应返回 MCP 服务器,MCP 客户端再把响应交给运行时,运行时调用模型。这个循环会一直重复,直到模型给出答复并返回给用户。

还记得吗?用户已经通过身份验证,并持有能标识自己身份的令牌。这个令牌就是所谓的 subject token(主体令牌),标明智能体将代表谁行事。要支持令牌交换,我们需要一个能够执行代码的 OAuth 客户端。它可以是 MCP 客户端与第三方 MCP 服务器之间的网关、自定义智能体应用,或是围绕现成编程智能体的 CLI 封装。今天的 Expense Desk 是一个自定义智能体应用,它实现了令牌交换,以便访问 Expense MCP 服务器。

这个 MCP 服务器也支持令牌交换,继续访问下游资源,也就是账本 API。账本 API 连接到实际存放费用数据的数据库。

05 5:42 762 字信息密度高

每次工具调用都使用独立令牌

Kim Maida

提示词和主体令牌会发送给 Expense Desk 智能体应用。智能体循环开始运行,模型提出一次工具调用。

Expense Desk 智能体会向 Keycloak 的安全令牌服务验证身份。这是一种特殊的授权服务器。Expense Desk 智能体可以用自己的客户端凭据或工作负载身份完成认证;它还会发送用户的主体令牌,声明用户身份及其授权级别。

接着,Expense Desk 的 OAuth 客户端创建令牌交换请求,申请访问 MCP 服务器的权限,而且只为这一次特定的工具调用申请。此时我们有三项信息:请求访问的智能体身份、智能体代表其行事的用户身份,以及用户授予智能体的访问级别。

然后要判断是否签发所请求的令牌。我们可以用策略来评估:请求访问什么资源、智能体是谁,以及它代表谁行事。如果委托链和所请求的访问权限都符合策略,Keycard 就会签发一个只能在 MCP 服务器上使用的访问令牌。这个令牌通常几分钟内就会过期,绝不能存储。

令牌会发送给 Expense Desk 的 MCP 客户端,客户端用它作为 bearer 凭据调用 Expense MCP 服务器。MCP 服务器验证令牌后,用它授权这次工具调用。工具还需要访问账本 API 资源,所以 MCP 服务器会再进行第二跳:向 Keycard 发起自己的令牌交换请求,申请访问下游的账本 API。Keycard 根据策略评估请求,然后签发一个仅包含这次特定工具调用所需权限的资源令牌。

MCP 服务器收到令牌后,用它调用账本 API。API 验证令牌并授予相应的请求权限。MCP 服务器从不存储令牌,调用一结束就会丢弃它。API 响应随后沿原路返回,智能体循环继续,直到模型把答案交给用户。

大体上,这就是今天要用 Keycard 实现的流程。我们再把这张幻灯片调出来。

06 8:49 296 字

搭建费用报销智能体工作坊

Kim Maida

我会和 Mason 一起在屏幕上逐步演示整个流程。你可以跟着做,也可以只看。工作坊会使用一个预先配置好的共享 Keycard 组织。如果你参与操作,就会和房间里的其他人处在同一个组织中,也能看到大家在做什么。

打开之前给出的链接,就会看到这个在沙盒中运行的工作坊。我们现在启动它,配置大概需要一两分钟。基本设定是先从一个不要求登录的费用报销智能体开始。它在任何时候都不知道是谁在操作,每个使用者也都通过 API 密钥使用这个智能体。

现场有几位朋友会帮忙填充演示数据。如果你也想跟着操作,之后会需要 Keycard 管理员权限。进行到那一步时,他们会留意用户列表里的新用户,并为你授予管理员权限。

07 10:29 434 字

起点:所有人共用 API 密钥

Kim Maida

工作坊刚开始时,你会看到这个应用。我们不知道任何人的身份。所有人都使用同一个 MCP 服务器,但各自运行自己的智能体;大家都用 API 密钥,可能用同一把,也可能各用各的,我们无从得知。

费用报销流程很常见:提交费用,然后批准或驳回,之后再付款——不过演示里实际上不会付款,所以你收不到钱。Expense Desk 的所有操作都通过智能体完成。我们先提交一笔费用。我告诉智能体要为工作坊零食报销 75 美元。它提交了申请,状态显示为待处理。

看下面的活动记录,可以发现这笔费用是通过 API 密钥获得的访问权限创建的。我们不知道用户是谁,也不知道智能体是谁;智能体自己还没有身份。

现在我刷新页面,批准或拒绝其他人的一笔费用。选中这笔后点批准,系统基本上就是把这件事作为一条提示词发给智能体。它批准了申请,记录显示创建者是这个 API 密钥。所以我们不知道是谁提交了这笔费用。大家都只用 API 密钥;我虽然批准了它,但记录里也没有谁批准的,因为我们手上只有 API 密钥。

08 12:53 545 字

给智能体建立自己的身份

Kim Maida

接下来,我们要给智能体一个身份,让它能够以自己的身份行事。第一步是加入共享的 Keycard 组织。跟着操作的朋友点击说明里的链接,就能用 GitHub 登录并加入 Keycard。进入后,左上角应该会显示“AI NYC 工作坊”,表示你加入了正确的组织。我把窗口挪一下,让大家看得更清楚。

跟着做的话,加入时你可能会看到几条同意授权的提示。这就是我之前讲过的流程:把自己的一部分访问权限委托给智能体,让它代表你使用。

这是 Keycard 控制台。先说应用。应用和资源都是注册对象,同一个对象可以既是应用又是资源。应用可以请求令牌,通过令牌交换逐步访问其他资源。我们先为智能体创建一个应用注册,把它叫作 agent app。因为大家都在同一个组织里,我们得用自己的 GitHub 用户名给应用和资源命名,才能区分各自创建的东西;每个应用标识符都必须唯一。

这里选择隐式同意,然后要获取重定向 URL。这个地址可以在沙盒环境里找到:打开终端运行这条命令,就能得到专属于你这个沙盒实例的重定向 URL。我把它复制过来,作为重定向地址。用户登录后就会被带回这里。现在创建应用。

这样我们就注册好了一个应用,费用报销智能体可以用它来请求令牌。不过,智能体也需要接收令牌,因为用户登录时会把主体令牌交给它。

09 16:54 678 字

给智能体建立自己的身份(续)

Kim Maida

为了让智能体接收令牌,我们还要再注册一次,并把这个智能体应用设为一个资源,也就是令牌的目标接收方。智能体接收的就是身份验证令牌。我们进入资源页面再添加一个资源:刚才那个叫 agent app,这个叫 agent resource。这里也用我的 GitHub 用户名,并使用类似的唯一标识符。

我把凭据提供方设为 zone provider,也就是由 Keycloak 负责处理令牌交换并为这个资源签发令牌。接下来指定这个资源由我的应用提供,也就是刚才创建的 agent app。这个关联会告诉 Keycloak:发给这个资源的登录令牌可以由该应用拿来交换。如果不建立关联,令牌交换请求就会被拒绝。

现在给智能体应用添加它依赖的资源。我回到应用列表找到它,打开依赖项并添加 agent resource,因为应用要通过令牌交换来访问下游资源。我们还要添加 Expense MCP 服务器。这个资源已经预先配置好了,大家共用,不必每个人都创建一个以自己名字命名的副本。

另外,我们希望把智能体的 API 密钥存放在 Keycard 里,而不是留在磁盘上。Keycard 也提供保险库,智能体的 API 密钥已经替你配置在里面了。选中 LLM API,最后再选中用户信息端点,这样我们就能知道当前登录用户是谁,并获取对应的身份信息。然后点击连接。

下一步是给这个 agent app 自己的身份。它必须先能识别自己,也就是完成登录。我点“添加凭据”,再选客户端 ID 和密钥。然后打开编辑器,进入 agent 文件夹,找到 `.env` 文件,把客户端 ID 粘贴进去。

10 21:06 165 字

给智能体建立自己的身份(续)

Kim Maida

我们这么做,是因为现在运行的是本地沙盒环境。如果在生产环境里,通常会用工作负载身份之类的方案。Keycard 还提供 CLI,可以动态填入密钥,不必把它们放在磁盘上。

最后告诉应用 agent resource 的标识符,也就是刚才创建的、带有我 GitHub 用户名的那个 agent resource。等页面显示更改已保存即可。

11 21:48 593 字

在代码中接入令牌交换

Kim Maida

到这里,我们已经配置好 Keycard,让它能够处理令牌交换请求。接下来要确保 Expense Desk 应用本身也能完成这套流程。

看一下代码:agent 文件夹里有一个 agent 文件。往下看……这个窗口挡住了。这里的 checkpoint 文件就是尚未接入经过身份验证的 MCP 访问时使用的版本。工作坊每一课都有一个检查点,里面放着该课结束时对应的代码。我们现在做到练习二,可以去 checkpoints 里找 authenticated 目录下的同一个文件。

接下来找到 MCP 工具集。这里把 Keycard SDK 提供的 Keycard Zone token 传进去。每当智能体要调用 MCP 服务器上的工具时,这段代码就会请求令牌。因此,每一次独立的工具调用都会拿到一个专门限定给该次调用的令牌。

再看 Keycard 文件里的 mint 函数,它会实际发起令牌签发请求。如果没有主体令牌,也就是说没有登录用户,智能体就会通过 client credentials grant(客户端凭据授权)以自己的身份认证。它会用客户端 ID 和客户端密钥向 Keycloak 证明自己的身份,也就意味着此时它是代表自己行事。

现在切到终端,让更新后的代码生效,切换到 checkpoint 二,然后重启服务。回到 Expense Desk,就能看到继续使用已认证费用报销智能体的界面。

12 25:49 56 字

在代码中接入令牌交换(续)

Kim Maida

现在点“以智能体身份继续”,然后问它:“现在使用的是哪个账户?我的审批额度是多少?”我可以直接把这句话复制进去。

13 26:06 293 字

智能体以自己的身份行事

Kim Maida

审批额度,就是你作为用户获准替别人审批的金额上限。页面显示我登录的身份是 Expense Desk 智能体 K Mida,也就是我们在 Keycloak 中创建、并为它配置客户端 ID 和密钥的应用。这个智能体的审批额度大约是 50 美元。

接下来我让智能体替我提交一笔 75 美元的工作坊周边用品费用。备注里写着这是代表 Kim 提交的,但活动详情显示,实际提交者是这个特定的智能体。所谓“代表 Kim”只是我告诉它写进备注里的内容;由于我这个用户并没有登录,它实际上无法核验这件事。这笔费用是以智能体自己的身份创建的。

现在我们回到应用页面看看……其实刚才那个页面可以不用关。就在这儿。

14 28:02 429 字

查看审计日志

Kim Maida

我们可以在 Keycloak 里查看活动记录,也就是 Keycloak 为这个应用生成的审计日志,列出针对它发生的所有活动。

这里有好几种资源,我要专门筛选 Expense MCP 资源,并把时间范围设为最近一小时。我们能看到一条凭据签发记录,使用的是客户端凭据授权,这表示执行者是应用本身,它正在访问 MCP 资源。

接着看预先为大家注册好的 Expense MCP actor。Expense MCP 服务器有多条注册记录,因为它既能接收智能体应用传来的令牌,也能把该令牌交换成访问账本 API 的下游令牌。MCP 服务器是大家共用的,所以我们把结果筛选到它调用账本 API 的记录。

我可以看其中任意一条。这里这次调用中,Expense MCP 服务器把从智能体应用收到的令牌交换成了访问账本 API 的令牌。委托链显示,发起请求的是 Expense MCP 服务器,它代表这个应用行事,访问的资源则是账本 API。这就是智能体以自身身份行事时的委托链记录。

15 31:23 517 字

加入人类用户身份,但不冒充用户

Kim Maida

现在智能体已经能识别自己、以自己的身份行事了。我们也许还希望它代表我们行事,但不能冒充我们。我们不想让记录看起来像是“Kim 做了这件事”,而是要显示“这个智能体用 Kim 的权限代表 Kim 做了这件事”。接下来,我们要把人类用户的身份加入流程。

现在要启用用户委托。我们得在新标签页打开 Expense Desk,因为嵌在沙盒里的 iframe 无法处理外部身份验证,所以把它放到外部窗口里打开。右侧现在有登录按钮,我点一下。它一直在转……好了,因为我之前已经登录过,所以系统自动帮我登录了。现在页面上能看到我的邮箱。

如果我问智能体当前使用哪个账户,以前它会说自己是以智能体身份在行事;现在它知道我已经作为人类用户通过了身份验证。我的审批额度与我的身份元数据关联,是 100 美元。

我还没有以人类用户身份提交过费用。把筛选器改成显示全部费用,就能看到之前那些记录仍然标注为通过 API 密钥提交。加入这些身份信息不会回头改写过去发生的事。我们也能看到 Expense Desk 智能体代表其他人行事的例子。

现在我们既能以人类用户身份行事,也仍然保留智能体以自身身份行事的能力。这个工作坊里的做法是让智能体可以审批低于某个金额的费用。

16 34:01 575 字

审批额度,以及谁批准了什么

Kim Maida

我先试这一笔。我提交一笔 30 美元的团队办公用品费用。系统会验证我的身份,然后提交费用。由于智能体可以自行审批低于 49.99 美元的费用,它提交申请后就以智能体自己的身份批准了。

点开活动详情,可以看到这笔费用是我用自己的邮箱创建的,之后由 Expense Desk 智能体批准。记录里显示了执行审批的智能体标识符,也说明了理由:办公用品符合条件,金额低于 50 美元,而且有明确的业务用途。

再试一下 75 美元的那笔。如果费用超过智能体可以自行处理的审批额度,状态就会变成待处理,需要人来审核。我可以告诉智能体:“我觉得这笔应该通过,请批准费用 123。”它会回答:“我不能批准或驳回自己的费用,得请另一位审核人处理。”之所以能做到这点,是因为现在我们知道所有已登录用户的身份,也知道智能体本身的身份。

之前演示时没展示这一点,但在没有身份信息的旧流程里,我可以批准自己的费用,也可以批准任何人的费用,因为系统根本不知道谁是谁。

我们找一笔其他人的待处理费用……我会发出审批指令。智能体走完了整套流程。现在查看这笔费用的活动记录:它是由 Expense Desk 智能体创建的——这是上一轮流程留下的记录——随后由我的身份驳回。这样我们就能清楚记录谁提交了什么、谁批准或驳回了什么。

此时回到 Keycloak 控制台,进入应用页面,就能找到这个应用。

17 38:04 13 字

审批额度,以及谁批准了什么(续)

Kim Maida

Kitematic 应用。

18 38:11 735 字信息密度高

追踪委托链

Kim Maida

我先清除之前的筛选条件,虽然它们应该已经清掉了。选择 actor,搜索我的邮箱,再把时间范围改成一小时。点开一条已签发的凭据,就能看到发起令牌交换请求的是我的应用 agent app Kitematic,它代表我这个人类用户 Kitematic Keycloak 行事,访问的是 Expense MCP 资源。这是第一跳。

然后再去应用列表里找 Expense MCP actor。其实不需要筛选,记录都在这里。打开一条为访问账本 API 而签发的凭据,可以看到第二跳是 Expense MCP 服务器代表我发起请求,访问账本 API。

第一跳里,智能体拿到我作为人类用户登录时获得的登录令牌,并把它交给 Keycard,交换成下一环节——MCP 服务器——所需的令牌。也就是说,它把主体令牌换成 MCP 服务器令牌,再用这个令牌调用 MCP 服务器,并请求限定到相应工具的作用域。

随后 MCP 服务器拿到智能体传来的令牌,向 Keycard 请求把它换成访问下一项资源——账本 API——所需的令牌。我们可以通过关联的 session 来跨跳追踪这些操作。这里不花时间逐个查找和复制 session 编号,但同一条事件序列的第一跳和第二跳会使用一致的编号。

我把这些页面关掉,现在交给 Mason。

Mason Egger

太棒了,谢谢 Kim。我随身带着我的小缓步动物毛绒玩具 Ziggy,到哪儿都带着。我们还有很多个,离开前记得拿一个,带回家给孩子或自己都行,不用不好意思。接下来我们先不继续讲怎么把安全机制都加进智能体,而是要看怎样部署智能体,确保它们能执行到底;即使失败,我们也知道如何处理,可靠地恢复运行,不丢掉整个流程、不白白浪费大量时间和算力。这就是 Temporal 发挥作用的地方。

19 41:27 1,026 字信息密度高

Temporal:为智能体提供持久执行

Mason Egger

Temporal 是一个持久执行框架。它运行你的代码,并维护应用状态。如果应用失败或遇到错误,Temporal 会把状态重建到出错的位置,然后继续执行。比如分布式系统出了故障,函数调用等环节可以用内置重试,也有各种故障处理方式。

我和客户、用户交流时,常听到大家需要让智能体具备持久性。实际上,智能体本身就是一个循环,不停地调用外部服务的工具。说到底,智能体就是带了一点思考能力的分布式系统。我们为分布式系统解决过的问题,同样适用于智能体循环。Temporal 能让应用持续运行,避免丢数据,也不用重新调用大语言模型、重复消耗 token 等等,让用户尽量感受不到中断。

简单讲讲 Temporal 应用代码的结构。这些内容可以留着之后看,我不深入讲代码。Temporal 里会构建 workflow(工作流),并用 activity(活动)来定义它们。最容易理解的方式是把工作流看成父函数,把活动看成子函数调用。我们把智能体循环实现成父函数调用,也就是一个工作流。每次工作流执行,例如 Keycard 为用户完成一次身份验证,都是一个工作流实例。每次工具调用则是一个活动。这些活动可能失败,而且我们预期它们会失败;发生故障时,可以重试,或重建状态再看接下来如何处理。

下面这个 `async def` 就是活动的样子,看起来和普通 Python 代码一样。Temporal 是代码优先的系统,你可以按需要构建,并连接到各种系统。

这里是结算工作流代码,我不逐行读了。它是一个 Temporal 工作流,可以设置重试频率,然后执行活动:先从账本扣款,再把它标记为已结算。中间有个计时器,用来模拟等待人工介入所需的时间。

其中一个活动就是这里这段常规代码。不过请看最上面的装饰器 `grant_resource`。Temporal 在代码库中提供了许多原生构件,其中一个叫 interceptor(拦截器),可以理解成代码运行到特定位置时触发的钩子。Keycard 团队实现了这个拦截器:活动执行时,它会向 Keycard 获取权限和身份,再返回继续执行。这样我们就能在 Temporal 工作流和活动中完成身份验证,并保持 Kim 刚才讲的身份隔离。每个 worker 可以有自己的身份,一组 worker 也各有身份,从而识别它们并限制权限范围。

接下来我们要找一下……我想我们已经在 Keycard 里配置好了 worker 身份。对。现在启动 worker。

20 45:28 182 字

Temporal:持久执行(续)

Mason Egger

我们已经配置好 Temporal 应用和所有环境变量,现在启动 worker。Temporal 使用 worker-server 架构:Temporal 服务负责维护执行状态和应用状态,另外还有一组 workers。你可以把它们想成 Kubernetes pod,或者 pod 里的进程;请求进来时,它们负责处理工作。接下来点“启动 worker”,先启动第一个。

21 46:02 617 字信息密度高

运行中杀掉 worker,再恢复执行

Mason Egger

现在 PID 572 的 worker 正在运行。Temporal worker 会运行刚才练习里搭好的智能体,并自动接受费用申请。我们可以看到 worker 和它的 PID 572。接下来启动一次结算:切到 client 标签页,发起结算工作流,就会看到 settlement 的工作流 ID。

回到 worker 标签页,可以看到 Temporal 应用输出的日志。它现在正在运行:我们先扣了一枚 token,并为这次调用签发令牌,然后继续执行。刷新 Temporal Web UI,就能看到应用正在运行。我得快点操作一下,然后继续讲……不是 Control,是 Command-Control-C。Mac 上这套快捷键我不太习惯。

刚才应用在运行,账本扣款已经完成。我直接强制杀掉应用。现在运行状态消失了。传统系统里这可能很麻烦:你得把状态存进数据库,等系统恢复后再把它重新加载。Temporal 则把应用状态保存在这里。第一个“账本扣款”活动的输出已经记录下来,活动任务完成了,也扣了 4,200。现在没有 worker 在运行,所以系统会报告工作流任务超时,应用已经停掉。

接着回到 worker 标签页,在结算进行到一半时重启 worker。应用就像故障从未发生过一样继续运行。它根据此前所有响应重建了智能体的完整状态,没有重新调用大语言模型,也没有重新执行之前的活动或函数。它恢复状态、重放操作并继续推进,最终让执行成功完成。

22 48:09 398 字

为什么智能体需要持久性

Mason Egger

为什么持久性对智能体很重要?智能体是循环,而循环里有很多昂贵的东西。大规模调用大语言模型并不便宜,还要处理 token 和各种故障状态。假设一个很长的循环已经走了 12 步,应用状态却全部丢失了。那你要么自己造一个 Temporal:把应用状态维护在数据库里,再实现所有状态重建和重试逻辑;要么使用 Temporal 这样的持久执行系统,让它替你处理。

这样一来,即使智能体下线或失败、大语言模型提供商宕机,甚至 AWS 整个区域都不可用,也没关系。等计算资源恢复,智能体会从刚才停下的准确位置继续执行。如果故障恢复得够快,用户甚至可能完全察觉不到服务中断。

刚才我们让 worker 调用暂停了一分钟,等待审批。假设你是用户,原本知道要等一分钟,故障发生后我在五秒内重启了 worker,你可能根本不会发现出过故障。这就是 Temporal 的作用:它替你处理恢复,让执行不论发生什么都能继续向前。

23 49:28 931 字信息密度高

不把密钥写进事件历史

Mason Egger

有意思的是,这一整套流程中的密钥并没有进入 Temporal 的事件历史。回到客户端运行这条命令——哎,我点错按钮了。还得输入正确的工作流 ID,不然不行。我回去把 ID 找出来。它在 client 标签页里。点向上箭头……希望我还记得 Mac 上怎么粘贴。好了,成功了。

现在能看到一个小 Python 脚本,它说明没有发送 JWT 令牌材料。我们没有把令牌交给整个事件历史。你能看到启动流程和结果。点进去,可以看到“账本扣款”以及下面的结果;每个独立函数都会记录在这里,第二个函数“标记为已结算”也已完成。但查看真正的事件历史,也就是底层记录时,里面找不到令牌,因为我们没有把它存进去。

Temporal 有两种主要方法让敏感数据不出现在历史里。一种是拦截器,也就是 Keycard 为我们提供的方案。Keycard 构建了一个拦截器,把数据和凭据完全排除在历史之外,需要执行时再注入。你可以把它想成即时凭据。

Temporal 还有一个很棒的功能叫 payload encoder(载荷编码器)。你刚才在 Temporal Web UI 里看到,数据是以明文放在那里的。你可以自己加密。Temporal 有一整套模式和库:启动一个 sidecar,创建加密算法并设置加密策略。无论你是自托管还是使用云服务,所有进入 Temporal 的数据都可以加密。我们读不到这些数据,也不掌管你的密钥;说实话,我们并不太关心你在里面做什么,我们关心的是把这些组件按顺序协同起来。

这就是 Temporal 以及用它构建智能体的快速介绍。Temporal 有很多集成可以试,比如 OpenAI、Pydantic AI、LangChain,还有其他很多框架。我想我们现在也在构建一个智能体 harness,之后会推出。想了解的话,欢迎来我们的展台找我们。

Expense Desk 这边,简单来说,我们会把刚才那个演示界面再调出来收尾,也可以回答一些问题。Keycard 负责建立智能体身份并配置 worker;Temporal 则作为执行层,确保智能体正常运行,不会因为灾难性故障、API 宕机,甚至 AWS 某个区域突然消失一天而停摆——这种事情确实会发生。好了,我就讲到这里。