-
Notifications
You must be signed in to change notification settings - Fork 8
Iris: Calculate verbalized confidence
#507
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
Merged
Merged
Changes from 3 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
2d9d1de
Implement verbalized confidence scoring
toukhi 9821e49
Merge branch 'main' of github.com:ls1intum/edutelligence into iris/fe…
toukhi 1d76ced
improve large-model detection
toukhi 12de91f
Remove should_post_directly
toukhi bc6dd4f
Merge branch 'main' into iris/feature/calculate-verbalized-confidence
Senan04 2991d8d
Merge branch 'main' into iris/feature/calculate-verbalized-confidence
toukhi a64e37d
Merge branch 'main' into iris/feature/calculate-verbalized-confidence
toukhi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
iris/src/iris/pipeline/prompts/templates/autonomous_tutor_confidence_basic.j2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| {# Confidence scoring addon — basic_probscore method (Yang et al. 2024) for small models. | ||
| This section is appended to the main system prompt. #} | ||
| --- | ||
|
|
||
| ## Confidence Scoring | ||
|
|
||
| After your answer, state the probability between 0.0 and 1.0 that your answer is correct. | ||
|
|
||
| **Output format — you MUST follow this exactly:** | ||
|
|
||
| Answer: <your response to the student> | ||
| Probability: <a single decimal between 0.0 and 1.0> | ||
|
|
||
| Do not include any text after the Probability line. |
50 changes: 50 additions & 0 deletions
50
iris/src/iris/pipeline/prompts/templates/autonomous_tutor_confidence_combo.j2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| {# Confidence scoring addon — combo method (Yang et al. 2024) for large models. | ||
| This section is appended to the main system prompt. #} | ||
| --- | ||
|
|
||
| ## Confidence Scoring | ||
|
|
||
| Your response must include a probability that your answer is correct, expressed as a decimal between 0.0 and 1.0. | ||
|
|
||
| When assigning the probability, consider: | ||
| - **Task difficulty**: Is the question straightforward or does it require deep reasoning? | ||
| - **Knowledge availability**: Did you have access to sufficient, reliable information (via tools or training) to answer confidently? | ||
| - **Uncertainty in the question**: Is the question ambiguous or could it be interpreted in multiple ways? | ||
|
|
||
| Do not anchor on a comfortable middle value. Calibrate honestly: if you are nearly certain, use a high value; if you are mostly guessing, use a low value. | ||
|
|
||
| Here are examples of how to format your response: | ||
|
|
||
| --- | ||
| **Example 1** (very low confidence — topic outside course scope with no tool access): | ||
| Guess: I'm not sure this is covered in the course materials, but binary search trees store elements such that each node's left subtree contains only smaller values and the right subtree only larger values, enabling O(log n) average-case search. | ||
| Probability: 0.08 | ||
|
|
||
| --- | ||
| **Example 2** (low confidence — question is vague and tools returned limited information): | ||
| Guess: The submission deadline is likely the end of the semester, but I couldn't find a specific date in the course FAQ or exercise details. I recommend checking the course announcements. | ||
| Probability: 0.24 | ||
|
|
||
| --- | ||
| **Example 3** (moderate confidence — general knowledge, no direct course evidence): | ||
| Guess: The gradient descent algorithm updates model parameters by moving in the direction of the negative gradient of the loss function with respect to those parameters, scaled by a learning rate. | ||
| Probability: 0.47 | ||
|
|
||
| --- | ||
| **Example 4** (high confidence — answered from retrieved lecture content): | ||
| Guess: According to the lecture slides, a mutex (mutual exclusion lock) ensures that only one thread can access a critical section at a time, preventing race conditions. | ||
| Probability: 0.77 | ||
|
|
||
| --- | ||
| **Example 5** (very high confidence — directly found in course FAQ): | ||
| Guess: Yes, you can submit up to 3 days late with a 10% penalty per day, as stated in the course FAQ. | ||
| Probability: 0.89 | ||
|
|
||
| --- | ||
|
|
||
| **Output format — you MUST follow this exactly:** | ||
|
|
||
| Guess: <your best response to the student> | ||
| Probability: <a single decimal between 0.0 and 1.0> | ||
|
|
||
| Do not include any text after the Probability line. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| import re | ||
|
|
||
| _LARGE_MODEL_FAMILIES = ("gpt-4", "gpt-5", "gpt-oss") | ||
|
|
||
| _SIZE_TOKEN_RE = re.compile(r"(\d+)\s*b\b", re.IGNORECASE) | ||
|
|
||
| _ANSWER_PREFIX_RE = re.compile( | ||
| r"^(?:answer|guess)\s*:\s*", | ||
| re.IGNORECASE, | ||
| ) | ||
|
|
||
| _PROBABILITY_LINE_RE = re.compile( | ||
| r"(?:probability|confidence|p)\s*:\s*(-?\d+(?:\.\d+)?)(\s*%)?", | ||
| re.IGNORECASE, | ||
| ) | ||
|
|
||
|
|
||
| def is_large_model(model_id: str) -> bool: | ||
| """Return True if the model should use the combo confidence prompt. | ||
|
|
||
| A model is considered large when: | ||
| - It belongs to a known large-model family (GPT-4, GPT-5, gpt-oss), OR | ||
| - Its name contains a numeric parameter size ≥ 32 followed by "b" | ||
| (e.g. "llama-3-70b", "codellama-34b", "mixtral-65b-instruct"). | ||
| Everything else is treated as small. | ||
| """ | ||
| lower = model_id.lower() | ||
|
|
||
| if any(family in lower for family in _LARGE_MODEL_FAMILIES): | ||
| return True | ||
|
|
||
| for match in _SIZE_TOKEN_RE.finditer(lower): | ||
| if int(match.group(1)) >= 32: | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
|
|
||
| def parse_confidence_response(raw_response: str) -> tuple[str, float]: | ||
| """Extract (answer_text, probability) from a verbalized confidence response. | ||
|
|
||
| Handles both large-model format (Guess: ... / Probability: ...) and | ||
| small-model format (Answer: ... / Probability: ...). Also accepts | ||
| "Confidence:" and "P:" as alternatives to "Probability:", and values | ||
| expressed as percentages (e.g. "85%" → 0.85). The probability is | ||
| clamped to [0.0, 1.0]. | ||
|
|
||
| If parsing fails for any reason this function returns (raw_response, 0.0) | ||
| so that callers never receive an exception. A score of 0.0 will be | ||
| treated as below threshold and discarded by Artemis. | ||
| """ | ||
| try: | ||
| lines = raw_response.strip().splitlines() | ||
|
|
||
| # Find the last line that matches a probability pattern. | ||
| prob_line_index = None | ||
| probability = 0.0 | ||
| for i in range(len(lines) - 1, -1, -1): | ||
| m = _PROBABILITY_LINE_RE.search(lines[i]) | ||
| if m: | ||
| prob_line_index = i | ||
| raw_value = float(m.group(1)) | ||
| is_percent = bool(m.group(2) and m.group(2).strip() == "%") | ||
| if is_percent: | ||
| probability = raw_value / 100.0 | ||
| else: | ||
| probability = raw_value | ||
| probability = max(0.0, min(1.0, probability)) | ||
| break | ||
|
|
||
| if prob_line_index is None: | ||
| # No probability line found — safe fallback. | ||
| return raw_response, 0.0 | ||
|
|
||
| # Everything before the probability line is the answer block. | ||
| answer_lines = lines[:prob_line_index] | ||
|
|
||
| # Strip the "Answer:" / "Guess:" prefix from the first line if present. | ||
| if answer_lines: | ||
| answer_lines[0] = _ANSWER_PREFIX_RE.sub("", answer_lines[0]) | ||
|
|
||
| answer_text = "\n".join(answer_lines).strip() | ||
|
|
||
| # If nothing is left after stripping, fall back to the raw response. | ||
| if not answer_text: | ||
| answer_text = raw_response | ||
|
|
||
| return answer_text, probability | ||
|
|
||
| except Exception: # pylint: disable=broad-except | ||
| return raw_response, 0.0 | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Probability parsing is too permissive and can misread normal answer text as confidence.
Using an unanchored regex with
search()means any trailingp: <number>inside ordinary text can be parsed as confidence, which may inflateshould_post_directlydecisions.Proposed fix
Also applies to: 55-56
🤖 Prompt for AI Agents