部署 Agent
查看 Markdown本页介绍如何在生产环境中运行 agent framework 的 session。 一次 Flow 执行就是一个 agent session。每次模型调用是一个 RunModel Step,每个 tool call 是独立的 Step。本页中的服务器限制都是 server-zd 的默认值。其余配置见 Server 参考 和 Application。
安装包
连同 framework 一起安装 adapter。Python adapter 发布在 PyPI 上。每个 adapter 都会带上 dex-agents 核心包和它支持的 Dex SDK。需要 Python 3.11 或更高版本。
pip install dex-agents-pydantic-ai "pydantic-ai-slim[openai]"
pip install dex-agents-langgraph
pip install dex-agents-openai-agents
pip install dex-agents-google-adk
pip install dex-agents-claude-agent-sdk
TypeScript adapter 发布在 npm 上。核心包和 Dex SDK 是 peer 依赖,所以应用只持有各自的 一份副本。需要 Node 22 或 24。
npm i @superdurable/dex-agents-vercel-ai @superdurable/dex-agents @superdurable/dex ai zod
npm i @superdurable/dex-agents-mastra @superdurable/dex-agents @superdurable/dex @mastra/core zod
npm i @superdurable/dex-agents-openai-agents @superdurable/dex-agents @superdurable/dex @openai/agents zod
npm i @superdurable/dex-agents-claude-agent-sdk @superdurable/dex-agents @superdurable/dex zod
如果要自己编写 runner,只安装核心包:
pip install dex-agents
npm i @superdurable/dex-agents @superdurable/dex@1.30.0
所有 agents 包共用一条版本线。Python adapter 要求同一版本的核心包,npm adapter 以 peer 依赖的方式依赖它。每个版本都固定了它支持的 Dex SDK,以及测试过的 framework 版本范围, 见兼容性表。 这些包还没到 1.0,minor 版本可能改变 API。在 lockfile 中固定确切版本,升级前先读 changelog。
在每个启动 session 或调用其 RPC 的进程中,构建同一个 session Flow。
Stream 后端
模型的实时文本、推理摘要、tool 进度和审批事件都写入 AgentEvents Stream。无论是 dexcli dev 还是生产 server,streamStore.backend 的默认值都是 memory,所以实时事件不需要额外的服务器配置。不要为 agent 把后端设为 disabled。设为 disabled 时,Step 写入会被丢弃,但不会让 Step 失败;Client 写入和 Stream 读取则返回 FAILED_PRECONDITION。默认配置等同于:
streamStore:
backend: memory
memory 后端把 Stream 保存在 active server-zd 进程的内存中。一个 server-zd 集群只有一个 active 进程,所以单节点不需要额外配置。standby 不保存 Stream。进程每次成为 active 进程时,Stream 都从空开始:重启之后、standby 接管之后, 以及让位之后。standby 对 Stream 调用返回 UNAVAILABLE,客户端会重新连接到 active 进程。
丢失 Stream 数据不会丢失 session。对话、tool call 和待审批项都保存在 Attribute 中。 错过事件的客户端用 get_agent_snapshot RPC 重新加载 session,然后从那里继续读取 Stream。收到 turn_completed 或 turn_failed 后,客户端用已保存的消息替换这一轮的 实时文本。不要把 Stream 当作事实记录。
规划 AgentEvents 容量
AgentEvents 的容量按 Flow type 和 Stream name 计算。同一个 agent 的所有 session 共享这份容量,它不是每个 session 的预算。默认值是 10 MiB。在 Python 中用 AgentSessionOptions 的 event_stream_capacity_bytes 设置,在 TypeScript 中用 createAgentSessionFlow 选项的 eventStreamCapacityBytes 设置。
服务器为每条消息计入序列化后的值、Flow ID 和 source,再加 512 字节。用量达到容量的 90% 时,后台 trimmer 会删除所有 session 中最旧的消息,直到用量降到 80%。如果 trim 跟不上,用量达到容量,写入会被拒绝。Step 会丢弃被拒绝的写入,但不会失败。容量应能装下 每个有客户端在看的 session 的最新一轮:
bytes per turn = messages per turn × (average message bytes + 512)
capacity ≥ concurrent sessions × bytes per turn ÷ 0.8
假设一轮写入 200 条消息,每条约 300 字节(含 Flow ID 和 source),那么每轮约 162 KB。 500 个 session 同时输出时,实时事件约占 81 MB。除以 0.8 约为 102 MB,所以 128 MiB 的容量 可以保留每个 session 的最新一轮。默认的 10 MiB 大约只能保留 50 个这样的轮次。
固定的 512 字节在小文本增量中占大头。Python 核心包为 runner 写入的每个文本增量写一条 Stream 消息。TypeScript 核心包会把连续的增量合并,最多合并 100 ms 或 1,024 个字符。 Python adapter 每轮的消息数会更多。
一条 Stream 消息最大 100 KiB,由 streamStore.maxMessageBytes 设置,更大的写入会被丢弃。 memory 后端把所有 Stream 都放在服务器内存中,所以服务器内存要按所有 agent Flow type 和其他 Stream 的容量之和来规划。
规划 Worker 容量
每个正在运行的模型调用、tool call 和 RPC handler 都占用一个 Worker task slot。等待用户 消息、审批或 tool 结果的 session 不占用 slot,等待发生在 Dex Server 中。每个 Worker 池的 容量应覆盖同时调用模型的轮次、同时运行的 tool call,以及 RPC 预留。
同一次模型响应中的 tool call 作为并行 Step 运行。Worker 的 slot 至少要够模型一次发出的 最大一批 tool call。默认的 task 上限是 CPU 数量。模型调用大部分时间在等网络,所以 agent Worker 通常需要更高的 maxConcurrentTasks。各 SDK 的选项名见 容量和关闭。
保留 RPC 预留容量。UI 以 RPC 的形式调用 get_agent_snapshot、send_user_message 和 resolve_interrupt。没有预留时,这些 调用要排在占满 Worker 的模型调用后面。不设置时,task 上限至少为 2 则预留一个 slot,否则为零。 Step 从不使用预留 slot。Step 任务队列持续增长,说明 Step 需要更多容量。相关指标见 Step 任务队列。
server-zd 默认为每个 app Worker ID 允许 256 个 stream (matching.maxConcurrentTasksCap)。一个 Worker 为每个 task slot 打开一个 stream, 所以它的 task 上限要落在这个范围内。需要更多时,运行更多 Worker 进程。
留出余量。没有 Worker 有空闲 slot 时,Step 会在队列中等待。等待不消耗 attempt, 也不计入 method timeout 和 heartbeat timeout。等待 slot 的一轮或一次 tool call 会花更长时间。 见 Tool call 的限制。
长时间模型调用和超时
这些 Step 选项由包设置,AgentSessionOptions 不能修改。
| Step | 方法超时 | Heartbeat 超时 | Attempt | 失败路由 |
|---|---|---|---|---|
| RunModel | 15 分钟 | 2 分钟 | 30 分钟内 3 次 | RecordTurnFailure |
| CompactContext | 15 分钟 | 2 分钟 | 30 分钟内 3 次 | RecordTurnFailure |
| CallTool | 2 小时,Dex 默认值 | 1 分钟,Dex 默认值 | 3 | RecordToolFailure |
| CallSingleAttemptTool | 2 小时,Dex 默认值 | 1 分钟,Dex 默认值 | 1 | RecordToolOutcomeUnknown |
runner 工作时,RunModel、CompactContext 和两种 tool Step 每 20 秒发送一次 heartbeat。所以慢但没有输出 的模型调用或 tool call 仍然在 heartbeat 超时之内。方法超时依然会结束卡住的调用。在 Python 中,runner 和 tool 代码要保持非阻塞:在 event loop 上的阻塞调用也会让后台 heartbeat 停下来。
一次模型调用必须在 15 分钟内完成。把 provider 或 framework 的请求超时设得比它短,这样慢 调用会带着 provider 的错误失败,后续 attempt 也还能落在 30 分钟的重试窗口内。Claude Agent SDK session 在一个 RunModel 中运行整段轮次,所以这一段必须在 15 分钟内完成。Dex 如何 发现丢失的 attempt,见 Heartbeat。
分开的 Worker 池
Dex 按 Flow type 路由工作。注册了某个 agent Flow type 的每个 Worker,都可能收到它的模型 调用、tool call 和 RPC。包会一起注册 session 的所有 Step,所以同一个 agent 的模型调用和 tool call 共用一个 Worker 池。某类工作挤占另一类工作时,可以这样拆分:
- 给每个 agent 独立的 Flow type 和独立的 Worker 部署,这样繁忙的 agent 不会占用其他 agent 的 slot。
- 把重量级或特殊的 tool 工作,比如浏览器、沙箱或 GPU 任务,放到有自己主机和扩缩容的服务中。 tool 用这次调用的幂等键调用该服务。session Worker 只需要等待网络,服务可以独立扩缩容。
长 session 的限制
一个 session 可以持续几个月。以下 server-zd 限制 决定它能增长到多大。
| Key | 默认值 | 限制对象 |
|---|---|---|
| limits.maxFlowStateBytes | 64 MiB | 一个 session 的全部存储:当前状态、Attribute 和 Channel 值,以及为 time travel 保留的被替换值 |
| values.maxValueBytes | 16 MiB | 单个值的上限,比如一条消息、一条 tool call 记录或一份 framework run state |
| history.windowSemanticEvents | 约 10,000 个事件 | 每个 run 保留的 Flow history。更早的事件会被裁剪。 |
| retention.closedFlowDuration | 7 天 | 已停止的 session 还能读取多久 |
每个 run 在启动时记录这些值。新值只对服务器带着新值重启之后启动的 session 生效。
包这样保存状态:
- AgentMessages 保存最新的消息,每条消息一个 AttributeMap 实例。保存一条消息只写这一条。 其中超过 64 条消息时,最早的消息移入不再重写的 AgentMessageChunks 实例。一个 chunk 最多 32 条消息、1 MiB,因此远低于 values.maxValueBytes。更大的消息不进入窗口,保存时直接放进 自己的 chunk,所以超过 values.maxValueBytes 的消息会让它所在的轮次立即失败,和以前一样。 AgentMessageIndex 记录消息所在的位置,只在写入或删除 chunk 时改变。每条消息写两次:一次在窗口中,一次在 它的 chunk 中;history 保留窗口副本期间,它作为被替换值计入预算。启用压缩时,RunModel 只加载 摘要之后的消息。不启用压缩时,每次模型调用都加载并发送完整历史,也不会删除任何消息。
- FrameworkRunState 在一轮等待 tool 结果时保存 framework 的状态。每次模型调用请求 tool 后,RunModel 都会重写它。它保存这一轮到目前为止的工作,包括 tool 输出。OpenAI Agents SDK 的状态还包含这一轮的输入,Vercel AI SDK 的状态会把每个 tool 输出保存两次。之前的每个值 都会作为被替换值保留,只要 history 还保留它,就计入 run 预算。
- AgentToolCalls 记录在一轮结束时删除。被删除的值同样会成为被替换值,在 history 窗口 裁剪掉它之前,仍计入 run 预算。
服务器会对 Step heartbeat 和 Step 完成等写入检查 run 预算,并且只在写入增加存储时检查。 session 超出预算后,这样的 Step 会失败且不重试。模型调用或 tool call 失败时,它所在的轮次 随之失败。没有失败路由的 Step 在它自己的写入越过预算时,会让整个 session 失败。保存下一条 用户消息的 AwaitUserMessage 就是这样的 Step。事务型 RPC 的写入,比如 send_user_message,不做检查。规划时让 session 远低于 64 MiB。
Flow history 大约保留一个 session 最新的 10,000 个事件。读取对话用 get_agent_snapshot 或 list_agent_messages,不要从 Flow history 读。 Time travel 只能以 history 窗口内的时间点为目标。 Time travel 到起点始终可用。
session 不会自己结束。完成后用 StopFlow 停止它。已停止的 session 及其 get_agent_snapshot RPC 在保留期内仍可用, 之后 Dex 会清除它。需要比 session 保存更久的对话记录,要在此之前用 list_agent_messages 复制出来。
压缩与存储上限
压缩从 agents 0.2.0 包开始提供,用来让模型输入保持在上下文窗口之内。在 AgentSessionOptions 中,或者在 Stepwise agent 的定义中设置 compaction,并给出模型的 上下文窗口 token 数。runner 必须支持压缩;Stepwise 支持,framework adapter 目前还不支持。 当一次模型调用的输入将达到窗口的 85% 时,session 会先运行一个 CompactContext Step。它用 一次模型调用把较早的消息折叠成一份摘要,下一次模型调用收到的是这份摘要和最新的消息。如果 较早的消息放不进窗口,Stepwise 会在摘要调用中略去其中最早的部分,并告诉模型。一个包含很多 tool call 的长轮次会在轮次中途压缩。
只有在该 Flow 类型的每个 Worker 都运行带有 CompactContext Step 的版本之后,才启用压缩。 读取 session 快照的客户端也需要 agents 0.2.0:0.1.0 客户端无法读取压缩期间快照中的 compacting_context 状态。
压缩也限定了 session 的存储。当最早的 chunk 中每条消息都已被摘要,且它之后至少还保存着 retained_message_limit(默认 1,000)条消息时,保留策略会删除这个 chunk。最新的 1,000 条 消息和摘要之后的每条消息始终保留,所以无论 session 运行多久,保存的消息都不再增长。在 AgentSessionOptions 中用 retained_message_limit、message_window_size、 message_chunk_size 和 message_chunk_max_bytes 设置上限、窗口大小和 chunk 限制。上限设为 None(TypeScript 中为 null)时保留每条消息。如果把 values.maxValueBytes 调到约 2 MiB 以下,也要同时调低 message_chunk_max_bytes。
被删除的消息不再出现在 list_agent_messages 和 get_agent_snapshot 中。分页在最早保存的 消息处结束,每一页的 deleted_before_sequence 表示保留策略删除了它之前的消息。如果应用 需要完整对话,就在消息之后又保存 retained_message_limit 条消息之前,用 list_agent_messages 把新消息复制出去。一个简单的做法是在每个 turn_completed 事件之后, 从上次复制到的序号之后开始复制。如果一轮可能保存的消息多于上限,就提高上限或设为 None。
根据保留的消息估算 run 预算。在一个实测的 session 中,每轮保存一个 100 字符的问题和一个 600 字符的回答,约 2.9 KB,session 在 8,000 token 的窗口下压缩。上限为 100 时,在第 200、 400、600 和 800 轮,保存的消息都在 162 KB 到 185 KB 之间,session 的全部活动状态在 167 KB 到 191 KB 之间,而 session 一共保存了 2.3 MB 的消息。使用默认上限 1,000 时,按上限乘以一条消息的 大小,加上摘要之后的消息,再加上 history 窗口保留的被替换值来规划。被删除的 chunk 在 history 窗口裁剪掉它之前,作为被替换值计入预算。
让长 session 保持在预算之内:
- 新的、无关的工作开一个新 session,不要让一个 session 无限增长。
- 让 tool 输出保持小。返回模型需要的内容,比如 ID、摘要或排名靠前的结果,而不是整份文档。 每个输出都会保存在它的 tool call 记录中、这一轮运行期间的 run state 中,以及消息中。
- 把文件、图片和长文档等大型产物放到你自己的 blob 存储中,让 tool 返回它们的引用。
审批和截止时间
需要审批的 tool call 在独立的 AwaitToolApproval Step 中等待。等待不占用 Worker slot, 也不受 Worker 重启和部署影响。
没有截止时间时,审批会一直等到有人回答,这一轮也跟着等待。新的用户消息会排队,直到这一轮 结束。在 Python 的 AgentSessionOptions 中设置 interrupt_deadline,或在 TypeScript 中设置 interruptDeadlineMs。到截止时间仍未处理的调用会被拒绝,消息是 "approval deadline passed",模型会看到这次拒绝。
session 在模型请求调用时,用 Worker 的时钟计算截止时间。保持 Worker 时钟同步。修改截止时间 选项后,只对之后产生的审批生效。Dex Timer 以整秒为单位,所以截止时间的 Timer 会向上取整, 最多晚一秒触发。从截止时间起,resolve_interrupt 返回 false,所以迟到的回答不会生效。
Step 持有同一把锁时,resolve_interrupt 可能以 RpcLockConflictError 失败。重试是 安全的。Python 的 AgentSessionClient 最多重试 5 秒。
Worker 被杀和重新部署
崩溃最多重跑当时正在运行的那一次调用。
| Worker 停掉时正在运行 | 结果 |
|---|---|
| RunModel | 这次模型调用重新运行,30 分钟内最多 3 次 attempt,之后这一轮失败。如果 tool 已经运行过,history 中的一条说明会告诉下一轮的模型不要重复它们。 |
| CompactContext | 只有摘要调用重新运行,30 分钟内最多 3 次 attempt。session 只保存一份摘要。如果所有 attempt 都失败,这一轮失败,下一条用户消息会再次压缩。 |
| CallTool,读取或幂等写入 | 用同一个幂等键再次运行。最后一次 attempt 之后,读取记录 failed,写入记录 outcome_unknown。 |
| CallSingleAttemptTool | 记录 outcome_unknown,不再运行。模型会看到结果未知。 |
| 等待用户消息、审批或 tool 结果 | 不会重跑任何东西。等待发生在 Dex Server 中。 |
| framework 无法推迟的 tool | tool 在 RunModel 内部运行,RunModel 重跑时它也会重复,属于至少一次。 |
| Claude Agent SDK 的一段轮次 | 被推迟的自定义 tool 在各自的 CallTool 或 CallSingleAttemptTool Step 中运行,规则同上。模型调用、inline 读取 tool,以及 Bash、Write、Edit、Task 等 CLI tool 在 RunModel 内部运行,RunModel 重跑时会重复,属于至少一次。 |
单次尝试的 tool 在少数很窄的情况下会运行两次,例如节点崩溃后 ASYNC 的重新运行。见 Tool call 的限制。
优雅停止 Worker 时,它会在 drain 超时内等待正在运行的 handler,默认 30 秒,然后取消它们。 被取消的模型调用会重新运行,被取消的 CallTool 会重试。因取消而停止的单次尝试 tool 会记录 outcome_unknown。把 drain 超时设得比通常的模型调用和 tool call 时间长,再把容器的终止 宽限期设得比 drain 超时长。先等新 Worker 注册完成, 再停止旧 Worker。
Tool call 的限制
单次尝试的 tool 在 CallSingleAttemptTool Step 中运行。这个 Step 负责 non_idempotent_write 和 unclassified tool。它应当最多运行一次 tool,并在 tool 可能 已经运行过时记录 outcome_unknown。tool 确定没有运行时,这次调用改为记录 failed,模型 可以再次调用这个 tool。有两种情况会打破“最多运行一次”这一承诺,两种都要提前准备。它们源于 Dex 交出任何 Step attempt 的方式。见失败与重新投递。
单次尝试的 tool 可能运行两次
Dex 在把 attempt 交给 Worker 时开始这个 attempt,并且不会再把同一个 attempt 编号交给另一个 Worker。如果 Worker 在 tool 运行期间停掉,或者断开了与 Dex 的连接,这个 attempt 会失败。单次 尝试的 tool 没有剩余的 retry,所以这次调用记录 outcome_unknown。之前的那次运行可能已经 完成了副作用,因此 session 不会再次运行这个 tool。
只有两种很窄的情况仍可能让单次尝试的 tool 运行两次:
- 这个 Step 使用 ASYNC durability,并且 Dex Server 节点在 Dex 把 attempt 的开始记录写入 object storage 之前崩溃。Dex 会回滚这次开始,并再次运行同一个 attempt 编号,可能在另一个 Worker 上。两次运行可能重叠。
- 取消是协作式的。Dex 取消一个 attempt 时,被中断的运行可能仍在继续,而 failure route 已经开始。
要让第二次运行无害,把这次调用的幂等键传给 tool 写入的服务。每个 tool call 都会收到一个幂等键: session 的 Flow ID、轮次 ID 和 tool call ID,用斜杠连接,例如 session-42/turn-3/call-7。 同一次调用的每次 attempt 都使用同一个键。服务按这个键去重时,把这个 tool 归类为 idempotent_write,这样它失败后也会重试。
从未运行的调用也可能记录 outcome_unknown
tool Step 失败时,它的 failure route 会从 recovery error 中读取 attempt_progress。见 失败与重新投递。CallTool 和 CallSingleAttemptTool 的处理方式相同:
| attempt_progress | 这次调用记录的结果 |
|---|---|
| NOT_STARTED | 没有 attempt 到达 Worker,所以 tool 没有运行。这次调用记录 failed,错误信息以 "the tool did not run, so it is safe to call again" 开头。模型会看到一次失败的 tool call,可以再次调用这个 tool。如果这次调用的 tool 已经向用户提过问题,说明它之前运行过,按下一行处理。 |
| NOT_COMPLETED,或 server 没有报告进度时的 UNSPECIFIED | tool 可能已经运行过。read 调用记录为 failed,其他调用记录为 outcome_unknown,session 不会再次运行它的 tool。 |
要在 get_agent_snapshot 或你自己的代码中识别这种调用,把它的错误信息开头与 Python 的 TOOL_CALL_NOT_RUN_ERROR_PREFIX、TypeScript 的 toolCallNotRunErrorPrefix 或 Go 的 ToolCallNotRunErrorPrefix 比较。
NOT_COMPLETED 是保守的结果,所以从未运行的调用仍可能记录 outcome_unknown。例如, server 在记录了 attempt 的开始之后、任务到达 Worker 之前崩溃。请把这种结果当作未知。
如果没有 Worker 接收 tool Step,这次调用会在队列中等待。当这个 Flow 类型的每个 Worker 都达到 task 上限,或者一个 Worker 都没有运行时,就会这样。调用不会失败,也不消耗 attempt,有 Worker 接收后才运行。如果 Flow 先超时或被停止,这次调用就不会运行。
让 tool Step 始终能被分发,避免调用长时间等待:
- 按规划 Worker 容量规划每个 Worker 池,并为最大的一批 tool call 留出余量。
- 每个 agent Flow 类型至少保持一个 Worker 在运行。Worker 池缩容到零时,tool call 会在队列中等待, 直到有 Worker 启动。
- 部署时,先启动新 Worker,等它们注册完成,再停止旧 Worker。
核对 outcome_unknown
outcome_unknown 表示效果可能发生了,也可能没有。session 从不重试这样的调用,模型会看到结果 未知。在 session 之外核对它:
- 找到这次调用。在这一轮运行期间,get_agent_snapshot 会在 tool_calls 中列出它,失败 信息在 error 中。AgentEvents Stream 中有一条状态为 outcome_unknown 的 tool_call_finished 事件。这一轮结束后,消息 history 中它的 tool 结果会说明结果未知。
- 用这次调用的幂等键或你自己的业务键,在目标系统中检查效果是否发生。
- Dex 确定从未运行的调用会记录 failed,而不是 outcome_unknown。如果 Flow 的 history 仍然显示 tool Step 的 attempt 从未到达 Worker,例如在 server 升级之前开始的调用,这次调用就 没有运行。
- 用 send_user_message 把实际结果告诉 session,让下一轮的模型基于它工作。
在 session 等待时升级 agent 代码
等待中的 session 运行的是接手它下一个 Step 的 Worker 上的代码。agent 循环不会重放,所以 部署在下一次模型调用或 tool call 时生效,即使在一轮中间也一样。滚动部署期间,同一个 session 的两个 Step 可能运行在不同版本上。
- 保持每个 agent 的 Flow type 不变。运行中的 session 靠它恢复。
- 只要运行中的轮次或待处理的审批还引用某个 tool,就保留这个 tool。
- 已记录的 tool call 保留模型请求它时适用的 effect 和审批规则。修改后的 tool policy 对之后 的调用生效。
- 修改后的 prompt 或模型在下一次模型调用时生效。修改后的 tool 在它下一次被调用时生效。
- 在一轮的各个 Step 之间,FrameworkRunState 保存 framework 序列化的状态。新 Worker 上的 framework 版本必须能恢复它。保持在 adapter 固定的 framework 版本范围内,并且同时升级 adapter 和 framework。
- 从 agents 0.1.0 升级时:先停止该 Flow type 的所有 0.1.0 Worker,再启动任何 0.2.0 Worker。 不要让两者同时运行。0.1.0 的 session 把每条消息都保存在 AgentMessages 中。 0.2.0 Worker 一旦在其中保存消息,就会把较早的消息移入 AgentMessageChunks,每个 Step 移动 少量 chunk。此后如果 0.1.0 Worker 运行这个 session 的 Step,这一轮会失败,因为它读不到被移走 的消息。
通用规则见 Flow 代码版本控制。
滚动部署期间的 session settings
只有在该 Flow type 的每个 Worker 都运行 agents 0.2.0 之后,才用 session settings 启动 session,或调用 update_session_settings。0.1.0 的 Worker 会丢弃它启动的 session 的 settings,也不会写入或读取一轮所保留的 settings 副本。由 0.1.0 Worker 启动的一轮没有 settings,所以它的部分模型调用可能使用 Worker 的默认模型。
凭证
把模型 API key 和 tool 凭证放在 Worker 的环境中,或放在 Worker 调用时读取的 secret store 中。每个 framework 都从环境中读取自己的模型 key,比如 OPENAI_API_KEY、 GOOGLE_API_KEY 或 ANTHROPIC_API_KEY。adapter 本身不处理凭证。
不要在 session 的启动输入、用户消息、tool 参数、tool 输出或 Attribute 中传递凭证。Session settings 属于启动输入和 session 状态,get_agent_snapshot 和浏览器 snapshot JSON 都会 返回它们,所以其中只放 Worker 能解析的引用,比如 model 名称或凭证名称。Dex 会把 它们保存在 Flow history 和状态中。Dex Web 会显示它们,history 会为 time travel 保留被替换 的值,已停止的 session 在保留期内仍可读取。任何获得授权的 Client 都能读取 AgentEvents。
属于某个用户的凭证,让 tool 在调用时从 secret store 中查找,查找用的 key 不能是凭证本身。 当你自己的 Flow 必须持有短期 secret 时,把它存放在 hard-delete Attribute 中,Flow 不再需要时 删除它。
Worker 和 Client 使用 bearer 凭证向 Dex Server 认证。见 身份验证。