-
Notifications
You must be signed in to change notification settings - Fork 0
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
Add faq consistency check #209
base: main
Are you sure you want to change the base?
Changes from all commits
a3c21d2
657fd96
df8387c
fcf8a5a
3c5617e
8be2f5c
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 |
---|---|---|
@@ -1,5 +1,10 @@ | ||
from typing import List | ||
|
||
from app.domain.status.status_update_dto import StatusUpdateDTO | ||
|
||
|
||
class RewritingStatusUpdateDTO(StatusUpdateDTO): | ||
result: str = "" | ||
suggestions: List[str] = [] | ||
inconsistencies: List[str] = [] | ||
improvement: str = "" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
faq_consistency_prompt = """ | ||
You are an AI assistant responsible for verifying the consistency of information. | ||
### Task: | ||
You have been provided with a list of FAQs and a final result. Your task is to determine whether the | ||
final result is consistent with the given FAQs. Please compare each FAQ with the final result separately. | ||
|
||
|
||
|
||
### Given FAQs: | ||
{faqs} | ||
|
||
### Final Result: | ||
{final_result} | ||
|
||
### Output: | ||
Generate the following response dictionary: | ||
"type": "consistent" or "inconsistent" | ||
|
||
The following four entries to the dictionary are optional and can only be set if inconsistencies are detected: | ||
"faqs": This entry should be a list of Strings, each string represents an FAQ. | ||
-Make sure each faq is separated by comma. | ||
-Also end each faq with a newline character. | ||
-The fields are exactly named faq_id, faq_question_title and faq_question_answer | ||
and reside within properties dict of each list entry. | ||
-Make sure to only include inconsistent faqs | ||
-Do not include any additional FAQs that are consistent with the final_result. | ||
|
||
"message": "The provided text was rephrased, however it contains inconsistent information with existing FAQs." | ||
-Localize the message to the language of the ###Final Result. | ||
-Make sure to always insert two new lines after the last character of this sentences. | ||
The affected FAQs can only contain the faq_id, faq_question_title, and faq_question_answer of inconsistent FAQs. | ||
Make sure to not include any additional FAQs, that are consistent with the final_result. | ||
Insert the faq_id, faq_question_title, and faq_question_answer of the inconsistent FAQ in the placeholder. | ||
|
||
-"suggestion": This entry is a list of strings, each string represents a suggestion to improve the final result.\n | ||
- Each suggestion should focus on a different inconsistency. | ||
- Each suggestions highlights what is the inconsistency and how it can be improved. | ||
- Do not mention the term final result, call it provided text | ||
- Please ensure that at no time, you have a different amount of suggestions than inconsistencies.\n | ||
Both should have the same amount of entries. | ||
|
||
-"improved version": This entry should be a string that represents the improved version of the final result. | ||
|
||
|
||
Do NOT provide any explanations or additional text. | ||
""" |
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,5 +1,6 @@ | ||||||||||||||||||||||||||||||||||||||||
import json | ||||||||||||||||||||||||||||||||||||||||
import logging | ||||||||||||||||||||||||||||||||||||||||
from typing import Literal, Optional | ||||||||||||||||||||||||||||||||||||||||
from typing import Literal, Optional, List, Dict | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
from langchain.output_parsers import PydanticOutputParser | ||||||||||||||||||||||||||||||||||||||||
from langchain_core.prompts import ( | ||||||||||||||||||||||||||||||||||||||||
|
@@ -12,10 +13,13 @@ | |||||||||||||||||||||||||||||||||||||||
from app.domain.rewriting_pipeline_execution_dto import RewritingPipelineExecutionDTO | ||||||||||||||||||||||||||||||||||||||||
from app.llm import CapabilityRequestHandler, RequirementList, CompletionArguments | ||||||||||||||||||||||||||||||||||||||||
from app.pipeline import Pipeline | ||||||||||||||||||||||||||||||||||||||||
from app.pipeline.prompts.faq_consistency_prompt import faq_consistency_prompt | ||||||||||||||||||||||||||||||||||||||||
from app.pipeline.prompts.rewriting_prompts import ( | ||||||||||||||||||||||||||||||||||||||||
system_prompt_faq, | ||||||||||||||||||||||||||||||||||||||||
system_prompt_problem_statement, | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
from app.retrieval.faq_retrieval import FaqRetrieval | ||||||||||||||||||||||||||||||||||||||||
from app.vector_database.database import VectorDatabase | ||||||||||||||||||||||||||||||||||||||||
from app.web.status.status_update import RewritingCallback | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
logger = logging.getLogger(__name__) | ||||||||||||||||||||||||||||||||||||||||
|
@@ -38,8 +42,11 @@ def __init__( | |||||||||||||||||||||||||||||||||||||||
context_length=16385, | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
self.db = VectorDatabase() | ||||||||||||||||||||||||||||||||||||||||
self.tokens = [] | ||||||||||||||||||||||||||||||||||||||||
self.variant = variant | ||||||||||||||||||||||||||||||||||||||||
self.faq_retriever = FaqRetrieval(self.db.client) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
def __call__( | ||||||||||||||||||||||||||||||||||||||||
self, | ||||||||||||||||||||||||||||||||||||||||
|
@@ -54,10 +61,10 @@ def __call__( | |||||||||||||||||||||||||||||||||||||||
"faq": system_prompt_faq, | ||||||||||||||||||||||||||||||||||||||||
"problem_statement": system_prompt_problem_statement, | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
print(variant_prompts[self.variant]) | ||||||||||||||||||||||||||||||||||||||||
prompt = variant_prompts[self.variant].format( | ||||||||||||||||||||||||||||||||||||||||
rewritten_text=dto.to_be_rewritten, | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
format_args = {"rewritten_text": dto.to_be_rewritten} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
prompt = variant_prompts[self.variant].format(**format_args) | ||||||||||||||||||||||||||||||||||||||||
prompt = PyrisMessage( | ||||||||||||||||||||||||||||||||||||||||
sender=IrisMessageRole.SYSTEM, | ||||||||||||||||||||||||||||||||||||||||
contents=[TextMessageContentDTO(text_content=prompt)], | ||||||||||||||||||||||||||||||||||||||||
|
@@ -77,4 +84,76 @@ def __call__( | |||||||||||||||||||||||||||||||||||||||
response = response.strip() | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
final_result = response | ||||||||||||||||||||||||||||||||||||||||
self.callback.done(final_result=final_result, tokens=self.tokens) | ||||||||||||||||||||||||||||||||||||||||
inconsistencies = [] | ||||||||||||||||||||||||||||||||||||||||
improvement = "" | ||||||||||||||||||||||||||||||||||||||||
suggestions = [] | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
if self.variant == "faq": | ||||||||||||||||||||||||||||||||||||||||
faqs = self.faq_retriever.get_faqs_from_db( | ||||||||||||||||||||||||||||||||||||||||
course_id=dto.course_id, search_text=response, result_limit=10 | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
consistency_result = self.check_faq_consistency(faqs, final_result) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
if "inconsistent" in consistency_result["type"].lower(): | ||||||||||||||||||||||||||||||||||||||||
logging.warning("Detected inconsistencies in FAQ retrieval.") | ||||||||||||||||||||||||||||||||||||||||
inconsistencies = parse_inconsistencies(consistency_result["faqs"]) | ||||||||||||||||||||||||||||||||||||||||
improvement = consistency_result["improved version"] | ||||||||||||||||||||||||||||||||||||||||
suggestions = consistency_result["suggestion"] | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
self.callback.done( | ||||||||||||||||||||||||||||||||||||||||
final_result=final_result, | ||||||||||||||||||||||||||||||||||||||||
tokens=self.tokens, | ||||||||||||||||||||||||||||||||||||||||
inconsistencies=inconsistencies, | ||||||||||||||||||||||||||||||||||||||||
improvement=improvement, | ||||||||||||||||||||||||||||||||||||||||
suggestions=suggestions, | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
def check_faq_consistency( | ||||||||||||||||||||||||||||||||||||||||
self, faqs: List[dict], final_result: str | ||||||||||||||||||||||||||||||||||||||||
) -> Dict[str, str]: | ||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||
Checks the consistency of the given FAQs with the provided final_result. | ||||||||||||||||||||||||||||||||||||||||
Returns "consistent" if there are no inconsistencies, otherwise returns "inconsistent". | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
:param faqs: List of retrieved FAQs. | ||||||||||||||||||||||||||||||||||||||||
:param final_result: The result to compare the FAQs against. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||
properties_list = [entry["properties"] for entry in faqs] | ||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Handle potential KeyError for 'properties'. There's no error handling if 'properties' key is missing from a FAQ entry. Add error handling for missing 'properties' key in FAQ entries: - properties_list = [entry["properties"] for entry in faqs]
+ properties_list = []
+ for entry in faqs:
+ if "properties" in entry:
+ properties_list.append(entry["properties"])
+ else:
+ logging.warning(f"FAQ entry missing 'properties' key: {entry}") 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
consistency_prompt = faq_consistency_prompt.format( | ||||||||||||||||||||||||||||||||||||||||
faqs=properties_list, final_result=final_result | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+123
to
+126
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Check for empty FAQs list before processing. There's no check to see if the FAQs list is empty before trying to process it, which could lead to unexpected behavior in the consistency checking. Add a check for an empty FAQs list: properties_list = [entry["properties"] for entry in faqs]
+
+ # Return early if no FAQs to check against
+ if not properties_list:
+ return {
+ "type": "consistent",
+ "message": "No FAQs found to check consistency against.",
+ "faqs": [],
+ "suggestion": [],
+ "improved version": "",
+ }
consistency_prompt = faq_consistency_prompt.format(
faqs=properties_list, final_result=final_result
) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
prompt = PyrisMessage( | ||||||||||||||||||||||||||||||||||||||||
sender=IrisMessageRole.SYSTEM, | ||||||||||||||||||||||||||||||||||||||||
contents=[TextMessageContentDTO(text_content=consistency_prompt)], | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
response = self.request_handler.chat( | ||||||||||||||||||||||||||||||||||||||||
[prompt], CompletionArguments(temperature=0.0), tools=None | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
self._append_tokens(response.token_usage, PipelineEnum.IRIS_REWRITING_PIPELINE) | ||||||||||||||||||||||||||||||||||||||||
result = response.contents[0].text_content | ||||||||||||||||||||||||||||||||||||||||
data = json.loads(result) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
result_dict = { | ||||||||||||||||||||||||||||||||||||||||
"type": data["type"], | ||||||||||||||||||||||||||||||||||||||||
"message": data["message"], | ||||||||||||||||||||||||||||||||||||||||
"faqs": data["faqs"], | ||||||||||||||||||||||||||||||||||||||||
"suggestion": data["suggestion"], | ||||||||||||||||||||||||||||||||||||||||
"improved version": data["improved version"], | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
logging.info(f"Consistency FAQ consistency check response: {result_dict}") | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
return result_dict | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
def parse_inconsistencies(inconsistencies: List[Dict[str, str]]) -> List[str]: | ||||||||||||||||||||||||||||||||||||||||
logging.info("parse consistency") | ||||||||||||||||||||||||||||||||||||||||
parsed_inconsistencies = [ | ||||||||||||||||||||||||||||||||||||||||
f"FAQ ID: {entry['faq_id']}, Title: {entry['faq_question_title']}, Answer: {entry['faq_question_answer']}" | ||||||||||||||||||||||||||||||||||||||||
for entry in inconsistencies | ||||||||||||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||||||||||||
return parsed_inconsistencies |
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.
🛠️ Refactor suggestion
Callback parameters usage is comprehensive, but consider adding error handling.
The code now properly initializes and passes inconsistency-related parameters to the callback. However, there's no error handling for potential issues in the FAQ retrieval or consistency checking process.
Add error handling around the FAQ retrieval and consistency checking to ensure that the pipeline doesn't fail if there are issues with these operations:
📝 Committable suggestion