Spaces:
Runtime error
Runtime error
"""Evaluating the responses from an index.""" | |
from __future__ import annotations | |
from typing import List, Optional | |
from gpt_index import ( | |
Document, | |
GPTListIndex, | |
QuestionAnswerPrompt, | |
RefinePrompt, | |
Response, | |
ServiceContext, | |
) | |
DEFAULT_EVAL_PROMPT = ( | |
"Please tell if a given piece of information " | |
"is supported by the context.\n" | |
"You need to answer with either YES or NO.\n" | |
"Answer YES if any of the context supports the information, even " | |
"if most of the context is unrelated. " | |
"Some examples are provided below. \n\n" | |
"Information: Apple pie is generally double-crusted.\n" | |
"Context: An apple pie is a fruit pie in which the principal filling " | |
"ingredient is apples. \n" | |
"Apple pie is often served with whipped cream, ice cream " | |
"('apple pie à la mode'), custard or cheddar cheese.\n" | |
"It is generally double-crusted, with pastry both above " | |
"and below the filling; the upper crust may be solid or " | |
"latticed (woven of crosswise strips).\n" | |
"Answer: YES\n" | |
"Information: Apple pies tastes bad.\n" | |
"Context: An apple pie is a fruit pie in which the principal filling " | |
"ingredient is apples. \n" | |
"Apple pie is often served with whipped cream, ice cream " | |
"('apple pie à la mode'), custard or cheddar cheese.\n" | |
"It is generally double-crusted, with pastry both above " | |
"and below the filling; the upper crust may be solid or " | |
"latticed (woven of crosswise strips).\n" | |
"Answer: NO\n" | |
"Information: {query_str}\n" | |
"Context: {context_str}\n" | |
"Answer: " | |
) | |
DEFAULT_REFINE_PROMPT = ( | |
"We want to understand if the following information is present " | |
"in the context information: {query_str}\n" | |
"We have provided an existing YES/NO answer: {existing_answer}\n" | |
"We have the opportunity to refine the existing answer " | |
"(only if needed) with some more context below.\n" | |
"------------\n" | |
"{context_msg}\n" | |
"------------\n" | |
"If the existing answer was already YES, still answer YES. " | |
"If the information is present in the new context, answer YES. " | |
"Otherwise answer NO.\n" | |
) | |
QUERY_RESPONSE_EVAL_PROMPT = ( | |
"Your task is to evaluate if the response for the query \ | |
is in line with the context information provided.\n" | |
"You have two options to answer. Either YES/ NO.\n" | |
"Answer - YES, if the response for the query \ | |
is in line with context information otherwise NO.\n" | |
"Query and Response: \n {query_str}\n" | |
"Context: \n {context_str}\n" | |
"Answer: " | |
) | |
QUERY_RESPONSE_REFINE_PROMPT = ( | |
"We want to understand if the following query and response is" | |
"in line with the context information: \n {query_str}\n" | |
"We have provided an existing YES/NO answer: \n {existing_answer}\n" | |
"We have the opportunity to refine the existing answer " | |
"(only if needed) with some more context below.\n" | |
"------------\n" | |
"{context_msg}\n" | |
"------------\n" | |
"If the existing answer was already YES, still answer YES. " | |
"If the information is present in the new context, answer YES. " | |
"Otherwise answer NO.\n" | |
) | |
class ResponseEvaluator: | |
"""Evaluate based on response from indices. | |
NOTE: this is a beta feature, subject to change! | |
Args: | |
service_context (Optional[ServiceContext]): ServiceContext object | |
""" | |
def __init__( | |
self, | |
service_context: Optional[ServiceContext] = None, | |
) -> None: | |
"""Init params.""" | |
self.service_context = service_context or ServiceContext.from_defaults() | |
def get_context(self, response: Response) -> List[Document]: | |
"""Get context information from given Response object using source nodes. | |
Args: | |
response (Response): Response object from an index based on the query. | |
Returns: | |
List of Documents of source nodes information as context information. | |
""" | |
context = [] | |
for context_info in response.source_nodes: | |
context.append(Document(context_info.source_text)) | |
return context | |
def evaluate(self, response: Response) -> str: | |
"""Evaluate the response from an index. | |
Args: | |
query: Query for which response is generated from index. | |
response: Response object from an index based on the query. | |
Returns: | |
Yes -> If answer, context information are matching \ | |
or If Query, answer and context information are matching. | |
No -> If answer, context information are not matching \ | |
or If Query, answer and context information are not matching. | |
""" | |
answer = str(response) | |
context = self.get_context(response) | |
index = GPTListIndex.from_documents( | |
context, service_context=self.service_context | |
) | |
response_txt: str = "" | |
EVAL_PROMPT_TMPL = QuestionAnswerPrompt(DEFAULT_EVAL_PROMPT) | |
REFINE_PROMPT_TMPL = RefinePrompt(DEFAULT_REFINE_PROMPT) | |
response_obj = index.query( | |
answer, | |
text_qa_template=EVAL_PROMPT_TMPL, | |
refine_template=REFINE_PROMPT_TMPL, | |
) | |
response_txt = str(response_obj) | |
return response_txt | |
class QueryResponseEvaluator: | |
"""Evaluate based on query and response from indices. | |
NOTE: this is a beta feature, subject to change! | |
Args: | |
service_context (Optional[ServiceContext]): ServiceContext object | |
""" | |
def __init__( | |
self, | |
service_context: Optional[ServiceContext] = None, | |
) -> None: | |
"""Init params.""" | |
self.service_context = service_context or ServiceContext.from_defaults() | |
def get_context(self, response: Response) -> List[Document]: | |
"""Get context information from given Response object using source nodes. | |
Args: | |
response (Response): Response object from an index based on the query. | |
Returns: | |
List of Documents of source nodes information as context information. | |
""" | |
context = [] | |
for context_info in response.source_nodes: | |
context.append(Document(context_info.source_text)) | |
return context | |
def evaluate(self, query: str, response: Response) -> str: | |
"""Evaluate the response from an index. | |
Args: | |
query: Query for which response is generated from index. | |
response: Response object from an index based on the query. | |
Returns: | |
Yes -> If answer, context information are matching \ | |
or If Query, answer and context information are matching. | |
No -> If answer, context information are not matching \ | |
or If Query, answer and context information are not matching. | |
""" | |
answer = str(response) | |
context = self.get_context(response) | |
index = GPTListIndex.from_documents( | |
context, service_context=self.service_context | |
) | |
response_txt: str = "" | |
QUERY_RESPONSE_EVAL_PROMPT_TMPL = QuestionAnswerPrompt( | |
QUERY_RESPONSE_EVAL_PROMPT | |
) | |
QUERY_RESPONSE_REFINE_PROMPT_TMPL = RefinePrompt(QUERY_RESPONSE_REFINE_PROMPT) | |
query_response = f"Question: {query}\nResponse: {answer}" | |
response_obj = index.query( | |
query_response, | |
text_qa_template=QUERY_RESPONSE_EVAL_PROMPT_TMPL, | |
refine_template=QUERY_RESPONSE_REFINE_PROMPT_TMPL, | |
) | |
response_txt = str(response_obj) | |
return response_txt | |