mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-23 08:56:42 +08:00
feat: Auto-adjust chunk recall weights based on user feedback (#12689)
### What problem does this PR solve? Implements automatic adjustment of knowledge base chunk recall weights based on user feedback (upvotes/downvotes). When users upvote or downvote a response, the system locates the corresponding knowledge snippets and adjusts their recall weight to improve future retrieval quality. **Closes #12670** **How it works:** 1. User upvotes/downvotes a response via `POST /thumbup` 2. System extracts chunk IDs from the conversation reference 3. For each referenced chunk: - Reads current `pagerank_fea` value from document store - Increments (+1) for upvote or decrements (-1) for downvote - Clamps weight to [0, 100] range - Updates chunk in ES/Infinity/OceanBase 4. Future retrievals score these chunks higher/lower based on accumulated feedback **Files changed:** - `api/db/services/chunk_feedback_service.py` - New service for updating chunk pagerank weights - `api/apps/conversation_app.py` - Integrated feedback service into thumbup endpoint - `test/testcases/test_web_api/test_chunk_feedback/` - Unit tests ### Type of change - [x] New Feature (non-breaking change which adds functionality) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Chat message feedback now updates per-chunk relevance weights (feature-flag gated), with configurable weighting and atomic updates across storage backends. * **Bug Fixes** * Stricter validation for message feedback inputs and more robust handling of feedback transitions. * **Tests** * Expanded test coverage for chunk-feedback behavior, weighting strategies, storage backends, and thumb-flip scenarios. * **Chores** * CI workflow extended to run the new chunk-feedback web API tests. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: mkdev11 <YOUR_GITHUB_ID+MkDev11@users.noreply.github.com> Co-authored-by: mkdev11 <MkDev11@users.noreply.github.com>
This commit is contained in:
@@ -597,6 +597,84 @@ class InfinityConnection(InfinityConnectionBase):
|
||||
self.connPool.release_conn(inf_conn)
|
||||
return True
|
||||
|
||||
def adjust_chunk_pagerank_fea(
|
||||
self,
|
||||
chunk_id: str,
|
||||
index_name: str,
|
||||
knowledgebase_id: str,
|
||||
delta: int,
|
||||
min_weight: int,
|
||||
max_weight: int,
|
||||
row_id: int | None = None,
|
||||
max_retries: int = 2,
|
||||
) -> bool:
|
||||
"""Adjust pagerank_fea on one chunk row in Infinity.
|
||||
|
||||
Uses row_id for a targeted update when available. If the row_id is
|
||||
stale (concurrent update changed it), re-reads the current row_id and
|
||||
retries up to *max_retries* times.
|
||||
"""
|
||||
table_name = f"{index_name}_{knowledgebase_id}"
|
||||
for attempt in range(max_retries + 1):
|
||||
inf_conn = self.connPool.get_conn()
|
||||
try:
|
||||
db_instance = inf_conn.get_database(self.dbName)
|
||||
table_instance = db_instance.get_table(table_name)
|
||||
|
||||
if row_id is None:
|
||||
df, _ = table_instance.output(
|
||||
[PAGERANK_FLD, "row_id()"]
|
||||
).filter(f"id = '{chunk_id}'").to_df()
|
||||
if df.empty:
|
||||
self.logger.warning(
|
||||
"adjust_chunk_pagerank_fea: chunk %s not found in %s",
|
||||
chunk_id, table_name,
|
||||
)
|
||||
return False
|
||||
current_weight = int(float(df[PAGERANK_FLD].iloc[0] or 0))
|
||||
row_id = int(df["row_id"].iloc[0])
|
||||
else:
|
||||
df, _ = table_instance.output(
|
||||
[PAGERANK_FLD]
|
||||
).filter(f"id = '{chunk_id}'").to_df()
|
||||
if df.empty:
|
||||
return False
|
||||
current_weight = int(float(df[PAGERANK_FLD].iloc[0] or 0))
|
||||
|
||||
new_weight = max(min_weight, min(max_weight, current_weight + delta))
|
||||
|
||||
table_instance.update(
|
||||
f"_row_id = {row_id}",
|
||||
{PAGERANK_FLD: new_weight},
|
||||
)
|
||||
self.logger.info(
|
||||
"adjust_chunk_pagerank_fea(chunk=%s, table=%s): %s -> %s via row_id=%s",
|
||||
chunk_id, table_name, current_weight, new_weight, row_id,
|
||||
)
|
||||
return True
|
||||
|
||||
except InfinityException as e:
|
||||
if attempt < max_retries:
|
||||
self.logger.warning(
|
||||
"adjust_chunk_pagerank_fea stale row_id=%s for chunk %s (attempt %s/%s): %s",
|
||||
row_id, chunk_id, attempt + 1, max_retries, e,
|
||||
)
|
||||
row_id = None
|
||||
continue
|
||||
self.logger.error(
|
||||
"adjust_chunk_pagerank_fea failed for chunk %s after %s attempts: %s",
|
||||
chunk_id, max_retries + 1, e,
|
||||
)
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(
|
||||
"adjust_chunk_pagerank_fea error for chunk %s: %s", chunk_id, e,
|
||||
)
|
||||
return False
|
||||
finally:
|
||||
self.connPool.release_conn(inf_conn)
|
||||
return False
|
||||
|
||||
"""
|
||||
Helper functions for search result
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user