mobile wallpaper 1
mobile wallpaper 2
mobile wallpaper 3
mobile wallpaper 4
3046 字
8 分钟
腾讯 AI Agent 架构面经:拆解会话、执行与工具状态的三层设计
2026-09-05

在近年来的大模型系统设计面试中,“请设计一个生产级 AI Agent 的对话与执行流程”是一道极为高频的高杠杆题目。

许多候选人一提到状态,往往只能给出前端维度的 isLoading,或是简陋的 thinking / acting / finished。但在真实复杂业务场景(例如需要多轮工具调用、人工审批流、网络中断恢复、超时重试以及处理退款转账等副作用)下,单薄的状态枚举会瞬间让系统陷入竞态或不一致。

回答这道题的核心,是理清两个根本问题:

  1. 当前执行到了哪一步?(生命周期流转与调度)
  2. 从这里继续执行需要哪些确定性数据?(上下文一致性、检查点与副作用屏障)

本文从零拆解生产级 Agent 对话运行时的三层状态模型,并系统推导状态流转、并发与中断恢复的严密闭环。


🏛️ 核心骨架:Session、Run 与 Tool Call 的三层分治#

不要把所有状态塞进同一个上下文对象中。一个具备容灾能力的运行时,必须在抽象上完成三层解耦:

graph TD subgraph SessionLayer [1. Session 会话层:生命周期容器] S[Session ID: sess_1024<br/>持续对话历史 / 插件配置 / 用户上下文] end subgraph RunLayer [2. Run 执行层:单次交互运行时] R1[Run 1: completed<br/>查订单详情] R2[Run 2: waiting / approval<br/>申请退款流程] end subgraph ToolLayer [3. Tool Call 工具层:具体执行单元] T1[ToolCall: query_order<br/>succeeded] T2[ToolCall: submit_refund<br/>unknown / reconciling] end SessionLayer --> R1 SessionLayer --> R2 R2 --> T1 R2 --> T2
层次职责与生命周期核心持久化数据
Session(会话层)用户与 Agent 持续交互的长周期容器消息历史(Messages)、用户偏好、当前活跃 Run 引用、租约信息
Run(单次执行层)Agent 为推进一次具体诉求而运行的任务实例顶层状态、活动阶段(Phase)、执行预算、等待上下文、错误原因
Step / Tool Call(步骤与工具层)一次模型推理或单次具体工具调用的执行原子输入参数、输出结果、尝试次数(Attempts)、幂等键(Idempotency Key)

核心分界线:一次 Run 结束,绝不等于 Session 结束#

例如用户提出:“帮我查下这个订单,如果符合条件就退款。”

  • 这是一个 Run。在此次执行中,Agent 可能先查询订单,发现满足条件,挂起等待用户确认;用户点击确认后,唤醒该 Run 完成退款并返回最终结果。
  • 用户随后说:“顺便再查一下另外那个订单。” 这时是在同一个 Session 下创建了一个全新的 Run
  • 对挂起中的任务补充信息或提交审批,是**恢复(Resume)**原有 Run,而不是无休止地重建执行实例。
职责边界约束

大模型可以提出“请求调用退款工具”,但是否执行、何时执行、如何流转必须由运行时(Runtime)强控制。绝不能因为模型在输出文本里写了一句“已获管理员批准”,运行时就绕过审批机制直接触发扣款。


🔄 Run 的生命周期与状态流转机理#

一个完备的 Run 顶层生命周期不需要将所有动作都枚举为状态。六个状态即可构成严密的有限状态机(FSM):

flowchart TD Q["queued:请求已排队"] --> P["running:准备上下文 (preparing_context)"] P --> M["running:调用模型 (calling_model)"] M --> D{"模型响应判定"} D -->|请求调用工具| V{"权限与参数校验"} V -->|校验通过| T["running:执行工具 (executing_tools)"] V -->|需要人工授权| A["waiting:等待审批 (approval)"] V -->|非法参数/越权| E["写回工具错误结果"] E --> P A -->|用户批准且校验复核| T A -->|用户拒绝| E T -->|工具产出结果/可重试错误| P D -->|需要用户补充参数| U["waiting:等待输入 (input)"] U -->|接收有效补充信息| P D -->|最终回复且无未完任务| C["completed (终态)"] M -->|模型服务瞬时不可用| R["waiting:等待重试 (retry)"] R -->|退避时间到且预算充足| P Any["任一非终态 (Any Active State)"] -.->|预算耗尽 / 致命异常| F["failed (终态)"] Any -.->|收到取消信号并优雅停机| K["cancelled (终态)"]

1. 顶层状态与内部阶段(Phase)解耦#

状态 (Status)语义与退出条件内部阶段 / 等待原因 (Phase / Reason)
queued任务已入队,等待排队调度或工作者拉取waiting_worker
running运行时正在主动向前推进计算或 I/Opreparing_context / calling_model / executing_tools
waiting执行挂起,依赖外部事件驱动唤醒waiting_input / approval / retry_backoff / reconciliation
completed本次 Run 正常结束(终态)无(清理活动上下文)
failed触发不可恢复错误,或重试预算耗尽(终态)记录致命错误上下文
cancelled收到用户或系统取消指令,且已安全停止(终态)保留已生效操作,清理未执行任务

2. 流式输出(Streaming)是事件,不是顶层状态#

前端界面呈现的打字机效果、思维链展开,本质上是模型调用的增量事件(text_deltatool_call_delta)。在服务端,Run 依然稳定处于 running 状态(Phase 为 calling_model)。
在流式结束的那一刻,系统必须完成关键校验:模型是否输出完整?工具参数是否被截断? 半截 JSON 绝不可流入执行管道。

3. completed 衡量的是执行过程,而非业务意图的达成#

查询结果显示“订单不满足退款要求”,Agent 礼貌告知用户无法退款,本次 Run 依然应当正常标记为 completed。业务逻辑拒绝不是系统运行故障,绝不能随意标为 failed


💾 故障容灾底座:崩溃恢复需要持久化哪些数据?#

假设执行器在工具刚刚发起的瞬间遭遇断电重启,数据库里如果仅有一行 status = "running",恢复进程将面对一片迷雾:工具到底调用出去没有?是否需要重新调模型?从哪一步续跑?

因此,生产环境必须实现确定性的检查点(Checkpoint)持久化:

数据分类核心字段设计容灾解决的问题
关联标识session_id, run_id, step_id, tool_call_id准确定位上下文归属,保证分布式跟踪链不断裂
持久化历史messages, role, content, tool_results记录已经被业务认可的事实,不随单次上下文压缩丢失
活动步骤快照current_step, pending_tools, snapshot_version重启后精确定位恢复点,防止已成功步骤重复执行
等待上下文wait_type, request_id, expire_at, resume_target节点重启后,收到审批或输入回调时知道唤醒哪个挂起操作
执行熔断预算model_call_count, token_usage, timeout_deadline设立刚性防线,防止死循环与 Token 账单爆炸
分布式租约lease_worker_id, lease_token, lease_expires_at防止旧节点假死唤醒后,双写竞争推进同一个 Run
工程原则:对话持久化历史 \neq 模型请求上下文

对话历史(Session History)是业务层面的不可变事实依据;而模型上下文(Model Context)是针对特定模型窗口组装的瞬时切片(包含剪裁、历史压缩、RAG 注入)。压缩上下文或做滑动窗口时,绝不能反向修改甚至删减持久化数据库中的真实消息记录。


⚡ 工具调用的并发控制与超时未知边界#

当大模型在一轮推理中并发请求了两个工具:query_user_level(只读)与 execute_refund(写副作用),Run 级别的单一状态无法表达内部并发进度,必须为每个 Tool Call 引入独立生命周期:

stateDiagram-v2 [*] --> pending: 接收到完整调用请求 pending --> running: 调度器派发尝试 (Attempt) running --> succeeded: 工具执行成功并返回数据 running --> unknown: 网络超时 / 响应未达 / 状态未决 running --> pending: 瞬时网络报错 (退避重试) running --> failed: 达到最大重试次数 pending --> cancelled: 用户中途取消 unknown --> succeeded: 对账反查确认外部已成功 unknown --> failed: 对账反查确认外部未执行 succeeded --> [*] failed --> [*] cancelled --> [*]

超时 \neq 失败:极其致命的副作用边界#

这是面试官最喜欢追问的高阶工程点:退款接口网络超时(HTTP 504),能直接重试吗?

绝对不能!HTTP 504 仅代表网关未收到下游回复,底层的扣款动作极有可能已经落库成功。若盲目重试,将导致灾难性的资金重复扣减

生产级 Agent 对待写副作用的防御准则:

  1. 引入 unknown(状态未决)状态:超时的工具调用立即挂起,进入 unknown 状态。
  2. 强制显式业务幂等键(Idempotency Key):在首次向外部系统发出网络调用前,运行时必须先持久化业务幂等键。即使模型在下一轮重新输出了新的 tool_call_id,底层业务调用的幂等凭据始终唯一。
  3. 主动对账机制(Reconciliation):状态未决的调用不能让 Agent 瞎猜,系统应调度专门的查询对账任务;若下游不支持查询,则将 Run 置为挂起并报警,引入人工核查兜底。

🛑 用户插话、取消与故障恢复策略#

1. 用户插话(User Interruption)#

若在 Agent 执行耗时任务过程中用户突然输入新消息,若直接并发推进,会导致同一会话的上下文产生分叉。

  • 排队与意图识别:单 Session 强约束同一时刻仅有一个活动 Run,其余输入入队暂存。
  • 插话安全点拦截:Agent 只能在特定的安全边界(例如下一次模型调用前、下一个工具启动前)读取插话。
  • 区分插话类型
    • 补充条件(“补充一下,订单号是 9527”):注入当前上下文,继续执行;
    • 意图切换(“算了别查了,帮我查查天气”):触发当前 Run 取消,清空后续步骤并开启新 Run。

2. 取消(Cancellation):发起 \neq 生效#

用户点击“取消”按钮时,系统不能原地将其标为 cancelled

  • 首先将请求标记为 cancel_requested_at
  • 向下游执行线程广播 AbortSignal
  • 等待正在执行的网络 I/O 优雅中断或退出,确保没有空中飞行的写操作后,Run 才正式落盘为终态 cancelled
  • 已经产生外部副作用的步骤(如已扣款)绝不会随取消自动回滚,界面必须清晰标明已生效操作。

3. 崩溃恢复(Restart Recovery)#

服务节点宕机重启后,恢复程序按如下优先级处理中断的 Run:

1. 校验租约令牌:确认原执行节点已超时失联,抢占执行权;
2. 读取检查点:
├── 仅收到半截模型响应 ──> 废弃残缺片段,在预算允许范围内重新发起 LLM 调用;
├── 工具调用已完成落库 ──> 直接复用已有结果,跳过重复执行;
├── 工具调用处于 unknown ─> 触发对账管道,禁止自动重放;
└── 处于 waiting 审批 ──> 校验审批时效,继续等待用户交互事件。

🎯 场景端到端推演:一笔退款业务的严密闭环#

我们用一笔典型的“订单退款”交互,来完整验收上述状态模型的自洽性:

阶段Run 状态 / Phase工具状态 (Tool Status)系统核心事实与一致性动作
1. 接收诉求queued-接收“查询订单并申请退款”,分配全局 run_id
2. 开始推演running / preparing_context-组装模型上下文,加载可用工具清单与扣减预算
3. 查询订单running / executing_toolsquery_order: running派发只读查询,生成只读步骤记录
4. 决策退款running / calling_modelquery_order: succeeded模型感知订单符合条件,输出调用 refund 的请求
5. 触发拦截waiting / approvalrefund: pending拦截写副作用,生成 approval_id 并挂起,等待人工授权
6. 用户授权running / executing_toolsrefund: running用户点击“同意”,持久化幂等键并向支付网关发起请求
7. 遇到超时waiting / reconciliationrefund: unknown支付网关超时,挂起 Run,切入对账等待
8. 对账完成running / preparing_contextrefund: succeeded对账服务确认扣款成功,回写最终数据
9. 达成闭环completed-模型向用户输出“已为您完成退款”,清理活动租约

总结:面试回答的标准落地模板#

在面试中拆解这套设计时,可以按照以下节奏递进输出:

  1. 先给结论,拉开层次:建立 Session(长周期容器)Run(单次交互运行时)Tool Call(原子执行单元) 的三层正交抽象。
  2. 给出核心状态机:用 queued / running / waiting / completed / failed / cancelled 明确生命周期,并将活动阶段与挂起原因下沉到内部字段。
  3. 点透高阶边界与防御机制
    • 流式输出是事件,不是顶层状态
    • 工具超时是 unknown,必须配合幂等键与对账,防止副作用二次放大
    • 检查点持久化与分布式租约,是实现断点续跑与防脑裂的根本基石

把以上边界和一致性推导清晰,就能向面试官充分证明:你不仅懂得如何 Prompt 调用大模型,更具备设计高可用、高可靠企业级分布式 Agent 运行时的全局工程把控力。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

腾讯 AI Agent 架构面经:拆解会话、执行与工具状态的三层设计
https://l1ngg.info/posts/tech/agent-conversation-state/
作者
L1ngg
发布于
2026-09-05
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

相关文章 智能推荐
1
写了半年 Agent,我才明白为什么「评估」不是「测试」
技术 很多做 Agent 项目的同学容易把模型评估(Evals)误当成工程测试,导致本地不敢重构、CI 成本爆炸。本文从一个正在深入钻研 Agent 架构的开发者视角,复盘如何跳出调参思维,以系统决策者的全局眼光去学习和设计真正可靠的自动化测试体系。
2
GraphRAG 原理与实战精解:从多跳实体推理、社区摘要到工程落地边界
技术 深度解析 GraphRAG(图增强检索生成)的核心原理。从实体消歧与多跳检索切入,对比微软 GraphRAG 的 Local Search 与 Global Search 机制,探讨图谱无法自动解决的边界缺陷,并横向对比 Karpathy 的 LLM Wiki 范式。
3
给 Agent 团队装上记忆:腾讯 TencentDB Agent Memory 速通
技术 腾讯云数据库团队开源的 Agent 记忆中心:Chat Memory / Skill / Wiki / CodeGraph 四类记忆资产,配团队面板和代理接入,Claude Code、Codex 等主流 agent 都能用。本文讲清机制、装法和门槛。
4
读 Karpathy 的 LLM Wiki:从无状态 RAG 到持久累积的个人知识库(附全文精译)
技术 Andrej Karpathy 提出了一种基于 LLM Agent 维护个人 Wiki 的新范式:将 Obsidian 作为 IDE,LLM 作为程序员,Wiki 作为代码库,打破传统 RAG 的单次检索局限。本文包含背景介绍、全文翻译与深度技术思考。
5
一份 SKILL.md 就是一部事故法典:feat-lifecycle 精读
技术 精读 Clowder AI 项目的 feat-lifecycle skill:一个多 agent 团队如何用流程文件,制度性地对抗 AI 重复造轮子、自我锚定和谎报完成

目录