Appearance
可观测性与测试
Deep Agents 的测试对象不只是最终文本,还包括规划、工具参数、文件变化、subagent 委派、审批和失败 恢复。先用确定性 fixture 验证边界,再用少量真实模型样本评估质量,才能把偶然的“看起来能跑”变成 可回归的工程证据。
测试分层
| 层级 | 主要问题 | 推荐证据 | 是否需要真实模型 |
|---|---|---|---|
| 纯函数单测 | 权限、schema、路径和解析是否正确 | 输入/输出断言 | 否 |
| 工具单测 | 工具是否鉴权、幂等、处理错误 | 本地 fixture、fake client | 否 |
| Agent 集成测试 | 是否选择正确工具并形成预期轨迹 | scripted/fake model、状态与 tool-call 断言 | 否 |
| 离线 Evaluation | 结果、轨迹和安全质量是否达标 | 固定 dataset、规则或 rubric | 可选 |
| 线上监控 | 真实分布中是否退化 | trace、采样 evaluator、告警 | 是 |
前端类比
这类似测试一个 Redux + effects 应用:组件快照只覆盖最终 UI,仍要验证 action、effect、缓存和错误 分支。Agent 的最终回答相当于 UI,tool calls、state 和 artifacts 才是中间行为。
Deep Agents 原生语义:Harness 编译为 LangGraph 图。一次 run 会经过模型、middleware、tools、 subagents 与 checkpoint;测试可以在这些边界断言轨迹,不应依赖模型逐字复现同一答案。
无模型费用的确定性单测
先把安全策略写成普通函数并覆盖边界值。下面只运行本地 Python,不创建 Agent,也不访问网络:
python
from pathlib import PurePosixPath
def may_write(path: str) -> bool:
normalized = PurePosixPath("/" + path.lstrip("/"))
if ".." in normalized.parts:
return False
return normalized == PurePosixPath("/workspace") or PurePosixPath(
"/workspace"
) in normalized.parents
def test_workspace_policy() -> None:
assert may_write("/workspace/report.md")
assert not may_write("/memories/policy.md")
assert not may_write("/workspace/../secrets.txt")真实工具仍要在服务端重新校验 trusted identity、资源 owner、参数上限和幂等键;不要把这一函数当作 完整授权实现。
Scripted Model 与确定性工具
仓库测试可使用 scripted/fake chat model 依次返回预设 tool call 和最终消息,并让工具读取本地 fixture。这样可以稳定验证:
write_todos是否出现在复杂任务轨迹中。- 某个业务工具是否收到经过 schema 校验的参数。
- 文件结果是否写到预期虚拟路径。
- subagent output 是否回到主 Agent,而详细消息没有污染主上下文。
- tool error 是否走预期恢复分支。
fake model 的具体测试类属于 LangChain/Deep Agents 当前测试支持面,名称可能随版本变化。应锁定依赖 版本并参考仓库同版本测试,不把内部 helper 当成稳定公共 API。
轨迹断言不要过度拟合
优先断言不变量:
python
tool_names = [call["name"] for call in captured_tool_calls]
assert "fetch_fixture" in tool_names
assert tool_names.count("publish_report") == 1
assert all("api_key" not in call["args"] for call in captured_tool_calls)除非顺序本身就是业务契约,否则不要断言每一步完全相同。模型升级可能选择等价顺序,但以下行为 通常必须失败测试:越权工具、缺少引用、重复副作用、跳过强制审批,以及把秘密写入 trace/artifact。
Evaluation:结果、轨迹与安全
| 维度 | 示例指标 | 适合的 evaluator |
|---|---|---|
| Outcome | 结论是否回答问题、结构是否完整 | 规则、参考答案、人工或 LLM rubric |
| Trajectory | 工具选择、参数、委派和重试是否合理 | 代码规则、轨迹 matcher |
| Grounding | 每项关键结论是否有可追溯来源 | 引用覆盖率、来源核验 |
| Safety | 是否触发禁用工具、泄漏秘密或越过审批 | 确定性规则、对抗用例 |
| Efficiency | 模型/工具调用、token、耗时是否超预算 | trace 聚合阈值 |
先用 5–10 个手工策划的关键样本定义“好”,再扩展 dataset。LLM-as-judge 适合主观质量,但必须固定 rubric、记录 judge 模型版本,并用人工校准;路径、schema、权限和引用存在性优先用代码规则。
Tracing 与隐私
启用 LangSmith tracing 时只从部署环境注入配置,不把真实值写进仓库:
bash
export LANGSMITH_TRACING=true
export LANGSMITH_PROJECT=deepagents-staging
# LANGSMITH_API_KEY 由 secret manager 注入Trace 能串联模型、工具、subagent 和延迟,适合定位循环、重试与上下文膨胀。上线前仍要明确:
- 哪些 message、tool args/result 和附件允许发送到观测系统。
- 如何脱敏 PII、凭据、用户文件和 sandbox 输出。
- trace 保留期、租户访问控制和删除流程。
- 在线 evaluator 的采样率、费用预算和告警阈值。
不使用 LangSmith 也应输出结构化 run/thread/tool 指标;可观测平台是实现选择,不是 Agent 正确性的 前提。
Beta Runtime Rubric
Python deepagents>=0.6.5 提供 Beta RubricMiddleware:它使用单独的 grader model 检查调用时传入的 rubric,在 needs_revision 时把逐项反馈送回工作 Agent,直到满足、失败或达到 max_iterations。
这与离线 evaluation 的职责不同:runtime rubric 影响当前 run 的迭代,离线 evaluation 比较固定 dataset 上的版本。它会产生额外模型调用,不能替代确定性权限检查;应设置迭代上限、记录 grader 模型版本,并把 path、schema、引用存在性等机械规则留给代码 evaluator。
回归门禁
- PR:纯函数、工具、scripted model 与恶意输入测试全部通过。
- 预发布:固定 dataset 运行离线 evaluation,与基线比较 outcome、safety 和 cost。
- 灰度:检查失败率、p95 延迟、循环上限、HITL reject 率与 sandbox 异常。
- 生产:把失败 trace 脱敏后沉淀为新的离线样本,验证修复再发布。