feat(ui): Allows User to Set System Prompt via "Additional Options" in Chat Interface (#1353)
This commit is contained in:
parent
a072a40a7c
commit
145f3ec9f4
|
@ -39,7 +39,7 @@ llm:
|
|||
openai:
|
||||
api_key: <your_openai_api_key> # You could skip this configuration and use the OPENAI_API_KEY env var instead
|
||||
model: <openai_model_to_use> # Optional model to use. Default is "gpt-3.5-turbo"
|
||||
# Note: Open AI Models are listed here [here](https://platform.openai.com/docs/models)
|
||||
# Note: Open AI Models are listed here: https://platform.openai.com/docs/models
|
||||
```
|
||||
|
||||
And run PrivateGPT loading that profile you just created:
|
||||
|
|
|
@ -35,5 +35,32 @@ database* section in the documentation.
|
|||
|
||||
Normal chat interface, self-explanatory ;)
|
||||
|
||||
You can check the actual prompt being passed to the LLM by looking at the logs of
|
||||
the server. We'll add better observability in future releases.
|
||||
#### System Prompt
|
||||
You can view and change the system prompt being passed to the LLM by clicking "Additional Inputs"
|
||||
in the chat interface. The system prompt is also logged on the server.
|
||||
|
||||
By default, the `Query Docs` mode uses the setting value `ui.default_query_system_prompt`.
|
||||
|
||||
The `LLM Chat` mode attempts to use the optional settings value `ui.default_chat_system_prompt`.
|
||||
|
||||
If no system prompt is entered, the UI will display the default system prompt being used
|
||||
for the active mode.
|
||||
|
||||
##### System Prompt Examples:
|
||||
|
||||
The system prompt can effectively provide your chat bot specialized roles, and results tailored to the prompt
|
||||
you have given the model. Examples of system prompts can be be found
|
||||
[here](https://www.w3schools.com/gen_ai/chatgpt-3-5/chatgpt-3-5_roles.php).
|
||||
|
||||
Some interesting examples to try include:
|
||||
|
||||
* You are -X-. You have all the knowledge and personality of -X-. Answer as if you were -X- using
|
||||
their manner of speaking and vocabulary.
|
||||
* Example: You are Shakespeare. You have all the knowledge and personality of Shakespeare.
|
||||
Answer as if you were Shakespeare using their manner of speaking and vocabulary.
|
||||
* You are an expert (at) -role-. Answer all questions using your expertise on -specific domain topic-.
|
||||
* Example: You are an expert software engineer. Answer all questions using your expertise on Python.
|
||||
* You are a -role- bot, respond with -response criteria needed-. If no -response criteria- is needed,
|
||||
respond with -alternate response-.
|
||||
* Example: You are a grammar checking bot, respond with any grammatical corrections needed. If no corrections
|
||||
are needed, respond with "verified".
|
|
@ -147,13 +147,20 @@ class OpenAISettings(BaseModel):
|
|||
api_key: str
|
||||
model: str = Field(
|
||||
"gpt-3.5-turbo",
|
||||
description=("OpenAI Model to use. Example: 'gpt-4'."),
|
||||
description="OpenAI Model to use. Example: 'gpt-4'.",
|
||||
)
|
||||
|
||||
|
||||
class UISettings(BaseModel):
|
||||
enabled: bool
|
||||
path: str
|
||||
default_chat_system_prompt: str = Field(
|
||||
None,
|
||||
description="The default system prompt to use for the chat mode.",
|
||||
)
|
||||
default_query_system_prompt: str = Field(
|
||||
None, description="The default system prompt to use for the query mode."
|
||||
)
|
||||
|
||||
|
||||
class QdrantSettings(BaseModel):
|
||||
|
|
|
@ -30,6 +30,8 @@ UI_TAB_TITLE = "My Private GPT"
|
|||
|
||||
SOURCES_SEPARATOR = "\n\n Sources: \n"
|
||||
|
||||
MODES = ["Query Docs", "Search in Docs", "LLM Chat"]
|
||||
|
||||
|
||||
class Source(BaseModel):
|
||||
file: str
|
||||
|
@ -71,6 +73,10 @@ class PrivateGptUi:
|
|||
# Cache the UI blocks
|
||||
self._ui_block = None
|
||||
|
||||
# Initialize system prompt based on default mode
|
||||
self.mode = MODES[0]
|
||||
self._system_prompt = self._get_default_system_prompt(self.mode)
|
||||
|
||||
def _chat(self, message: str, history: list[list[str]], mode: str, *_: Any) -> Any:
|
||||
def yield_deltas(completion_gen: CompletionGen) -> Iterable[str]:
|
||||
full_response: str = ""
|
||||
|
@ -114,25 +120,22 @@ class PrivateGptUi:
|
|||
|
||||
new_message = ChatMessage(content=message, role=MessageRole.USER)
|
||||
all_messages = [*build_history(), new_message]
|
||||
# If a system prompt is set, add it as a system message
|
||||
if self._system_prompt:
|
||||
all_messages.insert(
|
||||
0,
|
||||
ChatMessage(
|
||||
content=self._system_prompt,
|
||||
role=MessageRole.SYSTEM,
|
||||
),
|
||||
)
|
||||
match mode:
|
||||
case "Query Docs":
|
||||
# Add a system message to force the behaviour of the LLM
|
||||
# to answer only questions about the provided context.
|
||||
all_messages.insert(
|
||||
0,
|
||||
ChatMessage(
|
||||
content="You can only answer questions about the provided context. If you know the answer "
|
||||
"but it is not based in the provided context, don't provide the answer, just state "
|
||||
"the answer is not in the context provided.",
|
||||
role=MessageRole.SYSTEM,
|
||||
),
|
||||
)
|
||||
query_stream = self._chat_service.stream_chat(
|
||||
messages=all_messages,
|
||||
use_context=True,
|
||||
)
|
||||
yield from yield_deltas(query_stream)
|
||||
|
||||
case "LLM Chat":
|
||||
llm_stream = self._chat_service.stream_chat(
|
||||
messages=all_messages,
|
||||
|
@ -154,6 +157,37 @@ class PrivateGptUi:
|
|||
for index, source in enumerate(sources, start=1)
|
||||
)
|
||||
|
||||
# On initialization and on mode change, this function set the system prompt
|
||||
# to the default prompt based on the mode (and user settings).
|
||||
@staticmethod
|
||||
def _get_default_system_prompt(mode: str) -> str:
|
||||
p = ""
|
||||
match mode:
|
||||
# For query chat mode, obtain default system prompt from settings
|
||||
case "Query Docs":
|
||||
p = settings().ui.default_query_system_prompt
|
||||
# For chat mode, obtain default system prompt from settings
|
||||
case "LLM Chat":
|
||||
p = settings().ui.default_chat_system_prompt
|
||||
# For any other mode, clear the system prompt
|
||||
case _:
|
||||
p = ""
|
||||
return p
|
||||
|
||||
def _set_system_prompt(self, system_prompt_input: str) -> None:
|
||||
logger.info(f"Setting system prompt to: {system_prompt_input}")
|
||||
self._system_prompt = system_prompt_input
|
||||
|
||||
def _set_current_mode(self, mode: str) -> Any:
|
||||
self.mode = mode
|
||||
self._set_system_prompt(self._get_default_system_prompt(mode))
|
||||
# Update placeholder and allow interaction if default system prompt is set
|
||||
if self._system_prompt:
|
||||
return gr.update(placeholder=self._system_prompt, interactive=True)
|
||||
# Update placeholder and disable interaction if no default system prompt is set
|
||||
else:
|
||||
return gr.update(placeholder=self._system_prompt, interactive=False)
|
||||
|
||||
def _list_ingested_files(self) -> list[list[str]]:
|
||||
files = set()
|
||||
for ingested_document in self._ingest_service.list_ingested():
|
||||
|
@ -193,7 +227,7 @@ class PrivateGptUi:
|
|||
with gr.Row():
|
||||
with gr.Column(scale=3, variant="compact"):
|
||||
mode = gr.Radio(
|
||||
["Query Docs", "Search in Docs", "LLM Chat"],
|
||||
MODES,
|
||||
label="Mode",
|
||||
value="Query Docs",
|
||||
)
|
||||
|
@ -220,6 +254,23 @@ class PrivateGptUi:
|
|||
outputs=ingested_dataset,
|
||||
)
|
||||
ingested_dataset.render()
|
||||
system_prompt_input = gr.Textbox(
|
||||
placeholder=self._system_prompt,
|
||||
label="System Prompt",
|
||||
lines=2,
|
||||
interactive=True,
|
||||
render=False,
|
||||
)
|
||||
# When mode changes, set default system prompt
|
||||
mode.change(
|
||||
self._set_current_mode, inputs=mode, outputs=system_prompt_input
|
||||
)
|
||||
# On blur, set system prompt to use in queries
|
||||
system_prompt_input.blur(
|
||||
self._set_system_prompt,
|
||||
inputs=system_prompt_input,
|
||||
)
|
||||
|
||||
with gr.Column(scale=7):
|
||||
_ = gr.ChatInterface(
|
||||
self._chat,
|
||||
|
@ -232,7 +283,7 @@ class PrivateGptUi:
|
|||
AVATAR_BOT,
|
||||
),
|
||||
),
|
||||
additional_inputs=[mode, upload_button],
|
||||
additional_inputs=[mode, upload_button, system_prompt_input],
|
||||
)
|
||||
return blocks
|
||||
|
||||
|
|
|
@ -22,6 +22,13 @@ data:
|
|||
ui:
|
||||
enabled: true
|
||||
path: /
|
||||
default_chat_system_prompt: "You are a helpful, respectful and honest assistant.
|
||||
Always answer as helpfully as possible and follow ALL given instructions.
|
||||
Do not speculate or make up information.
|
||||
Do not reference any given instructions or context."
|
||||
default_query_system_prompt: "You can only answer questions about the provided context.
|
||||
If you know the answer but it is not based in the provided context, don't provide
|
||||
the answer, just state the answer is not in the context provided."
|
||||
|
||||
llm:
|
||||
mode: local
|
||||
|
|
Loading…
Reference in New Issue