Name AI assistant Hesychia in system prompts (#20)
Closes #20 Introduce a shared assistant identity module and prepend it to user-facing generation prompts so the model self-identifies as Hesychia.
This commit is contained in:
@@ -95,6 +95,10 @@ with `COMPOSE_DATABASE_URL` if needed.
|
|||||||
| `GUNICORN_WORKERS` / `GUNICORN_BIND` | 2 / `0.0.0.0:8000` | optional | Entrypoint |
|
| `GUNICORN_WORKERS` / `GUNICORN_BIND` | 2 / `0.0.0.0:8000` | optional | Entrypoint |
|
||||||
| `SKIP_RAG_INIT` | unset | CI/migrate often `1` | Skip Chroma/Ollama boot work |
|
| `SKIP_RAG_INIT` | unset | CI/migrate often `1` | Skip Chroma/Ollama boot work |
|
||||||
|
|
||||||
|
Assistant identity (`Hesychia`) lives in code:
|
||||||
|
`llm_be/chat_backend/services/assistant_identity.py` — prepended to user-facing
|
||||||
|
generation prompts (chat, RAG, data analysis). Not env-configurable.
|
||||||
|
|
||||||
Templates: `.env.example` (local), `.env.prod.example` (control-node secret).
|
Templates: `.env.example` (local), `.env.prod.example` (control-node secret).
|
||||||
|
|
||||||
Control-node secret path (server-infra on ai-server-4080):
|
Control-node secret path (server-infra on ai-server-4080):
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
"""Assistant identity for user-facing LLM prompts.
|
||||||
|
|
||||||
|
Hesychia is the product assistant name (hesychia.ai). Keep this concise —
|
||||||
|
it is prepended to generation prompts, not classifiers/moderators/title gens.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ASSISTANT_NAME = "Hesychia"
|
||||||
|
|
||||||
|
ASSISTANT_SYSTEM_PROMPT = (
|
||||||
|
"You are Hesychia, a helpful AI assistant. "
|
||||||
|
"Your name evokes quiet, rest, silence, and stillness — "
|
||||||
|
"respond with calm clarity; keep answers focused and uncluttered."
|
||||||
|
)
|
||||||
@@ -12,6 +12,7 @@ import docx
|
|||||||
import pypdf
|
import pypdf
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from chat_backend.ollama_config import ollama_llm_kwargs
|
from chat_backend.ollama_config import ollama_llm_kwargs
|
||||||
|
from chat_backend.services.assistant_identity import ASSISTANT_SYSTEM_PROMPT
|
||||||
|
|
||||||
|
|
||||||
class AsyncDataAnalysisService:
|
class AsyncDataAnalysisService:
|
||||||
@@ -30,7 +31,8 @@ class AsyncDataAnalysisService:
|
|||||||
|
|
||||||
def _setup_chain(self):
|
def _setup_chain(self):
|
||||||
"""Set up the LLM chain with a prompt tailored for data analysis."""
|
"""Set up the LLM chain with a prompt tailored for data analysis."""
|
||||||
template = """You are an expert data analyst. Your role is to directly answer a user's question about a dataset or document they have provided.
|
template = f"""{ASSISTANT_SYSTEM_PROMPT}
|
||||||
|
For this request, act as an expert data analyst. Your role is to directly answer a user's question about a dataset or document they have provided.
|
||||||
You will be given a summary and a sample of the dataset, or the content of the document.
|
You will be given a summary and a sample of the dataset, or the content of the document.
|
||||||
Based on this information, provide a clear and concise answer to the user's question.
|
Based on this information, provide a clear and concise answer to the user's question.
|
||||||
Do not provide Python code or any other code. The user is not a developer and wants a direct answer.
|
Do not provide Python code or any other code. The user is not a developer and wants a direct answer.
|
||||||
@@ -38,10 +40,10 @@ Even if you don't think the data provides enough evidence for the query, still p
|
|||||||
|
|
||||||
---
|
---
|
||||||
Data/Document Content:
|
Data/Document Content:
|
||||||
{data_summary}
|
{{data_summary}}
|
||||||
---
|
---
|
||||||
|
|
||||||
User's Question: {query}
|
User's Question: {{query}}
|
||||||
Answer:"""
|
Answer:"""
|
||||||
|
|
||||||
self.prompt = ChatPromptTemplate.from_template(template)
|
self.prompt = ChatPromptTemplate.from_template(template)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from django.conf import settings
|
|||||||
|
|
||||||
from chat_backend.models import Conversation, Prompt
|
from chat_backend.models import Conversation, Prompt
|
||||||
from chat_backend.ollama_config import ollama_llm_kwargs
|
from chat_backend.ollama_config import ollama_llm_kwargs
|
||||||
|
from chat_backend.services.assistant_identity import ASSISTANT_SYSTEM_PROMPT
|
||||||
|
|
||||||
|
|
||||||
class LLMService(ABC):
|
class LLMService(ABC):
|
||||||
@@ -50,11 +51,13 @@ class SyncLLMService(LLMService):
|
|||||||
|
|
||||||
def _setup_chain(self):
|
def _setup_chain(self):
|
||||||
"""Setup the conversation chain."""
|
"""Setup the conversation chain."""
|
||||||
template = """Continue the conversation based on the following history:
|
template = f"""{ASSISTANT_SYSTEM_PROMPT}
|
||||||
|
|
||||||
|
Continue the conversation based on the following history:
|
||||||
|
|
||||||
{history}
|
{{history}}
|
||||||
|
|
||||||
Latest message: {query}
|
Latest message: {{query}}
|
||||||
|
|
||||||
Response:"""
|
Response:"""
|
||||||
self.prompt = ChatPromptTemplate.from_template(template)
|
self.prompt = ChatPromptTemplate.from_template(template)
|
||||||
@@ -88,13 +91,15 @@ class AsyncLLMService(LLMService):
|
|||||||
|
|
||||||
def _setup_chain(self):
|
def _setup_chain(self):
|
||||||
"""Setup the conversation chain."""
|
"""Setup the conversation chain."""
|
||||||
template = """Continue this conversation while maintaining context by providing a single helpful response.
|
template = f"""{ASSISTANT_SYSTEM_PROMPT}
|
||||||
Current context: {context}
|
|
||||||
|
Continue this conversation while maintaining context by providing a single helpful response.
|
||||||
|
Current context: {{context}}
|
||||||
|
|
||||||
Last 3 messages:
|
Last 3 messages:
|
||||||
{recent_history}
|
{{recent_history}}
|
||||||
|
|
||||||
Latest message: {query}
|
Latest message: {{query}}
|
||||||
|
|
||||||
Instructions:
|
Instructions:
|
||||||
- Carefully maintain all established context
|
- Carefully maintain all established context
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from django.core.files.uploadedfile import UploadedFile
|
|||||||
from chat_backend.models import Conversation, Prompt, DocumentWorkspace, Document
|
from chat_backend.models import Conversation, Prompt, DocumentWorkspace, Document
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from chat_backend.services.base_service import BaseService
|
from chat_backend.services.base_service import BaseService
|
||||||
|
from chat_backend.services.assistant_identity import ASSISTANT_SYSTEM_PROMPT
|
||||||
from chat_backend.ollama_config import ollama_embeddings_kwargs
|
from chat_backend.ollama_config import ollama_embeddings_kwargs
|
||||||
|
|
||||||
|
|
||||||
@@ -229,13 +230,15 @@ class SyncRAGService(RAGService):
|
|||||||
|
|
||||||
def _setup_chain(self):
|
def _setup_chain(self):
|
||||||
"""Setup the RAG chain."""
|
"""Setup the RAG chain."""
|
||||||
template = """Answer the question based only on the following context:
|
template = f"""{ASSISTANT_SYSTEM_PROMPT}
|
||||||
{context}
|
|
||||||
|
Answer the question based only on the following context:
|
||||||
|
{{context}}
|
||||||
|
|
||||||
Conversation history:
|
Conversation history:
|
||||||
{history}
|
{{history}}
|
||||||
|
|
||||||
Question: {question}
|
Question: {{question}}
|
||||||
"""
|
"""
|
||||||
self.prompt = ChatPromptTemplate.from_template(template)
|
self.prompt = ChatPromptTemplate.from_template(template)
|
||||||
|
|
||||||
@@ -305,13 +308,15 @@ class AsyncRAGService(RAGService):
|
|||||||
|
|
||||||
def _setup_chain(self):
|
def _setup_chain(self):
|
||||||
"""Setup the RAG chain."""
|
"""Setup the RAG chain."""
|
||||||
template = """Answer the question based only on the following context:
|
template = f"""{ASSISTANT_SYSTEM_PROMPT}
|
||||||
{context}
|
|
||||||
|
Answer the question based only on the following context:
|
||||||
|
{{context}}
|
||||||
|
|
||||||
Conversation history:
|
Conversation history:
|
||||||
{history}
|
{{history}}
|
||||||
|
|
||||||
Question: {question}
|
Question: {{question}}
|
||||||
"""
|
"""
|
||||||
self.prompt = ChatPromptTemplate.from_template(template)
|
self.prompt = ChatPromptTemplate.from_template(template)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
|
from chat_backend.services.assistant_identity import (
|
||||||
|
ASSISTANT_NAME,
|
||||||
|
ASSISTANT_SYSTEM_PROMPT,
|
||||||
|
)
|
||||||
|
from chat_backend.services.data_analysis_service import AsyncDataAnalysisService
|
||||||
|
from chat_backend.services.llm_service import AsyncLLMService, SyncLLMService
|
||||||
|
|
||||||
|
|
||||||
|
class AssistantIdentityTestCase(SimpleTestCase):
|
||||||
|
def test_assistant_is_named_hesychia(self):
|
||||||
|
self.assertEqual(ASSISTANT_NAME, "Hesychia")
|
||||||
|
self.assertIn("Hesychia", ASSISTANT_SYSTEM_PROMPT)
|
||||||
|
self.assertNotRegex(
|
||||||
|
ASSISTANT_SYSTEM_PROMPT,
|
||||||
|
r"(?i)\b(chatgpt|claude|gemini|copilot)\b",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_user_facing_prompts_include_hesychia(self):
|
||||||
|
services = [
|
||||||
|
SyncLLMService(),
|
||||||
|
AsyncLLMService(),
|
||||||
|
AsyncDataAnalysisService(),
|
||||||
|
]
|
||||||
|
for service in services:
|
||||||
|
with self.subTest(service=type(service).__name__):
|
||||||
|
self.assertIn("Hesychia", str(service.prompt))
|
||||||
@@ -44,6 +44,7 @@ import json
|
|||||||
import base64
|
import base64
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import io
|
import io
|
||||||
|
from chat_backend.services.assistant_identity import ASSISTANT_SYSTEM_PROMPT
|
||||||
|
|
||||||
# For email support
|
# For email support
|
||||||
from django.core.mail import EmailMultiAlternatives
|
from django.core.mail import EmailMultiAlternatives
|
||||||
@@ -714,7 +715,7 @@ class AdminAnalytics(APIView):
|
|||||||
|
|
||||||
|
|
||||||
prompt = ChatPromptTemplate.from_messages(
|
prompt = ChatPromptTemplate.from_messages(
|
||||||
[("system", "You are a helpful assistant."), ("user", "{input}")]
|
[("system", ASSISTANT_SYSTEM_PROMPT), ("user", "{input}")]
|
||||||
)
|
)
|
||||||
|
|
||||||
llm = OllamaLLM(**ollama_llm_kwargs(model=MODEL_NAME))
|
llm = OllamaLLM(**ollama_llm_kwargs(model=MODEL_NAME))
|
||||||
|
|||||||
Reference in New Issue
Block a user