Files

96 lines
3.6 KiB
Python
Raw Permalink 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.
"""知识库消费指标单元测试(mock 数据,不依赖数据库)。"""
from types import SimpleNamespace
from unittest.mock import patch
from app.kb_metrics import kb_metrics, kb_metrics_overview
def _usage(agent_id, kb_id, chunk_id, segment_id, status="consumed"):
return SimpleNamespace(agent_id=agent_id, kb_id=kb_id, chunk_id=chunk_id,
segment_id=segment_id, status=status, file_name="f.md",
heading="h", excerpt="e")
def _segment(sid, references=None, status="approved"):
return SimpleNamespace(id=sid, status=status, references=references or [])
def _session(usage_rows, segments, kbs=()):
def exec(*_a, **_k):
# 简化:按调用顺序不可靠,直接用鸭子类型区分——这里用闭包计数不必要,
# kb_metrics_overview 内部按顺序 exec 三次:usage / kbs / segments,
# kb_metrics 内部两次:usage / segments。用可迭代队列处理。
raise AssertionError("请使用带计划的 mock")
return SimpleNamespace(exec=exec)
class _PlannedSession:
def __init__(self, queues):
self.queues = list(queues)
def exec(self, *_a, **_k):
return SimpleNamespace(all=lambda: self.queues.pop(0) if self.queues else [])
def get(self, model, row_id):
return None
def test_metrics_empty():
session = _PlannedSession([[], []])
report = kb_metrics(session)
assert report["hit_rate"] == 0.0
assert report["repeat_rate"] == 0.0
assert report["reference_coverage"] == 0.0
def test_hit_rate_and_repeat_rate():
usage = [
_usage(1, 1, "c1", 101), _usage(1, 1, "c2", 101),
_usage(2, 1, "c1", 102),
# 重复消费:agent1 再次用 c1(segment 103)→ pair (1, c1) 两条
_usage(1, 1, "c1", 103),
]
session = _PlannedSession([usage, []])
report = kb_metrics(session)
assert report["detail"]["hit_requests"] == 3 # (1,101)(2,102)(1,103)
assert report["detail"]["repeated_pairs"] == 1
assert report["repeat_rate"] == round(1 / 3, 4)
assert report["reference_coverage"] == 0.0 # 没有 segment 数据
def test_reference_coverage():
usage = [_usage(1, 1, "c1", 101)]
segments = [_segment(101, references=[{"file": "f"}]), _segment(102, references=[])]
session = _PlannedSession([usage, segments])
report = kb_metrics(session)
assert report["reference_coverage"] == 0.5
def test_miss_requests_lower_hit_rate():
usage = [_usage(1, 1, "c1", 101)]
# 段 102 是已完成的生产段但完全没有消费记录 → 记一次未命中
segments = [_segment(101, references=[{"x": 1}]), _segment(102)]
session = _PlannedSession([usage, segments])
report = kb_metrics(session)
assert report["detail"]["search_requests"] == 2
assert report["detail"]["miss_requests"] == 1
assert report["hit_rate"] == 0.5
def test_overview_by_kb_sorted():
usage = [
_usage(1, 1, "c1", 101), _usage(1, 1, "c2", 101),
_usage(1, 2, "c3", 102),
]
kbs = [
SimpleNamespace(id=1, name="主库", file_count=2, chunk_count=10),
SimpleNamespace(id=2, name="副库", file_count=1, chunk_count=10),
]
# kb_metrics_overview 先调 kb_metrics(usage, segments),再查 usage 和 kbs
session = _PlannedSession([usage, [], usage, kbs])
report = kb_metrics_overview(session)
assert report["by_kb"][0]["kb_id"] == 1 # 消费比 0.2 > 0.1
assert report["by_kb"][0]["consumed"] == 2
assert report["top_chunks"][0]["chunk_id"] == "c1" # c1 有 2 条记录(同 agent 两段)