forked from admin/PlantAI-rag-new
fix(r4-28v2-amend): 补 direct_flow_retriever 阈值参数链路+单测
上一提交中 direct_flow_retriever 的 qdrant_score_threshold 参数 (retrieve 签名/audit/调用点)未落盘,真实 search 路径会 TypeError。 本次补上三处 + 新增 qdrant_search 透传单测(不触发 IO 的对象伪造)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -117,6 +117,7 @@ class DirectFlowRetriever:
|
||||
use_qdrant: bool = True,
|
||||
use_neo4j: bool = True,
|
||||
use_graph_expansion: bool = True,
|
||||
qdrant_score_threshold: float | None = None,
|
||||
) -> Tuple[List[EvidenceItem], Dict[str, Any]]:
|
||||
effective_use_neo4j = bool(use_neo4j) and self.graph_schema in {
|
||||
"canonical",
|
||||
@@ -138,6 +139,7 @@ class DirectFlowRetriever:
|
||||
"use_graph_expansion": use_graph_expansion,
|
||||
"effective_use_neo4j": effective_use_neo4j,
|
||||
"effective_use_graph_expansion": effective_use_graph_expansion,
|
||||
"qdrant_score_threshold": qdrant_score_threshold,
|
||||
},
|
||||
"neo4j_status": (
|
||||
"enabled"
|
||||
@@ -153,7 +155,12 @@ class DirectFlowRetriever:
|
||||
per_query = max(10, min(qdrant_top_k // max(1, len(all_queries)), 50))
|
||||
if self.vector_query_workers == 1 or len(all_queries) == 1:
|
||||
query_rows = [
|
||||
(query, self.qdrant_search(query, per_query))
|
||||
(
|
||||
query,
|
||||
self.qdrant_search(
|
||||
query, per_query, score_threshold=qdrant_score_threshold
|
||||
),
|
||||
)
|
||||
for query in all_queries
|
||||
]
|
||||
else:
|
||||
@@ -162,7 +169,12 @@ class DirectFlowRetriever:
|
||||
thread_name_prefix="qa-vector",
|
||||
) as executor:
|
||||
futures = [
|
||||
executor.submit(self.qdrant_search, query, per_query)
|
||||
executor.submit(
|
||||
self.qdrant_search,
|
||||
query,
|
||||
per_query,
|
||||
score_threshold=qdrant_score_threshold,
|
||||
)
|
||||
for query in all_queries
|
||||
]
|
||||
query_rows = [
|
||||
|
||||
@@ -224,6 +224,46 @@ def test_chat_mode_passes_no_threshold():
|
||||
assert p._retriever_stub.last_kwargs["qdrant_score_threshold"] is None
|
||||
|
||||
|
||||
def test_direct_flow_retriever_threshold_passthrough():
|
||||
"""真实 retriever 的 qdrant_score_threshold 参数链路(不触发 IO)。
|
||||
|
||||
用对象伪造构造 DirectFlowRetriever 实例,直接调用 qdrant_search:
|
||||
- 传阈值时透传给 qdrant.query_points(同域向量阈值);
|
||||
- 不传阈值时 score_threshold=None(chat 保召回)。
|
||||
"""
|
||||
import rag.qa_v1_1_73.direct_flow_retriever as dfr_mod
|
||||
|
||||
class _FakeQdrant:
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
def query_points(self, **kwargs):
|
||||
self.calls.append(kwargs)
|
||||
from qdrant_client.http import models
|
||||
|
||||
return models.QueryResponse(points=[])
|
||||
|
||||
class _MinimalRetriever(dfr_mod.DirectFlowRetriever):
|
||||
"""绕过 __init__(不建连接),只测 qdrant_search 参数透传。"""
|
||||
|
||||
def __init__(self):
|
||||
self.qdrant = _FakeQdrant()
|
||||
self.collection = "plant_srt_pc2025_v3_20260817_normalized"
|
||||
self.embed_url = ""
|
||||
self.embed_model = ""
|
||||
|
||||
def embed(self, text):
|
||||
return [0.0] * 1024
|
||||
|
||||
r = _MinimalRetriever()
|
||||
r.qdrant_search("景甜是谁", 10, score_threshold=0.45)
|
||||
assert r.qdrant.calls[-1]["score_threshold"] == 0.45
|
||||
assert r.qdrant.calls[-1]["collection_name"] == r.collection
|
||||
|
||||
r.qdrant_search("arginine", 10)
|
||||
assert r.qdrant.calls[-1]["score_threshold"] is None
|
||||
|
||||
|
||||
def test_env_overrides(monkeypatch):
|
||||
monkeypatch.setenv("QA_MIN_VECTOR_SCORE", "0.5")
|
||||
assert score_gate._env_value("QA_MIN_VECTOR_SCORE", 0.45) == 0.5
|
||||
|
||||
Reference in New Issue
Block a user