-
Notifications
You must be signed in to change notification settings - Fork 6.2k
[BUG] Remove hard coded variables and better class extraction from KB #11490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e403a30
5d8379d
b7576a1
1f8b1b1
bdd52b4
2d6a9f5
f2fcada
798b385
95165da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,7 +13,15 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from openai import AsyncOpenAI, AsyncAzureOpenAI | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pydantic import BaseModel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from mindsdb.integrations.utilities.rag.settings import DEFAULT_RERANKING_MODEL, DEFAULT_LLM_ENDPOINT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from mindsdb.integrations.utilities.rag.settings import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_RERANKING_MODEL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_LLM_ENDPOINT, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_RERANKER_N, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_RERANKER_LOGPROBS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_RERANKER_TOP_LOGPROBS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_RERANKER_MAX_TOKENS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_VALID_CLASS_TOKENS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from mindsdb.integrations.libs.base import BaseMLEngine | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log = logging.getLogger(__name__) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -38,6 +46,11 @@ class BaseLLMReranker(BaseModel, ABC): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request_timeout: float = 20.0 # Timeout for API requests | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| early_stop: bool = True # Whether to enable early stopping | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| early_stop_threshold: float = 0.8 # Confidence threshold for early stopping | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| n: int = DEFAULT_RERANKER_N # Number of completions to generate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logprobs: bool = DEFAULT_RERANKER_LOGPROBS # Whether to include log probabilities | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| top_logprobs: int = DEFAULT_RERANKER_TOP_LOGPROBS # Number of top log probabilities to include | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_tokens: int = DEFAULT_RERANKER_MAX_TOKENS # Maximum tokens to generate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| valid_class_tokens: List[str] = DEFAULT_VALID_CLASS_TOKENS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class Config: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| arbitrary_types_allowed = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -234,6 +247,28 @@ async def search_relevancy_no_logprob(self, query: str, document: str) -> Any: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return rerank_data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async def search_relevancy_score(self, query: str, document: str) -> Any: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This method is used to score the relevance of a document to a query. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| query: The query to score the relevance of. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document: The document to score the relevance of. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A dictionary with the document and the relevance score. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug("Start search_relevancy_score") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker query: {query[:5]}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker document: {document[:50]}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker model: {self.model}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker temperature: {self.temperature}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker n: {self.n}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker logprobs: {self.logprobs}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker top_logprobs: {self.top_logprobs}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker max_tokens: {self.max_tokens}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.debug(f"Reranker valid_class_tokens: {self.valid_class_tokens}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| response = await self.client.chat.completions.create( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model=self.model, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages=[ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -306,17 +341,30 @@ async def search_relevancy_score(self, query: str, document: str) -> Any: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| temperature=self.temperature, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| n=1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logprobs=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| top_logprobs=4, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_tokens=3, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| n=self.n, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logprobs=self.logprobs, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| top_logprobs=self.top_logprobs, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_tokens=self.max_tokens, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Extract response and logprobs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| token_logprobs = response.choices[0].logprobs.content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Reconstruct the prediction and extract the top logprobs from the final token (e.g., "1") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final_token_logprob = token_logprobs[-1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| top_logprobs = final_token_logprob.top_logprobs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Find the token that contains the class number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Instead of just taking the last token, search for the actual class number token | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class_token_logprob = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for token_logprob in reversed(token_logprobs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if token_logprob.token in self.valid_class_tokens: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class_token_logprob = token_logprob | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # If we couldn't find a class token, fall back to the last non-empty token | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if class_token_logprob is None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warning("No class token logprob found, using the last token as fallback") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class_token_logprob = token_logprobs[-1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+355
to
+364
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class_token_logprob = None | |
| for token_logprob in reversed(token_logprobs): | |
| if token_logprob.token in self.valid_class_tokens: | |
| class_token_logprob = token_logprob | |
| break | |
| # If we couldn't find a class token, fall back to the last non-empty token | |
| if class_token_logprob is None: | |
| log.warning("No class token logprob found, using the last token as fallback") | |
| class_token_logprob = token_logprobs[-1] | |
| # Find all tokens that are valid class tokens | |
| class_token_logprobs = [token_logprob for token_logprob in token_logprobs if token_logprob.token in self.valid_class_tokens] | |
| if len(class_token_logprobs) == 0: | |
| log.warning("No class token logprob found, using the last token as fallback") | |
| class_token_logprob = token_logprobs[-1] | |
| elif len(class_token_logprobs) > 1: | |
| log.warning(f"Multiple class tokens found ({[t.token for t in class_token_logprobs]}), using the first one") | |
| class_token_logprob = class_token_logprobs[0] | |
| else: | |
| class_token_logprob = class_token_logprobs[0] |
Copilot
AI
Sep 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fallback to the last token when no class token is found could result in the same bug that was originally being fixed. Consider adding additional validation or a more robust fallback strategy, such as checking if the last token contains any numeric characters or returning an error/default score instead.
| log.warning("No class token logprob found, using the last token as fallback") | |
| class_token_logprob = token_logprobs[-1] | |
| # Try to use the last token only if it contains a numeric character | |
| last_token_logprob = token_logprobs[-1] | |
| if re.search(r'\d', last_token_logprob.token): | |
| log.warning("No class token logprob found, using the last token as fallback (contains digit)") | |
| class_token_logprob = last_token_logprob | |
| else: | |
| log.error("No valid class token found in logprobs; returning default score 0.0") | |
| rerank_data = {"document": document, "relevance_score": 0.0} | |
| log.debug(f"Reranker score: 0.0") | |
| log.debug("End search_relevancy_score") | |
| return rerank_data |
Copilot
AI
Aug 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Add a debug log statement here to show which class token was selected, similar to the logging mentioned in the PR description. This would help with debugging and monitoring the fix in production.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fallback logic could fail with an IndexError if
token_logprobsis empty. Add a check to ensuretoken_logprobsis not empty before accessingtoken_logprobs[-1].