-
Notifications
You must be signed in to change notification settings - Fork 5k
Use prompty to store prompts #2178
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
f69861d
eda6292
e25468c
4063767
c78ffed
6fac970
adf0353
ff40caa
04b2254
3a6152b
3b3f163
e42d0d0
b4ccc08
4cfd7ca
fa958df
4ef717c
37d9346
a507438
e413978
890b8ad
794730d
962791a
9492378
c46cb42
adba0c7
06df17f
753f9a7
f088bdc
ca4d37b
8354c93
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 |
---|---|---|
|
@@ -24,8 +24,8 @@ | |
from openai import AsyncOpenAI | ||
from openai.types.chat import ChatCompletionMessageParam | ||
|
||
from approaches.promptmanager import PromptManager | ||
from core.authentication import AuthenticationHelper | ||
from text import nonewlines | ||
|
||
|
||
@dataclass | ||
|
@@ -109,6 +109,7 @@ def __init__( | |
openai_host: str, | ||
vision_endpoint: str, | ||
vision_token_provider: Callable[[], Awaitable[str]], | ||
prompt_manager: PromptManager, | ||
): | ||
self.search_client = search_client | ||
self.openai_client = openai_client | ||
|
@@ -121,6 +122,7 @@ def __init__( | |
self.openai_host = openai_host | ||
self.vision_endpoint = vision_endpoint | ||
self.vision_token_provider = vision_token_provider | ||
self.prompt_manager = prompt_manager | ||
|
||
def build_filter(self, overrides: dict[str, Any], auth_claims: dict[str, Any]) -> Optional[str]: | ||
include_category = overrides.get("include_category") | ||
|
@@ -205,6 +207,10 @@ async def search( | |
def get_sources_content( | ||
self, results: List[Document], use_semantic_captions: bool, use_image_citation: bool | ||
) -> list[str]: | ||
|
||
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. I moved this function out of text.py since it was a 2-line file, and the function is only used in this one method. |
||
def nonewlines(s: str) -> str: | ||
return s.replace("\n", " ").replace("\r", " ") | ||
|
||
if use_semantic_captions: | ||
return [ | ||
(self.get_citation((doc.sourcepage or ""), use_image_citation)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
|
||
from approaches.approach import ThoughtStep | ||
from approaches.chatapproach import ChatApproach | ||
from approaches.promptmanager import PromptManager | ||
from core.authentication import AuthenticationHelper | ||
|
||
|
||
|
@@ -38,6 +39,7 @@ def __init__( | |
content_field: str, | ||
query_language: str, | ||
query_speller: str, | ||
prompt_manager: PromptManager | ||
): | ||
self.search_client = search_client | ||
self.openai_client = openai_client | ||
|
@@ -52,16 +54,10 @@ def __init__( | |
self.query_language = query_language | ||
self.query_speller = query_speller | ||
self.chatgpt_token_limit = get_token_limit(chatgpt_model, default_to_minimum=self.ALLOW_NON_GPT_MODELS) | ||
|
||
@property | ||
def system_message_chat_conversation(self): | ||
return """Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers. | ||
Answer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question. | ||
If the question is not in English, answer in the language used in the question. | ||
Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brackets to reference the source, for example [info1.txt]. Don't combine sources, list each source separately, for example [info1.txt][info2.pdf]. | ||
{follow_up_questions_prompt} | ||
{injected_prompt} | ||
""" | ||
self.prompt_manager = prompt_manager | ||
self.query_rewrite_prompt = self.prompt_manager.load_prompt("chat_query_rewrite.prompty") | ||
self.query_rewrite_tools = self.prompt_manager.load_tools("chat_query_rewrite_tools.json") | ||
self.answer_prompt = self.prompt_manager.load_prompt("chat_answer_question.prompty") | ||
|
||
@overload | ||
async def run_until_final_call( | ||
|
@@ -101,37 +97,21 @@ async def run_until_final_call( | |
original_user_query = messages[-1]["content"] | ||
if not isinstance(original_user_query, str): | ||
raise ValueError("The most recent message content must be a string.") | ||
user_query_request = "Generate search query for: " + original_user_query | ||
|
||
tools: List[ChatCompletionToolParam] = [ | ||
{ | ||
"type": "function", | ||
"function": { | ||
"name": "search_sources", | ||
"description": "Retrieve sources from the Azure AI Search index", | ||
"parameters": { | ||
"type": "object", | ||
"properties": { | ||
"search_query": { | ||
"type": "string", | ||
"description": "Query string to retrieve documents from azure search eg: 'Health care plan'", | ||
} | ||
}, | ||
"required": ["search_query"], | ||
}, | ||
}, | ||
} | ||
] | ||
|
||
rendered_query_prompt = self.prompt_manager.render_prompt( | ||
self.query_rewrite_prompt, {"user_query": original_user_query, "past_messages": messages[:-1]} | ||
) | ||
tools: List[ChatCompletionToolParam] = self.query_rewrite_tools | ||
|
||
# STEP 1: Generate an optimized keyword search query based on the chat history and the last question | ||
query_response_token_limit = 100 | ||
query_messages = build_messages( | ||
model=self.chatgpt_model, | ||
system_prompt=self.query_prompt_template, | ||
system_prompt=rendered_query_prompt.system_content, | ||
few_shots=rendered_query_prompt.few_shot_messages, | ||
past_messages=rendered_query_prompt.past_messages, | ||
new_user_content=rendered_query_prompt.new_user_content, | ||
tools=tools, | ||
few_shots=self.query_prompt_few_shots, | ||
past_messages=messages[:-1], | ||
new_user_content=user_query_request, | ||
max_tokens=self.chatgpt_token_limit - query_response_token_limit, | ||
fallback_to_default=self.ALLOW_NON_GPT_MODELS, | ||
) | ||
|
@@ -169,32 +149,31 @@ async def run_until_final_call( | |
minimum_reranker_score, | ||
) | ||
|
||
sources_content = self.get_sources_content(results, use_semantic_captions, use_image_citation=False) | ||
content = "\n".join(sources_content) | ||
|
||
# STEP 3: Generate a contextual and content specific answer using the search results and chat history | ||
|
||
# Allow client to replace the entire prompt, or to inject into the exiting prompt using >>> | ||
system_message = self.get_system_prompt( | ||
overrides.get("prompt_template"), | ||
self.follow_up_questions_prompt_content if overrides.get("suggest_followup_questions") else "", | ||
text_sources = self.get_sources_content(results, use_semantic_captions, use_image_citation=False) | ||
rendered_answer_prompt = self.prompt_manager.render_prompt( | ||
self.answer_prompt, | ||
self.get_system_prompt_variables(overrides.get("prompt_template")) | ||
| { | ||
mattgotteiner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"include_follow_up_questions": bool(overrides.get("suggest_followup_questions")), | ||
"past_messages": messages[:-1], | ||
"user_query": original_user_query, | ||
"text_sources": text_sources, | ||
}, | ||
) | ||
|
||
response_token_limit = 1024 | ||
messages = build_messages( | ||
model=self.chatgpt_model, | ||
system_prompt=system_message, | ||
past_messages=messages[:-1], | ||
# Model does not handle lengthy system messages well. Moving sources to latest user conversation to solve follow up questions prompt. | ||
new_user_content=original_user_query + "\n\nSources:\n" + content, | ||
system_prompt=rendered_answer_prompt.system_content, | ||
past_messages=rendered_answer_prompt.past_messages, | ||
new_user_content=rendered_answer_prompt.new_user_content, | ||
max_tokens=self.chatgpt_token_limit - response_token_limit, | ||
fallback_to_default=self.ALLOW_NON_GPT_MODELS, | ||
) | ||
|
||
data_points = {"text": sources_content} | ||
|
||
extra_info = { | ||
"data_points": data_points, | ||
"data_points": {"text": text_sources}, | ||
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. I moved data_points into the dict itself, as we weren't using that variable separately anyway. |
||
"thoughts": [ | ||
ThoughtStep( | ||
"Prompt to generate search query", | ||
|
Uh oh!
There was an error while loading. Please reload this page.