news 2026/10/5 3:02:34

如何为Agent代码写可靠的测试?Shepherd离线确定性测试实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何为Agent代码写可靠的测试?Shepherd离线确定性测试实践

如何为Agent代码写可靠的测试?Shepherd离线确定性测试实践

【免费下载链接】shepherdA runtime substrate that turns an agent's execution into a reversible, Git-like trace, so meta-agents can observe, fork, replay, and revert any run. Couples agent and environments in a copy-on-write fork ~5x faster than docker commit, with ~95% KV-cache reuse on replay. Framework built for meta-agents to supervise, optimize, and train other agents项目地址: https://gitcode.com/gh_mirrors/shepherd16/shepherd

Shepherd 是一个把 Agent 执行过程变成可逆、类 Git 执行轨迹(trace)的运行时底座,支持观察、fork、重放与回退任意一次运行。而 Shepherd 离线确定性测试 正是解决「Agent 代码难以测试」这一痛点的核心实践:无需网络、无需 API 密钥、无需花钱,每次运行都得到完全一致的结果,让 CI 里的 Agent 测试告别 flaky(不稳定)。

为什么 Agent 代码的测试这么难 🤔

如果你写过基于大模型的 Agent,大概率遇到过这些问题:

痛点后果
输出随机每次断言都可能失败,测试形同虚设
依赖网络与 API 密钥测试环境配置复杂,密钥泄露风险
调用计费CI 每跑一轮都在烧钱
环境差异模型版本、温度、上下文都会改变结果

传统做法是用 mock 模拟模型返回,但 mock 得越多,测试就越偏离真实行为。Shepherd 的思路不同:它把「离线确定性 provider」做成一个一等公民 provider——不是为测试临时糊上的假模型,而是像真实 provider 一样被选择、被调用,只是回答来自录制好的转录(transcript)。

核心机制:离线 provider + 可逆执行轨迹

Shepherd 中,任务(task)只声明「想要什么」——类型化的契约和 docstring,从不在代码里指定「谁来回答」。由 workspace 统一选择 provider:

import shepherd as sp with sp.workspace(model="claude:sonnet-4-5"): ... # 这里面的每次任务调用都由同一个 provider 应答

文档与 CI 默认使用离线确定性 provider(在 retained run 中它叫static):调用不读任何凭证、不发出任何网络请求,答案由录制的转录重放。官方文档里所有示例都跑在它上面,「你读到的就是运行到的」。

同时,Shepherd 把每次运行记录为持久的执行轨迹:workspace 基于写时复制(copy-on-write)fork,Agent 的产物以「retained output(保留输出)」形式暂存在一旁,供你先检查、再决定select(采纳)、apply(合并)还是discard(丢弃)。这个可逆性正是可靠测试与可恢复运行的基础。

实践一:测试与程序走完全相同的调用路径 ✅

写测试时,用和生产程序完全一样的方式调用任务:在 workspace 里打开离线 provider,然后在测试体内调用任务。这样测的就是真实运行路径,而不是一个孤立的 mock。官方 quickstart 的最小示例 hello.py 连续跑两遍,输出的 review 逐字符相同——确定性本身就是目标。

实践二:断言类型化返回值,而不是解析文本

任务声明了返回类型,Shepherd 会把模型回答强制转换为该类型再交给你。测试因此可以直接读字段:

def test_triage_matches_contract(): with sp.workspace(model="claude:sonnet-4-5"): triage = triage_change(SAMPLE_DIFF) assert isinstance(triage, Triage) assert (triage.category, triage.priority) == ("bugfix", "high")

返回类型就是契约。没有 JSON 解析、没有正则刮字符串,契约变了测试立刻红。若回答无法转成声明的类型,会得到明确的sp.DeliveryFailed,而不是一个模棱两可的坏字符串。

实践三:把失败契约也纳入测试 🧪

Shepherd 的类型化失败同样是行为的一部分,值得逐个钉住:

  • sp.DeliveryFailed:录制答案无法转成声明的返回类型——说明返回类型或 docstring 契约已经漂移,收紧类型再跑。
  • RuntimeError(workspace 相关):任务在with sp.workspace(...)之外被调用。Shepherd 没有「隐藏的默认模型」,无 workspace 立即失败,而不是偷偷回退。

这两类断言能抓住绝大多数「悄悄变坏」的场景。

实践四:让 CI 直接运行文档里的示例 🚀

Shepherd 的文档本身就是被测试的。看 test_hello.py 的做法:CI 测试直接把hello.py当作真实脚本跑一遍,再断言文档承诺的输出片段确实被打印——文档展示什么,测试就运行什么,杜绝文档与实现脱节。

更进一步,test_world_hero.py 验证的是「执行证据」:它在真实安装环境中新建一个shepherd init工作区,把发布页面里逐字节相同的 hero 代码片段作为真正的__main__脚本运行,断言输出包含['NOTE.txt']和预期文本。这意味着用户照着文档敲的每一行,都在 CI 里被原样执行过。

实践五:用可逆轨迹重放失败运行,而非盲目重试

当一次运行失败或产物不合预期时,Shepherd 的轨迹让你可以精确回到失败现场:检查 retained output 想改什么、读取它的变更内容、然后 select/discard/apply。重放时离线 provider 保证结果逐字节一致,配合写时复制 fork(比 docker commit 快约 5 倍)和重放时约 95% 的 KV-cache 复用,「复现—定位—重试」循环的成本极低。相关的视觉化恢复示例可在 visual_artifact 示例集 中查看。

快速上手清单

  1. pip install shepherd-ai(要求 Python 3.11+;Windows 请用 WSL)
  2. mkdir demo && cd demo && shepherd init把目录变成 Shepherd 工作区
  3. 编写任务(函数签名 + docstring 即契约)
  4. 测试中用sp.workspace(model=...)固定离线 provider,断言类型化返回值
  5. 把文档示例本身纳入 pytest,让 CI 跑文档

延伸阅读

  • 测试指南:test-shepherd-code.md
  • 确定性演示:deterministic-demo.md
  • provider 概念(离线 provider 是一等公民):providers.md
  • 离线 quickstart 示例:offline_task.py
  • 文档系统的「跑文档即测试」实现:test_docs_system.py
  • 项目总览与离线快速开始:README.md

【免费下载链接】shepherdA runtime substrate that turns an agent's execution into a reversible, Git-like trace, so meta-agents can observe, fork, replay, and revert any run. Couples agent and environments in a copy-on-write fork ~5x faster than docker commit, with ~95% KV-cache reuse on replay. Framework built for meta-agents to supervise, optimize, and train other agents项目地址: https://gitcode.com/gh_mirrors/shepherd16/shepherd

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 3:01:51

数据分析入门实战:用Pandas搞定数据清洗三大硬骨头

1. 任务定位:一个“看名字就知道要求”的开胃题Wk.2_HW,拆开就是 Week 2 Homework。但凡经历过几个像样的项目制课程或内部训练营,一看到这种命名的目录,基本就能猜到它背后是一套有节奏的任务体系:第一周打基础&#…

作者头像 李华
网站建设 2026/10/5 3:01:43

慈善钓鱼:灾害背后的双向诈骗与识别防护

每次大型灾害过后,社交媒体上都会被两类内容刷屏:一类是真实的求助与募捐,另一类是趁乱生长的伪装帖。后者在安全圈里有个专门说法,叫“慈善钓鱼”——拿灾难当鱼饵,拿同情心当鱼钩,等捐款人咬住钩子再完成…

作者头像 李华
网站建设 2026/10/5 3:01:00

GPU租赁实战指南:从算力瓶颈到PyTorch环境配置一次讲透

上周一个做视觉检测的朋友问我要怎么上深度学习,说公司预算卡得紧,两片RTX 4090就要四万多,实在下不去手。我给他指了条租GPU的路子,按小时包一台带RTX 4090的云主机,第一天跑下来成本不到一百块钱,效果和自…

作者头像 李华
网站建设 2026/10/5 2:59:39

of_graph_get_remote_port解析:嵌入式Linux设备树图形绑定核心机制

1. 这个函数名背后藏着嵌入式Linux设备树驱动开发的底层逻辑of_graph_get_remote_port——光看这个名字,你可能以为它只是个普通API调用。但如果你正在调试一块带MIPI CSI摄像头的ARM开发板,或者在移植一个HDMI音频编解码器驱动,又或者正被某…

作者头像 李华
网站建设 2026/10/5 2:59:24

WPF DataGrid点击单元格立即进入编辑模式的完整实现

上个月在给公司内部的数据录入工具做交互改造,WPF的DataGrid用了这么久,收到最多的抱怨就是录数效率低:鼠标点到一个格子,以为能直接打字了,结果系统只是把单元格选中而已,还得再点一下、按F2、或者双击&am…

作者头像 李华
网站建设 2026/10/5 2:58:31

SpringBoot+MyBatis+MySQL实战:游戏介绍系统开发与部署全解析

这个项目是我帮学生做的一个课程设计,名字叫《逃跑吧少年》介绍系统。说白了就是一个游戏官网式的信息展示平台,把角色图鉴、地图玩法、攻略资讯这些内容做成一个能看能管的完整站点。技术栈选了SpringBootMyBatisMySQL,SpringBoot负责把整个…

作者头像 李华