Files

4.4 KiB
Raw Permalink Blame History

id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week
id title type domain stack tags level prerequisites est_hours related week
ai.langgraph.scenario.refund-approval 退款工单 Agent:人工审批、任务状态和崩溃恢复 scenario ai
langgraph
fastapi
postgresql
人机协作
审批流
任务状态
异常恢复
幂等
流式进度
advanced
ai.langgraph.persistence-hitl
3
ai.langgraph.interview
ai.agent-ops.scenario.agent-quality-gate
backend.postgresql.scenario.order-state-audit
12

退款工单 Agent:人工审批、任务状态和崩溃恢复

业务背景与问题

客服系统接入 Agent 自动处理退款工单:识别工单类型和金额、查询订单、起草回复、执行退款。试运行发现:

  1. 大额退款不能让 Agent 直接执行,需要主管审批,审批可能隔天才处理;
  2. 模型接口偶尔超时,整个工单就失败了,要客服手动重新提交;
  3. 一次发版重启,几十个“处理中”的工单状态卡住,不知道执行到哪一步;
  4. 有工单重复退款了两次;
  5. 客服页面只显示“处理中”,不知道 Agent 在做什么。

约束

  • 审批阈值:500 元及以上需要人工审批。
  • 退款接口是第三方支付接口,支持幂等键。
  • 服务多实例部署,可能随时重启。

方案设计

flowchart LR
  A[分类<br/>结构化输出校验] -->|不合法| H[转人工]
  A --> B[起草回复<br/>RetryPolicy 重试]
  B -->|小额| D[执行退款 + 发送<br/>幂等键=工单号]
  B -->|大额| C[interrupt 等待审批]
  C -->|同意| D
  C -->|拒绝| E[结束]
  1. LangGraph + PostgresSaver:每一步保存检查点,thread_id = 工单号。
  2. 审批:审批节点调用 interrupt,同时把工单状态改为 waiting_approval 写入业务表;主管在后台点击后,接口调用 Command(resume=...) 继续。
  3. 临时错误:模型调用节点配置 RetryPolicy,只重试超时 / 限流 / 5xx。
  4. 崩溃恢复:后台巡检任务定期找出状态是“处理中”但长时间没有更新的工单,用 invoke(None, config) 从检查点继续(多实例下要先抢占租约,避免两个实例同时恢复同一个工单)。
  5. 幂等:退款和发送都用工单号做幂等键;状态更新用条件更新(WHERE status = ...)。
  6. 流式进度:节点里用 get_stream_writer() 发送进度,接口转成 SSE 推给客服页面。

关键代码

完整可运行示例:examples/ticket-flow。审批接口(FastAPI,示意):

@app.post("/tickets/{ticket_id}/approval")
async def approve(ticket_id: str, body: ApprovalIn, user=Depends(require_role("supervisor"))):
    cfg = {"configurable": {"thread_id": ticket_id}}
    snap = await graph.aget_state(cfg)
    if snap.next != ("approve",):
        raise HTTPException(409, "工单不在待审批状态")
    await graph.ainvoke(Command(resume={"ok": body.ok, "note": body.note, "by": user.id}), cfg)
    return {"status": (await graph.aget_state(cfg)).values["status"]}

取舍

选择 优点 缺点
LangGraph 检查点(本方案) 自带暂停 / 恢复 / 历史,代码少 依赖框架;检查点表需要清理
自己用状态机 + 任务表实现 完全可控,和业务表一体 要自己实现恢复、重试、事件流
工作流引擎(Temporal 等) 可靠性强,适合长流程 学习和运维成本高
全部人工审批 最安全 失去自动化的意义;用阈值和抽检平衡

易错点

  • 审批节点在 interrupt 之前就执行了退款。
  • 检查点和业务表的状态不一致:以业务表为准对账,或者在同一个节点里同时更新。
  • 恢复任务没有租约,多实例同时恢复同一个工单。
  • 审批接口没有校验当前状态,重复点击导致重复恢复。
  • 审批人看不到 Agent 的依据:审批数据要包含订单信息、起草内容、分类结果。

面试怎么讲

“退款 Agent 我用 LangGraph 做,检查点存在 PostgreSQL,thread_id 就是工单号。大额退款在审批节点 interrupt,状态写成待审批,主管点同意后用 Command resume 继续。模型超时用节点级重试;服务重启后巡检任务抢到租约,再从检查点续跑,已经完成的步骤不会重复执行;退款接口用工单号做幂等键,防止重复退款。前端通过 SSE 看到每一步的进度。”