Привет! Для того чтобы обращаться к нейросети Ollama (которая установлена на моем компьютере) удаленно, я решил написать простого Telegram-бота. Этот бот понимает русский язык и отвечает на сообщения. Давайте разберём его по частям!
Как установить Ollama себе на ПК я рассказал в статье: Ollama - ваш персональный AI на компьютере. Просто и мощно!
1. Основные компоненты программы
package main
import (
"context"
"fmt"
"log"
"os"
"strings"
"time"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
ollama "github.com/prathyushnallamothu/ollamago"
)- package main - главный пакет программы
- import - библиотеки для работы с Telegram, нейросетью Ollama и другими базовыми функциями
2. Настройки бота
const (
llmModel = "deepseek-r1:32b" // Используемая модель нейросети
maxHistoryLen = 30 // Максимальная длина истории сообщений
typingDelay = 5 * time.Second // Задержка перед показом "печатает"
)
var (
botToken = "ВАШ_ТОКЕН" // Ключ от Telegram-бота
targetID int64 = 123456 // ID вашего аккаунта
ollamaURL = "http://127.0.0.1:11434" // Адрес Ollama-сервера
)Здесь мы задаём:
- Какую языковую модель использовать (в моем случае это deepseek-r1:32b)
- Сколько сообщений помнить (чтобы не перегружать память)
- Токен бота (получаем у @BotFather)
- Ваш личный ID (чтобы бот отвечал только вам)
3. Сердце бота - структура Bot
type Bot struct {
api *tgbotapi.BotAPI // Подключение к Telegram
client *ollama.Client // Подключение к Ollama
history []ollama.Message // История диалога
}- api - общение с Telegram
- client - общение с нейросетью
- history - память диалога
4. Запуск программы
func main() {
// Создаём клиент для Ollama
opts := []ollama.Option{ollama.WithTimeout(time.Hour)} // Ждём ответ до 1 часа
if ollamaURL != "" {
opts = append(opts, ollama.WithBaseURL(ollamaURL))
}
bot := &Bot{
client: ollama.NewClient(opts...),
history: make([]ollama.Message, 0, maxHistoryLen+10),
}
// Загружаем инструкции для нейросети
bot.loadPrompts()
// Запускаем бота
if err := bot.start(); err != nil {
log.Fatalf("Bot failed: %v", err)
}
}Здесь:
- Настраиваем подключение к Ollama
- Создаём объект бота
- Загружаем правила для нейросети
- Запускаем основную логику
5. Загрузка правил для нейросети
func (b *Bot) loadPrompts() {
prompts := []struct {
role string
content string
}{
{"user", `Строгие правила: 1. Пиши всегда на РУССКОМ! 2. Запрещены иероглифы!`},
{"system", "Хорошо, я буду стого соблюдать все правила"},
}
b.history = make([]ollama.Message, 0, len(prompts))
for _, p := range prompts {
b.history = append(b.history, ollama.Message{
Role: p.role,
Content: p.content,
})
}
}Это как дать боту инструкцию:
- Чтобы нейросеть по умолчанию отвечала на русском языке
- DeepSeek часто вставляет иероглифы в текст, избавляемся от них
Нейросеть подтверждает, что поняла правила
Вы можете добавлять свои правила или инструкции для нейросети
6. Основной цикл работы бота
func (b *Bot) start() error {
// Подключаемся к Telegram
api, err := tgbotapi.NewBotAPI(botToken)
if err != nil {
return fmt.Errorf("bot init failed: %w", err)
}
b.api = api
log.Printf("Authorized as %s", b.api.Self.UserName)
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
// Слушаем сообщения
updates := b.api.GetUpdatesChan(u)
for update := range updates {
if update.Message == nil || update.Message.From.ID != targetID {
continue
}
// Обработка команд
if update.Message.IsCommand() {
if update.Message.Command() == "start" {
b.processMessage(update, "Привет!")
}
continue
}
// Обработка обычных сообщений
if text := strings.TrimSpace(update.Message.Text); text != "" {
b.processMessage(update, text)
}
}
return nil
}Бот постоянно проверяет:
- Пришло ли новое сообщение
- От нужного ли пользователя
- Это команда или обычный текст
7. Обработка сообщений
func (b *Bot) processMessage(update tgbotapi.Update, text string) {
// Добавление сообщения пользователя в историю
b.history = append(b.history, ollama.Message{
Role: "user",
Content: text,
})
// Показываем "Печатает..."
typingCtx, cancelTyping := context.WithCancel(context.Background())
go b.showTyping(typingCtx, update.Message.Chat.ID)
defer cancelTyping()
// Получаем ответ от нейросети
resp, err := b.getModelResponse()
if err != nil {
log.Printf("Chat error: %v", err)
b.sendText(update.Message.Chat.ID, "Ошибка обработки запроса")
return
}
// Обрабатываем ответ (Обрезаем размышления DeepSeek)
_, processedResp, _ := strings.Cut(resp, "</think>")
// Сохраняем ответ в историю
b.history = append(b.history, ollama.Message{
Role: "system",
Content: processedResp,
})
// Отправляем ответ
b.sendResponse(update.Message.Chat.ID, processedResp)
// Чистим историю от старых сообщений
b.trimHistory()
}Этапы обработки:
- Сохраняем вопрос пользователя
- Показываем анимацию печати
- Отправляем вопрос нейросети
- Форматируем ответ
- Отправляем ответ пользователю
- Убираем старые сообщения из памяти
8. Общение с нейросетью
func (b *Bot) getModelResponse() (string, error) {
// Ждём ответ не более 10 минут
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
// Отправляем запрос
resp, err := b.client.Chat(ctx, ollama.ChatRequest{
Model: llmModel,
Messages: b.history, // Вся история диалога
})
if err != nil {
return "", fmt.Errorf("chat failed: %w", err)
}
return resp.Message.Content, nil
}Здесь бот:
- Ждёт ответ от нейросети
- Передаёт всю историю диалога
- Возвращает полученный ответ
9. Отправка сообщений
func (b *Bot) sendResponse(chatID int64, response string) {
if len(response) == 0 {
return
}
// Короткие сообщения - отправляем текстом
if len([]rune(response)) < 4096 {
fmt.Println(response)
msg := tgbotapi.NewMessage(chatID, response)
msg.ParseMode = tgbotapi.ModeMarkdown
if _, err := b.api.Send(msg); err != nil {
b.sendAsFile(chatID, response)
}
} else {
// Длинные сообщения - отправляем файлом
b.sendText(chatID, "Слишком длинное сообщение!")
b.sendAsFile(chatID, response)
}
}Важно: Telegram имеет ограничение на длину сообщений (4096 символов), поэтому длинные ответы отправляются файлом.
10. Полезные фишки
Индикатор печати:
func (b *Bot) showTyping(ctx context.Context, chatID int64) {
ticker := time.NewTicker(typingDelay)
defer ticker.Stop()
for {
select {
case <-ticker.C:
action := tgbotapi.NewChatAction(chatID, tgbotapi.ChatTyping)
b.api.Send(action)
case <-ctx.Done():
return
}
}
}Каждые 5 секунд бот показывает анимацию "печатает", пока нейросеть думает.
Очистка истории:
func (b *Bot) trimHistory() {
if len(b.history) <= maxHistoryLen {
return
}
// Оставляем первые 5 системных сообщений
// и последние 25 сообщений диалога
keep := 5
if len(b.history) > keep {
b.history = append(b.history[:keep], b.history[len(b.history)-(maxHistoryLen-keep):]...)
}
}Чтобы нейросеть не "перегружалась", сохраняем только последние 30 сообщений.
Как это работает вместе:
- Вы пишете сообщение в Telegram
- Бот добавляет его в историю диалога
- Бот показывает "печатает..."
- Нейросеть обрабатывает запрос с учётом всей истории
- Бот форматирует ответ
- Ответ отправляется вам
- Старые сообщения удаляются из памяти

Советы для начинающих:
- Всегда проверяйте ошибки (как в b.api.Send(msg))
- Экспериментируйте с разными моделями Ollama
- Ограничивайте длину истории для экономии памяти
Этот бот - отличная основа для создания умных помощников! Вы можете добавить новые функции, например:
- Распознавание голосовых сообщений
- Работу с базами данных
- Поддержку нескольких пользователей
Весь код бота есть на Boosty, переходите и скачивайте.
Спасибо за ваше время и внимание! Ваша поддержка очень важна для меня! Если вам понравилась статья, пожалуйста, поставьте лайк этой статье на моем канале Дзен
Подпишитесь на мой Телеграм-канал, чтобы быть в курсе новых статей.
Удачи!