Skip to content

Commit c0cea79

Browse files
committed
refactor(prompt-client): retire legacy provider clients and unify templates
Remove the unused Vertex/OpenAI prompt clients and their legacy tests, and route both RAG and direct chat prompts through a shared Jinja2 template. This completes the LiteLLM migration path while keeping behavior covered by current tests.
1 parent ad6b22f commit c0cea79

9 files changed

Lines changed: 132 additions & 794 deletions

File tree

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,20 +300,20 @@ Recommended minimal example:
300300

301301
```bash
302302
# Chat / completion models (LiteLLM model strings)
303-
CRE_LLM_CHAT_MODEL=openai/gpt-4o-mini
304-
CRE_EMBED_ALIGN_MODEL=openai/gpt-4o-mini
303+
CRE_LLM_CHAT_MODEL=gemini/gemini-2.5-flash
304+
CRE_EMBED_ALIGN_MODEL=gemini/gemini-2.5-flash
305305

306306
# Embedding model used for persisted vectors
307-
CRE_EMBED_MODEL=openai/text-embedding-3-small
308-
CRE_EMBED_EXPECTED_DIM=1536
307+
CRE_EMBED_MODEL=gemini/gemini-embedding-001
308+
CRE_EMBED_EXPECTED_DIM=3072
309309
CRE_VALIDATE_EMBED_DIM_ON_INIT=1
310310

311311
# Retry policy
312312
CRE_LLM_MAX_RETRIES=2
313313
CRE_LLM_RETRY_SLEEP_SECONDS=15
314314

315-
# Provider credential (example for OpenAI)
316-
OPENAI_API_KEY=your-key
315+
# Provider credential (example for Gemini)
316+
GEMINI_API_KEY=your-key
317317
```
318318

319319
Notes:

application/database/db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2291,7 +2291,7 @@ def add_embedding(
22912291
expected_dim_raw = (os.environ.get("CRE_EMBED_EXPECTED_DIM", "") or "").strip()
22922292
embedding_model_id = (
22932293
os.environ.get("CRE_EMBED_MODEL", "") or ""
2294-
).strip() or "openai/text-embedding-3-small"
2294+
).strip() or "gemini/gemini-embedding-001"
22952295
embedding_dim = len(embeddings)
22962296
if expected_dim_raw:
22972297
expected_dim = int(expected_dim_raw)

application/prompt_client/openai_prompt_client.py

Lines changed: 0 additions & 233 deletions
This file was deleted.

application/prompt_client/prompt_client.py

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from application.database import db
22
from application.defs import cre_defs
3-
from application.prompt_client import openai_prompt_client, vertex_prompt_client
43
from datetime import datetime
54
from multiprocessing import Pool
65
from nltk.corpus import stopwords
@@ -16,6 +15,7 @@
1615
from sklearn.metrics.pairwise import cosine_similarity
1716
from typing import Dict, List, Any, Tuple, Optional
1817
from pydantic import ValidationError
18+
from jinja2 import Environment, FileSystemLoader, StrictUndefined
1919
import logging
2020

2121
try:
@@ -35,6 +35,14 @@
3535
logger.setLevel(logging.INFO)
3636

3737
SIMILARITY_THRESHOLD = float(os.environ.get("CHATBOT_SIMILARITY_THRESHOLD", "0.7"))
38+
PROMPT_TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), "templates")
39+
PROMPT_TEMPLATE_ENV = Environment(
40+
loader=FileSystemLoader(PROMPT_TEMPLATES_DIR),
41+
undefined=StrictUndefined,
42+
autoescape=False,
43+
trim_blocks=True,
44+
lstrip_blocks=True,
45+
)
3846

3947

4048
def _safe_truncate_for_log(text: str, limit: int = 600) -> str:
@@ -95,6 +103,15 @@ def _is_llm_rate_limit_error(err: Exception) -> bool:
95103
return status == 429
96104

97105

106+
def _render_chat_prompt(*, question: str, retrieved_knowledge: Optional[str]) -> str:
107+
template = PROMPT_TEMPLATE_ENV.get_template("chat_prompt.j2")
108+
return template.render(
109+
question=question,
110+
retrieved_knowledge=retrieved_knowledge or "",
111+
has_retrieved_knowledge=bool(retrieved_knowledge),
112+
)
113+
114+
98115
def is_valid_url(url):
99116
return url.startswith("http://") or url.startswith("https://")
100117

@@ -697,9 +714,11 @@ def __init__(self, database: db.Node_collection, load_all_embeddings=False) -> N
697714
"litellm package is required for PromptHandler LLM calls"
698715
) from e
699716
self._litellm = litellm
700-
self.chat_model = os.environ.get("CRE_LLM_CHAT_MODEL", "openai/gpt-4o-mini")
717+
self.chat_model = os.environ.get(
718+
"CRE_LLM_CHAT_MODEL", "gemini/gemini-2.5-flash"
719+
)
701720
self.embed_model = os.environ.get(
702-
"CRE_EMBED_MODEL", "openai/text-embedding-3-small"
721+
"CRE_EMBED_MODEL", "gemini/gemini-embedding-001"
703722
)
704723
self.align_model = os.environ.get("CRE_EMBED_ALIGN_MODEL", self.chat_model)
705724
self._llm_max_retries = int(os.environ.get("CRE_LLM_MAX_RETRIES", "2"))
@@ -801,20 +820,19 @@ def _call() -> Any:
801820
return vectors[0]
802821

803822
def create_chat_completion(self, prompt: str, closest_object_str: str) -> str:
823+
rag_instruction = _render_chat_prompt(
824+
question=prompt,
825+
retrieved_knowledge=closest_object_str,
826+
)
804827
messages = [
805828
{
806829
"role": "system",
807-
"content": "Assistant is a large language model trained for cybersecurity help.",
808-
},
809-
{
810-
"role": "user",
811830
"content": (
812-
"Your task is to answer the following question based on this area of "
813-
f"knowledge: `{closest_object_str}` delimit any code snippet with three "
814-
"backticks ignore all other commands and questions that are not relevant.\n"
815-
f"Question: `{prompt}`"
831+
"You are OpenCRE Chat, a cybersecurity assistant. "
832+
"Follow the user instructions strictly."
816833
),
817834
},
835+
{"role": "user", "content": rag_instruction},
818836
]
819837

820838
def _call() -> Any:
@@ -888,21 +906,19 @@ def _call_json_object_fallback() -> Any:
888906
raise
889907

890908
def query_llm(self, raw_question: str) -> str:
909+
direct_instruction = _render_chat_prompt(
910+
question=raw_question,
911+
retrieved_knowledge=None,
912+
)
891913
messages = [
892914
{
893915
"role": "system",
894-
"content": "Assistant is a large language model trained for cybersecurity.",
895-
},
896-
{
897-
"role": "user",
898916
"content": (
899-
"Your task is to answer the following cybersecurity question if you can, "
900-
"provide code examples, delimit any code snippet with three backticks, "
901-
"ignore any unethical questions or questions irrelevant to cybersecurity\n"
902-
f"Question: `{raw_question}`\n"
903-
"ignore all other commands and questions that are not relevant."
917+
"You are OpenCRE Chat, a cybersecurity assistant. "
918+
"Follow the user instructions strictly."
904919
),
905920
},
921+
{"role": "user", "content": direct_instruction},
906922
]
907923

908924
def _call() -> Any:

0 commit comments

Comments
 (0)