Temporal 是一个开源的持久化执行(Durable Execution)引擎,为构建可靠的长时运行工作流提供基础设施。它把工作流的每一步决策以事件历史(Event History)的形式持久化到服务端,工作进程(Worker)不保存任何状态——任何一步崩溃,服务端都能从最近一次完成的操作无缝恢复执行。Temporal 专为「几分钟到几个月」的任务设计,典型场景包括:LLM Agent 的多轮工具调用循环、需要等待人工审批的业务流程、跨系统的长时数据迁移。它提供 Go、TypeScript、Python、Java、.NET、PHP 六种官方 SDK,开发者用普通代码编写工作流,由引擎负责重试、超时、恢复与可观测性。本篇按安装、上手、核心能力、生产部署、选型对比的顺序展开,帮助你判断它是否适合作为 AI 工作流的执行底座。
掌握 Temporal,意味着你能把动辄数小时、跨多系统依赖的 AI Agent 工作流,从「崩溃即丢失」变成「可恢复、可重试、可审计」的生产级基础设施。这是 AI 工程化落地中稀缺的底层能力。
目录
速览卡是工具类内容的固定首屏模块:30 秒判断「这工具是什么、能不能商用、适不适合我」。
为什么需要 Temporal:进程一崩一切重来,到崩溃后从断点续跑
构建跨多个 LLM 调用、外部 API、数据库写入的长时流程时,常见的做法是用一个常驻进程循环串起所有步骤。进程一旦被 OOM 杀死、发版重启、网络分区或 LLM 调用超时,整个流程状态全部丢失;为恢复状态只能手工重跑,或自建状态表、补偿逻辑和重试胶水代码。任务时长一旦超过几十分钟,这种脆弱性就会演变成生产事故。
Temporal 的解法是把工作流作为状态机运行在引擎中:每一次决策(调用了哪个 Activity、收到什么信号、定时器何时到期)都作为事件追加写入服务端数据库。Worker 不保存状态,崩溃重启后从事件历史重建执行现场,继续执行尚未完成的步骤;已完成的 Activity 直接从历史中读取上次结果,不会重复执行。重试、超时、心跳、信号等可靠性机制由引擎内建,业务代码不再需要手写。
与 LangChain/LangGraph 这类 Agent 框架不同,Temporal 不关心你如何构造 prompt 或编排工具调用,它的定位是承载这些 Agent 逻辑的执行底座。通过官方 temporalio-langchain 集成包,Agent 循环可以放进 Temporal 工作流运行,获得持久化与可恢复能力——两者是互补关系而非替代关系。
安装与环境配置:3 步就绪
步骤一·安装 CLI。Temporal CLI 内置一键启动的开发服务器(含 Server、Web UI、默认命名空间),是上手最快的路径。macOS 用 Homebrew 安装,Linux/CI 用官方安装脚本。
步骤二·启动开发环境。temporal server start-dev 在 localhost:7233 启动 gRPC 服务,并在 8233 端口提供 Web UI。需要完整自托管依赖(Server + Web UI + PostgreSQL + Elasticsearch)时,可直接拉取官方 docker-compose 仓库:git clone https://github.com/temporalio/docker-compose.git && cd docker-compose && docker compose up -d。
步骤三·验证安装。用 CLI 列出命名空间与工作流列表;浏览器打开 http://localhost:8233 看到 Web UI 即就绪。
# 1. 安装 Temporal CLIbrew install temporal # macOScurl -sSf https://temporal.download/cli.sh | sh # Linux / CI # 2. 启动本地开发环境(含 Web UI,默认 8233 端口)temporal server start-dev # 3. 验证安装temporal operator namespace listtemporal workflow list --namespace default
快速上手:30 分钟跑通第一个持久化 Agent 工作流
最小可用流程包含四步:安装 Python SDK、编写一个工作流(先执行 LLM 调用 Activity,再等待人工审批信号)、启动 Worker 消费任务队列、用 CLI 触发工作流。开发服务器自带持久化,无需额外配置数据库。
1. 安装 SDK:执行 pip install temporalio。
2. 创建 worker.py:定义 AgentWorkflow 与 call_llm Activity,代码见下方示例。
3. 启动 Worker:终端 1 运行 python worker.py,Worker 开始轮询 agent-demo 任务队列。
4. 触发工作流:终端 2 用 CLI 启动,指定任务队列、工作流 ID、工作流类型与 JSON 输入。
5. 观察等待状态:打开 UI(localhost:8233)查看事件历史,工作流在第一步完成后挂起,等待审批信号。
6. 发送信号放行:执行 temporal workflow signal 发送 approve 信号,工作流继续第二段调用并返回结果。
结果说明:在 UI 的事件历史中可看到每一步;杀掉 Worker 进程再重启,工作流会从最后一步继续而非从头开始。进阶技巧:接入真实 LLM 时,为 Activity 配置 heartbeat_timeout 并在长调用循环中上报心跳;需要复用 LangChain 组件时,使用官方 temporalio-langchain 集成包。
import asynciofrom datetime import timedeltafrom temporalio import activity, workflowfrom temporalio.client import Clientfrom temporalio.worker import Worker # Activity:承载外部副作用(LLM API 调用)的环节@activity.defnasync def call_llm(prompt: str, step: int) -> str: # 生产环境替换为真实 LLM API 调用,并定期发送心跳 return f"第{step}步已处理: {prompt}" # Workflow:确定性编排逻辑,状态由服务端持久化@workflow.defnclass AgentWorkflow: def __init__(self) -> None: self.approved = False @workflow.run async def run(self, prompt: str) -> str: await workflow.execute_activity( call_llm, prompt, 1, start_to_close_timeout=timedelta(minutes=5), retry_policy=workflow.RetryPolicy(maximum_attempts=3), ) # 等待人工审批信号,期间整个执行状态持久化在服务端 await workflow.wait_condition(lambda: self.approved) return await workflow.execute_activity( call_llm, prompt, 2, start_to_close_timeout=timedelta(minutes=5), ) @workflow.signal async def approve(self) -> None: self.approved = True async def main() -> None: client = await Client.connect("localhost:7233") worker = Worker(client, task_queue="agent-demo", workflows=[AgentWorkflow]) await worker.run() if __name__ == "__main__": asyncio.run(main())
# 终端 1:启动 Workerpython worker.py # 终端 2:触发工作流temporal workflow start \ --task-queue agent-demo \ --workflow-id contract-review-001 \ --type AgentWorkflow \ --input '"分析这份合同的违约条款"' # 人工审批通过后,发送信号放行temporal workflow signal --workflow-id contract-review-001 --name approve # 查看完整事件历史temporal workflow show --workflow-id contract-review-001
核心能力详解:5 大支柱
支柱一·确定性执行与事件溯源。确定性执行(deterministic execution)指同一段工作流代码在相同输入下必然产生相同的执行轨迹——禁止在工作流内部读取系统时钟、生成随机数或直接调用外部 API。引擎以事件溯源(event sourcing)方式把每次决策追加写入事件历史;Worker 重启或缓存失效时,从空状态重放历史重建内存状态,保证恢复后行为与崩溃前完全一致。
支柱二·可靠的重试、超时与心跳。Activity 自动获得指数退避重试,可配置最大重试次数与退避系数,与 start_to_close_timeout(从开始到完成的超时)配合使用。对长达几十分钟到几小时的 LLM 调用或批处理任务,应开启心跳(heartbeat):Worker 定期上报进度,服务端据此判断 Worker 是否失联,并在超时后把任务调度给其他 Worker,避免长任务白跑。
支柱三·人工审批与人机协作。Signal(信号)用于从外部向运行中的工作流注入数据,不阻塞发送方;Query(查询)只读获取当前状态,不产生副作用;Update 提供双向 RPC 语义。结合 workflow.wait_condition(),工作流可以无限期挂起等待人工在审批系统、IM 或 UI 中点击确认,期间状态完整持久化。
支柱四·子工作流与 Saga 补偿。子工作流(Child Workflow)用于把流程拆分为独立可管理的分段,支持并行扇出与聚合;父工作流跟踪所有子工作流状态。Saga 模式用于跨系统事务补偿:例如「先扣款再发货」的流程,发货 Activity 失败后执行退款补偿 Activity,保证数据最终一致。
支柱五·Nexus 跨命名空间编排。Nexus 是 Temporal 的跨命名空间调用协议,在 v1.24 正式 GA。大型组织可将不同团队的工作流按命名空间隔离,通过 Nexus 安全调用彼此的工作流,避免了把所有耦合塞进单一命名空间的运维噩梦,同时为每个命名空间设定独立的权限、限流与故障域。
生产部署与监控:从上线到运维
部署方式一·自托管 Kubernetes。生产环境推荐使用官方 Helm Chart(github.com/temporalio/helm-charts)部署在 Kubernetes 集群,存储后端可选 MySQL、PostgreSQL 或 Cassandra;实时检索、按任意属性过滤查询依赖高级可见性(Advanced Visibility),需要额外部署 Elasticsearch/OpenSearch。生产集群至少 3 个 Server 节点,升级前先核对 SDK 与 Server 的版本兼容矩阵。
部署方式二·Temporal Cloud(托管版)。由官方托管的命名空间服务,负责升级、扩缩容与高可用,按工作流执行量计费。适合不想运维基础组件的中型团队;自托管与 Cloud 在 SDK 层面完全一致,仅连接地址与鉴权方式不同,迁移成本低。
可观测性。Web UI 提供每个工作流的事件时间线(Event History)、轮次 JSON 视图与失败定位;CLI 的 temporal workflow show、temporal workflow list 用于命令行排查;各 SDK 内建 OpenTelemetry 支持,可导出链路追踪(Tracing)与指标(Metrics)到 Prometheus/Grafana。生产排障三板斧:先看事件历史中失败前的最后一条事件,再查 Activity 的重试次数与心跳间隔,最后结合 Worker 日志确认是否为代码确定性被破坏。
<p class="para-label">避坑清单:</p>
<ul class="dash-list"><li>工作流代码必须确定性:直接在工作流里调用外部 API、读取系统时间或随机数,会在恢复重放时执行多次导致状态错乱。所有副作用必须封装进 Activity。</li><li>Activity 会被自动重试,必须保证幂等:LLM 调用、扣款、发消息等操作重复执行是常态;长任务配置 heartbeat_timeout 并在循环中调用 heartbeat() 上报进度。</li><li>注意 SDK 与 Server 版本兼容:老版本 SDK 连接新版本 Server 会报 unsupported version;升级 Server 前先查官方兼容矩阵,避免线上事故。</li><li>大 Payload 限制:默认单条事件数据上限约 2MB(动态配置可调)。超大文档先写入对象存储,在工作流中只传引用,或用 Data Converter 做压缩与加密。</li></ul>
| 维度 | Temporal | AWS Step Functions | Airflow | LangGraph(持久化模式) |
|---|---|---|---|---|
| 定位 | 通用持久化执行引擎 | AWS 云原生状态机服务 | 数据管道调度与编排 | LLM Agent 编排框架 |
| 编排范式 | 代码即工作流(多语言 SDK,确定性执行) | 声明式 JSON 状态机(ASL) | DAG 声明式 + Python 算子 | 状态图(StateGraph)+ 节点/边 |
| 状态持久化 | 服务端事件历史,默认持久化 | 服务端持久化执行状态 | 元数据库保存调度状态 | 需配置 Checkpointer(Postgres/Redis) |
| 重试机制 | 内建指数退避、心跳、超时策略 | 内建重试与超时 | 任务级重试参数 | 无内建重试,需自建 |
| 人机交互 | Signal/Query/Update 一等公民 | 需外部集成实现 | 不原生支持 | interrupt 断点内建 |
| 部署运维 | 自托管(K8s/Helm)或 Temporal Cloud | AWS 全托管 | 自托管(K8s/Composer) | 嵌入应用进程运行 |
| License | MIT 开源 / Cloud 按量计费 | 按状态转换计费 | Apache 2.0 | MIT |
| 适合谁 | 长时业务、Agent 工作流、SRE 团队 | AWS 生态内流程编排 | 批处理数据管道团队 | LLM Agent 快速原型 |
选型建议:快速验证 LLM Agent 逻辑用 LangGraph;需要生产级长时可靠执行、跨系统编排与人工审批,选择 Temporal;纯 AWS 生态且流程较短用 Step Functions;批处理 ETL 管道用 Airflow。Temporal 与 LangGraph/LangChain 不是对立关系——官方 temporalio-langchain 集成包可把 Agent 循环装进 Temporal 工作流,兼得两者的迭代速度与生产可靠性。
版本迭代
Temporal Server 保持约 6 周一个正式版本的节奏,主线围绕稳定性、可观测性与跨组织编排能力演进:2024 年重点落地 Nexus 跨命名空间协议,2025 年完成对状态引擎内部存储机制的 Transition History 重构。SDK 侧各语言持续追赶功能对齐。(截至训练数据,可能已有更新版本)
| 版本 | 时间 | 变化 | 提升 |
|---|---|---|---|
| v1.21.0 | 2024-07 | Nexus 开放公开预览 | 跨命名空间调用进入预览,配套动态配置项落地 |
| v1.23.0 | 2024-10 | 大规模场景稳定性增强 | 高工作流密度下的性能与稳定性改进,调度能力优化 |
| v1.24.0 | 2024-12 | Nexus 正式 GA | 跨命名空间编排协议正式可用,可观测性进一步增强 |
| v1.25.0 | 2025-04 | Transition History 重构 | 状态机内部存储机制重构,显著降低内存占用与历史事件开销 |
选型时优先使用 v1.24 及以上版本以获得 Nexus GA 能力;v1.25 的 Transition History 重构对内存占用是关键收益,适合高吞吐生产环境。升级前务必核对 SDK 兼容矩阵——SDK 版本落后于 Server 两个大版本时会出现协议不兼容报错。
AI 应用场景
长时 Agent 循环的持久化执行
阶段:Agent 编排 / 持久化执行
解决的问题:传统 Agent 循环跑在单进程内,进程崩溃、LLM 调用超时、第三方 API 限流都会导致整个多轮会话丢失。Temporal 将每一轮工具调用持久化为事件,崩溃后从最近完成的一轮恢复,LLM 调用失败自动按退避策略重试。
具体案例:某合同审查 Agent 单次任务 30-60 分钟、含 10 余轮 LLM 调用与文档解析步骤。接入后任务中断率趋近于零,无需人工重启与结果校验;结合官方 temporalio-langchain 集成包,现有 LangChain 链与工具无需重写即可获得持久化能力。
人工审批流(Human-in-the-loop)
阶段:人机协作 / 状态等待
解决的问题:AI 自动审核后需要人工确认才能继续的场景(放款、确诊建议、内容发布),进程重启会导致「审批过了但流程丢了」的严重事故。Temporal 用 Signal 机制让工作流无限期挂起等待,审批结果由外部系统注入。
具体案例:保险理赔 AI 初审流程:自动完成资料核验与风险评分后,触发人工复核信号并挂起;审批系统确认后自动继续执行赔款通知。审批挂起状态全程持久化,服务发版重启不影响任何未决审批。
常见误区
误区Temporal 就是更高级的定时任务调度器,用来跑 crontab 的。
正解调度(Schedule)只是其能力之一。核心价值是持久化执行:把整条工作流的事件历史落库,崩溃自动恢复、失败自动重试、人工信号中途介入、全过程可观测。定时触发只是工作流的入口方式之一,正如 HTTP 触发也只是入口之一。
为何常见:Temporal UI 中有明显的时间线与调度入口,加上多数教程从定时任务切入,容易把它类比为调度平台。
误区反正 Python SDK 能写任意代码,我就在工作流函数里直接调 OpenAI。
正解工作流代码必须是确定性的纯编排逻辑。直接调用 HTTP API、读系统时钟、生成随机数,都会在恢复重放时产生不同行为,导致状态错乱甚至死锁。外部调用必须封装进 Activity,由引擎统一管理重试、超时与心跳。
为何常见:框架不强制拦截这些调用,本地单次运行「看起来能跑」,问题只在崩溃恢复或重放时才暴露,隐蔽性极强。
误区Worker 进程挂了,跑到一半的工作流不就全丢了吗?
正解执行状态全部在服务端。Worker 是无状态的:重启并连上同一命名空间后,通过重放事件历史精确恢复内存状态,从崩溃点继续执行未完成步骤。丢数据的反而是那些把状态存在进程内存里的自研方案。
为何常见:习惯了「进程内状态即一切」的传统后端开发模型,对「无状态 Worker + 服务端溯源」架构缺乏直觉。
误区我用 Redis 存状态 + 消息队列传任务也能实现同样效果,何必引入新组件?
正解队列管消息传递、数据库管存储,Temporal 管的是「多步骤长流程中每一步至少执行一次、失败可重试补偿、人工可介入」的编排语义。自己拼三层要复刻事件历史、重放、心跳检测、确定性调度,工程量远超直接使用引擎。
为何常见:Temporal 内部确实涉及存储与排队,概念上有重叠,容易误判为可替代的分布式组件组合。
面试题
Q1. Temporal 对工作流代码最核心的约束是什么?
- A.必须用 Go 语言编写
- B.必须是无状态的纯函数
- C.必须具有确定性,相同输入产生相同执行轨迹← 正确答案
- D.必须在 1 秒内完成执行
答案:C。确定性是 Temporal 一切机制的前提——只有代码可重放,服务端才能用事件历史重建状态。A 错在多语言 SDK 均支持;B 混淆了「无状态」与「确定性」,工作流内部可以维护局部变量;D 无此限制,Temporal 恰是为长时任务设计。
Q2. 一键启动带 Web UI 的本地开发环境的命令是?
- A.temporal server start-dev← 正确答案
- B.temporal workflow start
- C.temporal operator namespace create
- D.temporal cluster health
答案:A。temporal server start-dev 会同时启动 Server、Web UI(8233 端口)与默认命名空间,是官方推荐的本地开发入口。B 用于触发工作流,C 用于创建命名空间,D 用于检查集群健康状态。
Q3. 需要调用外部 HTTP API 的代码应放在哪个位置?
- A.Workflow 的函数体内
- B.Signal 处理器内
- C.Query 处理器内
- D.Activity 的函数体内← 正确答案
答案:D。Activity 是承载副作用的唯一正确位置,外部调用会被引擎统一管理重试与超时。A 会破坏确定性导致重放不一致;B 和 C 中也不应执行有副作用的调用,Signal 只负责注入数据、Query 只负责读取状态。
Q4. Activity 执行超过 start_to_close_timeout 会发生什么?
- A.超时自动延长并继续等待
- B.该 Activity 被判失败并触发重试策略← 正确答案
- C.整个工作流立即失败终止
- D.需要人工确认后才能继续
答案:B。start_to_close_timeout 是 Activity 从开始到完成的硬超时,超时后该次执行被标记失败,按 RetryPolicy 决定是否重试及退避策略。A 无此机制;C 只有重试耗尽后才成立;D 不适用于超时场景。
Q5. 从工作流外部向运行中的工作流注入数据(如人工审批结果)的正确机制是?
- A.Signal 信号← 正确答案
- B.Query 查询
- C.Timer 定时器
- D.Saga 补偿
答案:A。Signal 是一等公民的异步入站通道,不阻塞发送方,工作流内可用 wait_condition 挂起等待。B 只能读状态不能写;C 是工作流内部机制;D 是失败时的补偿模式,与数据注入无关。
Q6. Python SDK 中让工作流挂起等待某条件成立再继续的 API 是?
- A.workflow.sleep()
- B.workflow.wait_condition()← 正确答案
- C.asyncio.sleep()
- D.workflow.execute_child_workflow()
答案:B。wait_condition 是 Python SDK 提供的条件等待原语,配合 Signal 实现人工审批挂起。A/C 是定时器语义,无法响应外部信号;D 用于创建子工作流,与条件等待无关。
Q7. 关于工作流 Replay 机制,下列说法正确的是?
- A.Replay 发生在 Worker 重启或缓存失效时← 正确答案
- B.Replay 期间可以自由调用外部 API
- C.重放使用的是服务端已持久化的事件历史← 正确答案
- D.Replay 会重新执行已完成的 Activity
答案:AC。Replay 是恢复机制:Worker 重启或缓存失效时,用服务端事件历史从空状态重放,重建内存状态,期间代码绝对不允许产生副作用。B 正是破坏确定性的典型错误;D 错,已完成的 Activity 直接读取历史结果,不会重复执行。
Q8. Temporal 服务端恢复工作流时,如何处理已完成的 Activity?
- A.从事件历史中直接读取上次执行结果,不重复执行← 正确答案
- B.重新调度 Activity 以获取最新返回值
- C.丢弃历史结果并从头执行整个工作流
- D.向客户端进程询问上次结果
答案:A。事件历史记录了每个 Activity 的输入与输出,恢复时直接回放结果,保证「至少一次执行」语义下不产生重复副作用。B 会导致不确定性;C 违背持久化执行的恢复目标;D 客户端可能已不存在,没有询问通道。
Q9. 下列哪些做法会破坏工作流的确定性?
- A.在工作流中调用 random.random()← 正确答案
- B.在工作流中读取 datetime.utcnow()← 正确答案
- C.在工作流中调用 workflow.execute_activity()
- D.在 Activity 中调用外部 API
答案:AB。随机数与当前时间在重放时会产生不同结果,直接破坏确定性。C 是标准编排原语、D 是副作用的正确位置,两者均不破坏确定性。判断标准是:这段代码在重放时是否必然产生相同结果。
Q10. 关于长时间运行的 Activity(如数小时的 LLM 批处理),正确做法是?
- A.不设置超时,任务永远不会失败
- B.设置合理的 start_to_close_timeout← 正确答案
- C.周期调用 heartbeat() 上报进度← 正确答案
- D.把外部调用写进工作流函数体内
答案:BC。超时与心跳是长任务标配:B 设置硬性上限避免无限悬挂,C 让服务端感知 Worker 存活状态,Worker 失联后及时调度到其他节点。A 不设超时会让任务悬挂且不可控;D 破坏确定性,任何外部调用都应放在 Activity。
参考来源
- webpageTemporal GitHub 主仓库Server 源码与 Release Notes