准确率照旧,错的是另一批
目标
给节点包一层,把在哪里做了什么留在账簿里,并用黄金数据集得出准确率和答错条目的列表。与修改规则后的第二个版本比较,用名字区分新坏掉的和新修好的,并测量成本和路径的变化。
为什么重要
修改智能体之后,用一个分数来问“变好了吗”是很常见的。但分数相同,而内部有一个被修好、一个被弄坏,那就不是变好了,而是变了。分数是个数,我们需要知道的是名字。 观测只要给节点包一层。这里有一个重要的选择——时间也测出来留着,但不用于判定。同样的代码、同样的输入,时间也会因机器和负载而不同,用时间判定的回归检查会波动,最后被关掉。判定用次数和大小。 黄金数据集可以小,但必须是每次都一样的。而且要留着现在会错的条目,修复之后才看得出修好了什么。全都答对的黄金数据集什么也抓不到。 即使质量不变,成本和路径也可能回归。节点调用次数对同一个输入总是同样的值,所以可以用作回归指标;足迹变了的话,即使答案看起来相同,也是不同的行为。 评分器不会相信你写下的说明。它会真正导入你的模块,用任意的咨询来运行,并把黄金数据集的判定和两个版本的差异与评分器另外计算的值对照。
步骤
- 在 /root/work/ageval/evalkit.py 中创建
LABELS、ANSWER、classify_v1、State、五个节点(normalize、refund、shipping、other、finish)、ROUTE、build_graph(version="v1")、run_one(text, version="v1")。 - 增加
PROFILE、reset_profile()、instrument(name, fn),让build_graph把所有节点包一层再加入。 - 增加
hotspots(texts, version="v1"),给出每个节点的调用次数和最忙的节点。 - 增加
GOLDEN和evaluate(version="v1"),给出准确率和答错条目的列表。 - 增加
classify_v2和compare(old="v1", new="v2"),区分新坏掉的条目和新修好的条目。 - 增加
cost_delta(old="v1", new="v2"),测量节点调用次数的变化。 - 增加
path_changes(old="v1", new="v2"),找出足迹变了的条目。 - 在 /root/work/ageval/eval_report.json 和 /root/work/ageval/eval_report.md 中记录测得的内容。
参考
- 执行契约:评分器会把
/root/work/ageval/evalkit.py当作 Python 模块导入,直接使用上面列出的名称。不会作为脚本运行。 classify_v1(text):含有"환불"就返回"환불",否则含有"배송"就返回"배송",否则返回"기타"(韩文,依次意为“退款”“配送”“其他”)。classify_v2(text):含有"배송"就返回"배송",否则含有"환불"或"반품"(韩文,意为“退货”)就返回"환불",否则返回"기타"。检查顺序与 v1 不同——这就是本实验的材料。- 状态键:
text、clean、label、answer、trace。只有trace使用接续拼接的 Reducer。节点名称和状态键不能重名——重名的话,编译时会出现ValueError: 'x' is already being used as a state key。 normalize把text中的空白缩减成一个,放入clean。分类看的是clean。refund、shipping、other放入label和ANSWER[라벨](占位符为标签),三者都汇聚到finish。五个节点都把自己的名称写入trace。ROUTE = {"환불": "refund", "배송": "shipping", "기타": "other"}(韩文,意为“退款”“配送”“其他”)用作条件边的路径映射。run_one(text, version)的答案:{"label": 문자열, "answer": 문자열, "trace": [...]}(占位符均为字符串)。PROFILE是{노드이름: {"calls": 정수, "written": 정수, "ms": 실수}}(占位符依次为节点名称、整数、整数、实数)。written是把该节点返回的字典的键数量累加的值。ms只测量留着,不用于判定。hotspots(texts, version)的答案:{"calls": {...}, "total_calls": 정수, "busiest": 문자열, "timed": [...정렬된 노드 이름]}(占位符依次为整数、字符串、“已排序的节点名称”)。每次调用都重置账簿。busiest是调用次数最多的节点,次数相同则按名称升序。GOLDEN是六对(문의, 정답라벨)(占位符依次为咨询与正确答案标签):("환불 절차 알려 주세요", "환불")、("반품하고 싶어요", "환불")、("배송비 환불되나요", "환불")、("배송 언제 오나요", "배송")、("영수증 좀 보내 주세요", "기타")、("반품 배송비는 누가 내나요", "배송")(韩文,咨询依次意为“请告诉我退款流程”“我想退货”“运费可以退款吗”“配送什么时候到”“请把收据发给我”“退货的运费由谁承担”,标签依次为“退款”“退款”“退款”“配送”“其他”“配送”)。evaluate(version)的答案:{"total": 정수, "correct": 정수, "accuracy": 실수, "wrong": [{"text":…, "gold":…, "got":…}, …]}(占位符依次为整数、整数、实数)。wrong遵循黄金数据集的顺序。compare(old, new)的答案:{"old_accuracy": 실수, "new_accuracy": 실수, "newly_broken": [...정렬됨], "newly_fixed": [...정렬됨]}(占位符依次为实数、实数、“已排序”、“已排序”)。cost_delta(old, new)的答案:{"old_calls": 정수, "new_calls": 정수, "delta": 정수}(占位符均为整数)。是把整个黄金数据集各运行一次之后的调用次数。path_changes(old, new)的答案:按text升序给出[{"text":…, "old": [...], "new": [...]}, …]。足迹相同的条目不放入。- 这个 Pod 没有互联网。langgraph 0.2.60 已经装好了。
- 官方文档:Graph API overview · Use the graph API · Streaming
- 常见错误:每次调用都不清空账簿(前一次运行的数字会混进来)、用时间判定回归、不留下答错条目的名字、每次运行都重新抽取黄金数据集。
把咨询送往分支
在 /root/work/ageval/evalkit.py 中创建 LABELS、ANSWER、classify_v1、State、五个节点、ROUTE、build_graph(version="v1")、run_one(text, version="v1")。
根据 normalize 生成的 clean 来分类。条件函数返回标签,ROUTE 决定去哪个节点——让标签名称和节点名称不相同,是为了清楚地显示路径映射所做的事。version 参数目前只接收 "v1" 一个。
给节点包一层,留下账簿
增加 PROFILE、reset_profile()、instrument(name, fn),让 build_graph 把五个节点全部包一层再加入。账簿里留下 calls、written、ms。
包装函数调用原来的节点并把结果原样返回,同时在旁边记下数字。written 是该节点返回的字典的键数量。时间也一起测出来留着,但请用注释写明不用于判定——为什么这样做,是这一步的关键。
哪个节点最忙
增加 hotspots(texts, version="v1"),让它给出 {"calls": {...}, "total_calls": 정수, "busiest": 문자열, "timed": [...]}(占位符依次为整数与字符串)。每次调用都重置账簿。
不清空账簿的话,前一次运行的数字会混进来,就不知道在测什么了。busiest 是调用次数最多的节点,次数相同则按名称升序区分,让每次都得到同样的答案。timed 是记录了时间的节点的名称列表。
手工标好正确答案的六条
增加 GOLDEN 六对和 evaluate(version="v1"),让它给出 {"total", "correct", "accuracy", "wrong"}。wrong 中放入 text、gold、got。
黄金数据集可以小,但必须每次都一样。而且要留着现在会错的条目,修复之后才看得出修好了什么——全都答对的黄金数据集什么也抓不到。不要只给出准确率,要连同答错条目的名字一起给出。
分数相同,却是别的条目答错
增加 classify_v2 和 compare(old="v1", new="v2")。答案是 {"old_accuracy", "new_accuracy", "newly_broken", "newly_fixed"},两个列表要排序。
classify_v2 是把 "반품"(韩文,意为“退货”)视为退款的同时改了检查顺序的版本。先测一下两个版本的准确率,问问自己仅凭这个数字能不能下判断。把旧版本里对、新版本里错的条目,和相反的条目分别收集起来,分数所掩盖的东西就看出来了。
质量相同,成本也会变
增加 cost_delta(old="v1", new="v2"),让它给出 {"old_calls", "new_calls", "delta"}。是把整个黄金数据集各运行一次之后的节点调用次数。
调用次数对同一个输入总是同样的值,所以可以用作回归指标——这就是与时间的不同之处。直接使用前面步骤做的 hotspots 即可。在这个图里无论走哪个分支节点数都一样,那么也想一想 delta 说明了什么。
同样的答案走了不同的路
增加 path_changes(old="v1", new="v2"),只把足迹变了的条目按 text 升序以 [{"text", "old", "new"}, ...] 给出。
标签相同,但经过的节点不同,就是不同的行为。现在答案看起来相同,下次改动时会分道扬镳。足迹相同的条目不要放入——列表短,人才会去看。
判断该发布什么
在 /root/work/ageval/eval_report.json 中写入 old_accuracy、new_accuracy、newly_broken、newly_fixed、cost、path_changes、busiest、total_calls,在 /root/work/ageval/eval_report.md 中用 ## 어디서 무엇을 했는지 어떻게 기록했나(韩文,意为“如何记录在哪里做了什么”)、## 점수만 보면 놓치는 것(韩文,意为“只看分数会漏掉的东西”)、## 비용과 경로도 회귀한다(韩文,意为“成本和路径也会回归”)、## 다음에 무엇을 하겠는가(韩文,意为“下一步打算做什么”)四节来写。
cost 原样放入 cost_delta 的答案,path_changes 是变了的条目的个数。busiest、total_calls 是把整个黄金数据集用 v1 运行时的值。第四节里,请根据这些结果写下你对该发布哪个版本的判断——答案不止一个。