# 路线 02:Agent 执行、暂停与恢复
## 学习场景
客户要求查询订单,随后申请换货。沿着同一个 `run_id` 阅读请求受理、模型调用、工具执行、客户补充信息、客户确认和主管审批,观察每一步怎样保存进度、检查权限和继续执行。
图中后端路径相对 `src/zhifu/`。连续箭头表示直接函数调用,箭头文字注明调用条件;间断箭头明确标注 HTTP、框架调度、对象返回或持久数据关系。框架节点和存储节点单独标明类型。`load`、`model`、`followup` 是 `build_graph` 内部函数,`execute` 是 `build_tool_graph` 内部函数。返回[路线目录](README.md)。
## 图 1:请求受理、发布配置与工作进程调度
```mermaid
flowchart TD
HTTP["HTTP 请求
POST /openapi/v1/agent/runs"]
A["modules/agent_runtime/api.py
enqueue
身份、店铺权限和幂等检查"]
B["modules/agent_runtime/service.py
queue_run
配置快照、任务数量和运行期限"]
C["modules/merchant/service.py
current_release_version
读取店铺当前发布版本"]
R[("MySQL
modules/merchant/models.py
AgentRelease:发布配置")]
D[("MySQL
modules/agent_runtime/models.py
AgentRun:QUEUED 与 release_snapshot")]
E["modules/agent_runtime/worker.py
main → execute_one
持续领取运行"]
F["modules/agent_runtime/business_wait.py
reconcile
核对业务等待,见图 3"]
G["modules/agent_runtime/worker.py
claim
租户调度、期限和执行租约"]
H["modules/agent_runtime/capacity.py
acquire
申请并发额度"]
I["modules/agent_runtime/runtime.py
build_graph → build_tool_graph
构建主图及工具子图"]
J["LangGraph 框架
graph.ainvoke
按 next_node 调度,见图 2"]
HTTP -. "HTTP / FastAPI 路由分发" .-> A
A -->|新请求| B
A -. "相同幂等键及内容:读取原运行并复核权限" .-> D
B --> C
B -. "按版本读取 manifest" .-> R
B -. "事务提交:保存 graph_version 和模型配置" .-> D
E -->|每轮首先调用| F
E -->|核对之后领取| G
D -. "跨进程:读取排队任务或过期租约" .-> G
G -->|选定租户后| H
G -. "事务提交:RUNNING,lease_token 增加" .-> D
E -->|领取成功后| I
E -->|调用已构建的图| J
I -. "返回已编译图对象" .-> J
```
`enqueue` 对重复请求执行 `validate_result_access`,当前权限撤销后不能继续读取旧工具结果。新运行保存店铺发布配置;没有店铺发布记录时使用 `AgentSettings` 与当前 `GRAPH_VERSION`。`queue_run` 验证 `graph_version` 已登记在 `GRAPH_RELEASES` 中,当前默认版本为 `after-sales-v10`。
`claim` 优先考虑商家预留额度,再按租户最近获得调度机会的时间选择租户,租户内部按创建时间选择任务。Redis 额度不足时保持排队。租约更新后,旧工作进程无法通过 `locked_run` 的 `lease_token` 检查。
会话消息的另一个入口是 `conversations/api.py` 的 `accept_message`:它准备最近消息、调用同一个 `queue_run`,再保存 `conversation_id`、`control_version` 与 `active_run_id`。该调用与独立运行入口共用后续执行流程。
### 图 1 源码导航
1. [api.py:enqueue](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/api.py:60)、[validate_result_access](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/api.py:128):找到相同幂等键的查询和权限复核。
2. [service.py:queue_run](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/service.py:20)、[merchant/service.py:current_release_version](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/merchant/service.py:78):追踪 `release_snapshot`、`graph_version` 与 `deadline_at` 的来源。
3. [config.py:GRAPH_RELEASES](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/config.py:104):核对不同版本的 `clarification`、`business_wait`、`followup` 开关。
4. [worker.py:execute_one](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/worker.py:137)、[claim](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/worker.py:28)、[capacity.py:acquire](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/capacity.py:75):分别追踪工作进程、数据库领取和 Redis 并发控制。
5. [runtime.py:build_graph](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:244)、[conversations/api.py:accept_message](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/conversations/api.py:205):查看图构建与会话入口的连接位置。
## 图 2:LangGraph 调度模型、工具与最终答复
```mermaid
flowchart TD
G["LangGraph 框架
graph.ainvoke / add_conditional_edges
依据节点返回的 next_node 调度"]
L["modules/agent_runtime/runtime.py
load
读取已保存的 next_node"]
M["modules/agent_runtime/runtime.py
model
校验引用、读取记忆、调用模型并保存响应"]
T["modules/agent_runtime/runtime.py
execute
工具子图中的执行节点"]
F["modules/agent_runtime/runtime.py
followup
处理单独的回访登记工具"]
K["modules/agent_runtime/runtime.py
locked_run
身份、控制权、租约和店铺权限检查"]
V["modules/agent_runtime/tools.py
model_tools → tool_definitions
按 graph_version 声明工具"]
P["LangChain / 模型服务
ChatOpenAI.bind_tools(...).ainvoke
返回答复或 tool_calls"]
I["modules/agent_runtime/tools.py
invoke_tool
参数校验与业务服务调用"]
W["modules/agent_runtime/inputs.py:pause_for_input
modules/agent_runtime/business_wait.py:pause_for_business
保存等待状态,见图 3"]
C["modules/conversations/service.py
finish_run
保存最终会话事件并释放 active_run_id"]
G -. "框架调度:START → load" .-> L
G -. "框架调度:next_node=model" .-> M
G -. "框架调度:next_node=tools,进入工具子图" .-> T
G -. "框架调度:next_node=followup" .-> F
L --> K
M -->|调用模型前及提交结果前| K
T -->|读取工具请求及提交工具结果前| K
F --> K
M --> V
M -. "SDK 调用并通过 HTTP 访问模型服务" .-> P
T -->|订单、工单、创建方案等工具| I
F -->|create_followup_request| I
T -->|补充信息,或方案创建后的业务等待| W
M -->|无 tool_calls:设置 COMPLETED 后调用| C
L -. "节点返回 next_node" .-> G
M -. "节点返回 tools 或 done" .-> G
T -. "节点返回 model、followup 或 wait" .-> G
F -. "节点返回 model" .-> G
```
`build_graph` 通过 `add_node` 注册内部函数,通过 `add_conditional_edges` 定义运行方向。工具节点返回后,由 LangGraph 根据 `next_node` 调度下一节点。`done` 与 `wait` 都连接 `END`;前者对应完成,后者保留等待状态,后续通过图 3 的入口继续原运行。
工具执行与权限检查使用同一套版本清单。`execute` 对每个工具参数调用 Pydantic 校验,并用 `agent:{run_id}:{step}:{index}` 生成业务幂等标识。工具结果、步骤编号和下一节点在数据库事务中共同提交。`create_followup_request` 必须单独调用;工具节点先保存 `next_node=followup`,由框架继续执行回访节点。知识检索使用专用分支:事务外检索,返回后调用 `verified_results`,具体流程见路线 04。
`model` 在网络调用前保存 `ModelAttempt`,通过 `BudgetCallback` 检查预算与记录计量。模型网络请求处于两个短事务之间;返回后保存已经产生的用量,再检查运行权限、知识引用和记忆版本。工作进程遇到异常时保存 `FAILED` 和 `error_code`,并在 `finally` 中释放并发额度。
### 图 2 源码导航
1. [runtime.py:build_graph](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:244)、[load](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:247)、[model](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:284):结合函数末尾的图注册代码阅读调度关系。
2. [runtime.py:locked_run](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:47):查看 `token_hash`、会话控制版本、租约与店铺状态检查。
3. [runtime.py:build_tool_graph / execute](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:95)、[followup](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:252):追踪工具结果、幂等标识和下一节点的共同提交。
4. [tools.py:model_tools](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/tools.py:65)、[tool_definitions](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/tools.py:49)、[invoke_tool](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/tools.py:79):比较工具声明和执行时采用的同一版本规则。
5. [budget_callback.py:BudgetCallback](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/budget_callback.py:24)、[conversations/service.py:finish_run](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/conversations/service.py:96):阅读 LangChain 回调和最终会话事件的保存位置。
## 图 3:补充信息、客户确认与主管审批
```mermaid
flowchart TD
T["modules/agent_runtime/runtime.py
execute
执行需要等待的工具"]
P["modules/agent_runtime/inputs.py
pause_for_input
等待客户补充信息"]
B["modules/agent_runtime/business_wait.py
pause_for_business
等待方案确认或审批"]
R[("MySQL
modules/agent_runtime/models.py
AgentRun + RunInputEvent:状态和输入收据")]
H["HTTP / 客户操作
POST /openapi/v1/agent/runs/{run_id}/inputs"]
A["modules/agent_runtime/api.py
inputs → owned_run
校验本人运行与当前权限"]
I["modules/agent_runtime/inputs.py
accept_input
校验等待类型、版本、期限与幂等键"]
X["HTTP / 客户或主管操作
确认方案、修订方案、提交审批决定"]
Y["modules/after_sales/api.py
confirm / revise / decide → command
提交相应业务操作"]
S["modules/after_sales/service.py
AfterSalesService.execute
调用 confirm、revise 或 decide"]
E[("MySQL
modules/after_sales/models.py
Ticket + Confirmation + Approval + BusinessEvent")]
W["modules/agent_runtime/worker.py
execute_one
每轮核对业务等待"]
Q["modules/agent_runtime/business_wait.py
reconcile → apply_event
核验当前方案、业务事件与授权"]
C["modules/agent_runtime/worker.py
claim
重新领取同一个 run_id"]
T -->|request_clarification| P
T -->|创建方案且版本启用 business_wait| B
P -. "同事务:WAITING_USER,expected_input_type=clarification" .-> R
B -. "同事务:WAITING_USER 或 WAITING_APPROVAL" .-> R
H -. "HTTP / FastAPI 路由分发" .-> A
A -->|owned_run 返回后| I
I -. "同事务:保存输入收据并设置 QUEUED/model" .-> R
X -. "HTTP / FastAPI 路由分发" .-> Y
Y --> S
S -. "事务提交:当前业务状态、确认和审批证据" .-> E
W --> Q
R -. "读取业务等待运行" .-> Q
E -. "跨进程:读取已提交业务事件和当前版本" .-> Q
Q -->|DRAFT、NEEDS_REVISION 或 WAITING_REVIEW| B
Q -. "其他有效业务状态:保存收据并设置 QUEUED/model" .-> R
Q -. "权限或业务证据检查失败:设置 FAILED" .-> R
R -. "跨进程:领取 QUEUED,等待到期则记录 FAILED" .-> C
```
图中的 `A`、`Y`、`Q` 分别合并显示同一文件内的直接调用;这些调用对应各自入口函数的实际代码。`inputs` 调用 `owned_run` 后才调用 `accept_input`。售后 `command` 调用 `AfterSalesService.execute`;后者根据 `action` 调用对应业务方法。`reconcile` 调用 `apply_event`,统一处理业务检查异常。
补充信息只允许 `expected_input_type=clarification`,必须匹配当前 `interrupt_id` 与 `run_version`。方案确认和审批等待通过售后接口产生业务记录。`apply_event` 检查当前工单版本、客户确认、主管审批及主管当前权限;相同业务事件由 `business_cursor` 和输入收据约束重复处理。方案修订后,等待信息改用新的方案版本及等待标识。
规则失效或订单版本变化时,`apply_event` 可以将工单置为 `NEEDS_REVISION` 并继续等待;订单快照仅仅超过时效时返回 `False`,等待订单同步。审批人权限撤销时,`reconcile` 保存 `FAILED` 和 `APPROVER_REVOKED`。会话接管与取消通过状态、控制版本和租约检查阻止后续提交。
`api.py` 的 `resume` 供 `SERVICE` 身份核对已保存输入收据;输入受理或业务核对事务已经完成重新排队。该接口返回原收据与当前运行状态。
### 图 3 源码导航
1. [inputs.py:pause_for_input](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/inputs.py:63)、[accept_input](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/inputs.py:87):追踪等待标识、输入收据和重新排队。
2. [api.py:inputs](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/api.py:182)、[owned_run](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/api.py:102)、[resume](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/api.py:204):核对客户输入与内部收据查询各自的身份要求。
3. [business_wait.py:pause_for_business](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/business_wait.py:30)、[reconcile](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/business_wait.py:157)、[apply_event](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/business_wait.py:62):按调用方向阅读等待保存、事件核对和业务分支。
4. [after_sales/api.py:command](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/api.py:45)、[confirm](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/api.py:142)、[decide](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/api.py:173)、[AfterSalesService.execute](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/service.py:199):找到产生业务证据的接口事务。
## 关键数据与状态
- [AgentRun](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/models.py:10):`messages`、`step`、`next_node` 保存执行进度;`graph_version` 与 `release_snapshot` 保存本次运行采用的配置;恢复时继续使用这些配置。
- `status` 包括 `QUEUED`、`RUNNING`、`WAITING_USER`、`WAITING_APPROVAL`、`COMPLETED`、`FAILED`、`CANCELLED`。`version` 处理客户端并发;`lease_token` 处理工作进程执行权;`control_version` 处理会话接管。
- [RunInputEvent](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/models.py:60):通过租户、运行、幂等键和等待标识约束输入记录。业务恢复收据还保存 `source_event_id`、方案版本和工单版本。
- [ModelAttempt](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/models.py:86):区分模型请求已经开始、响应已收到和结果未知,保留调用次数及实际用量。
- 新运行及恢复后的执行期限为 10 分钟;补充信息和业务等待期限为 24 小时。工作进程单次执行限制 120 秒,领取租约为 125 秒。每次运行最多 6 次模型调用、20 个执行步骤,每轮最多 4 个工具调用;单个账户未结束运行数量限制为 3。
## 阅读检查问题
1. 工作进程在工具事务提交后终止,新的工作进程依据哪些字段继续执行?同一方案为何不会重复创建?
2. 店铺发布了新的 Agent 配置,正在等待客户补充信息的运行恢复后采用哪个版本?工具声明与执行怎样使用这个版本?
3. 客户补充信息、客户确认方案、主管审批分别保存什么记录?审批后撤销主管权限,运行恢复过程中哪一步会拒绝继续?
## 测试文件阅读入口
本路线仅阅读以下用例及其断言,没有执行测试或模型调用。测试文件中的运行条件和断言用于理解设计边界。
- [test_agent_runtime.py:test_tool_graph_creates_one_proposal_on_replay](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_agent_runtime.py:63) 与 [test_expired_lease_resumes_committed_tool_without_duplicate](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_agent_runtime.py:151):阅读工具重复执行、租约过期及原工具结果复用。
- [test_agent_inputs.py:test_resume_same_run_atomic_idempotency_and_event](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_agent_inputs.py:54) 与 [test_registered_old_graph_remains_executable](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_agent_inputs.py:138):阅读相同输入并发重试和旧图版本继续执行。
- [test_business_wait.py:test_confirmation_approval_restore_same_run_once](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_business_wait.py:67)、[test_revision_replaces_wait_and_requires_new_confirmation](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_business_wait.py:106)、[test_takeover_and_approver_revocation_prevent_resume](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_business_wait.py:150):阅读业务恢复、方案修订、会话接管与授权撤销。