Spaces:
Runtime error
Runtime error
File size: 7,590 Bytes
b699122 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
"""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
|