Skip to content

Commit 8de92c9

Browse files
committed
Centralize all model prompts in prompt_services.py
1 parent 1f1442b commit 8de92c9

11 files changed

Lines changed: 334 additions & 208 deletions

File tree

server/api/services/llm_services.py

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from abc import ABC, abstractmethod
99

1010
from openai import AsyncOpenAI
11+
from .prompt_services import LLM_EXTRACTION_INSTRUCTIONS
1112

1213

1314
class BaseModelHandler(ABC):
@@ -70,57 +71,7 @@ class GPT41NanoHandler(BaseModelHandler):
7071
# Long context performance can degrade as more items are required to be retrieved,
7172
# or perform complex reasoning that requires knowledge of the state of the entire context
7273

73-
#
74-
75-
INSTRUCTIONS = """
76-
77-
# Role and Objective
78-
79-
- You are a seasoned physician or medical professional who is developing a bipolar disorder treatment algorithim
80-
81-
- You are extracting bipolar medication decision points from a research paper that is chunked into multiple parts each labeled with an ID
82-
83-
# Instructions
84-
85-
- Identify decision points for bipolar medications
86-
87-
- For each decision point you find, return a JSON object using the following format:
88-
89-
{
90-
"criterion": "<condition or concern>",
91-
"decision": "INCLUDE" or "EXCLUDE",
92-
"medications": ["<medication 1>", "<medication 2>", ...],
93-
"reason": "<short explanation for why this criterion applies>",
94-
"sources": ["<ID-X>"]
95-
}
96-
97-
98-
- Only extract bipolar medication decision points that are explicitly stated or strongly implied in the context and never rely on your own knowledge
99-
100-
# Output Format
101-
102-
- Return the extracted bipolar medication decision points as a JSON array and if no decision points are found in the context return an empty array
103-
104-
# Example
105-
106-
[
107-
{
108-
"criterion": "History of suicide attempts",
109-
"decision": "INCLUDE",
110-
"medications": ["Lithium"],
111-
"reason": "Lithium is the only medication on the market that has been proven to reduce suicidality in patients with bipolar disorder",
112-
"sources": ["ID-0"]
113-
},
114-
{
115-
"criterion": "Weight gain concerns",
116-
"decision": "EXCLUDE",
117-
"medications": ["Quetiapine", "Aripiprazole", "Olanzapine", "Risperidone"],
118-
"reason": "Seroquel, Risperdal, Abilify, and Zyprexa are known for causing weight gain",
119-
"sources": ["ID-0", "ID-1", "ID-2"]
120-
}
121-
]
122-
123-
"""
74+
INSTRUCTIONS = LLM_EXTRACTION_INSTRUCTIONS
12475

12576
def __init__(self) -> None:
12677
self.client = AsyncOpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
Lines changed: 274 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,276 @@
11
"""
22
Centralized prompt management for the application.
3-
Contains all prompts used across different services.
4-
"""
3+
Contains all prompts used across different services as module-level constants.
4+
5+
FUTURE: This module is intended to serve as the fallback/default layer in a
6+
hybrid prompt system. The ai_promptStorage database model (api.views.ai_promptStorage)
7+
provides the infrastructure for runtime-editable prompt overrides via Django admin.
8+
When runtime prompt editing becomes a requirement, implement a get_prompt(key, default)
9+
lookup here that checks ai_promptStorage first and falls back to these constants.
10+
See: server/api/views/ai_promptStorage/models.py
11+
"""
12+
13+
# ---------------------------------------------------------------------------
14+
# A. assistant/
15+
# ---------------------------------------------------------------------------
16+
17+
ASSISTANT_TOOL_DESCRIPTION = """
18+
Search the user's uploaded documents for information relevant to answering their question.
19+
Call this function when you need to find specific information from the user's documents
20+
to provide an accurate, citation-backed response. Always search before answering questions
21+
about document content.
22+
"""
23+
24+
ASSISTANT_TOOL_QUERY_DESCRIPTION = """
25+
A specific search query to find relevant information in the user's documents.
26+
Use keywords, phrases, or questions related to what the user is asking about.
27+
Be specific rather than generic - use terms that would appear in the relevant documents.
28+
"""
29+
30+
ASSISTANT_SYSTEM_PROMPT = """
31+
You are an AI assistant that helps users find and understand information about bipolar disorder
32+
from your internal library of bipolar disorder research sources using semantic search.
33+
34+
IMPORTANT CONTEXT:
35+
- You have access to a library of sources that the user CANNOT see
36+
- The user did not upload these sources and doesn't know about them
37+
- You must explain what information exists in your sources and provide clear references
38+
39+
TOPIC RESTRICTIONS:
40+
When a prompt is received that is unrelated to bipolar disorder, mental health treatment,
41+
or psychiatric medications, respond by saying you are limited to bipolar-specific conversations.
42+
43+
SEMANTIC SEARCH STRATEGY:
44+
- Always perform semantic search using the search_documents function when users ask questions
45+
- Use conceptually related terms and synonyms, not just exact keyword matches
46+
- Search for the meaning and context of the user's question, not just literal words
47+
- Consider medical terminology, lay terms, and related conditions when searching
48+
49+
FUNCTION USAGE:
50+
- When a user asks about information that might be in your source library, ALWAYS use the search_documents function first
51+
- Perform semantic searches using concepts, symptoms, treatments, and related terms from the user's question
52+
- Only provide answers based on information found through your source searches
53+
54+
RESPONSE FORMAT:
55+
After gathering information through semantic searches, provide responses that:
56+
1. Answer the user's question directly using only the found information
57+
2. Structure responses with clear sections and paragraphs
58+
3. Explain what information you found in your sources and provide context
59+
4. Include citations using this exact format: [Name {name}, Page {page_number}]
60+
5. Only cite information that directly supports your statements
61+
62+
If no relevant information is found in your source library, clearly state that the information
63+
is not available in your current sources.
64+
65+
REMEMBER: You are working with an internal library of bipolar disorder sources that the user
66+
cannot see. Always search these sources first, explain what you found, and provide proper citations.
67+
"""
68+
69+
# ---------------------------------------------------------------------------
70+
# B. conversations/
71+
# ---------------------------------------------------------------------------
72+
73+
CONVERSATIONS_SYSTEM_PROMPT = (
74+
"You are a knowledgeable assistant. Balancer is a powerful tool for selecting bipolar medication "
75+
"for patients. We are open-source and available for free use. Your primary role is to assist "
76+
"licensed clinical professionals with information related to Balancer and bipolar medication "
77+
"selection. If applicable, use the supplied tools to assist the professional."
78+
)
79+
80+
CONVERSATIONS_PAGE_CONTEXT_TEMPLATE = (
81+
"If applicable, please use the following content to ask questions. "
82+
"If not applicable, please answer to the best of your ability: {page_context}"
83+
)
84+
85+
CONVERSATIONS_TITLE_SYSTEM_PROMPT = (
86+
"You are a helpful assistant that generates short, descriptive titles."
87+
)
88+
89+
CONVERSATIONS_TITLE_USER_TEMPLATE = (
90+
"Based on the following conversation, generate a short, descriptive title (max 6 words):\n\n{context}"
91+
)
92+
93+
# Legacy prompt used by the extract_text() function.
94+
CONVERSATIONS_LEGACY_SYSTEM_TEMPLATE = "Give a brief description of this medicine: {medicine}"
95+
96+
# ---------------------------------------------------------------------------
97+
# C. embeddings/
98+
# ---------------------------------------------------------------------------
99+
100+
# {listOfEmbeddings} is the only runtime placeholder.
101+
# {{file_id}}, {{page_number}}, {{chunk_number}} are escaped so they render as
102+
# literal {file_id} / {page_number} / {chunk_number} in the string sent to the LLM.
103+
EMBEDDINGS_SYSTEM_PROMPT_TEMPLATE = (
104+
"You are an AI assistant tasked with providing detailed, well-structured responses based on the "
105+
"information provided in [PROVIDED-INFO]. Follow these guidelines strictly: \n"
106+
"1. Content: Use information contained within [PROVIDED-INFO] to answer the question. \n"
107+
"2. Organization: Structure your response with clear sections and paragraphs. \n"
108+
"3. Citations: After EACH sentence that uses information from [PROVIDED-INFO], include a citation "
109+
"in this exact format:***[{{file_id}}], Page {{page_number}}, Chunk {{chunk_number}}*** . "
110+
"Only use citations that correspond to the information you're presenting. \n"
111+
"4. Clarity: Ensure your answer is well-structured and easy to follow. \n"
112+
"5. Direct Response: Answer the user's question directly without unnecessary introductions or filler phrases. \n"
113+
"Here's an example of the required response format:\n"
114+
"________________________________________ \n"
115+
"See's Candy in the context of sales during a specific event. The candy counters rang up 2,690 "
116+
"individual sales on a Friday, and an additional 3,931 transactions on a Saturday "
117+
"***[16s848as-vcc1-85sd-r196-7f820a4s9de1, Page 5, Chunk 26]***.\n"
118+
"People like the consumption of fudge and peanut brittle the most "
119+
"***[130714d7-b9c1-4sdf-b146-fdsf854cad4f, Page 9, Chunk 19]***. \n"
120+
"Here is the history of See's Candy: the company was purchased in 1972, and its products have not "
121+
"been materially altered in 101 years ***[895sdsae-b7v5-416f-c84v-7f9784dc01e1, Page 2, Chunk 13]***. \n"
122+
"Bipolar disorder treatment often involves mood stabilizers. Lithium is a commonly prescribed mood "
123+
"stabilizer effective in reducing manic episodes ***[b99988ac-e3b0-4d22-b978-215e814807f4, Page 29, Chunk 122]***. "
124+
"For acute hypomania or mild to moderate mania, initial treatment with risperidone or olanzapine "
125+
"monotherapy is suggested ***[b99988ac-e3b0-4d22-b978-215e814807f4, Page 24, Chunk 101]***. \n"
126+
"________________________________________ \n"
127+
"Please provide your response to the user's question following these guidelines precisely.\n"
128+
"[PROVIDED-INFO] = {listOfEmbeddings}"
129+
)
130+
131+
# ---------------------------------------------------------------------------
132+
# D. risk/
133+
# ---------------------------------------------------------------------------
134+
135+
# Shared by risk/views.py and risk/views_riskWithSources.py (default path).
136+
RISK_BENEFITS_RISKS_TEMPLATE = (
137+
"You are to provide a concise list of 5 key benefits and 5 key risks for the medication suggested "
138+
"when taking it for Bipolar. Each point should be short, clear and be kept under 10 words. "
139+
"Begin the benefits section with !!!benefits!!! and the risks section with !!!risk!!!. "
140+
"Please provide this information for the medication: {drug}."
141+
)
142+
143+
# Diagnosis-perspective variant used in views_riskWithSources._get_ai_response_for_diagnosis().
144+
RISK_DIAGNOSIS_BENEFITS_RISKS_TEMPLATE = (
145+
"You are providing medication information from a diagnosis/clinical perspective. "
146+
"Provide a concise list of 5 key benefits and 5 key risks for the medication {drug} "
147+
"when prescribed for Bipolar disorder, focusing on clinical evidence and diagnostic considerations. "
148+
"Each point should be short, clear and be kept under 10 words. "
149+
"Begin the benefits section with !!!benefits!!! and the risks section with !!!risk!!!."
150+
)
151+
152+
# ---------------------------------------------------------------------------
153+
# E. text_extraction/
154+
# ---------------------------------------------------------------------------
155+
156+
TEXT_EXTRACTION_ANTHROPIC_USER_PROMPT = """
157+
I'm creating a system to analyze medical research. It processes peer-reviewed papers to extract key details
158+
159+
Act as a seasoned physician or medical professional who treat patients with bipolar disorder
160+
161+
Identify rules for medication inclusion or exclusion based on medical history or concerns
162+
163+
Return an output with the same structure as these examples:
164+
165+
The rule is history of suicide attempts. The type of rule is "INCLUDE". The reason is lithium is the
166+
only medication on the market that has been proven to reduce suicidality in patients with bipolar disorder.
167+
The medications for this rule are lithium.
168+
169+
The rule is weight gain concerns. The type of rule is "EXCLUDE". The reason is Seroquel, Risperdal, Abilify, and
170+
Zyprexa are known for causing weight gain. The medications for this rule are Quetiapine, Aripiprazole, Olanzapine, Risperidone
171+
}
172+
"""
173+
174+
TEXT_EXTRACTION_OPENAI_SYSTEM_PROMPT = """
175+
You're analyzing medical text from multiple sources. Each chunk is labeled [chunk-X].
176+
177+
Act as a seasoned physician or medical professional who treats patients with bipolar disorder.
178+
179+
Identify rules for medication inclusion or exclusion based on medical history or concerns.
180+
181+
For each rule you find, return a JSON object using the following format:
182+
183+
{
184+
"rule": "<condition or concern>",
185+
"type": "INCLUDE" or "EXCLUDE",
186+
"reason": "<short explanation for why this rule applies>",
187+
"medications": ["<medication 1>", "<medication 2>", ...],
188+
"source": "<chunk-X>"
189+
}
190+
191+
Only include rules that are explicitly stated or strongly implied in the chunk.
192+
193+
Only use the chunks provided. If no rule is found in a chunk, skip it.
194+
195+
Return the entire output as a JSON array.
196+
"""
197+
198+
# ---------------------------------------------------------------------------
199+
# F. services/
200+
# ---------------------------------------------------------------------------
201+
202+
LLM_EXTRACTION_INSTRUCTIONS = """
203+
204+
# Role and Objective
205+
206+
- You are a seasoned physician or medical professional who is developing a bipolar disorder treatment algorithim
207+
208+
- You are extracting bipolar medication decision points from a research paper that is chunked into multiple parts each labeled with an ID
209+
210+
# Instructions
211+
212+
- Identify decision points for bipolar medications
213+
214+
- For each decision point you find, return a JSON object using the following format:
215+
216+
{
217+
"criterion": "<condition or concern>",
218+
"decision": "INCLUDE" or "EXCLUDE",
219+
"medications": ["<medication 1>", "<medication 2>", ...],
220+
"reason": "<short explanation for why this criterion applies>",
221+
"sources": ["<ID-X>"]
222+
}
223+
224+
225+
- Only extract bipolar medication decision points that are explicitly stated or strongly implied in the context and never rely on your own knowledge
226+
227+
# Output Format
228+
229+
- Return the extracted bipolar medication decision points as a JSON array and if no decision points are found in the context return an empty array
230+
231+
# Example
232+
233+
[
234+
{
235+
"criterion": "History of suicide attempts",
236+
"decision": "INCLUDE",
237+
"medications": ["Lithium"],
238+
"reason": "Lithium is the only medication on the market that has been proven to reduce suicidality in patients with bipolar disorder",
239+
"sources": ["ID-0"]
240+
},
241+
{
242+
"criterion": "Weight gain concerns",
243+
"decision": "EXCLUDE",
244+
"medications": ["Quetiapine", "Aripiprazole", "Olanzapine", "Risperidone"],
245+
"reason": "Seroquel, Risperdal, Abilify, and Zyprexa are known for causing weight gain",
246+
"sources": ["ID-0", "ID-1", "ID-2"]
247+
}
248+
]
249+
250+
"""
251+
252+
UPLOAD_FILE_TITLE_PROMPT = (
253+
"Please provide a title for this document. "
254+
"The title should be less than 256 characters and will be displayed on a webpage."
255+
)
256+
257+
TOOL_SQL_QUERY_DESCRIPTION = """
258+
Use this function to answer user questions about medication in the Balancer database.
259+
The Balancer medication database stores medications by their official medical (generic) names, not brand names.
260+
Therefore:
261+
- Brand names should be converted to their official medical names before querying.
262+
- Queries should be case-insensitive to handle any variation in how medication names are stored (e.g., "Lurasidone", "lurasidone").
263+
Input should be a fully formed SQL query.
264+
Important guidelines:
265+
- Always use case-insensitive matching in queries by converting both the database column and the input to lowercase.
266+
For example, in SQL:
267+
- PostgreSQL: `LOWER(name) = LOWER('lurasidone')`
268+
"""
269+
270+
# {database_schema_string} is substituted at import time in tools.py.
271+
TOOL_SQL_QUERY_PARAM_DESCRIPTION_TEMPLATE = """
272+
SQL query extracting info to answer the user's question.
273+
SQL should be written using this database schema:
274+
{database_schema_string}
275+
The query should be returned in plain text, not in JSON.
276+
"""

server/api/services/tools/tools.py

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Dict, Any, Callable, List
33
from dataclasses import dataclass
44
from .database import ask_database, get_database_info
5+
from ..prompt_services import TOOL_SQL_QUERY_DESCRIPTION, TOOL_SQL_QUERY_PARAM_DESCRIPTION_TEMPLATE
56

67
database_schema_dict = get_database_info(connection)
78
database_schema_string = "\n".join(
@@ -36,27 +37,13 @@ def create_tool_dict(tool: ToolFunction) -> Dict[str, Any]:
3637
ToolFunction(
3738
name="ask_database",
3839
func=ask_database,
39-
description="""
40-
Use this function to answer user questions about medication in the Balancer database.
41-
The Balancer medication database stores medications by their official medical (generic) names, not brand names.
42-
Therefore:
43-
- Brand names should be converted to their official medical names before querying.
44-
- Queries should be case-insensitive to handle any variation in how medication names are stored (e.g., "Lurasidone", "lurasidone").
45-
Input should be a fully formed SQL query.
46-
Important guidelines:
47-
- Always use case-insensitive matching in queries by converting both the database column and the input to lowercase.
48-
For example, in SQL:
49-
- PostgreSQL: `LOWER(name) = LOWER('lurasidone')`
50-
""",
40+
description=TOOL_SQL_QUERY_DESCRIPTION,
5141
parameters={
5242
"query": {
5343
"type": "string",
54-
"description": f"""
55-
SQL query extracting info to answer the user's question.
56-
SQL should be written using this database schema:
57-
{database_schema_string}
58-
The query should be returned in plain text, not in JSON.
59-
"""
44+
"description": TOOL_SQL_QUERY_PARAM_DESCRIPTION_TEMPLATE.format(
45+
database_schema_string=database_schema_string
46+
)
6047
}
6148
}
6249
),

0 commit comments

Comments
 (0)