Spaces:
Sleeping
Sleeping
gary-boon
Claude Opus 4.5
commited on
Commit
·
3d9d9ee
1
Parent(s):
3e80769
Remove mistral_common to fix dependency conflict
Browse files- Remove mistral_common from requirements (conflicts with numpy/pydantic)
- Simplify prompt_formatter to use manual Mistral format
- Format: [INST] {system}\n\n{user} [/INST] (no <s>, tokenizer adds BOS)
- Keep recommended_temperature=0.15 for Devstral
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- backend/prompt_formatter.py +13 -62
- requirements.txt +0 -1
backend/prompt_formatter.py
CHANGED
|
@@ -5,54 +5,12 @@ Handles formatting prompts appropriately for different model types:
|
|
| 5 |
- Instruction models: System prompt + user message with chat template
|
| 6 |
"""
|
| 7 |
|
| 8 |
-
from typing import Dict, Optional, Any
|
| 9 |
import logging
|
| 10 |
|
| 11 |
logger = logging.getLogger(__name__)
|
| 12 |
|
| 13 |
|
| 14 |
-
def _try_mistral_common_format(messages: List[Dict[str, str]], model_name: str) -> Optional[str]:
|
| 15 |
-
"""
|
| 16 |
-
Try to use mistral_common for proper Mistral/Devstral chat formatting.
|
| 17 |
-
Returns None if mistral_common is not available or fails.
|
| 18 |
-
"""
|
| 19 |
-
try:
|
| 20 |
-
from mistral_common.protocol.instruct.messages import (
|
| 21 |
-
SystemMessage, UserMessage
|
| 22 |
-
)
|
| 23 |
-
from mistral_common.protocol.instruct.request import ChatCompletionRequest
|
| 24 |
-
from mistral_common.tokens.tokenizers.mistral import MistralTokenizer
|
| 25 |
-
|
| 26 |
-
# Load the tokenizer from HF hub
|
| 27 |
-
tokenizer = MistralTokenizer.from_hf_hub(model_name)
|
| 28 |
-
|
| 29 |
-
# Build messages
|
| 30 |
-
mistral_messages = []
|
| 31 |
-
for msg in messages:
|
| 32 |
-
if msg["role"] == "system":
|
| 33 |
-
mistral_messages.append(SystemMessage(content=msg["content"]))
|
| 34 |
-
elif msg["role"] == "user":
|
| 35 |
-
mistral_messages.append(UserMessage(content=msg["content"]))
|
| 36 |
-
|
| 37 |
-
# Encode to get token IDs
|
| 38 |
-
request = ChatCompletionRequest(messages=mistral_messages)
|
| 39 |
-
tokenized = tokenizer.encode_chat_completion(request)
|
| 40 |
-
|
| 41 |
-
# Decode back to text for use with HF tokenizer
|
| 42 |
-
# This gives us the properly formatted prompt string
|
| 43 |
-
decoded = tokenizer.decode(tokenized.tokens)
|
| 44 |
-
|
| 45 |
-
logger.info(f"Used mistral_common format for {model_name}")
|
| 46 |
-
return decoded
|
| 47 |
-
|
| 48 |
-
except ImportError:
|
| 49 |
-
logger.warning("mistral_common not available, using fallback format")
|
| 50 |
-
return None
|
| 51 |
-
except Exception as e:
|
| 52 |
-
logger.warning(f"mistral_common formatting failed: {e}, using fallback")
|
| 53 |
-
return None
|
| 54 |
-
|
| 55 |
-
|
| 56 |
class PromptFormatter:
|
| 57 |
"""
|
| 58 |
Unified prompt formatting for different model types.
|
|
@@ -62,9 +20,9 @@ class PromptFormatter:
|
|
| 62 |
- Model treats it as text to continue
|
| 63 |
|
| 64 |
Instruction models (Devstral, instruct variants):
|
| 65 |
-
-
|
| 66 |
-
-
|
| 67 |
-
-
|
| 68 |
"""
|
| 69 |
|
| 70 |
def format(
|
|
@@ -110,9 +68,8 @@ class PromptFormatter:
|
|
| 110 |
Format prompt for instruction-tuned models.
|
| 111 |
|
| 112 |
Priority:
|
| 113 |
-
1.
|
| 114 |
-
2.
|
| 115 |
-
3. Manual Mistral format fallback
|
| 116 |
"""
|
| 117 |
# Get system prompt (override > model default > generic fallback)
|
| 118 |
system_prompt = system_prompt_override or model_config.get("system_prompt")
|
|
@@ -125,15 +82,7 @@ class PromptFormatter:
|
|
| 125 |
{"role": "user", "content": prompt}
|
| 126 |
]
|
| 127 |
|
| 128 |
-
#
|
| 129 |
-
architecture = model_config.get("architecture", "")
|
| 130 |
-
hf_path = model_config.get("hf_path", "")
|
| 131 |
-
if architecture == "mistral" or "mistral" in hf_path.lower():
|
| 132 |
-
formatted = _try_mistral_common_format(messages, hf_path)
|
| 133 |
-
if formatted:
|
| 134 |
-
return formatted
|
| 135 |
-
|
| 136 |
-
# Try tokenizer's native chat template
|
| 137 |
if hasattr(tokenizer, 'chat_template') and tokenizer.chat_template is not None:
|
| 138 |
try:
|
| 139 |
formatted = tokenizer.apply_chat_template(
|
|
@@ -146,16 +95,18 @@ class PromptFormatter:
|
|
| 146 |
except Exception as e:
|
| 147 |
logger.warning(f"chat_template failed: {e}, using manual format")
|
| 148 |
|
| 149 |
-
# Fallback: Manual Mistral/Llama format
|
| 150 |
-
# Note:
|
| 151 |
return self._manual_mistral_format(prompt, system_prompt)
|
| 152 |
|
| 153 |
def _manual_mistral_format(self, prompt: str, system_prompt: str) -> str:
|
| 154 |
"""
|
| 155 |
-
Manual Mistral instruction format
|
| 156 |
|
| 157 |
Format: [INST] {system}\n\n{user} [/INST]
|
| 158 |
-
|
|
|
|
|
|
|
| 159 |
"""
|
| 160 |
logger.info("Using manual Mistral instruction format")
|
| 161 |
return f"[INST] {system_prompt}\n\n{prompt} [/INST]"
|
|
|
|
| 5 |
- Instruction models: System prompt + user message with chat template
|
| 6 |
"""
|
| 7 |
|
| 8 |
+
from typing import Dict, Optional, Any
|
| 9 |
import logging
|
| 10 |
|
| 11 |
logger = logging.getLogger(__name__)
|
| 12 |
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
class PromptFormatter:
|
| 15 |
"""
|
| 16 |
Unified prompt formatting for different model types.
|
|
|
|
| 20 |
- Model treats it as text to continue
|
| 21 |
|
| 22 |
Instruction models (Devstral, instruct variants):
|
| 23 |
+
- Wrap with system prompt + user message
|
| 24 |
+
- Use tokenizer's chat_template if available
|
| 25 |
+
- Fallback to manual Mistral format
|
| 26 |
"""
|
| 27 |
|
| 28 |
def format(
|
|
|
|
| 68 |
Format prompt for instruction-tuned models.
|
| 69 |
|
| 70 |
Priority:
|
| 71 |
+
1. Tokenizer's native chat_template (if available)
|
| 72 |
+
2. Manual Mistral format fallback
|
|
|
|
| 73 |
"""
|
| 74 |
# Get system prompt (override > model default > generic fallback)
|
| 75 |
system_prompt = system_prompt_override or model_config.get("system_prompt")
|
|
|
|
| 82 |
{"role": "user", "content": prompt}
|
| 83 |
]
|
| 84 |
|
| 85 |
+
# Try tokenizer's native chat template first
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
if hasattr(tokenizer, 'chat_template') and tokenizer.chat_template is not None:
|
| 87 |
try:
|
| 88 |
formatted = tokenizer.apply_chat_template(
|
|
|
|
| 95 |
except Exception as e:
|
| 96 |
logger.warning(f"chat_template failed: {e}, using manual format")
|
| 97 |
|
| 98 |
+
# Fallback: Manual Mistral/Llama instruction format
|
| 99 |
+
# Note: We DON'T include <s> - the tokenizer adds BOS automatically
|
| 100 |
return self._manual_mistral_format(prompt, system_prompt)
|
| 101 |
|
| 102 |
def _manual_mistral_format(self, prompt: str, system_prompt: str) -> str:
|
| 103 |
"""
|
| 104 |
+
Manual Mistral instruction format.
|
| 105 |
|
| 106 |
Format: [INST] {system}\n\n{user} [/INST]
|
| 107 |
+
|
| 108 |
+
Note: BOS token (<s>) is NOT included - the tokenizer adds it
|
| 109 |
+
automatically during tokenization with add_special_tokens=True (default).
|
| 110 |
"""
|
| 111 |
logger.info("Using manual Mistral instruction format")
|
| 112 |
return f"[INST] {system_prompt}\n\n{prompt} [/INST]"
|
requirements.txt
CHANGED
|
@@ -10,7 +10,6 @@ pydantic==2.5.0
|
|
| 10 |
torch>=2.3.0
|
| 11 |
transformers>=4.44.0
|
| 12 |
accelerate>=0.30.0
|
| 13 |
-
mistral_common>=1.5.0 # Required for Devstral chat template formatting
|
| 14 |
|
| 15 |
# Utilities
|
| 16 |
numpy==1.24.3
|
|
|
|
| 10 |
torch>=2.3.0
|
| 11 |
transformers>=4.44.0
|
| 12 |
accelerate>=0.30.0
|
|
|
|
| 13 |
|
| 14 |
# Utilities
|
| 15 |
numpy==1.24.3
|