mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 13:16:24 +00:00
fix(memory): keep a zero confidence from scoring as the default (#5586)
or 0.5 cannot distinguish an explicit 0.0 from an unset field, so a discounted fact got the default confidence weight in both the FTS5 document and the substring fallback, while the same row indexed through FTS5Retrieval.index_fact kept its zero weight.
This commit is contained in:
parent
7c948a38c4
commit
c77e8744fa
@ -578,11 +578,13 @@ class FTS5RetrievalAdapter:
|
||||
payload = dict(fact)
|
||||
payload["scope"] = {"userId": scope.get("userId"), "agentName": scope.get("agentName")}
|
||||
source = payload.get("source")
|
||||
confidence = payload.get("confidence")
|
||||
return {
|
||||
"fact_id": self._document_id(fact_id, scope),
|
||||
"content": content,
|
||||
"category": str(payload.get("category") or "context"),
|
||||
"confidence": float(payload.get("confidence") or 0.5),
|
||||
# 0.0 is a persisted confidence storage._normalize_fact accepts; only unset/null defaults.
|
||||
"confidence": 0.5 if confidence is None else float(confidence),
|
||||
"created_at": payload.get("createdAt") if isinstance(payload.get("createdAt"), str) else None,
|
||||
"scope_user": scope_user,
|
||||
"scope_agent": scope_agent,
|
||||
|
||||
@ -1822,7 +1822,10 @@ class FileMemoryStorage(MemoryStorage):
|
||||
for fact in facts:
|
||||
content = fact.get("content")
|
||||
if isinstance(content, str) and query_lower in content.lower():
|
||||
results.append({"fact": fact, "score": float(fact.get("confidence") or 0.5), "matchType": "substring"})
|
||||
# 0.0 is a persisted confidence _normalize_fact accepts; only unset/null defaults.
|
||||
confidence = fact.get("confidence")
|
||||
score = 0.5 if confidence is None else float(confidence)
|
||||
results.append({"fact": fact, "score": score, "matchType": "substring"})
|
||||
results.sort(key=lambda result: result["score"], reverse=True)
|
||||
return results[:top_k]
|
||||
|
||||
|
||||
@ -287,3 +287,34 @@ def test_deermem_create_and_restart_use_retrieval_adapter(tmp_path: Path) -> Non
|
||||
|
||||
restarted = DeerMem(backend_config=config)
|
||||
assert any(fact["id"] == fact_id for fact in restarted.search("restart retrieval", user_id="alice"))
|
||||
|
||||
|
||||
def test_indexed_zero_confidence_keeps_its_retrieval_weight(tmp_path: Path) -> None:
|
||||
adapter = FTS5RetrievalAdapter(tmp_path / "facts.sqlite3")
|
||||
scope = {"userId": "alice", "agentName": "agent-a"}
|
||||
try:
|
||||
adapter.upsert({**_fact("zero", "confidence weight probe"), "confidence": 0.0}, scope=scope, path="")
|
||||
adapter.upsert({**_fact("half", "confidence weight probe"), "confidence": 0.5}, scope=scope, path="")
|
||||
unset_fact = _fact("unset", "confidence weight probe")
|
||||
del unset_fact["confidence"]
|
||||
adapter.upsert(unset_fact, scope=scope, path="")
|
||||
scores = {item["fact"]["id"]: item["score"] for item in adapter.search("confidence", scopes=[scope], top_k=5, mode="fts5", filters=None)}
|
||||
|
||||
assert scores["zero"] < scores["half"]
|
||||
# A missing confidence still falls back to the default, so only the explicit 0.0 is discounted.
|
||||
assert scores["unset"] == pytest.approx(scores["half"])
|
||||
finally:
|
||||
adapter.close()
|
||||
|
||||
|
||||
def test_substring_fallback_keeps_zero_confidence_weight(tmp_path: Path) -> None:
|
||||
storage = FileMemoryStorage(DeerMemConfig(storage_path=str(tmp_path)))
|
||||
scope = {"userId": "alice", "agentName": "agent-a"}
|
||||
try:
|
||||
storage.upsert_fact({**_fact("zero", "substring confidence probe"), "confidence": 0.0}, user_id="alice", agent_name="agent-a")
|
||||
storage.upsert_fact({**_fact("half", "substring confidence probe"), "confidence": 0.5}, user_id="alice", agent_name="agent-a")
|
||||
scores = {item["fact"]["id"]: item["score"] for item in storage.search_facts("substring", scopes=[scope], top_k=5)}
|
||||
|
||||
assert scores == {"zero": 0.0, "half": 0.5}
|
||||
finally:
|
||||
storage.close()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user