muse-agent-example/tests/单元/test_偏好重排.py

108 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""偏好重排纯函数合同:分列计数、有界惩罚、确定性探索位与权重护栏。"""
import pytest
from muse.上下文.偏好重排 import (
偏好信号,
偏好值,
合并信号表,
应用拒绝惩罚,
权重表,
构建偏好路,
注入探索位,
)
@pytest.mark.case_id(
"NC-w32-a10015",
environment="离线",
given="挑选信号行与消费统计",
when="合并信号表",
then=["弱强信号分列计数不混算;同版本两路信号并存"],
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
)
def test_合并信号表分列不混算__a10015():
表 = 合并信号表(
[
{"method_version_id": "v1", "选用次数": 3, "拒绝次数": 1, "选中位次": [1, 2]},
{"method_version_id": "v2", "选用次数": 0, "拒绝次数": 2, "选中位次": []},
],
{"v1": 5, "v3": 2},
)
assert 表["v1"] == 偏好信号(3, 1, 5, (1, 2))
assert 表["v2"] == 偏好信号(0, 2, 0, ())
assert 表["v3"] == 偏好信号(0, 0, 2, ())
# 分列:选用与消费不互相折算
assert 偏好值(表["v1"]) == pytest.approx(3 * 0.05 + 1 * -0.08 + 5 * 0.10)
@pytest.mark.case_id(
"NC-w32-a10016",
environment="离线",
given="正负偏好信号与双路融合分",
when="构建偏好路并应用拒绝惩罚",
then=["只有正偏好进路;惩罚有界且不超过偏好路末位贡献"],
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
)
def test_正偏好进路负偏好有界惩罚__a10016():
信号表 = {
"v1": 偏好信号(选用次数=2),
"v2": 偏好信号(拒绝次数=3),
"v3": 偏好信号(),
}
路 = 构建偏好路(信号表)
assert set(路) == {"v1"} and 路["v1"] > 0
融合 = {"v1": 0.03, "v2": 0.03, "v3": 0.03}
调整 = 应用拒绝惩罚(融合, 信号表)
assert 调整["v1"] == 0.03 and 调整["v3"] == 0.03
assert 调整["v2"] < 0.03
# 惩罚上界 = 路权重/61(偏好路末位贡献量级)
assert 0.03 - 调整["v2"] <= 权重表["路权重"] / 61.0 + 1e-12
# 大量拒绝也不能把惩罚推出上界(有界归一)
巨量 = {"v9": 偏好信号(拒绝次数=10000)}
融合巨量 = {"v9": 0.03}
assert 0.03 - 应用拒绝惩罚(融合巨量, 巨量)["v9"] < 权重表["路权重"] / 61.0
@pytest.mark.case_id(
"NC-w32-a10017",
environment="离线",
given="含已探索头部与未探索尾部的排名",
when="注入探索位",
then=["至多两个未探索版本晋升,替换头部末尾已探索项,结果确定"],
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
)
def test_探索位晋升确定且有界__a10017():
信号表 = {"a": 偏好信号(选用次数=1), "b": 偏好信号(消费次数=1), "c": 偏好信号(拒绝次数=1)}
排名 = [("a", 0.9), ("b", 0.8), ("c", 0.7), ("d", 0.6), ("e", 0.5)]
新排名, 探索集 = 注入探索位(排名, 信号表, 3)
头部 = [vid for vid, _ in 新排名[:3]]
# d、e 未探索:晋升两个,替换头部末尾的已探索项(c、b)
assert 头部[0] == "a" and set(头部[1:]) == {"d", "e"}
assert 探索集 == {"d", "e"}
# 未晋升的尾部按原序接回,候选回填链完整、总长度不变
assert [vid for vid, _ in 新排名] == ["a", "d", "e", "b", "c"]
# 确定性:同输入同输出
assert 注入探索位(排名, 信号表, 3)[0] == 新排名
# 头部已含足量未探索项时不动
不动, 集 = 注入探索位([("d", 0.9), ("e", 0.8), ("a", 0.7)], 信号表, 3)
assert [vid for vid, _ in 不动] == ["d", "e", "a"] and 集 == {"d", "e"}
# 全已探索且无尾部候选时不动
全探索 = [("a", 0.9), ("b", 0.8)]
assert 注入探索位(全探索, 信号表, 2)[0] == 全探索
@pytest.mark.case_id(
"NC-w32-a10018",
environment="离线",
given="版本化权重表",
when="核对权重护栏",
then=["偏好路权重不超过0.25,权重表带版本标识"],
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
)
def test_权重表护栏__a10018():
assert 权重表["version"] == "preference-rerank-v1"
assert 0 < 权重表["路权重"] <= 0.25
assert 权重表["种类权重"]["拒绝"] < 0 < 权重表["种类权重"]["选用"]
assert 权重表["探索位"] in (1, 2)