"""推断偏好聚合的纯函数护栏:事件阈值、比例、原话依据、条数上限与排序。""" import pytest from muse.作者经验.推断偏好 import 生成建议, 聚合挑选明细 def _明细(动作, 原话="", 时刻=0): return { "feedback_id": f"fb-{动作}-{时刻}", "created_at": 时刻, "domain": "combat", "query": "机甲", "quote": 原话, "method_version_id": "v1", "action": 动作, } @pytest.mark.case_id( "NC-w32-a10020", environment="离线", given="构造的挑选明细(时间倒序)", when="聚合明细并生成推断建议", then=["分列计数、依据取最近非空原话、护栏与排序生效"], contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md#偏好双轨关系", ) def test_聚合与建议护栏__a10020(): # 明细按时间倒序(与存储读法一致):最近的原话在前 明细 = [ _明细("selected", "最近的打戏原话", 9), _明细("selected", "", 8), _明细("selected", "较早的原话", 7), _明细("selected", "", 6), _明细("rejected", "", 5), ] 聚合 = 聚合挑选明细(明细) 桶 = 聚合[("combat", "v1")] assert 桶["选用次数"] == 4 and 桶["拒绝次数"] == 1 assert 桶["选用依据"]["quote"] == "最近的打戏原话" 标题表 = {"v1": {"title": "机甲近身刀法"}} 建议 = 生成建议(聚合, 标题表) assert len(建议) == 1 条 = 建议[0] assert 条["topic"] == "参考偏好:combat" assert "机甲近身刀法" in 条["text"] and "选用 4 次" in 条["text"] assert 条["quote"] == "最近的打戏原话" assert 条["feedback_id"] == "fb-selected-9" assert 条["证据"]["causality"] == "not_established" # 护栏1:支撑事件不足 5 不生成 assert 生成建议(聚合挑选明细(明细[:3]), 标题表) == [] # 护栏2:选用未达 3 倍拒绝不生成(3选2拒=5事件但 3 < 3*2) 胶着 = [ _明细("selected", "原话", 5), _明细("selected", "", 4), _明细("selected", "", 3), _明细("rejected", "", 2), _明细("rejected", "", 1), ] assert 生成建议(聚合挑选明细(胶着), 标题表) == [] # 护栏3:无原话依据不生成 无原话 = [_明细("selected", "", i) for i in range(5)] assert 生成建议(聚合挑选明细(无原话), 标题表) == [] # 回避倾向:拒绝 ≥5 且 ≥3 倍选用,带拒绝原话 回避 = [_明细("rejected", "不要这种花哨写法", 9)] + [_明细("rejected", "", i) for i in range(4)] 回避建议 = 生成建议(聚合挑选明细(回避), 标题表) assert len(回避建议) == 1 and "避免" in 回避建议[0]["text"] assert 回避建议[0]["quote"] == "不要这种花哨写法" # 护栏4:至多 5 条,按支撑事件降序 多版本 = {} for 序 in range(7): vid = f"v{序}" 行 = [ {**_明细("selected", f"原话{序}", 时刻), "method_version_id": vid} for 时刻 in range(5 + 序) ] 多版本.update(聚合挑选明细(行)) 全部 = 生成建议(多版本, {f"v{序}": {"title": f"方法{序}"} for 序 in range(7)}) assert len(全部) == 5 事件数 = [条["支撑事件"] for 条 in 全部] assert 事件数 == sorted(事件数, reverse=True)