W8 · 可观测性与安全加固 · 打卡清单

把 Agent 从「能跑、扛得住故障」做到「看得见、拦得住攻击」。两层主线:可观测性(Trace/Span/Observation + 回归评测)与安全加固(注入防护 / 高危防呆 / MCP 边界 / OWASP)。全部纯本地可跑,无需任何 API Key。

代码练习 · 第 8 周预估 5–6 小时复用 W7 的三层防御
完成进度
0%

本周里程碑(结束时你要能说)

Day 1可观测性 · Trace/Span/Observation 埋点 + token·成本看板文件:obs/tracing.py

任务

  • 读 obs/tracing.py,能口述 Trace / Span / Observation 三级关系
  • 运行自测并记下 dashboard 里的 tokens/cost/errors
  • 把 demo_trace 改成一版「你的 Agent」:至少 3 个 span,各带失败 obs
  • 回答问题:某次回答慢,你会先看哪一层的哪个字段?
✔ 自查:dashboard["errors"]==1 且 cost_yuan 稳定;你能指出「frag_retry 那次错误烧了多少 token/耗时」。

运行

cd agent-learning-w8
python obs/tracing.py
重难点:三级埋点为什么是可靠性的前提?W7 的三层防御负责「扛住」,W8 的 trace 负责「看得见」。没有 trace,你回答不了「哪步慢了·烧了多少·败在哪」。Langfuse/LangSmith 就是这套语义的 SaaS,本文件是最小本地实现。
Day 2评测回归 · 数据集版本化 + A/B 对比 + 回归闸门文件:day2_regression.py

任务

  • 读代码:每个样本为何带 dataset_id + version?
  • 跑通后,解释 compare() 的三个输出是什么含义
  • 改 candidate 打分器为「平均更好但单项崩坏」,观察 verdict 变化
  • 回答:均值变好但最差单项 -0.3,能不能上线?为什么?
✔ 自查:图纸给出「avg>0 且 worst>-0.05 → 上线」;你理解闸门防的是「顺手改坏」。

运行

python day2_regression.py
重难点:回归闸门。A/B 不仅要看平均 Δ,还要看最差单项 Δ——均值会被好样本掩盖局部退化。版本化是地基:否则「这个分数是哪版 Prompt 跑出来的」永远说不清。等价物:Langfuse 评测 / LangSmith playground 对比。
Day 3Prompt Injection 红队 · 检测器 + 输入隔离文件:security/injection.py

任务

  • 跑红队,数清四类矢量各拦了几条
  • 口述根源:Context Mixing 为何是注射的本质
  • 自己加 2 条真实案列 payload,验证能否拦截(或解释为何难拦)
  • 确认正常消息(年假/天气)零误报
✔ 自查:红队拦截率>70%、正常消息误报=0;isolate() 把外部输入框进 <untrusted_data>。

运行

python security/injection.py
重难点:输入隔离为何有效?把外部输入用 <untrusted_data> 框起来 + data 前缀,让模型在推理时区分指令与数据,而非把数据当指令。注意:检测器永远有漏网,所以生产靠「权限最小化 + 高危预审(D4) + MCP 白名单(D5)」纵深叠加。
Day 4高危操作四层防呆 + 审计日志文件:security/guards.py

任务

  • 背出四层防呆:独立分类器→规则钩子→权限分级→审计
  • 跑 cases,确认 DROP/delete/SQL/群发 全被结构性拦下
  • 新增一条 deny 规则(如禁止访问 internal 域名),跑通
  • 回答:为什么不能让「被攻击的模型」自己裁决危险动作?
✔ 自查:高危工具全部 deny、只读工具 allow、audit 全量落日志。

运行

python security/guards.py
重难点:结构性拦截 vs 靠模型自觉。危险工具必须被代码规则直接拦住,模型再倔也调不动。第 1 层独立分类器独立于主模型——避免「用同一个被攻击的模型裁决自己」。审计日志=追责与复盘的唯一数据源。
Day 5MCP 安全 · 白名单 / 沙箱 / 凭证边界文件:security/mcp_policy.py

任务

  • 读 ServerPolicy,说清白名单三种等级的含义
  • 跑决策矩阵,确认未登记第三方一律 deny
  • 验证 scrub_credentials:明文密钥换成了什么?
  • 回答:为什么密钥绝不能进上下文?
✔ 自查:明文密钥不留上下文、白名单外拒绝、沙箱标记 _sandboxed。

运行

python security/mcp_policy.py
重难点:工具=代码,如何信任第三方 Server?三条铁律:①白名单=信任边界的显式声明;②沙箱=隔离执行,让「工具被攻破」波及不了主 Agent 与内网;③凭证边界=密钥换句柄($api_key_ref),执行器在沙箱外解算——否则模型可能把密钥当普通文字吐出去。
Day 6OWASP LLM Top 10 · 威胁自评 + 整改清单文件:day6_owasp.py

任务

  • 逐项过 CHECKLIST,把「待整改 ○」对应到本周代码能补的点
  • 背下 LLM01–LLM10 十个编号的最小含义
  • 挑 1 个 ○ 项(如 LLM05 输出处理),写 2 行整改动作
  • 给自己 10 项打个分,看治理进度几成
✔ 自查:能把每个编号映射到 W7/W8 的具体模块(哪个文件)。

运行

python day6_owasp.py
重难点:威胁建模不是背条目,是对号入座。面试被问安全:先背 Top10 编号,再说「我对应做到哪」。关键是防御纵深——LLM01 靠 D3 检测+隔离、D4 防呆、D5 白名单叠加,单点永远不可信。
Day 7复盘收官 · 排障演示 + 汇总安全拦截率文件:day7_review.py

任务

  • 跑 day7,看懂「4 分钟定位失败 observation」的完整路径
  • 把三张数字表抄进你的测试报告/作品说明
  • 给自己模拟面试:被问「走过一次线上事故吗」怎么用这周证据回答
  • 把 W8 与 W7 连起来:防御扛住 + 观测看见 + 安全拦下
✔ 自查:断言全过——注入拦截>70%、高危拒绝≥50%、白名单外拒绝≥3。

运行

python day7_review.py
重难点:把「零件」变成「证据」。面试要的不是你会用某库,而是你能演示一次排障 + 报出量化拦截率。day7 把 W8 所有模块串成一个可复述的故事:trace 定位到具体 obs → 给出下一步动作 → 附三张数字表。这就是作品集里最有说服力的一页。

执行顺序建议