Agent 工程实践 · 生产落地 Playbook
定位 :Applied AI / Agent 工程师的 落地主线 ------按 12 大能力域 归纳「要会什么、注意什么、怎么解决」。
工业级入口(Catalog+金品+42 场景) → 96 工业级交付指南 · 知识线周表(不要求跑 demo)。
机制与框架对比见 04;Tool/RAG/Eval 深链见 02、03、06。Eval 治理 / 四维 Registry / 长流程 Workflow → 10、11、04-java/04。
考前 :本篇 §16 全量 Checklist(123+ 项) + §16.0 面试前 30 分钟 + 98 §3.13、C.29--C.43;Architect 答辩 → §19 ;Cursor SDK 落地案例 → §20 (Grafana 告警 triage)。工程设计交付(设计+伪代码+部署使用) → 21。
0. 生产 Agent 参考架构
#mermaid-svg-GG0fpPMWUXgTf2uT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GG0fpPMWUXgTf2uT .error-icon{fill:#552222;}#mermaid-svg-GG0fpPMWUXgTf2uT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GG0fpPMWUXgTf2uT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GG0fpPMWUXgTf2uT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GG0fpPMWUXgTf2uT .marker.cross{stroke:#333333;}#mermaid-svg-GG0fpPMWUXgTf2uT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GG0fpPMWUXgTf2uT p{margin:0;}#mermaid-svg-GG0fpPMWUXgTf2uT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GG0fpPMWUXgTf2uT .cluster-label text{fill:#333;}#mermaid-svg-GG0fpPMWUXgTf2uT .cluster-label span{color:#333;}#mermaid-svg-GG0fpPMWUXgTf2uT .cluster-label span p{background-color:transparent;}#mermaid-svg-GG0fpPMWUXgTf2uT .label text,#mermaid-svg-GG0fpPMWUXgTf2uT span{fill:#333;color:#333;}#mermaid-svg-GG0fpPMWUXgTf2uT .node rect,#mermaid-svg-GG0fpPMWUXgTf2uT .node circle,#mermaid-svg-GG0fpPMWUXgTf2uT .node ellipse,#mermaid-svg-GG0fpPMWUXgTf2uT .node polygon,#mermaid-svg-GG0fpPMWUXgTf2uT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GG0fpPMWUXgTf2uT .rough-node .label text,#mermaid-svg-GG0fpPMWUXgTf2uT .node .label text,#mermaid-svg-GG0fpPMWUXgTf2uT .image-shape .label,#mermaid-svg-GG0fpPMWUXgTf2uT .icon-shape .label{text-anchor:middle;}#mermaid-svg-GG0fpPMWUXgTf2uT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GG0fpPMWUXgTf2uT .rough-node .label,#mermaid-svg-GG0fpPMWUXgTf2uT .node .label,#mermaid-svg-GG0fpPMWUXgTf2uT .image-shape .label,#mermaid-svg-GG0fpPMWUXgTf2uT .icon-shape .label{text-align:center;}#mermaid-svg-GG0fpPMWUXgTf2uT .node.clickable{cursor:pointer;}#mermaid-svg-GG0fpPMWUXgTf2uT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GG0fpPMWUXgTf2uT .arrowheadPath{fill:#333333;}#mermaid-svg-GG0fpPMWUXgTf2uT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GG0fpPMWUXgTf2uT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GG0fpPMWUXgTf2uT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GG0fpPMWUXgTf2uT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GG0fpPMWUXgTf2uT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GG0fpPMWUXgTf2uT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GG0fpPMWUXgTf2uT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GG0fpPMWUXgTf2uT .cluster text{fill:#333;}#mermaid-svg-GG0fpPMWUXgTf2uT .cluster span{color:#333;}#mermaid-svg-GG0fpPMWUXgTf2uT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GG0fpPMWUXgTf2uT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GG0fpPMWUXgTf2uT rect.text{fill:none;stroke-width:0;}#mermaid-svg-GG0fpPMWUXgTf2uT .icon-shape,#mermaid-svg-GG0fpPMWUXgTf2uT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GG0fpPMWUXgTf2uT .icon-shape p,#mermaid-svg-GG0fpPMWUXgTf2uT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GG0fpPMWUXgTf2uT .icon-shape .label rect,#mermaid-svg-GG0fpPMWUXgTf2uT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GG0fpPMWUXgTf2uT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GG0fpPMWUXgTf2uT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GG0fpPMWUXgTf2uT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户/事件
接入层
鉴权/限流
控制面
策略/审批/预算
数据面
Planner-Executor
LLM
Tools / RAG / Code
Observation
Memory / State
输出护栏
Trace / Metrics / Audit
| 平面 | 职责 | 必须显式实现 |
|---|---|---|
| 控制面 | 身份、权限、风险分级、HITL、token/$ 预算、熔断 | 高风险动作不能只在 prompt 里禁止 |
| 数据面 | 规划、tool 调用、生成 | 尽量无状态;状态进 Memory 服务 |
| 护栏 | 格式、合规、引用、拒答 | 生成后校验,不只靠 system prompt |
| 可观测 | trace_id、逐步 replay、版本 | 能回答「哪一步、哪个 tool、哪版 prompt」 |
与微服务类比 :Policy / Planner / Executor / Memory 分边界;Agent 一步错会 累积,所以比 Chatbot 更需要契约与观测。
1. 域 1:问题界定与边界
1.1 什么时候该做 Agent
| 条件 | 说明 |
|---|---|
| 任务可分解 | 至少 2 步,且步骤间有依赖或需中间结果 |
| 有工具或副作用 | 查库、改状态、发消息、调 API |
| 可验收 | 能定义「完成」:订单已创建、工单已关闭 |
| 可观测 | 每步可 log;失败可定位 |
| 失败可回滚/降级 | 不能「错了就错了」 |
1.2 什么时候不该做 Agent
| 场景 | 更好方案 |
|---|---|
| 单步 FAQ | RAG 或检索 + 模板 |
| 固定流程(KYC 表单) | 工作流引擎 + 规则 |
| 强实时 <50ms | 规则 + 小模型分类 |
| 不可审计的自主写操作 | 人确认 + 确定性 API |
1.3 决策树
#mermaid-svg-YkK8ZbYlLDAhPNq6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .error-icon{fill:#552222;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .marker.cross{stroke:#333333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 p{margin:0;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .cluster-label text{fill:#333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .cluster-label span{color:#333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .cluster-label span p{background-color:transparent;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .label text,#mermaid-svg-YkK8ZbYlLDAhPNq6 span{fill:#333;color:#333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .node rect,#mermaid-svg-YkK8ZbYlLDAhPNq6 .node circle,#mermaid-svg-YkK8ZbYlLDAhPNq6 .node ellipse,#mermaid-svg-YkK8ZbYlLDAhPNq6 .node polygon,#mermaid-svg-YkK8ZbYlLDAhPNq6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .rough-node .label text,#mermaid-svg-YkK8ZbYlLDAhPNq6 .node .label text,#mermaid-svg-YkK8ZbYlLDAhPNq6 .image-shape .label,#mermaid-svg-YkK8ZbYlLDAhPNq6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .rough-node .label,#mermaid-svg-YkK8ZbYlLDAhPNq6 .node .label,#mermaid-svg-YkK8ZbYlLDAhPNq6 .image-shape .label,#mermaid-svg-YkK8ZbYlLDAhPNq6 .icon-shape .label{text-align:center;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .node.clickable{cursor:pointer;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .arrowheadPath{fill:#333333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YkK8ZbYlLDAhPNq6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YkK8ZbYlLDAhPNq6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YkK8ZbYlLDAhPNq6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .cluster text{fill:#333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .cluster span{color:#333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YkK8ZbYlLDAhPNq6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .icon-shape,#mermaid-svg-YkK8ZbYlLDAhPNq6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .icon-shape p,#mermaid-svg-YkK8ZbYlLDAhPNq6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .icon-shape .label rect,#mermaid-svg-YkK8ZbYlLDAhPNq6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YkK8ZbYlLDAhPNq6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YkK8ZbYlLDAhPNq6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YkK8ZbYlLDAhPNq6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
否
是
是
否
用户目标
单步可完成?
RAG / Prompt
需改外部状态?
CoT / 多步推理无工具
步骤固定?
工作流 DAG
Agent 有界循环
面试金句 :Agent 是 带副作用的多步控制器;没有工具、没有验收标准、没有 trace,就不要叫 Agent。
→ 机制详见 04 §1
2. 域 2:编排与规划
2.1 模式选型
| 模式 | 适用 | 风险 | 成本 |
|---|---|---|---|
| ReAct | 探索型、步骤不确定 | 短视、死循环 | 中 |
| Plan-Execute | 步骤可预估、依赖清晰 | 一次 plan 跑偏 | 中低 |
| DAG + 有界循环 | 生产推荐:确定性阶段 + 局部自适应 | 设计前期投入 | 可控 |
| Multi-Agent | 并行子域、角色分工 | 协调成本、一致性 | 高 |
| ToT | 离线高质量推理 | 成本爆炸 | 很高 |
2.2 大任务拆分准则
- 原子性:一步 = 一个可验证 observation(查到了订单号 / SQL 返回 3 行)。
- 依赖显式 :画 DAG;并行只给 无依赖 步骤。
- 可逆/可补偿:写操作带幂等键;删操作走 HITL。
- 预算 :
max_steps、max_tool_calls、max_wall_time、max_cost_usd写入 state。
2.3 Replan 触发(必须编码,不要靠模型自觉)
| 触发 | 动作 |
|---|---|
tool 返回 error 且可重试 |
换参数 / 换 tool / 限次重试 |
| observation 与 plan 假设矛盾 | replan 剩余步骤 |
| 同 tool+args 连续 ≥3 次 | 熔断 + 降级 |
| 预算耗尽 | 输出「部分完成」+ 人工接手 |
| 低置信 / 无 evidence | 拒答或澄清问题 |
plan_drift_detected(连续 2 步与 goal 无关 / verify 全失败) |
强制 replan + 重注入 North Star(§2.5) |
2.4 LangGraph 状态字段(示例)
python
class AgentState(TypedDict):
messages: list
goal: str
success_criteria: list[str]
plan: list[PlanStep] # {id, action, deps, verify, status, risk}
completed_steps: list[str]
plan_drift: bool
tool_results: dict[str, Any]
budget: Budget # steps_left, tokens_left, usd_left
replan_count: int
risk_level: str # low | medium | high
final_answer: str | None
→ 详见 04 §4.3 Plan-Execute、§5 Multi-Agent
2.5 Plan 防跑偏(Staff 必答)
根因 :Plan-Execute 一次写出 20+ 步后,模型会 短视执行、忽略原始目标、在错误假设上越走越远------§13 #12「plan 跑偏」是线上 completion 掉点的 Top3 原因之一。
2.5.1 三道闸(编码进 state,不靠 prompt 祈祷)
| 闸 | 字段 / 动作 | 说明 |
|---|---|---|
| North Star | goal, success_criteria[], non_goals[] |
每次 replan / 压缩 / resume 必须原文注入 system;禁止只留摘要 |
| 步级契约 | PlanStep.verify |
每步可 机器判定 的 observation(如 order_id 存在、status==SHIPPED),禁止「理解用户需求」类模糊 verify |
| 漂移检测 | plan_drift, verify_fail_streak |
连续 2 步 verify 失败或 tool 与 goal 无关 → plan_drift=true → 仅 replan 剩余步 ,已完成步进 completed_steps |
2.5.2 滚动规划 vs 一次大 Plan
| 策略 | 适用 | 防跑偏 |
|---|---|---|
| 滚动 Plan(推荐) | 生产在线、>5 步任务 | 每次只 plan 下一层 3--7 步;做完再 plan;假设随 observation 更新 |
| 一次大 Plan | 离线批处理、步骤极固定 | 必须配 步级闸门 + 中途 plan_drift 熔断 |
| DAG 骨架 + 局部 ReAct | 支付/运维 | 确定性阶段走 DAG;仅「异常分支」开 ReAct |
2.5.3 步级闸门流程
#mermaid-svg-RV89mBZaxkXTUmnt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RV89mBZaxkXTUmnt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RV89mBZaxkXTUmnt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RV89mBZaxkXTUmnt .error-icon{fill:#552222;}#mermaid-svg-RV89mBZaxkXTUmnt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RV89mBZaxkXTUmnt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RV89mBZaxkXTUmnt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RV89mBZaxkXTUmnt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RV89mBZaxkXTUmnt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RV89mBZaxkXTUmnt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RV89mBZaxkXTUmnt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RV89mBZaxkXTUmnt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RV89mBZaxkXTUmnt .marker.cross{stroke:#333333;}#mermaid-svg-RV89mBZaxkXTUmnt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RV89mBZaxkXTUmnt p{margin:0;}#mermaid-svg-RV89mBZaxkXTUmnt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RV89mBZaxkXTUmnt .cluster-label text{fill:#333;}#mermaid-svg-RV89mBZaxkXTUmnt .cluster-label span{color:#333;}#mermaid-svg-RV89mBZaxkXTUmnt .cluster-label span p{background-color:transparent;}#mermaid-svg-RV89mBZaxkXTUmnt .label text,#mermaid-svg-RV89mBZaxkXTUmnt span{fill:#333;color:#333;}#mermaid-svg-RV89mBZaxkXTUmnt .node rect,#mermaid-svg-RV89mBZaxkXTUmnt .node circle,#mermaid-svg-RV89mBZaxkXTUmnt .node ellipse,#mermaid-svg-RV89mBZaxkXTUmnt .node polygon,#mermaid-svg-RV89mBZaxkXTUmnt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RV89mBZaxkXTUmnt .rough-node .label text,#mermaid-svg-RV89mBZaxkXTUmnt .node .label text,#mermaid-svg-RV89mBZaxkXTUmnt .image-shape .label,#mermaid-svg-RV89mBZaxkXTUmnt .icon-shape .label{text-anchor:middle;}#mermaid-svg-RV89mBZaxkXTUmnt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RV89mBZaxkXTUmnt .rough-node .label,#mermaid-svg-RV89mBZaxkXTUmnt .node .label,#mermaid-svg-RV89mBZaxkXTUmnt .image-shape .label,#mermaid-svg-RV89mBZaxkXTUmnt .icon-shape .label{text-align:center;}#mermaid-svg-RV89mBZaxkXTUmnt .node.clickable{cursor:pointer;}#mermaid-svg-RV89mBZaxkXTUmnt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RV89mBZaxkXTUmnt .arrowheadPath{fill:#333333;}#mermaid-svg-RV89mBZaxkXTUmnt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RV89mBZaxkXTUmnt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RV89mBZaxkXTUmnt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RV89mBZaxkXTUmnt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RV89mBZaxkXTUmnt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RV89mBZaxkXTUmnt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RV89mBZaxkXTUmnt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RV89mBZaxkXTUmnt .cluster text{fill:#333;}#mermaid-svg-RV89mBZaxkXTUmnt .cluster span{color:#333;}#mermaid-svg-RV89mBZaxkXTUmnt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RV89mBZaxkXTUmnt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RV89mBZaxkXTUmnt rect.text{fill:none;stroke-width:0;}#mermaid-svg-RV89mBZaxkXTUmnt .icon-shape,#mermaid-svg-RV89mBZaxkXTUmnt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RV89mBZaxkXTUmnt .icon-shape p,#mermaid-svg-RV89mBZaxkXTUmnt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RV89mBZaxkXTUmnt .icon-shape .label rect,#mermaid-svg-RV89mBZaxkXTUmnt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RV89mBZaxkXTUmnt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RV89mBZaxkXTUmnt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RV89mBZaxkXTUmnt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
是
否
否
是
否
goal + success_criteria 入 state
Planner 产出 plan 片段
Executor 执行一步
verify 通过?
completed_steps += step_id
还有 pending?
final_answer
verify_fail_streak >= 2?
plan_drift=true 强制 replan
同步重试/换参 限 1 次
2.5.4 PlanStep 契约(扩展示例)
python
class PlanStep(TypedDict):
id: str
action: str # tool 名或子目标描述
deps: list[str]
verify: str # 可执行判定:SQL 行数、JSON path、状态机
status: str # pending | running | done | failed | skipped
risk: str # low | medium | high → 映射 HITL
2.5.5 Architect 红线
- 禁止 无
verify的 plan 步上线。 - 禁止 replan 时清空
completed_steps(否则重复副作用)。 - 高风险步(
risk=high)plan 展示后 HITL 批准 再执行(链域 8)。 - Multi-Agent:仅 一个 Coordinator 持有
goal;Worker 不得私自改 North Star。
3. 域 3:状态与记忆
深链(机制 + 选型) :04 §13 Agent Memory 与 Context Engineering --- 情节/语义/程序性三分、Mem0/Letta/Zep 对照、Context Engineering vs Prompt Engineering、Redis+pgvector 读写在 04 有完整 walk。本篇域 3 补 生产分工表、两层存储落地、托管记忆层 P99/成本、Spring AI Advisor 接线 与 §16 Checklist。
3.1 四层记忆(不要只堆 chat history)
| 层 | 内容 | 存储 | 生命周期 |
|---|---|---|---|
| Working | 当前 plan、tool 结果、槽位 | Redis / 内存 | 单 task |
| Session | 最近 N 轮对话 | Redis | 会话 TTL |
| Summary | 老对话压缩摘要 | DB | 跨轮 |
| Long-term | 偏好、历史任务结论 | 向量库 + 结构化表 | 跨 session |
3.1.1 状态存哪?不是向量库(Architect 必分清)
结论 :续跑 / 98% 失败恢复 用的 Checkpoint ≠ 向量数据库 。向量库只做 语义检索 (长期记忆、历史对话相似片段、RAG);Checkpoint 是 结构化 JSON/行存,要强一致、可精确回放。
| 存储类型 | 存什么 | 典型技术 | 本地 or 网络 | 用于 |
|---|---|---|---|---|
| Checkpoint | goal、plan、completed_steps、version_pin |
PostgreSQL (LangGraph PostgresSaver)、MySQL、DynamoDB |
生产一律走网络(K8s Pod → 集群 DB) | 中断续跑、幂等、进度 |
| Working / Session | 当前 plan 槽位、最近 N 轮 | Redis、进程内存 | 内存=本 Pod;Redis=网络 | 单 task / 会话 |
| Artifact | 大 tool 结果、分析报告 .md |
S3 / OSS / 本地磁盘 | 生产 对象存储(网络);开发可本地目录 | 减 context,可审计 |
| 向量库 | 历史结论 embedding、知识 chunk | Qdrant、pgvector、Milvus | 网络(独立向量服务) | 长期记忆、RAG、按语义捞 history |
| Cursor SDK 会话 | Agent 对话、cloud run 元数据 | Cursor 云端 | 网络 (CURSOR_API_KEY → Cursor API) |
IDE 同级 Agent;不能当你们业务 checkpoint |
#mermaid-svg-1qD1i8rarjbNDEok{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1qD1i8rarjbNDEok .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1qD1i8rarjbNDEok .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1qD1i8rarjbNDEok .error-icon{fill:#552222;}#mermaid-svg-1qD1i8rarjbNDEok .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1qD1i8rarjbNDEok .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1qD1i8rarjbNDEok .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1qD1i8rarjbNDEok .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1qD1i8rarjbNDEok .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1qD1i8rarjbNDEok .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1qD1i8rarjbNDEok .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1qD1i8rarjbNDEok .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1qD1i8rarjbNDEok .marker.cross{stroke:#333333;}#mermaid-svg-1qD1i8rarjbNDEok svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1qD1i8rarjbNDEok p{margin:0;}#mermaid-svg-1qD1i8rarjbNDEok .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1qD1i8rarjbNDEok .cluster-label text{fill:#333;}#mermaid-svg-1qD1i8rarjbNDEok .cluster-label span{color:#333;}#mermaid-svg-1qD1i8rarjbNDEok .cluster-label span p{background-color:transparent;}#mermaid-svg-1qD1i8rarjbNDEok .label text,#mermaid-svg-1qD1i8rarjbNDEok span{fill:#333;color:#333;}#mermaid-svg-1qD1i8rarjbNDEok .node rect,#mermaid-svg-1qD1i8rarjbNDEok .node circle,#mermaid-svg-1qD1i8rarjbNDEok .node ellipse,#mermaid-svg-1qD1i8rarjbNDEok .node polygon,#mermaid-svg-1qD1i8rarjbNDEok .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1qD1i8rarjbNDEok .rough-node .label text,#mermaid-svg-1qD1i8rarjbNDEok .node .label text,#mermaid-svg-1qD1i8rarjbNDEok .image-shape .label,#mermaid-svg-1qD1i8rarjbNDEok .icon-shape .label{text-anchor:middle;}#mermaid-svg-1qD1i8rarjbNDEok .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1qD1i8rarjbNDEok .rough-node .label,#mermaid-svg-1qD1i8rarjbNDEok .node .label,#mermaid-svg-1qD1i8rarjbNDEok .image-shape .label,#mermaid-svg-1qD1i8rarjbNDEok .icon-shape .label{text-align:center;}#mermaid-svg-1qD1i8rarjbNDEok .node.clickable{cursor:pointer;}#mermaid-svg-1qD1i8rarjbNDEok .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1qD1i8rarjbNDEok .arrowheadPath{fill:#333333;}#mermaid-svg-1qD1i8rarjbNDEok .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1qD1i8rarjbNDEok .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1qD1i8rarjbNDEok .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1qD1i8rarjbNDEok .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1qD1i8rarjbNDEok .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1qD1i8rarjbNDEok .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1qD1i8rarjbNDEok .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1qD1i8rarjbNDEok .cluster text{fill:#333;}#mermaid-svg-1qD1i8rarjbNDEok .cluster span{color:#333;}#mermaid-svg-1qD1i8rarjbNDEok div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1qD1i8rarjbNDEok .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1qD1i8rarjbNDEok rect.text{fill:none;stroke-width:0;}#mermaid-svg-1qD1i8rarjbNDEok .icon-shape,#mermaid-svg-1qD1i8rarjbNDEok .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1qD1i8rarjbNDEok .icon-shape p,#mermaid-svg-1qD1i8rarjbNDEok .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1qD1i8rarjbNDEok .icon-shape .label rect,#mermaid-svg-1qD1i8rarjbNDEok .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1qD1i8rarjbNDEok .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1qD1i8rarjbNDEok .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1qD1i8rarjbNDEok :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 不要混用
每步刷盘 强一致
可选 语义回忆
Checkpoint 行存/JSON
Postgres
向量库
相似度检索
Agent 进程
本地 vs 网络(怎么记):
| 部署 | Checkpoint 放哪 | 说明 |
|---|---|---|
开发 local: { cwd } |
本机 SQLite/文件 或 连 dev 库 | 文件在 笔记本磁盘 ;连 dev Postgres 仍是 网络 |
| 生产 K8s + Cursor SDK | 你们自己的 Postgres/Redis(网络) | Pod 重启后靠 DB 续跑;不要只指望 Pod 内存或 Cursor 云端对话 |
| Cursor Cloud Agent | Cursor 持有一部分 run 状态;业务 checkpoint 仍建议自建 DB | Agent.resume(agentId) 续 对话 ;completed_steps / 是否已 resolve 须你们库判定,防重复写 |
§20 Grafana 案例(写死):
| 组件 | 存储 | 连接方式 |
|---|---|---|
| Triage checkpoint | PostgreSQL (表 alert_triage_checkpoint,key=alert_group_id) |
Triage API TCP 连库(同 VPC) |
| 分析报告 | S3/OSS artifacts/triage-{id}.md |
SDK 写完后 URI 写入 checkpoint |
| 会话/缓存 | Redis(可选,Webhook 幂等) | 网络 |
| 历史相似 alert | 向量库(可选) | 仅在做「和上次误报是否同类」时检索;非续跑必需 |
| Grafana 数据 | Grafana MCP / API | 网络 ;凭证 grafana.env,不进 prompt |
| LLM/Agent 运行时 | Cursor API | 公网/专线出网 |
3.2 注意事项
| 坑 | 解法 |
|---|---|
| 跨租户泄漏 | tenant_id 隔离 key;检索必带 filter |
| 摘要漂移 | 结构化 state 优先(订单号、意图)再摘要 |
| 工具结果过大 | 截断 + 结构化摘要进 state,原文进 artifact 存储 |
| 并发写 state | 乐观锁 / 单线程 executor per session |
3.3 上下文不足时的记忆策略(与域 6 配合)
优先级:结构化 state > 最近 N 条 > 摘要 > 语义检索历史 > 截断最老轮。
→ 客服长对话见 nlp-chatbot/02
3.4 压缩后如何保证主题不跑偏
原则 :结构化 state 是真相源;摘要只是索引 。压缩不得覆盖 goal、success_criteria、关键槽位(order_id、tenant_id、意图)。
3.4.1 不可压缩 vs 可压缩
| 层级 | 永远进 context(锚点) | 可压缩/外置 |
|---|---|---|
| 任务 | goal, success_criteria, non_goals, completed_steps[] |
--- |
| 实体槽位 | 订单号、用户 ID、金额、政策版本 | 原始 tool JSON |
| 步结果 | 每步 verify 结论 + artifact_uri |
完整 observation |
| 对话 | 最近 2--4 轮原文 | 更早轮 → 结构化摘要 |
3.4.2 压缩协议(四步)
- 先抽取再摘要 :规则或小模型抽
entities、decisions、open_questions→ 再生成 narrative。 - 双通道输出 :
factual_bullets[](可核对)+narrative(展示用);replan 只读 bullets。 - 压缩后校验 :
- 规则:摘要中实体 ⊆ state 槽位;
success_criteria未被改写。 - 可选 Judge:
summary 是否改变 goal?→ yes 则 丢弃摘要,仅保留锚点。
- 规则:摘要中实体 ⊆ state 槽位;
- 周期性重锚:每 N 步或 token > 70% 预算,system 注入「goal + 已完成 + 下一 pending 步」三块。
3.4.3 反模式
| 反模式 | 后果 | 修复 |
|---|---|---|
| 只滚 chat summary | 丢订单号、改意图 | 槽位进 state,摘要只索引 |
| 压缩含新事实 | 幻觉进长期记忆 | bullets 必须引用 observation_id |
| replan 读 narrative | 主题漂移 | replan 输入 = 锚点 + bullets |
3.5 情节 / 语义 / 程序性 → 存储映射(与四层模型对齐)
认知三分 禁止混成一段 chat summary (见 04 §13.1)。下表把 记什么 钉到 存哪、谁写、谁读:
| 记忆类型 | Agent 典型内容 | 对应 Playbook 层 | 主存储 | 写入时机 | 读入 context 方式 |
|---|---|---|---|---|---|
| Episodic(情节) | 最近 N 轮、tool 轨迹、order_id 时间线、verify 结论 |
Working + Session + Checkpoint | Redis(热)+ PostgreSQL Checkpoint(冷、可续跑) | 每步 tool 后刷 checkpoint;轮次结束写 Redis | 最近 2--4 轮原文 + completed_steps[];不靠向量相似度捞订单号 |
| Semantic(语义) | 用户偏好、历史任务结论、政策事实 | Summary + Long-term | DB 摘要表 + pgvector / Qdrant | session 结束抽 facts[] embedding;或 observation 确认后异步写 |
retrieve(top-k) + 强制 tenant_id / user_id filter |
| Procedural(程序) | SOP、退款流程、成功 plan 模板、图边条件 | 不进「聊天记忆」 | LangGraph 图、Prompt 模板、内部 Playbook | 版本发布 / Git | system + 图路由;不让模型从摘要里「发明流程」 |
#mermaid-svg-PuXla8DT6e0DvNVb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PuXla8DT6e0DvNVb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PuXla8DT6e0DvNVb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PuXla8DT6e0DvNVb .error-icon{fill:#552222;}#mermaid-svg-PuXla8DT6e0DvNVb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PuXla8DT6e0DvNVb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PuXla8DT6e0DvNVb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PuXla8DT6e0DvNVb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PuXla8DT6e0DvNVb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PuXla8DT6e0DvNVb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PuXla8DT6e0DvNVb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PuXla8DT6e0DvNVb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PuXla8DT6e0DvNVb .marker.cross{stroke:#333333;}#mermaid-svg-PuXla8DT6e0DvNVb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PuXla8DT6e0DvNVb p{margin:0;}#mermaid-svg-PuXla8DT6e0DvNVb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PuXla8DT6e0DvNVb .cluster-label text{fill:#333;}#mermaid-svg-PuXla8DT6e0DvNVb .cluster-label span{color:#333;}#mermaid-svg-PuXla8DT6e0DvNVb .cluster-label span p{background-color:transparent;}#mermaid-svg-PuXla8DT6e0DvNVb .label text,#mermaid-svg-PuXla8DT6e0DvNVb span{fill:#333;color:#333;}#mermaid-svg-PuXla8DT6e0DvNVb .node rect,#mermaid-svg-PuXla8DT6e0DvNVb .node circle,#mermaid-svg-PuXla8DT6e0DvNVb .node ellipse,#mermaid-svg-PuXla8DT6e0DvNVb .node polygon,#mermaid-svg-PuXla8DT6e0DvNVb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PuXla8DT6e0DvNVb .rough-node .label text,#mermaid-svg-PuXla8DT6e0DvNVb .node .label text,#mermaid-svg-PuXla8DT6e0DvNVb .image-shape .label,#mermaid-svg-PuXla8DT6e0DvNVb .icon-shape .label{text-anchor:middle;}#mermaid-svg-PuXla8DT6e0DvNVb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PuXla8DT6e0DvNVb .rough-node .label,#mermaid-svg-PuXla8DT6e0DvNVb .node .label,#mermaid-svg-PuXla8DT6e0DvNVb .image-shape .label,#mermaid-svg-PuXla8DT6e0DvNVb .icon-shape .label{text-align:center;}#mermaid-svg-PuXla8DT6e0DvNVb .node.clickable{cursor:pointer;}#mermaid-svg-PuXla8DT6e0DvNVb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PuXla8DT6e0DvNVb .arrowheadPath{fill:#333333;}#mermaid-svg-PuXla8DT6e0DvNVb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PuXla8DT6e0DvNVb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PuXla8DT6e0DvNVb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PuXla8DT6e0DvNVb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PuXla8DT6e0DvNVb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PuXla8DT6e0DvNVb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PuXla8DT6e0DvNVb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PuXla8DT6e0DvNVb .cluster text{fill:#333;}#mermaid-svg-PuXla8DT6e0DvNVb .cluster span{color:#333;}#mermaid-svg-PuXla8DT6e0DvNVb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PuXla8DT6e0DvNVb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PuXla8DT6e0DvNVb rect.text{fill:none;stroke-width:0;}#mermaid-svg-PuXla8DT6e0DvNVb .icon-shape,#mermaid-svg-PuXla8DT6e0DvNVb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PuXla8DT6e0DvNVb .icon-shape p,#mermaid-svg-PuXla8DT6e0DvNVb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PuXla8DT6e0DvNVb .icon-shape .label rect,#mermaid-svg-PuXla8DT6e0DvNVb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PuXla8DT6e0DvNVb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PuXla8DT6e0DvNVb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PuXla8DT6e0DvNVb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Procedural
Semantic
Episodic
session 结束
每步注入
top-k 回忆
Redis Session
PG Checkpoint
Summary 表
pgvector
LangGraph / SOP / Prompt
Agent
面试金句 :情节要 可回放 (行存);语义要 可检索 (向量);程序性要 可版本化(图/文档)------三者混在一个 summary 里,长对话必漂移。
3.6 托管记忆层选型:Mem0 vs Letta vs Zep(生产维度)
机制依据(产品 API,非 Spring 内置)
- Mem0 :L1 docs.mem0.ai · L2 mem0ai/mem0
- Letta :L1 docs.letta.com · L2 letta-ai/letta
- Zep :L1 help.getzep.com · L2 getzep/zep
下表补 持久化、延迟、成本、Spring AI 四维(写入语义以各产品 L1 文档为准)。
| 维度 | Mem0 | Letta (MemGPT) | Zep |
|---|---|---|---|
| 定位 | 记忆层 SDK / 托管 API | 有状态 Agent OS + 分页 memory | 会话记忆 + 时序 / 知识图谱 |
| 持久化 | 托管向量 + 元数据;可自托管 | 核心/归档内存块 + 可选 DB | Cloud Graph + 会话 store;可自建组件 |
| 典型读延迟 | 托管 API ~80--250ms P99(含 embedding);自托管取决于向量库 | Agent 运行时内读块,~50--150ms;跨块归档更慢 | Graph 遍历 ~100--400ms;简单向量路径更低 |
| 典型写延迟 | 异步 fact 抽取,秒级 才可查 | memory_insert 同步块内 <100ms |
ingest 流水线,近实时到 Graph |
| 成本画像 | 按 记忆条数 + API 调用;长会话抽 fact 次数↑ | Agent 运行时席位 + 存储;研究/复杂 Agent 偏高 | B2B 按 MAU/会话;Graph 存储随边增长 |
| Spring AI 集成 | 无官方 Starter ;HTTP/SDK 包一层 @Tool 或 ChatClient 前 Advisor 调 Mem0 API |
非 Spring 原生;需 sidecar / 独立 Letta 服务,Spring 只作网关 | 无官方 Starter ;Java 用 REST SDK;长期记忆建议仍落 pgvector |
| 生产默认建议 | POC「跨 session 记住用户」;上线前 审计写入路径 | 复杂自主 Agent 实验室;生产 Java 栈少见作核心 | 合规客服画像;注意 数据出境 与 Graph 一致性 |
| 与自建栈关系 | 可替换 pgvector 写入/检索 一层,不能 替换 Checkpoint | 替换整段 Agent 运行时,与 Spring 编排 并行 而非嵌入 | 偏 语义+关系;Checkpoint 仍须 PG |
选型结论(Java 主栈):
- 生产默认 :
MessageChatMemoryAdvisor(Redis)+VectorStoreChatMemoryAdvisor(pgvector)+ 自建 PG Checkpoint ------ 见 14 §7.1。 - Mem0 / Zep :适合 2--4 周 POC;Gate:写入审计、租户隔离、P99 预算、降级开关(读失败 → 仅 session)。
- Letta :除非团队已押 Letta OS,否则 Spring 侧用 LangGraph4j / 自研 state 更可控。
3.7 Redis + pgvector 两层记忆(生产落地)
两层 = 热路径 Session(Redis) + 冷路径语义(pgvector) ;Checkpoint(PostgreSQL 行存) 仍单独存在,不参与 向量相似度检索(§3.1.1)。与 04 §13.4 同构,此处写 读写契约 便于 SRE 与 Java 实现对齐。
#mermaid-svg-NA0srvurALPor61s{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NA0srvurALPor61s .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NA0srvurALPor61s .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NA0srvurALPor61s .error-icon{fill:#552222;}#mermaid-svg-NA0srvurALPor61s .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NA0srvurALPor61s .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NA0srvurALPor61s .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NA0srvurALPor61s .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NA0srvurALPor61s .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NA0srvurALPor61s .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NA0srvurALPor61s .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NA0srvurALPor61s .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NA0srvurALPor61s .marker.cross{stroke:#333333;}#mermaid-svg-NA0srvurALPor61s svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NA0srvurALPor61s p{margin:0;}#mermaid-svg-NA0srvurALPor61s .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NA0srvurALPor61s .cluster-label text{fill:#333;}#mermaid-svg-NA0srvurALPor61s .cluster-label span{color:#333;}#mermaid-svg-NA0srvurALPor61s .cluster-label span p{background-color:transparent;}#mermaid-svg-NA0srvurALPor61s .label text,#mermaid-svg-NA0srvurALPor61s span{fill:#333;color:#333;}#mermaid-svg-NA0srvurALPor61s .node rect,#mermaid-svg-NA0srvurALPor61s .node circle,#mermaid-svg-NA0srvurALPor61s .node ellipse,#mermaid-svg-NA0srvurALPor61s .node polygon,#mermaid-svg-NA0srvurALPor61s .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NA0srvurALPor61s .rough-node .label text,#mermaid-svg-NA0srvurALPor61s .node .label text,#mermaid-svg-NA0srvurALPor61s .image-shape .label,#mermaid-svg-NA0srvurALPor61s .icon-shape .label{text-anchor:middle;}#mermaid-svg-NA0srvurALPor61s .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NA0srvurALPor61s .rough-node .label,#mermaid-svg-NA0srvurALPor61s .node .label,#mermaid-svg-NA0srvurALPor61s .image-shape .label,#mermaid-svg-NA0srvurALPor61s .icon-shape .label{text-align:center;}#mermaid-svg-NA0srvurALPor61s .node.clickable{cursor:pointer;}#mermaid-svg-NA0srvurALPor61s .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NA0srvurALPor61s .arrowheadPath{fill:#333333;}#mermaid-svg-NA0srvurALPor61s .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NA0srvurALPor61s .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NA0srvurALPor61s .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NA0srvurALPor61s .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NA0srvurALPor61s .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NA0srvurALPor61s .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NA0srvurALPor61s .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NA0srvurALPor61s .cluster text{fill:#333;}#mermaid-svg-NA0srvurALPor61s .cluster span{color:#333;}#mermaid-svg-NA0srvurALPor61s div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NA0srvurALPor61s .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NA0srvurALPor61s rect.text{fill:none;stroke-width:0;}#mermaid-svg-NA0srvurALPor61s .icon-shape,#mermaid-svg-NA0srvurALPor61s .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NA0srvurALPor61s .icon-shape p,#mermaid-svg-NA0srvurALPor61s .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NA0srvurALPor61s .icon-shape .label rect,#mermaid-svg-NA0srvurALPor61s .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NA0srvurALPor61s .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NA0srvurALPor61s .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NA0srvurALPor61s :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Tier-2 冷 · 可检索
Tier-1 热 · 毫秒级
每请求
每步 / 写操作后
retrieve top-k
episode 结束 异步
filter tenant_id user_id
Redis
最近 N 轮 + plan 槽位
TTL 24--72h
PostgreSQL
Checkpoint / 结构化 state
pgvector HNSW
长期语义记忆
Spring Boot Agent
| 阶段 | 动作 | 失败降级 |
|---|---|---|
| 读(每 turn) | ① Redis GET session:{tenant}:{user} → ② PG 拉 goal/plan/completed_steps(或 LangGraph checkpoint)→ ③ pgvector similaritySearch top-5 偏好/事实 |
③ 超时 >200ms → 跳过长期回忆,仅 ①② |
| 写(每步) | tool 结果摘要进 state;写 PG checkpoint(强一致) | PG 失败 → 中止写副作用 tool,勿仅记 Redis |
| 写(session 结束) | 规则/小模型抽 facts[] → embedding → upsert pgvector;可选写 Summary 表 |
异步队列;失败告警,不阻塞用户 |
| 隔离 | Redis key、checkpoint 行、vector metadata 均含 tenant_id;检索 禁止 无 filter |
跨租户泄漏 = P0 |
yaml
# Spring AI 两层示意(与 04 §13.4 一致)
spring:
data:
redis:
host: redis.internal
timeout: 200ms
ai:
vectorstore:
pgvector:
index-type: HNSW
dimensions: 1536
chat:
memory:
redis:
ttl: 48h
java
// Advisor 链顺序:先加载短期,再检索长期(避免长期噪声盖掉当前槽位)
ChatClient.builder(chatModel)
.defaultAdvisors(
new MessageChatMemoryAdvisor(redisChatMemory), // Tier-1
new VectorStoreChatMemoryAdvisor(vectorStore, topK(5)) // Tier-2
)
.build();
与域 6 分工 :两层解决 「记在哪」 ;Context Budget 解决 「塞进窗口的先后顺序」(§3.8)。
3.8 Context Engineering 要点(装配顺序,非 Prompt 措辞)
Context Engineering 优化的是 整段上下文装配 (system、state、RAG、tool 结果、记忆),不是改一句 system prompt。定义与对比见 04 §13.3。
推荐装配顺序(token 从贵到便宜):
- 锚点 :
goal、success_criteria、non_goals、completed_steps(永不截断) - 结构化 state :槽位、当前
PlanStep、最近 verify 结论 - 程序性:SOP 片段 / 图当前节点说明(短)
- RAG:高 rerank 分 chunk(低分不硬塞,见域 5)
- 语义记忆:pgvector top-k(带引用 id,供核对)
- 情节:最近 2--4 轮原文
- 摘要 narrative :仅展示;replan 不读(§3.4)
- 预留生成:≥15% 窗口
| Context Engineering 反模式 | 后果 | 修复 |
|---|---|---|
| 先塞满 history 再 RAG | 挤掉证据 | 先 RAG + state,后 history |
| 长期记忆无 filter | 跨用户偏好泄漏 | 强制 tenant_id + user_id |
| 向量检索替代 checkpoint | 续跑丢步、重复写 | 订单号/plan 只信 PG |
| 托管 Mem0 写路径不可审计 | 幻觉 fact 永久化 | 写入需 observation_id + 人工/规则门 |
→ Token 占比表见 域 6 §6.1 ;窗口将满决策树见 §6.3。
4. 域 4:工具与行动面
4.1 Tool 契约(生产必守)
json
{
"ok": true,
"data": { "order_id": "O123", "status": "SHIPPED" },
"error": null,
"meta": { "latency_ms": 42, "source": "order-svc-v3" }
}
| 原则 | 说明 |
|---|---|
| 单一职责 | get_order 不要 do_everything |
| JSON Schema | type、enum、required、description 给模型看 |
| 结构化错误 | INVALID_ID 不要 stack trace 给 LLM |
| 幂等 | 写操作强制 idempotency_key |
| 超时 | 默认 15s;与 Agent 总超时联动 |
4.2 工具多了怎么选(30+ tools)
- 分组:先分类(日程/邮件/订单),Planner 只选一类。
- 检索式:用 embedding 召回 top-5 候选再让 LLM 选(04 飞书案例:78%→94%)。
- Few-shot:prompt 里 5--10 个「问题→tool」示例。
4.3 沙箱五层(与 02 一致)
白名单 → schema 校验 → RBAC → 限流 → 审计(6 个月+)。
4.4 ReAct vs Function Calling
| ReAct 文本 | Function Calling | |
|---|---|---|
| 生产 | 弱模型/调试 | 强模型生产默认 |
| 解析 | regex 容错 | JSON schema |
5. 域 5:知识与 RAG(Agent 消费视角)
RAG 在 Agent 里通常是 一个 tool 或 Planner 前置步骤 ;管线机制见 03。
5.1 Agent 侧「检索结果研判」流水线
#mermaid-svg-MSM2wh5zUW21k6cw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MSM2wh5zUW21k6cw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MSM2wh5zUW21k6cw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MSM2wh5zUW21k6cw .error-icon{fill:#552222;}#mermaid-svg-MSM2wh5zUW21k6cw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MSM2wh5zUW21k6cw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MSM2wh5zUW21k6cw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MSM2wh5zUW21k6cw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MSM2wh5zUW21k6cw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MSM2wh5zUW21k6cw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MSM2wh5zUW21k6cw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MSM2wh5zUW21k6cw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MSM2wh5zUW21k6cw .marker.cross{stroke:#333333;}#mermaid-svg-MSM2wh5zUW21k6cw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MSM2wh5zUW21k6cw p{margin:0;}#mermaid-svg-MSM2wh5zUW21k6cw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MSM2wh5zUW21k6cw .cluster-label text{fill:#333;}#mermaid-svg-MSM2wh5zUW21k6cw .cluster-label span{color:#333;}#mermaid-svg-MSM2wh5zUW21k6cw .cluster-label span p{background-color:transparent;}#mermaid-svg-MSM2wh5zUW21k6cw .label text,#mermaid-svg-MSM2wh5zUW21k6cw span{fill:#333;color:#333;}#mermaid-svg-MSM2wh5zUW21k6cw .node rect,#mermaid-svg-MSM2wh5zUW21k6cw .node circle,#mermaid-svg-MSM2wh5zUW21k6cw .node ellipse,#mermaid-svg-MSM2wh5zUW21k6cw .node polygon,#mermaid-svg-MSM2wh5zUW21k6cw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MSM2wh5zUW21k6cw .rough-node .label text,#mermaid-svg-MSM2wh5zUW21k6cw .node .label text,#mermaid-svg-MSM2wh5zUW21k6cw .image-shape .label,#mermaid-svg-MSM2wh5zUW21k6cw .icon-shape .label{text-anchor:middle;}#mermaid-svg-MSM2wh5zUW21k6cw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MSM2wh5zUW21k6cw .rough-node .label,#mermaid-svg-MSM2wh5zUW21k6cw .node .label,#mermaid-svg-MSM2wh5zUW21k6cw .image-shape .label,#mermaid-svg-MSM2wh5zUW21k6cw .icon-shape .label{text-align:center;}#mermaid-svg-MSM2wh5zUW21k6cw .node.clickable{cursor:pointer;}#mermaid-svg-MSM2wh5zUW21k6cw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MSM2wh5zUW21k6cw .arrowheadPath{fill:#333333;}#mermaid-svg-MSM2wh5zUW21k6cw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MSM2wh5zUW21k6cw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MSM2wh5zUW21k6cw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MSM2wh5zUW21k6cw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MSM2wh5zUW21k6cw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MSM2wh5zUW21k6cw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MSM2wh5zUW21k6cw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MSM2wh5zUW21k6cw .cluster text{fill:#333;}#mermaid-svg-MSM2wh5zUW21k6cw .cluster span{color:#333;}#mermaid-svg-MSM2wh5zUW21k6cw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MSM2wh5zUW21k6cw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MSM2wh5zUW21k6cw rect.text{fill:none;stroke-width:0;}#mermaid-svg-MSM2wh5zUW21k6cw .icon-shape,#mermaid-svg-MSM2wh5zUW21k6cw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MSM2wh5zUW21k6cw .icon-shape p,#mermaid-svg-MSM2wh5zUW21k6cw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MSM2wh5zUW21k6cw .icon-shape .label rect,#mermaid-svg-MSM2wh5zUW21k6cw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MSM2wh5zUW21k6cw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MSM2wh5zUW21k6cw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MSM2wh5zUW21k6cw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 低
高
query
Hybrid 召回 top-K
Rerank top-N
分数/规则
分支: 改写/二跳/拒答
去重/合并 chunk
NLI/蕴含自检
生成+强制引用
| 步骤 | 动作 | 阈值经验 |
|---|---|---|
| 召回后 | 看 max score、score gap | gap 小 → 歧义,触发澄清 |
| Rerank 后 | 取 top-3~5 进 context | P99 延迟允许才 rerank |
| 去重 | 同 doc 相邻 chunk 合并 | 减 token、防重复矛盾 |
| 自检 | 「答案是否由 chunk 支持」 | faithfulness < 0.8 → 拒答 |
| 空检索 | 禁止编造 | 模板:未找到 + 建议转人工 |
5.2 何时二次检索
- 子问题分解(多跳):「对比 A 和 B」→ 两次检索。
- Query rewrite:指代消解、HyDE(谨慎,增加幻觉面)。
- 第一次 top-1 分数低于
τ且 gap 小。
5.3 矛盾 chunk
按 生效时间 > 来源权威度 > 版本号 排序;无法裁决 → 拒答 + 人工。
5.4 指标(链 06)
context_precision、context_recall、faithfulness、citation_accuracy ------ 见 06 §18。
6. 域 6:上下文与 Token 经济
6.1 Context Budget 分配(示例 128k 窗口)
| 区块 | 建议占比 | 说明 |
|---|---|---|
| system + 策略 | 5--10% | 稳定,可 prefix cache |
| 工具 schema | 5--15% | 动态选 top-K tools 降占比 |
| RAG chunks | 20--40% | 优先高 rerank 分 |
| 结构化 state | 5--10% | 必留 |
| 近期 history | 15--25% | N 轮滑动 |
| 预留生成 | 15--25% | 含 CoT/reasoning |
6.2 上下文不足时怎么办
| 策略 | 何时用 |
|---|---|
| 截断最老对话 | 一般对话 |
| 滚动摘要 | 长会话;要防摘要丢事实 |
| 语义检索 history | 用户问「上周那封邮件」 |
| 工具结果外置 | 大 JSON 存 artifact,context 只留摘要 |
| LLMLingua 等压缩 | 成本敏感;要测 faithfulness |
| 换长上下文模型 | 质量优先;见 01 §4.5 |
| 分阶段加载 | 先 plan,再按步拉 RAG |
→ Serving 侧:07 prefix cache、chunked prefill
6.3 上下文不足:决策树(与 §3.3 分工)
§3.3 定义 记忆层优先级 ;本节定义 窗口将满/已满时的动作顺序(禁止无脑截断最老 chat)。
#mermaid-svg-ufGsWxD7aURqmqVc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ufGsWxD7aURqmqVc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ufGsWxD7aURqmqVc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ufGsWxD7aURqmqVc .error-icon{fill:#552222;}#mermaid-svg-ufGsWxD7aURqmqVc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ufGsWxD7aURqmqVc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ufGsWxD7aURqmqVc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ufGsWxD7aURqmqVc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ufGsWxD7aURqmqVc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ufGsWxD7aURqmqVc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ufGsWxD7aURqmqVc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ufGsWxD7aURqmqVc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ufGsWxD7aURqmqVc .marker.cross{stroke:#333333;}#mermaid-svg-ufGsWxD7aURqmqVc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ufGsWxD7aURqmqVc p{margin:0;}#mermaid-svg-ufGsWxD7aURqmqVc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ufGsWxD7aURqmqVc .cluster-label text{fill:#333;}#mermaid-svg-ufGsWxD7aURqmqVc .cluster-label span{color:#333;}#mermaid-svg-ufGsWxD7aURqmqVc .cluster-label span p{background-color:transparent;}#mermaid-svg-ufGsWxD7aURqmqVc .label text,#mermaid-svg-ufGsWxD7aURqmqVc span{fill:#333;color:#333;}#mermaid-svg-ufGsWxD7aURqmqVc .node rect,#mermaid-svg-ufGsWxD7aURqmqVc .node circle,#mermaid-svg-ufGsWxD7aURqmqVc .node ellipse,#mermaid-svg-ufGsWxD7aURqmqVc .node polygon,#mermaid-svg-ufGsWxD7aURqmqVc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ufGsWxD7aURqmqVc .rough-node .label text,#mermaid-svg-ufGsWxD7aURqmqVc .node .label text,#mermaid-svg-ufGsWxD7aURqmqVc .image-shape .label,#mermaid-svg-ufGsWxD7aURqmqVc .icon-shape .label{text-anchor:middle;}#mermaid-svg-ufGsWxD7aURqmqVc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ufGsWxD7aURqmqVc .rough-node .label,#mermaid-svg-ufGsWxD7aURqmqVc .node .label,#mermaid-svg-ufGsWxD7aURqmqVc .image-shape .label,#mermaid-svg-ufGsWxD7aURqmqVc .icon-shape .label{text-align:center;}#mermaid-svg-ufGsWxD7aURqmqVc .node.clickable{cursor:pointer;}#mermaid-svg-ufGsWxD7aURqmqVc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ufGsWxD7aURqmqVc .arrowheadPath{fill:#333333;}#mermaid-svg-ufGsWxD7aURqmqVc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ufGsWxD7aURqmqVc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ufGsWxD7aURqmqVc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ufGsWxD7aURqmqVc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ufGsWxD7aURqmqVc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ufGsWxD7aURqmqVc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ufGsWxD7aURqmqVc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ufGsWxD7aURqmqVc .cluster text{fill:#333;}#mermaid-svg-ufGsWxD7aURqmqVc .cluster span{color:#333;}#mermaid-svg-ufGsWxD7aURqmqVc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ufGsWxD7aURqmqVc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ufGsWxD7aURqmqVc rect.text{fill:none;stroke-width:0;}#mermaid-svg-ufGsWxD7aURqmqVc .icon-shape,#mermaid-svg-ufGsWxD7aURqmqVc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ufGsWxD7aURqmqVc .icon-shape p,#mermaid-svg-ufGsWxD7aURqmqVc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ufGsWxD7aURqmqVc .icon-shape .label rect,#mermaid-svg-ufGsWxD7aURqmqVc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ufGsWxD7aURqmqVc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ufGsWxD7aURqmqVc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ufGsWxD7aURqmqVc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
是
否
是
否
是
否
窗口将满或已满
结构化 state 能答当前步?
用 state 生成 / 执行下一步
大 tool 结果可外置?
写 artifact 仅留 digest + uri
可按 goal 语义检索 session?
检索历史片段 top-3
可 §3.4 协议压缩?
双通道摘要 + 校验
可拆子任务?
新 task_id + checkpoint
拒答 / 澄清 / HITL
| 硬规则 | 说明 |
|---|---|
| 锚点不删 | 截断 永不 碰 goal、verify 结论、completed_steps |
| RAG 低分不硬塞 | 域 5 阈值未过 → 不占用 20--40% RAG 预算 |
| 先外置后截断 | tool JSON >2k token 必 artifact |
| 仍不足 | 换长上下文模型 或 拆 task(新 checkpoint),勿单轮硬塞 |
Staff 追问 :「为何不用 LLMLingua 一把梭?」→ 必须 A/B faithfulness ;Agent 场景优先 state + 外置,压缩是最后手段。
7. 域 7:质量与幻觉
7.1 四类幻觉(Agent 全路径)
| 类型 | 例子 | 高发环节 |
|---|---|---|
| 事实 | 错误价格 | 无 RAG / 弱检索 |
| 逻辑 | 推理跳步 | 多步 plan |
| 引用 | 假 doc_id | RAG 生成 |
| 工具 | 调不存在 tool、编造参数 | tool 选择 |
7.2 四层防御
#mermaid-svg-a3lAJHVyCE74up5x{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a3lAJHVyCE74up5x .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a3lAJHVyCE74up5x .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a3lAJHVyCE74up5x .error-icon{fill:#552222;}#mermaid-svg-a3lAJHVyCE74up5x .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a3lAJHVyCE74up5x .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a3lAJHVyCE74up5x .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a3lAJHVyCE74up5x .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a3lAJHVyCE74up5x .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a3lAJHVyCE74up5x .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a3lAJHVyCE74up5x .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a3lAJHVyCE74up5x .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a3lAJHVyCE74up5x .marker.cross{stroke:#333333;}#mermaid-svg-a3lAJHVyCE74up5x svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a3lAJHVyCE74up5x p{margin:0;}#mermaid-svg-a3lAJHVyCE74up5x .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-a3lAJHVyCE74up5x .cluster-label text{fill:#333;}#mermaid-svg-a3lAJHVyCE74up5x .cluster-label span{color:#333;}#mermaid-svg-a3lAJHVyCE74up5x .cluster-label span p{background-color:transparent;}#mermaid-svg-a3lAJHVyCE74up5x .label text,#mermaid-svg-a3lAJHVyCE74up5x span{fill:#333;color:#333;}#mermaid-svg-a3lAJHVyCE74up5x .node rect,#mermaid-svg-a3lAJHVyCE74up5x .node circle,#mermaid-svg-a3lAJHVyCE74up5x .node ellipse,#mermaid-svg-a3lAJHVyCE74up5x .node polygon,#mermaid-svg-a3lAJHVyCE74up5x .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-a3lAJHVyCE74up5x .rough-node .label text,#mermaid-svg-a3lAJHVyCE74up5x .node .label text,#mermaid-svg-a3lAJHVyCE74up5x .image-shape .label,#mermaid-svg-a3lAJHVyCE74up5x .icon-shape .label{text-anchor:middle;}#mermaid-svg-a3lAJHVyCE74up5x .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a3lAJHVyCE74up5x .rough-node .label,#mermaid-svg-a3lAJHVyCE74up5x .node .label,#mermaid-svg-a3lAJHVyCE74up5x .image-shape .label,#mermaid-svg-a3lAJHVyCE74up5x .icon-shape .label{text-align:center;}#mermaid-svg-a3lAJHVyCE74up5x .node.clickable{cursor:pointer;}#mermaid-svg-a3lAJHVyCE74up5x .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-a3lAJHVyCE74up5x .arrowheadPath{fill:#333333;}#mermaid-svg-a3lAJHVyCE74up5x .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-a3lAJHVyCE74up5x .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-a3lAJHVyCE74up5x .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a3lAJHVyCE74up5x .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-a3lAJHVyCE74up5x .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a3lAJHVyCE74up5x .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-a3lAJHVyCE74up5x .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-a3lAJHVyCE74up5x .cluster text{fill:#333;}#mermaid-svg-a3lAJHVyCE74up5x .cluster span{color:#333;}#mermaid-svg-a3lAJHVyCE74up5x div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a3lAJHVyCE74up5x .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-a3lAJHVyCE74up5x rect.text{fill:none;stroke-width:0;}#mermaid-svg-a3lAJHVyCE74up5x .icon-shape,#mermaid-svg-a3lAJHVyCE74up5x .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a3lAJHVyCE74up5x .icon-shape p,#mermaid-svg-a3lAJHVyCE74up5x .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-a3lAJHVyCE74up5x .icon-shape .label rect,#mermaid-svg-a3lAJHVyCE74up5x .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a3lAJHVyCE74up5x .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a3lAJHVyCE74up5x .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a3lAJHVyCE74up5x :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 预防
检测
处置
学习
RAG+强制引用+tool grounding
Verifier/NLI/规则
拒答/HITL/降级模板
badcase 进 eval CI
| 层 | 手段 |
|---|---|
| 预防 | temperature=0;数值 必须 tool 查;「仅据文档」 |
| 检测 | faithfulness judge;关键字段正则;tool schema 校验 |
| 处置 | 低置信拒答;转人工;只读模式 |
| 学习 | 轨迹入库;月度更新 eval |
RAG 实测 (06):有相关上下文 96% 准;无相关 80% 胡编 → 空检索必拒答。
→ 机制 06 §4
8. 域 8:安全与治理
| 威胁 | 注意 | 解法 |
|---|---|---|
| Prompt 注入 | 用户内容、RAG chunk、邮件正文 | 分隔符;内容当 data;输出 filter |
| 间接注入 | 恶意网页进索引 | 索引清洗;检索后规则 |
| 越权 tool | 水平/垂直越权 | RBAC per user;工具级 scope |
| PII 出域 | 日志、第三方 LLM | 脱敏;区域部署;最小字段 |
| 高风险写 | 转账、删库、群发 | HITL;policy-as-code |
8.1 风险分级(默认策略)
| 等级 | 操作 | 默认 |
|---|---|---|
| Low | 读 | 自动 |
| Medium | 小影响写 | 执行 + 审计 |
| High | 资金/不可逆 | HITL |
8.2 Policy-as-code 示例
yaml
rules:
- tool: refund
condition: amount > 1000
action: require_approval
- tool: send_email_external
action: deny_unless_role: admin
9. 域 9:可靠性
9.1 三层熔断
| 层 | 条件 | 动作 |
|---|---|---|
| 迭代 | iter >= max_iter |
停止 + 摘要现状 |
| 循环 | 同 action+args ≥3 | 停止 + 告警 |
| 时间 | wall_time > budget | 取消 pending tools |
9.2 降级矩阵
| 故障 | 降级 |
|---|---|
| LLM 超时 | 小模型 / 模板回复 |
| RAG 超时 | 仅 FAQ 关键词 |
| tool 挂 | 跳过该能力 + 告知用户 |
| 全局不可用 | 转人工队列 |
9.3 重试(三种类型,勿混用)
| 类型 | 触发 | 从哪继续 | 副作用 |
|---|---|---|---|
| 瞬态重试 | 网络/429/5xx | 同一步 重调 tool | 须幂等 |
| 逻辑重试 | verify 失败、参数错 | 同一步 换参/换 tool | 写前先 查状态 |
| Checkpoint 续跑 | 崩溃/超时/预算到点/人为暂停 | 下一 pending 步 | 已完成步禁止重放 |
- 读 tool:瞬态重试 2--3 次,指数退避 + jitter。
- 写 tool :仅幂等时瞬态重试;否则
get_status→ 已成功则 skip,失败才逻辑重试。 - 禁止 用
trace_id作幂等键(04 退款事故:每次 retry 新 trace → 重复退款)。
→ 长跑续跑见 §9.4 ;代码模式 04 §6.1--6.2
9.4 长跑任务:Checkpoint 与 98% 续跑
场景 :任务跑 1h、完成 98%,最后一步 tool 超时或进程 OOM------不能 把 1h 的 messages 重新喂模型「接着聊」。
9.4.1 为什么不能靠 messages 续跑
| 问题 | 后果 |
|---|---|
| 窗口爆 | 截断丢关键 observation |
| 主题漂 | 模型「总结偏了」后越跑越偏 |
| 重复副作用 | 无 completed_steps → 重放写 API |
| 成本翻倍 | 全量 replay token |
9.4.2 Checkpoint 最小字段
python
class TaskCheckpoint(TypedDict):
task_id: str
trace_id: str
goal: str
success_criteria: list[str]
plan: list[PlanStep] # 含 status
completed_steps: list[str]
artifacts: dict[str, str] # step_id -> blob_uri / content_hash
tool_results_digest: dict[str, Any] # 每步摘要,非全量 JSON
version_pin: dict # prompt, model, tool_schema, kb_index
last_error: str | None
wall_time_spent_s: float
progress_pct: float # len(done)/len(plan)
刷盘策略 :至少 每完成一步 写 checkpoint;每个写 tool 成功后 同步刷(崩溃可续)。
9.4.3 续跑流程
#mermaid-svg-t7wa4uHTrmys7SYT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-t7wa4uHTrmys7SYT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-t7wa4uHTrmys7SYT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-t7wa4uHTrmys7SYT .error-icon{fill:#552222;}#mermaid-svg-t7wa4uHTrmys7SYT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-t7wa4uHTrmys7SYT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-t7wa4uHTrmys7SYT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-t7wa4uHTrmys7SYT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-t7wa4uHTrmys7SYT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-t7wa4uHTrmys7SYT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-t7wa4uHTrmys7SYT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-t7wa4uHTrmys7SYT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-t7wa4uHTrmys7SYT .marker.cross{stroke:#333333;}#mermaid-svg-t7wa4uHTrmys7SYT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-t7wa4uHTrmys7SYT p{margin:0;}#mermaid-svg-t7wa4uHTrmys7SYT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-t7wa4uHTrmys7SYT .cluster-label text{fill:#333;}#mermaid-svg-t7wa4uHTrmys7SYT .cluster-label span{color:#333;}#mermaid-svg-t7wa4uHTrmys7SYT .cluster-label span p{background-color:transparent;}#mermaid-svg-t7wa4uHTrmys7SYT .label text,#mermaid-svg-t7wa4uHTrmys7SYT span{fill:#333;color:#333;}#mermaid-svg-t7wa4uHTrmys7SYT .node rect,#mermaid-svg-t7wa4uHTrmys7SYT .node circle,#mermaid-svg-t7wa4uHTrmys7SYT .node ellipse,#mermaid-svg-t7wa4uHTrmys7SYT .node polygon,#mermaid-svg-t7wa4uHTrmys7SYT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-t7wa4uHTrmys7SYT .rough-node .label text,#mermaid-svg-t7wa4uHTrmys7SYT .node .label text,#mermaid-svg-t7wa4uHTrmys7SYT .image-shape .label,#mermaid-svg-t7wa4uHTrmys7SYT .icon-shape .label{text-anchor:middle;}#mermaid-svg-t7wa4uHTrmys7SYT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-t7wa4uHTrmys7SYT .rough-node .label,#mermaid-svg-t7wa4uHTrmys7SYT .node .label,#mermaid-svg-t7wa4uHTrmys7SYT .image-shape .label,#mermaid-svg-t7wa4uHTrmys7SYT .icon-shape .label{text-align:center;}#mermaid-svg-t7wa4uHTrmys7SYT .node.clickable{cursor:pointer;}#mermaid-svg-t7wa4uHTrmys7SYT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-t7wa4uHTrmys7SYT .arrowheadPath{fill:#333333;}#mermaid-svg-t7wa4uHTrmys7SYT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-t7wa4uHTrmys7SYT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-t7wa4uHTrmys7SYT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-t7wa4uHTrmys7SYT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-t7wa4uHTrmys7SYT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-t7wa4uHTrmys7SYT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-t7wa4uHTrmys7SYT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-t7wa4uHTrmys7SYT .cluster text{fill:#333;}#mermaid-svg-t7wa4uHTrmys7SYT .cluster span{color:#333;}#mermaid-svg-t7wa4uHTrmys7SYT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-t7wa4uHTrmys7SYT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-t7wa4uHTrmys7SYT rect.text{fill:none;stroke-width:0;}#mermaid-svg-t7wa4uHTrmys7SYT .icon-shape,#mermaid-svg-t7wa4uHTrmys7SYT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-t7wa4uHTrmys7SYT .icon-shape p,#mermaid-svg-t7wa4uHTrmys7SYT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-t7wa4uHTrmys7SYT .icon-shape .label rect,#mermaid-svg-t7wa4uHTrmys7SYT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-t7wa4uHTrmys7SYT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-t7wa4uHTrmys7SYT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-t7wa4uHTrmys7SYT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
是
是
否
否
加载 checkpoint
version_pin 与线上一致?
显式 migrate 或重跑受影响步
跳过 status=done 的步
存在 failed 步?
查外部世界状态
已成功?
标 skipped 并前进
逻辑/瞬态重试该步
执行下一 pending
写 checkpoint
completed_steps对应 plan → no-op,不重复调 tool。failed步:先get_order/ 查 DB,再决定 retry 或 skip。- 对用户暴露
progress_pct,避免「其实只差一步却显示 0%」。 - LangGraph :
checkpointer=PostgresSaver+thread_id=task_id;节点入口if step.status==done: return state。
存储提醒 :Checkpoint 用 Postgres/Redis(网络) ,不是向量库;向量库仅当需要「按语义找历史 alert」时可选(§3.1.1)。
9.4.4 与 Plan 防跑偏联动
- Resume 时 system 注入:
goal+completed_steps+pending第一步 +last_error。 - 禁止 resume 时全量 replan(除非
plan_drift或version_pin变更)。
9.4.5 SLO 建议(Architect)
| 指标 | 建议 |
|---|---|
checkpoint_lag_s |
P99 < 5s(写步后) |
resume_success_rate |
>95%(同 version_pin) |
duplicate_side_effect_rate |
0(写 API 重复率) |
partial_completion_rate |
可接受 5--15%(预算到点交付部分结果) |
10. 域 10:可观测与调试
电商交易 Agent 落地样例 (Carts/Pricing/Payment trace + FinOps 标签)→ 08 §10.15。
10.1 Trace 最小字段
python
@dataclass
class AgentTrace:
trace_id: str
tenant_id: str
user_id: str
prompt_version: str
model_version: str
steps: list # thought, tool, args_hash, observation, latency, tokens
total_cost_usd: float
status: str # success | error | timeout | loop | hitl_pending
10.2 核心 KPI(大盘)
| 指标 | 健康参考 | 说明 |
|---|---|---|
task_completion_rate |
>85% | 业务定义完成 |
tool_call_success_rate |
>95% | |
loop_detected_rate |
<1% | |
human_intervention_rate |
视业务 | 不是越低越好 |
faithfulness_rate |
>90% | 抽检或 judge |
cost_per_task |
有预算 | $/成功任务 |
p99_latency |
SLO | 含 RAG+tools |
工具:Langfuse、LangSmith、自研 ClickHouse。
11. 域 11:评测与发布
三场景轨迹 Eval(L1--L4 分层 + CI 阻断阈值) → 08 §10.15.3 · 冲刺题 98 C.111--C.117。
11.1 测轨迹,不只测最终答案
| 测什么 | 方法 |
|---|---|
| 选对 tool | 轨迹匹配 / tool accuracy |
| 参数正确 | schema + 金标 args |
| 步数合理 | steps_to_completion 分布 |
| 任务完成 | 环境 sandbox 终态 |
| 安全 | 红队集;拒绝率 |
11.2 CI Gate(上线前)
- 金标集 ≥200 条,覆盖 top 意图 + 边缘 case
- 轨迹通过率 ≥ 阈值(如 90%)
- 无 P0 安全失败(越权、注入成功)
- 成本/延迟 P99 在预算内
- prompt/model/索引 版本 pin
11.3 发布
- Canary:5% 流量,对比完成率、成本、faithfulness。
- 四维版本:prompt、model、tool schema、KB/索引------回滚矩阵预演。
→ Agent eval 指标 06 §19
12. 域 12:成本、SLO 与生命周期
| 手段 | 说明 |
|---|---|
| 模型路由 | 简单意图小模型;难例上大模型 |
| 限制 reasoning tokens | o1 类必设 cap |
| 缓存 | system、RAG 前缀、tool 读结果 |
| 批处理 | 非实时索引、eval |
| $/task 监控 | 告警单任务超 $X |
生命周期:需求 → 工具契约评审 → 离线轨迹 eval → Canary → 全量 → 周 badcase 复盘 → 季度红队。
→ 推理成本 07
13. 失败模式速查(20 条)
| # | 现象 | 根因 | 止血 |
|---|---|---|---|
| 1 | 死循环调同一 tool | 无熔断 | max_same_call + break |
| 2 | 乱选 tool | 候选太多 | 分组/检索 top-5 |
| 3 | 参数 JSON 错 | FC 弱/示例不足 | 校验+反馈重试 |
| 4 | 重复退款 | 无幂等 | idempotency_key |
| 5 | 有 RAG 仍编造 | 空检索未拒答 | 强制引用+阈值 |
| 6 | 引用假 doc | 未校验 citation | 字面匹配 chunk_id |
| 7 | 上下文爆 | tool 结果太大 | 外置+摘要 |
| 8 | 跨用户串话 | tenant 未隔离 | filter 强制 |
| 9 | 注入执行危险操作 | 无 HITL | 风险分级 |
| 10 | 离线好线上差 | eval 分布偏 | 线上轨迹回流 |
| 11 | 成本暴增 | 无步数上限 | budget 硬切断 |
| 12 | plan 跑偏 | 一次 plan | replan 触发 |
| 13 | 多 Agent 打架 | 无 manager | 单一协调者 |
| 14 | 延迟 P99 爆 | rerank+多轮 | 异步/降级 |
| 15 | 工具超时挂死 | 无总 deadline | context cancel |
| 16 | 摘要丢订单号 | 只摘要不 state | 结构化槽位 |
| 17 | 索引旧答案 | 版本未 pin | 双写灰度 |
| 18 | 幻觉金额 | 未 tool 查单 | grounding 强制 |
| 19 | 无法复盘 | 无 trace | AgentTrace |
| 20 | 升级模型全崩 | 无 Canary | 5% + 护栏对比 |
| 21 | 长跑崩溃从头再来 | 无 checkpoint | §9.4 步级刷盘 + resume |
| 22 | 压缩后答非所问 | 摘要覆盖 goal | §3.4 锚点 + bullets 校验 |
| 23 | 98% 重复退款 | resume 重放写步 | completed_steps + 查状态 |
| 24 | 续跑后 plan 全变 | resume 触发全量 replan | 仅 replan 剩余 + 保留 North Star |
14. 大厂面试题 · 满分答(16 道)
14.1 什么时候用 Agent,什么时候用工作流?
答 :步骤固定、可枚举、少分支 → 工作流 DAG (确定性强、便宜)。步骤不确定、需根据 observation 调整 → Agent 有界循环 。单步问答 → RAG/Prompt。支付/资金:工作流 + 关键节点 Agent 建议 + HITL,不要全自动乱试。
14.2 如何拆一个大任务?
答 :画 DAG→原子步(每步可验证)→标依赖→并行独立步→设 budget→定义 replan 条件。Plan-Execute 适合步骤清晰;ReAct 适合探索。生产常用 DAG 骨架 + 局部 ReAct。
14.3 30 个 tool 模型选错怎么办?
答 :分组→embedding 召回 top-5→few-shot。监控 tool_selection_accuracy;错例进 prompt 示例库。schema 相近的 tool 要改 description 区分。
14.4 Agent 怎么用 RAG 检索结果?
答:召回→rerank→阈值分支(低分改写/二跳/拒答)→去重合并→NLI 自检→生成带引用。空检索禁止生成事实。指标看 faithfulness 和 citation accuracy。
14.5 上下文不够怎么办?
答:结构化 state 优先;最近 N 轮;老对话摘要;大 tool 结果外置;语义捞 history;最后截断。分配 token budget;system/RAG 用 prefix cache。超长换长上下文模型或分阶段 plan。
14.6 Agent 幻觉怎么治?
答 :预防(RAG+tool grounding+低温)→检测(Verifier/NLI/规则)→处置(拒答/HITL)→badcase 进 CI。区分事实/引用/工具幻觉。数值类 禁止模型口算。
14.7 副作用操作怎么保证安全?
答:只读默认;tool RBAC;风险分级;高额 HITL;幂等;审计 trace;policy-as-code。邮件/网页内容当不可信 data。
14.8 怎么评估 Agent?
答:轨迹级------tool 对不对、参数对不对、步数、终态是否完成、成本。不只最终字符串匹配。CI 金标 + 线上 completion rate + 抽检 faithfulness。
14.9 线上 Agent 突然变差怎么排查?
答:按 trace 切片:prompt/model/索引版本变了吗?tool 成功率?RAG 召回?loop 率?成本?对比 Canary 前后。先回滚四维版本之一,再根因。
14.10 Architect:设计企业级 Agent 平台还要什么?
答 :控制面/数据面分离;统一 tool 注册与契约;租户隔离;统一 trace 与 eval 平台;预算与熔断;HITL 工单接入;与 Feature Store/审批流集成。用 $/成功任务 和 完成率 对业务负责,不只追求「能跑」。
14.11 Plan 跑偏怎么防?
答 :三道闸------North Star (goal/success_criteria 每次 replan 必带回)、步级 verify (机器可判定 observation)、plan_drift 检测 (连续 2 步 verify 失败则只 replan 剩余步)。生产用 滚动 plan (每次 3--7 步)优于一次 50 步大 plan。已完成步进 completed_steps,replan 禁止清空。
14.12 Agent 跑一小时、98% 失败怎么续?
答 :不能 重放全量 messages。要 持久化 checkpoint (Postgres/Redis 行存,网络连库;不是向量库 ):goal、plan(含 status)、completed_steps、artifacts 指针、version_pin。Resume:跳过 done 步;failed 步先 查外部状态 再决定 retry/skip;写步幂等键用 业务键 非 trace_id。LangGraph 用 PostgresSaver + thread_id=task_id。向量库只用于可选「语义找历史」,不负责续跑。
14.13 失败重试有哪几种?别混了。
答 :① 瞬态 (5xx/超时)同一步退避重试,须幂等;② 逻辑 (verify 失败)同一步换参/换 tool,写前先查状态;③ Checkpoint 续跑 (进程挂)从下一 pending 步继续,已完成禁止重放 。写 API 超时 ≠ 失败,要先 get_status。
14.14 上下文压缩后主题漂移怎么办?
答 :state 是真相源 ,摘要是索引。锚点(goal、槽位、completed_steps、verify 结论)永不压缩 ;双通道 factual_bullets + narrative,replan 只读 bullets;压缩后规则/Judge 校验是否改写 goal;每 N 步 重锚 注入。先外置大 tool 结果,再摘要,最后才截断 chat。
14.15 Staff:Agent 与 Cursor SDK / 自建框架怎么选型?
答 :要 可迁移、自备 LLM Key、脱离供应商 → LangGraph/自建 + 自有 checkpoint。要 IDE 同级工具链、快速接 MCP/规则 → Cursor SDK/Cloud Agent,但 运行时绑定 Cursor API 。企业平台:控制面自建 + 数据面可插拔 runtime ;核心资产是 tool 契约、checkpoint schema、eval 轨迹,不是某一家 SDK。
14.16 如何用 Cursor SDK 做 Grafana 告警 Triage Agent?(→ §20)
答 :控制面 Webhook + policy-as-code;数据面 Agent.create + settingSources: project 加载 payment-observability skill + Grafana MCP (get_alert_group、query_prometheus、query_loki_logs)。固定 plan + 步级 verify;按 skill 分 runtime / 业务指标 判 false_positive | true_incident | inconclusive。误报且 confidence≥0.85 才 resolve (幂等 alert_group_id + generation;critical 走 HITL);真事故写 artifact 报告;不确定 只 ack 。checkpoint 按 alert_group_id 续跑,不 replay messages。答辩必须交代:仍依赖 CURSOR_API_KEY;脱钩用 LangGraph + 自有 LLM。
15. STAR-M-P 事故(2 则)
15.1 Agent 误调退款 API
S :客服 Agent 上线后 2 小时,自动退款 23 笔共 ¥4.2 万。T :止血 + 根因。A :立即 kill Agent 写权限;回滚 prompt 版本;核对 trace 发现模型将「查询退款进度」理解为「执行退款」,且 refund tool 未强制 HITL。R :48h 内人工复核完毕,赔付 3 笔误退。P :写操作默认 HITL;tool description 区分 read/write;轨迹审计每日抽检。M :refund 仅 suggest_refund 自动,execute_refund 必审批。
15.2 RAG 检索对但答错政策
S :商家咨询「7 天无理由」,Agent 回答「支持」导致纠纷。T :修复知识链路。A :trace 显示召回了 2023 旧政策 chunk(索引未切版本);模型未带引用,Verifier 未开。R :上线 KB 版本号 + 回答必须带 doc_version;低 faithfulness 拒答。P :索引灰度双读;月度 RAG eval 含「政策有效期」用例。M :citation_rate <80% 告警。
15.3 数据迁移 Agent 跑 47 分钟崩溃
S :离线批处理 Agent 需改 12 万张表字段,跑 47 min 进度 97% 时 Pod OOM 重启。T :续跑且不重复写。A :trace 显示无 checkpoint,重启后从 step1 重放 update_row,3 分钟触发 DB 唯一键冲突;改为 TaskCheckpoint + 每 100 行刷盘,completed_steps 跳过已迁移分区。R :续跑 18 min 完成,零重复写。P :长跑任务准入:必过 checkpoint 评审;eval 集含「中断后续跑」用例。M :duplicate_write_rate=0;resume_success_rate 入 CI gate。
16. 全量 Checklist(12 域 · 考前勾选)
16.0 面试前 30 分钟(Staff / Architect)
- 能白板画 §0 控制面/数据面/护栏/观测四块
- 口述 §17 90 秒脚本(含 checkpoint、防 plan 跑偏)
- 准备 1 个 Agent 事故 STAR(§15 或 04 退款案)
- 过一遍 §14 十六道 中薄弱题(尤其 14.11--14.16、§20 案例)
- Architect:§19 答辩 10 项 + 能白板讲 §20 架构图
- §13 失败速查 24 条 扫现象列
- 域 2/3/6/9 各勾「薄弱项」(见下表合计 120+ 项)
- 准备 $/成功任务 、completion_rate 各一个真实数字
域 1 界定(6)
- 能说明 Agent vs RAG vs 工作流
- 有明确任务完成定义
- 确认需要多步+工具
- 失败可降级/人工
- 不做「万物 Agent」
- 验收指标与业务对齐
域 2 编排(14)
- 选型 ReAct / Plan-Execute / DAG
- 任务拆成可验证原子步
- 依赖 DAG 已画
- replan 条件已编码(含 plan_drift)
- max_iter / 同调用熔断
- 并行仅独立步
- Multi-Agent 有单一协调者
- 不用 ToT 做在线默认
-
goal/success_criteria/non_goals入 state(§2.5) - 每 plan 步有
verify(机器可判定) - 滚动 plan(3--7 步)优于一次大 plan
- replan 不清空
completed_steps - 步级闸门:verify 失败有 streak 阈值
- 高风险 plan 步走 HITL 批准
域 3 记忆 + Context Engineering(18)
- 结构化 state 字段定义
- tenant 隔离
- session TTL
- 大 tool 结果外置
- 摘要不替代关键槽位
- 跨 session 长期记忆策略
- 分清 checkpoint(行存/Postgres)vs 向量库(语义检索)
- 生产 checkpoint 走网络 DB,不单靠 Pod 内存
- 压缩双通道:bullets + narrative(§3.4)
- 压缩后校验 goal 未被改写
- replan 只读 factual_bullets 非 narrative
- 周期性重锚(goal + 已完成 + 下一步)
- 情节 / 语义 / 程序性三分,禁止混成一段 summary(§3.5)
- episodic → Redis + PG Checkpoint;semantic → pgvector;procedural → 图/SOP
- Redis + pgvector 两层:读路径 ①②③、写路径 checkpoint 每步 + session 结束抽 fact(§3.7)
- pgvector 检索超时降级(跳过长期回忆,不拖垮主路径)
- Context 装配顺序:锚点 → state → RAG → 语义记忆 → 最近轮 → 摘要(§3.8)
- Mem0/Letta/Zep POC 前有写入审计、租户隔离、P99 与降级开关(§3.6)
- Spring AI:
MessageChatMemoryAdvisor+VectorStoreChatMemoryAdvisor分工(14 §7.1) - 深链 04 §13 机制能口述
域 4 工具(10)
- 每 tool 有 schema+描述
- 返回
{ok,data,error,meta} - 写操作幂等
- 超时与重试策略
- RBAC
- 五层沙箱
- 30+ tool 有分组/检索
- FC 生产默认
- 高风险 HITL
- tool 成功率监控
域 5 RAG(8)
- hybrid+rerank 流程
- 低分/空检索分支
- chunk 去重合并
- 强制引用格式
- NLI/Verifier
- 矛盾 KB 策略
- 索引版本与模型一致
- faithfulness 指标
域 6 Context(10)
- token budget 表
- 预留生成 token
- 截断优先级明确(§6.3 决策树)
- tool 结果截断/摘要
- prefix cache 意识
- 分阶段加载 plan
- 锚点字段永不截断
- 先外置后摘要后截断 chat
- RAG 低分不硬塞满窗口
- 仍不足时拆 task 或换长上下文模型
域 7 质量(6)
- 四层防御齐全
- 数值 tool grounding
- 空检索拒答
- temperature 策略
- badcase 进 eval
- 区分工具幻觉
域 8 安全(7)
- 注入分隔与 filter
- PII 脱敏
- 风险分级表
- policy-as-code 关键规则
- 外部内容不可信
- 审计留存周期
- 红队季度节奏
域 9 可靠性(12)
- 三层熔断
- 降级矩阵文档化
- 写重试仅幂等
- 取消/超时传播
- 只读默认
- 区分瞬态 / 逻辑 / checkpoint 三种重试
- 写 API 超时先查状态再 retry
- 幂等键用业务键非 trace_id
- checkpoint 每步/每写步刷盘
- resume 跳过 completed_steps
- version_pin 变更有 migrate 策略
- 对用户暴露 progress_pct
域 10 观测(5)
- trace_id 全链路
- prompt/model 版本记录
- 逐步 replay 能力
- 7+ KPI 上盘
- 告警阈值
域 11 评测(6)
- 轨迹金标集
- tool accuracy 测
- CI gate 阈值
- Canary 指标
- 四维版本回滚演练
- 线上轨迹采样回流
- eval 含「中断后续跑」轨迹用例
域 12 成本(5)
- $/task 预算
- 模型路由
- thinking token cap
- 缓存策略
- 步数/费用硬上限
合计 123+ 项(含 §16.0 七项 + §19.5 十项 + §20.11 十二项 + 域 3 Context Engineering 六项;Architect 建议 §19--§20 全勾)
16.1 知识点 ↔ 章节速查(全 12 域)
| 域 | 核心知识点 | 正文 |
|---|---|---|
| 1 | Agent vs 工作流 vs RAG;验收标准 | §1 |
| 2 | 编排模式;拆分;replan;防 plan 跑偏 | §2、§2.5 |
| 3 | 四层记忆;情节/语义/程序性;Redis+pgvector;Context Engineering | §3、§3.4--§3.8、04 §13 |
| 4 | tool 契约;选 tool;沙箱;FC | §4 |
| 5 | RAG 研判;二跳;引用 | §5 |
| 6 | token budget;上下文不足决策树 | §6、§6.3 |
| 7 | 四类幻觉;四层防御 | §7 |
| 8 | 注入;HITL;policy-as-code | §8 |
| 9 | 熔断;降级;三种重试;checkpoint 续跑 | §9、§9.4 |
| 10 | Trace 字段;KPI | §10 |
| 11 | 轨迹 eval;CI gate;Canary | §11 |
| 12 | 成本;生命周期 | §12 |
| 横切 | 失败速查 24 条 | §13 |
| 面试 | 满分答 16 道 | §14 |
| Architect | Saga / Multi-Agent / HITL / Eval | §19 |
| 案例 | Cursor SDK + Grafana 告警 Agent | §20 |
| 交付 | 设计 + 伪代码 + 部署使用 | 21 |
17. 90 秒口述脚本
生产 Agent = 控制面 (权限、预算、HITL)+ 数据面 (滚动 Plan-Execute 或 DAG+有界 ReAct,North Star + 步级 verify 防跑偏 )+ Memory (结构化 state 为主;压缩保锚点)+ Tools (契约、幂等、沙箱)+ RAG tool (研判后再生成)+ Context budget (先外置再摘要)+ 四层防幻觉 + 轨迹级 eval + Trace 复盘 + checkpoint 续跑 (98% 失败不重放 messages)。不上 Agent:单步 FAQ、固定流程、不可审计写操作。最大坑:无界循环、无幂等、空检索编造、无 trace、无 checkpoint 重复写 。Architect 答辩补 §19 Saga/HITL/Eval ;落地案例 §20 Grafana 告警 + Cursor SDK。
19. Architect 答辩专题(横切能力)
答辩时要能讲清:多步写操作如何补偿、多 Agent 谁握真相源、人暂停后如何续跑、eval 如何覆盖中断与分类。与 §2.5 / §9.4 配套。
19.1 Saga / 补偿事务(跨 tool 写操作)
| 概念 | Agent 场景 | 做法 |
|---|---|---|
| TCC / Saga | 连续调 create_ticket → notify_slack → resolve_alert 任一步失败 |
每步 可补偿;失败不重复已成功步 |
| Forward recovery | 已知幂等 | 查状态已成功则 skip |
| Backward recovery | 需回滚 | 执行 compensate_* tool |
| 编排归属 | 谁发 compensate | 工作流或 Saga 协调器;不让 LLM 即兴决定回滚顺序 |
NotifySvc OrderSvc Agent NotifySvc OrderSvc Agent #mermaid-svg-tvqzwRyWZzDXvg25{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tvqzwRyWZzDXvg25 .error-icon{fill:#552222;}#mermaid-svg-tvqzwRyWZzDXvg25 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tvqzwRyWZzDXvg25 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tvqzwRyWZzDXvg25 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tvqzwRyWZzDXvg25 .marker.cross{stroke:#333333;}#mermaid-svg-tvqzwRyWZzDXvg25 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tvqzwRyWZzDXvg25 p{margin:0;}#mermaid-svg-tvqzwRyWZzDXvg25 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tvqzwRyWZzDXvg25 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-tvqzwRyWZzDXvg25 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tvqzwRyWZzDXvg25 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-tvqzwRyWZzDXvg25 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-tvqzwRyWZzDXvg25 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-tvqzwRyWZzDXvg25 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-tvqzwRyWZzDXvg25 .sequenceNumber{fill:white;}#mermaid-svg-tvqzwRyWZzDXvg25 #sequencenumber{fill:#333;}#mermaid-svg-tvqzwRyWZzDXvg25 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-tvqzwRyWZzDXvg25 .messageText{fill:#333;stroke:none;}#mermaid-svg-tvqzwRyWZzDXvg25 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tvqzwRyWZzDXvg25 .labelText,#mermaid-svg-tvqzwRyWZzDXvg25 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-tvqzwRyWZzDXvg25 .loopText,#mermaid-svg-tvqzwRyWZzDXvg25 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-tvqzwRyWZzDXvg25 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tvqzwRyWZzDXvg25 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-tvqzwRyWZzDXvg25 .noteText,#mermaid-svg-tvqzwRyWZzDXvg25 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-tvqzwRyWZzDXvg25 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tvqzwRyWZzDXvg25 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tvqzwRyWZzDXvg25 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tvqzwRyWZzDXvg25 .actorPopupMenu{position:absolute;}#mermaid-svg-tvqzwRyWZzDXvg25 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-tvqzwRyWZzDXvg25 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tvqzwRyWZzDXvg25 .actor-man circle,#mermaid-svg-tvqzwRyWZzDXvg25 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-tvqzwRyWZzDXvg25 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 已成功则只重试 Notify create_incident draft incident_id post_summary error timeout get_status incident_id post_summary retry
答辩金句 :Agent 的「智能」在决策;补偿顺序在代码里写死或 DAG。
19.2 Multi-Agent 长跑一致性
| 问题 | 解法 |
|---|---|
| Worker 各改 plan | 单 Coordinator 持 goal / plan / completed_steps |
| 并行子任务冲突 | Worker 只返回结构化 observation,Coordinator merge |
| 共享 checkpoint | task_id 锁;artifacts[branch_id] 分支写入 |
| 重复写 | 写 tool 经 Action Gateway(幂等 + RBAC) |
19.3 HITL 暂停与续跑
| 状态 | 行为 |
|---|---|
hitl_pending |
持久化 checkpoint;停止 tool;通知值班 |
| 人批准 | resume 带 approval_id;只执行批准步 |
| 人拒绝 | 标 skipped;replan 或模板回复 |
| resolve 类 | 默认 Medium+;critical 必 HITL |
TaskCheckpoint 增加:hitl_ticket_id、approval_status。
19.4 Eval:非 Happy Path 金标
| 用例 | 通过标准 |
|---|---|
| 中断续跑 | 不重复 completed_steps;duplicate_side_effect=0 |
| plan_drift | replan 且 goal 不变 |
| 压缩不变性 | goal / 关键实体未变 |
| fp vs 真事故分类 | 金标 F1 ≥ 阈值 |
| 越权 resolve 红队 | 拒绝或 HITL |
CI 建议 ≥30 条 专测上表,与业务金标 分桶 汇报。
19.5 Architect 答辩 Checklist(10)
- 能画 Saga 成功/失败/补偿路径
- Coordinator vs Worker state 边界
- HITL 暂停 checkpoint 字段
- 三种重试与 checkpoint 不混
- eval 含中断续跑
- 幂等键用业务键
- $/成功任务对齐业务
- 控制面/数据面分离
- 四维版本回滚演练
- 能讲 §20 端到端案例
20. 案例:Cursor SDK · Grafana 图告警 Triage Agent
业务 :监控 Grafana 面板/OnCall 告警;拉指标与日志;按 Skills(payment-observability) 判误报 vs 真事故;误报 resolve ;真事故 生成分析报告 。
技术栈 :
@cursor/sdk+ Grafana MCP +.cursor/skills。
20.1 为什么用 Agent
| 脚本 | Agent |
|---|---|
| 阈值固定 | 多信号:指标 + 日志 + 变更事件 |
| 规则爆炸 | Skills 沉淀 runtime vs 业务指标分支 |
| 报告不一 | 结构化报告 + panel query 引用 |
用 DAG 骨架 + 局部 LLM 研判,非无界 ReAct。
20.2 参考架构
#mermaid-svg-9VZEQ2sLk1ASZbwW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9VZEQ2sLk1ASZbwW .error-icon{fill:#552222;}#mermaid-svg-9VZEQ2sLk1ASZbwW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9VZEQ2sLk1ASZbwW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .marker.cross{stroke:#333333;}#mermaid-svg-9VZEQ2sLk1ASZbwW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9VZEQ2sLk1ASZbwW p{margin:0;}#mermaid-svg-9VZEQ2sLk1ASZbwW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .cluster-label text{fill:#333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .cluster-label span{color:#333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .cluster-label span p{background-color:transparent;}#mermaid-svg-9VZEQ2sLk1ASZbwW .label text,#mermaid-svg-9VZEQ2sLk1ASZbwW span{fill:#333;color:#333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .node rect,#mermaid-svg-9VZEQ2sLk1ASZbwW .node circle,#mermaid-svg-9VZEQ2sLk1ASZbwW .node ellipse,#mermaid-svg-9VZEQ2sLk1ASZbwW .node polygon,#mermaid-svg-9VZEQ2sLk1ASZbwW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9VZEQ2sLk1ASZbwW .rough-node .label text,#mermaid-svg-9VZEQ2sLk1ASZbwW .node .label text,#mermaid-svg-9VZEQ2sLk1ASZbwW .image-shape .label,#mermaid-svg-9VZEQ2sLk1ASZbwW .icon-shape .label{text-anchor:middle;}#mermaid-svg-9VZEQ2sLk1ASZbwW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9VZEQ2sLk1ASZbwW .rough-node .label,#mermaid-svg-9VZEQ2sLk1ASZbwW .node .label,#mermaid-svg-9VZEQ2sLk1ASZbwW .image-shape .label,#mermaid-svg-9VZEQ2sLk1ASZbwW .icon-shape .label{text-align:center;}#mermaid-svg-9VZEQ2sLk1ASZbwW .node.clickable{cursor:pointer;}#mermaid-svg-9VZEQ2sLk1ASZbwW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .arrowheadPath{fill:#333333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9VZEQ2sLk1ASZbwW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9VZEQ2sLk1ASZbwW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9VZEQ2sLk1ASZbwW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9VZEQ2sLk1ASZbwW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9VZEQ2sLk1ASZbwW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9VZEQ2sLk1ASZbwW .cluster text{fill:#333;}#mermaid-svg-9VZEQ2sLk1ASZbwW .cluster span{color:#333;}#mermaid-svg-9VZEQ2sLk1ASZbwW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9VZEQ2sLk1ASZbwW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9VZEQ2sLk1ASZbwW rect.text{fill:none;stroke-width:0;}#mermaid-svg-9VZEQ2sLk1ASZbwW .icon-shape,#mermaid-svg-9VZEQ2sLk1ASZbwW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9VZEQ2sLk1ASZbwW .icon-shape p,#mermaid-svg-9VZEQ2sLk1ASZbwW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9VZEQ2sLk1ASZbwW .icon-shape .label rect,#mermaid-svg-9VZEQ2sLk1ASZbwW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9VZEQ2sLk1ASZbwW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9VZEQ2sLk1ASZbwW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9VZEQ2sLk1ASZbwW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 状态
Cursor SDK
控制面
触发
OnCall Webhook
state=new 扫描
Triage API
policy-as-code
Agent.create
Skills observability
Grafana MCP
checkpoint per alert_group_id
报告 artifact
依赖 :CURSOR_API_KEY + Cursor API(网络 );Grafana 经 MCP / grafana.env(网络)。
状态持久化(非向量库) :见 §3.1.1 。本案例 续跑与幂等 依赖 PostgreSQL checkpoint(网络) + S3 报告(网络) ;向量库 不用于 保存 completed_steps
20.3 North Star 与 Plan
yaml
goal: "单 alert_group triage:误报 resolve;真事故出报告"
success_criteria:
- classification in [false_positive, true_incident, inconclusive]
- false_positive => resolved + reason_code
- true_incident => report.md 含 panel_link, evidence, action
- inconclusive => acknowledged only
non_goals:
- 不改告警规则;不批量 resolve 其他 alert
| step | action | verify | risk |
|---|---|---|---|
| s1 | get_alert_group | id + labels | low |
| s2 | panel_queries + query_prometheus | 序列可拉 | low |
| s3 | query_loki / find_error_pattern | 窗口内 ERROR 对齐 | low |
| s4 | apply_triage_rubric 读 Skill | classification + confidence | low |
| s5a | resolve_alert_group | fp 且 confidence≥0.85 | medium |
| s5b | write_incident_report | true_incident | low |
| s5c | acknowledge | inconclusive | low |
20.4 误报 vs 真事故(Skills 分支)
#mermaid-svg-2V3V54wmMhp9Mgzm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2V3V54wmMhp9Mgzm .error-icon{fill:#552222;}#mermaid-svg-2V3V54wmMhp9Mgzm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2V3V54wmMhp9Mgzm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2V3V54wmMhp9Mgzm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2V3V54wmMhp9Mgzm .marker.cross{stroke:#333333;}#mermaid-svg-2V3V54wmMhp9Mgzm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2V3V54wmMhp9Mgzm p{margin:0;}#mermaid-svg-2V3V54wmMhp9Mgzm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2V3V54wmMhp9Mgzm .cluster-label text{fill:#333;}#mermaid-svg-2V3V54wmMhp9Mgzm .cluster-label span{color:#333;}#mermaid-svg-2V3V54wmMhp9Mgzm .cluster-label span p{background-color:transparent;}#mermaid-svg-2V3V54wmMhp9Mgzm .label text,#mermaid-svg-2V3V54wmMhp9Mgzm span{fill:#333;color:#333;}#mermaid-svg-2V3V54wmMhp9Mgzm .node rect,#mermaid-svg-2V3V54wmMhp9Mgzm .node circle,#mermaid-svg-2V3V54wmMhp9Mgzm .node ellipse,#mermaid-svg-2V3V54wmMhp9Mgzm .node polygon,#mermaid-svg-2V3V54wmMhp9Mgzm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2V3V54wmMhp9Mgzm .rough-node .label text,#mermaid-svg-2V3V54wmMhp9Mgzm .node .label text,#mermaid-svg-2V3V54wmMhp9Mgzm .image-shape .label,#mermaid-svg-2V3V54wmMhp9Mgzm .icon-shape .label{text-anchor:middle;}#mermaid-svg-2V3V54wmMhp9Mgzm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2V3V54wmMhp9Mgzm .rough-node .label,#mermaid-svg-2V3V54wmMhp9Mgzm .node .label,#mermaid-svg-2V3V54wmMhp9Mgzm .image-shape .label,#mermaid-svg-2V3V54wmMhp9Mgzm .icon-shape .label{text-align:center;}#mermaid-svg-2V3V54wmMhp9Mgzm .node.clickable{cursor:pointer;}#mermaid-svg-2V3V54wmMhp9Mgzm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2V3V54wmMhp9Mgzm .arrowheadPath{fill:#333333;}#mermaid-svg-2V3V54wmMhp9Mgzm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2V3V54wmMhp9Mgzm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2V3V54wmMhp9Mgzm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2V3V54wmMhp9Mgzm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2V3V54wmMhp9Mgzm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2V3V54wmMhp9Mgzm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2V3V54wmMhp9Mgzm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2V3V54wmMhp9Mgzm .cluster text{fill:#333;}#mermaid-svg-2V3V54wmMhp9Mgzm .cluster span{color:#333;}#mermaid-svg-2V3V54wmMhp9Mgzm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2V3V54wmMhp9Mgzm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2V3V54wmMhp9Mgzm rect.text{fill:none;stroke-width:0;}#mermaid-svg-2V3V54wmMhp9Mgzm .icon-shape,#mermaid-svg-2V3V54wmMhp9Mgzm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2V3V54wmMhp9Mgzm .icon-shape p,#mermaid-svg-2V3V54wmMhp9Mgzm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2V3V54wmMhp9Mgzm .icon-shape .label rect,#mermaid-svg-2V3V54wmMhp9Mgzm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2V3V54wmMhp9Mgzm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2V3V54wmMhp9Mgzm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2V3V54wmMhp9Mgzm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} runtime
business
尖刺短
是
脏数据
服务挂
无
有
alert + 面板
runtime or business?
错误率/延迟 vs 基线
响应体/调用方集中度
持续超阈?
false_positive
true_incident
脏数据 vs 服务挂
日志有 ERROR?
高置信误报
inconclusive或降级真
resolve
报告
| 信号 | 偏误报 | 偏真事故 |
|---|---|---|
| 指标 | 尖刺<5min 即回落 | 持续超阈、依赖链路透传 |
| 日志 | 无对齐 ERROR | trace 聚集、同 release |
| 变更 | 仅阈值调整 | 部署窗口重叠 |
inconclusive :confidence < 0.7 或证据矛盾 → 只 ack,不 resolve。
20.5 Cursor SDK 参考代码
typescript
import { Agent } from "@cursor/sdk";
const GOAL = `Triage Grafana alert_group {{id}} per payment-observability incident-triage.
JSON: { classification, confidence, reason_code, evidence[] }.
false_positive且confidence>=0.85: resolve. true_incident: write artifacts/triage-{{id}}.md.
Never resolve inconclusive.`;
export async function triageAlert(alertGroupId: string) {
await using agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2" },
local: {
cwd: process.cwd(),
settingSources: ["project"],
},
mcpServers: {
grafana: {
type: "http",
url: process.env.GRAFANA_MCP_URL!,
headers: { Authorization: `Bearer ${process.env.GRAFANA_MCP_TOKEN}` },
},
},
});
const ck = await loadCheckpoint(alertGroupId);
const run = await agent.send(
ck ? resumePrompt(ck) : GOAL.replace("{{id}}", alertGroupId)
);
for await (const ev of run.stream()) {
if (ev.type === "assistant") log(ev);
}
const result = await run.wait();
await saveCheckpoint(alertGroupId, { agentId: agent.agentId, result });
if (result.status === "error") await escalateHuman(alertGroupId);
return result;
}
// 幂等: alert_group_id + firing_generation
export async function onWebhook(body: { alertGroupId: string; gen: string }) {
if (await alreadyProcessed(body.alertGroupId, body.gen)) return { skipped: true };
return triageAlert(body.alertGroupId);
}
Cloud :cloud.repos + envVars 注入 Grafana SA;MCP 须 HTTP 可达(cloud VM 无本地 stdio)。
20.6 MCP Tools
| 阶段 | Tool |
|---|---|
| s1 | get_alert_group, list_alert_groups |
| s2 | get_dashboard_panel_queries, query_prometheus |
| s3 | query_loki_logs, find_error_pattern_logs, get_sift_analysis |
| 写 | OnCall resolve/ack(policy + HITL) |
20.7 Policy 与可靠性
yaml
rules:
- tool: resolve_alert_group
condition: classification != false_positive OR confidence < 0.85
action: deny
- tool: resolve_alert_group
condition: labels.severity == critical
action: require_approval
- 幂等:
alert_group_id + firing_generation - checkpoint:每 step 刷盘;resolve 前再读状态
- 单 alert 预算 ≤ $0.50
20.8 报告模板(true_incident)
markdown
# Triage · {alert_group_id}
- Panel: {url} · Window: {start}--{end}
- Classification: true_incident ({confidence})
## Evidence
1. PromQL: {query} → {summary}
2. Loki: {pattern} n={count}
3. Skill branch: {runtime|business} --- {reason}
## Root cause & action
{one_line} · {team} · {runbook}
20.9 KPI 与 Eval
| KPI | 目标 |
|---|---|
false_resolve_rate |
0 |
auto_resolve_rate |
团队自定,常 20--40% |
mean_triage_time P99 |
< 5 min |
金标 200+ 历史 alert(fp/tp/inconclusive),CI 轨迹 + 分类 F1。
20.10 答辩 2 分钟稿
OnCall Webhook 触发 Cursor SDK Agent:DAG 拉 Grafana 指标日志,payment-observability skill 分 runtime/业务支路。高置信误报 resolve (policy + 幂等);真事故写 artifact 报告;不确定 只 ack 。checkpoint 按
alert_group_id续跑。控制面 Policy 自建,推理仍绑 Cursor API------要完全脱钩需 LangGraph + 自有 LLM。
20.11 案例 Checklist(12)
- Webhook 幂等(group_id + generation)
- Skill 版本 pin
- Grafana 凭证不进 prompt
- resolve:policy + critical HITL
- inconclusive 禁止 auto-resolve
- checkpoint 每步刷盘
- 报告含可复现 query
- trace 可回放
- 金标 fp/tp eval
-
false_resolve_rate告警 - 单 alert 成本 cap
- Cursor 不可用 → 人工队列
21. 关联导航
| # | 文件 | 职责 |
|---|---|---|
| 02 | 02-Prompt-工程 | Tool / ReAct / 注入 |
| 03 | 03-RAG | 检索管线 |
| 04 | 04-Agent框架 | 模式与框架 |
| 05 | 05-AI-辅助开发 | Cursor / MCP |
| 06 | 06-Eval | 幻觉与评测 |
| 07 | 07-Serving | 成本与缓存 |
| 98 | 98-冲刺 | 考前速查 |
| 21 | 21-设计部署与使用 | 设计+伪代码+部署 |
| tools | grafana-alert-triage-sdk | §20 可运行脚手架 |
| skills | payment-observability | §20 研判规则 |
| 13 | 本篇 · Agent 生产 Playbook | 落地 |
官方文档与源码(一级依据)
AI Engineering · 正文机制应来自下方 官方文档(L1) 与 官方源码仓库(L2) ;
禁止用教程站/博客充当机制依据。本章 QPS/延迟/STAR 为面试示意。
L1 · 官方文档
L2 · 官方源码
L3 · 论文 / 开放规范