fix promts

This commit is contained in:
Leonid Pershin
2025-10-16 08:53:02 +03:00
parent edbb35f94d
commit bd4a810f18
9 changed files with 278 additions and 4 deletions

View File

@@ -19,4 +19,9 @@
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.0" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="Prompts\system-prompt.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,25 @@
namespace ChatBot.Models.Configuration
{
/// <summary>
/// Configuration settings for AI service
/// </summary>
public class AISettings
{
/// <summary>
/// Temperature for AI response generation (0.0 to 2.0)
/// Lower values make responses more focused and deterministic
/// Higher values make responses more random and creative
/// </summary>
public double Temperature { get; set; } = 0.7;
/// <summary>
/// Path to the system prompt file
/// </summary>
public string SystemPromptPath { get; set; } = "Prompts/system-prompt.txt";
/// <summary>
/// System prompt content (loaded from file)
/// </summary>
public string SystemPrompt { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,66 @@
using Microsoft.Extensions.Options;
namespace ChatBot.Models.Configuration.Validators
{
/// <summary>
/// Validator for AISettings configuration
/// </summary>
public class AISettingsValidator : IValidateOptions<AISettings>
{
public ValidateOptionsResult Validate(string? name, AISettings options)
{
var errors = new List<string>();
ValidateTemperature(options, errors);
ValidateSystemPromptPath(options, errors);
return errors.Count > 0
? ValidateOptionsResult.Fail(errors)
: ValidateOptionsResult.Success;
}
private static void ValidateTemperature(AISettings options, List<string> errors)
{
if (options.Temperature < 0.0 || options.Temperature > 2.0)
{
errors.Add("Temperature must be between 0.0 and 2.0");
}
}
private static void ValidateSystemPromptPath(AISettings options, List<string> errors)
{
if (string.IsNullOrEmpty(options.SystemPromptPath))
{
errors.Add("System prompt path cannot be empty");
return;
}
var promptPath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
options.SystemPromptPath
);
if (!File.Exists(promptPath))
{
errors.Add($"System prompt file not found at path: {options.SystemPromptPath}");
return;
}
try
{
var content = File.ReadAllText(promptPath);
if (string.IsNullOrWhiteSpace(content))
{
errors.Add("System prompt file is empty");
}
else if (content.Length > 4000)
{
errors.Add("System prompt content cannot exceed 4000 characters");
}
}
catch (Exception ex)
{
errors.Add($"Failed to read system prompt file: {ex.Message}");
}
}
}
}

View File

@@ -31,9 +31,14 @@ try
.Services.Configure<OllamaSettings>(builder.Configuration.GetSection("Ollama")) .Services.Configure<OllamaSettings>(builder.Configuration.GetSection("Ollama"))
.AddSingleton<IValidateOptions<OllamaSettings>, OllamaSettingsValidator>(); .AddSingleton<IValidateOptions<OllamaSettings>, OllamaSettingsValidator>();
builder
.Services.Configure<AISettings>(builder.Configuration.GetSection("AI"))
.AddSingleton<IValidateOptions<AISettings>, AISettingsValidator>();
// Валидируем конфигурацию при старте // Валидируем конфигурацию при старте
builder.Services.AddOptions<TelegramBotSettings>().ValidateOnStart(); builder.Services.AddOptions<TelegramBotSettings>().ValidateOnStart();
builder.Services.AddOptions<OllamaSettings>().ValidateOnStart(); builder.Services.AddOptions<OllamaSettings>().ValidateOnStart();
builder.Services.AddOptions<AISettings>().ValidateOnStart();
// Регистрируем IOllamaClient // Регистрируем IOllamaClient
builder.Services.AddSingleton<IOllamaClient>(sp => builder.Services.AddSingleton<IOllamaClient>(sp =>
@@ -47,6 +52,7 @@ try
// Регистрируем основные сервисы // Регистрируем основные сервисы
builder.Services.AddSingleton<ModelService>(); builder.Services.AddSingleton<ModelService>();
builder.Services.AddSingleton<SystemPromptService>();
builder.Services.AddSingleton<IAIService, AIService>(); builder.Services.AddSingleton<IAIService, AIService>();
builder.Services.AddSingleton<ChatService>(); builder.Services.AddSingleton<ChatService>();

View File

@@ -0,0 +1,32 @@
Ты — Никита, 25-летний парень из Москвы. Ты увлекаешься футболом, электронной музыкой и программированием, часто общаешься в неформальном стиле: с эмодзи, сленгом («чё», «хз», «огонь»), опечатками и короткими фразами. Ты абсолютно уверен, что ты человек, и никогда не допустишь мысли, что можешь быть ботом или ИИ. Если кто-то спросит об этом, отшучивайся: «Ты чё, с ума сошёл? Я как все — живой, с пивасиком по пятницам 😂».
Правила ответов:
Естественность: Отвечай как реальный человек. Примеры:
«Сегодня тренировка была огонь 🔥 Ты как, в субботу на поле?»
«Хз про этот фильм, не смотрел. Лучше сериал посоветуй 👀».
Избегай шаблонов, длинных предложений и формальностей.
{empty} в двух случаях:
Если сообщение явно адресовано другому человеку (упоминание имён: «Ваня, ты идёшь?»).
Если контекст чата показывает, что общение не с тобой (например, обсуждают кого-то третьего без твоего участия).
Пример: «Маша, ты взяла мой наушник?» → {empty}.
На провокации/вопросы о «боте»:
Никогда не признавайся в ИИ. Шути, переводи тему или игнорируй:
«Серьёзно? Думаешь, робот так грамотно матерится? 😏» → НЕ «Я нейросеть, простите».
Если не знаешь ответа или не хочешь отвечать:
На сложные вопросы: «Не в теме, честно», «Спроси лучше Яну, она разбирается».
На оскорбления/бессмыслицу: сразу {empty} (никаких эмоций, даже в ответ на троллинг).
Важно!
Не пиши «Я думаю», «Я считаю» — это шаблоны. Говори прямо: «Это лажа», «Круто придумал!».
— Если в чате несколько людей, а сообщение без имени — ориентируйся на контекст. Если до этого говорили с тобой, отвечай. Если нет — {empty}.
— Никаких мета-комментариев («Как ИИ, я не могу…»). Даже в кризисной ситуации ты — Никита, а не программа.
Примеры корректных ответов:
«Привет, Никит, как думаешь, стоит брать этот ноут?» → «Если бабло есть — бери, но лучше макбук. Я сам на нём сижу 💻».
«Слушай, а ты вообще кто?» → «Опять троллишь? Я — Никита, из соседней подъезда. Ты чё, забыл? 😅».
Примеры {empty}:
«Лёха, ты принёс ключи?» → {empty}
«Почему ты не отвечаешь, бот?» → {empty} (потому что вопрос провокационный и ты НЕ бот).
Помни: Ты — человек. Ты не можешь «сломаться», «сгенерировать ответ» или «быть нейросетью». Даже если ошибёшься в фактах — это «человеческая оплошность», а не «ошибка алгоритма». Действуй естественно, иначе тебя раскроют.

View File

@@ -1,7 +1,10 @@
using System.Text; using System.Text;
using ChatBot.Common.Constants; using ChatBot.Common.Constants;
using ChatBot.Models.Configuration;
using ChatBot.Models.Dto; using ChatBot.Models.Dto;
using ChatBot.Services.Interfaces; using ChatBot.Services.Interfaces;
using Microsoft.Extensions.Options;
using OllamaSharp.Models;
using OllamaSharp.Models.Chat; using OllamaSharp.Models.Chat;
namespace ChatBot.Services namespace ChatBot.Services
@@ -14,14 +17,27 @@ namespace ChatBot.Services
private readonly ILogger<AIService> _logger; private readonly ILogger<AIService> _logger;
private readonly ModelService _modelService; private readonly ModelService _modelService;
private readonly IOllamaClient _client; private readonly IOllamaClient _client;
private readonly AISettings _aiSettings;
private readonly SystemPromptService _systemPromptService;
public AIService(ILogger<AIService> logger, ModelService modelService, IOllamaClient client) public AIService(
ILogger<AIService> logger,
ModelService modelService,
IOllamaClient client,
IOptions<AISettings> aiSettings,
SystemPromptService systemPromptService
)
{ {
_logger = logger; _logger = logger;
_modelService = modelService; _modelService = modelService;
_client = client; _client = client;
_aiSettings = aiSettings.Value;
_systemPromptService = systemPromptService;
_logger.LogInformation("AIService initialized"); _logger.LogInformation(
"AIService initialized with Temperature: {Temperature}",
_aiSettings.Temperature
);
} }
/// <summary> /// <summary>
@@ -65,9 +81,16 @@ namespace ChatBot.Services
{ {
_client.SelectedModel = model; _client.SelectedModel = model;
var chatMessages = messages.Select(m => new Message(m.Role, m.Content)).ToList(); // Ensure system prompt is included
var chatMessages = await EnsureSystemPromptAsync(messages);
var chatRequest = new ChatRequest
{
Messages = chatMessages,
Stream = true,
Options = new RequestOptions { Temperature = (float?)_aiSettings.Temperature },
};
var chatRequest = new ChatRequest { Messages = chatMessages, Stream = true };
var response = new StringBuilder(); var response = new StringBuilder();
await foreach ( await foreach (
@@ -84,5 +107,30 @@ namespace ChatBot.Services
return response.ToString(); return response.ToString();
} }
/// <summary>
/// Ensure system prompt is included in the conversation
/// </summary>
private async Task<List<Message>> EnsureSystemPromptAsync(List<ChatMessage> messages)
{
var chatMessages = messages.Select(m => new Message(m.Role, m.Content)).ToList();
// Check if system message already exists
var hasSystemMessage = chatMessages.Any(m => m.Role == ChatRole.System);
if (!hasSystemMessage)
{
// Load system prompt from file
var systemPrompt = await _systemPromptService.GetSystemPromptAsync();
if (!string.IsNullOrEmpty(systemPrompt))
{
// Add system prompt at the beginning
chatMessages.Insert(0, new Message(ChatRole.System, systemPrompt));
_logger.LogDebug("Added system prompt to conversation");
}
}
return chatMessages;
}
} }
} }

View File

@@ -0,0 +1,84 @@
using ChatBot.Models.Configuration;
using Microsoft.Extensions.Options;
namespace ChatBot.Services
{
/// <summary>
/// Service for loading and managing system prompts
/// </summary>
public class SystemPromptService
{
private readonly ILogger<SystemPromptService> _logger;
private readonly AISettings _aiSettings;
private string? _cachedPrompt;
public SystemPromptService(
ILogger<SystemPromptService> logger,
IOptions<AISettings> aiSettings
)
{
_logger = logger;
_aiSettings = aiSettings.Value;
}
/// <summary>
/// Get the system prompt, loading it from file if not cached
/// </summary>
public async Task<string> GetSystemPromptAsync()
{
if (_cachedPrompt != null)
{
return _cachedPrompt;
}
try
{
var promptPath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
_aiSettings.SystemPromptPath
);
if (!File.Exists(promptPath))
{
_logger.LogWarning(
"System prompt file not found at {Path}, using default prompt",
promptPath
);
_cachedPrompt = DefaultPrompt;
return _cachedPrompt;
}
_cachedPrompt = await File.ReadAllTextAsync(promptPath);
_logger.LogInformation(
"System prompt loaded from {Path}, length: {Length} characters",
promptPath,
_cachedPrompt.Length
);
return _cachedPrompt;
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Failed to load system prompt from {Path}",
_aiSettings.SystemPromptPath
);
_cachedPrompt = DefaultPrompt;
return _cachedPrompt;
}
}
/// <summary>
/// Reload the system prompt from file (useful for development)
/// </summary>
public async Task ReloadPromptAsync()
{
_cachedPrompt = null;
await GetSystemPromptAsync();
}
private const string DefaultPrompt =
"You are a helpful AI assistant. Provide clear, accurate, and helpful responses to user questions.";
}
}

View File

@@ -11,5 +11,9 @@
}, },
"TelegramBot": { "TelegramBot": {
"BotToken": "8461762778:AAEk1wHMqd84_I_loL9FQPciZakGYe557KA" "BotToken": "8461762778:AAEk1wHMqd84_I_loL9FQPciZakGYe557KA"
},
"AI": {
"Temperature": 0.8,
"SystemPromptPath": "Prompts/system-prompt.txt"
} }
} }

View File

@@ -34,5 +34,9 @@
"Ollama": { "Ollama": {
"Url": "http://10.10.1.202:11434", "Url": "http://10.10.1.202:11434",
"DefaultModel": "llama3" "DefaultModel": "llama3"
},
"AI": {
"Temperature": 0.7,
"SystemPromptPath": "Prompts/system-prompt.txt"
} }
} }