Почему вашему Raspberry Pi 5 нужен ИИ-ассистент?
Каждый день мы тратим часы на рутинные задачи: проверяем почту, планируем встречи, ищем важные письма. Облачные ассистенты вроде Google Assistant или Siri удобны, но они отправляют ваши данные на сервера корпораций. Что если собрать персонального помощника, который работает полностью на вашем устройстве, уважает вашу приватность и выполняет именно те задачи, которые нужны вам?
Проблема: Облачные ИИ-сервисы имеют доступ ко всей вашей переписке, историю запросов хранят неопределённое время, а их функционал ограничен тем, что решила добавить компания.
Решение: Локальный ИИ-агент на Raspberry Pi 5 с моделью FunctionGemma. Это не просто чат-бот, а полноценный агент, который умеет выполнять функции (functions) — например, подключаться к вашему почтовому ящику через API и читать письма, или создавать события в календаре. Всё обрабатывается на устройстве, данные никуда не уходят.
Что такое FunctionGemma и почему она идеальна для Pi 5?
FunctionGemma — это специальная версия модели Gemma 2B от Google, оптимизированная для вызова функций (function calling). В отличие от обычных языковых моделей, она обучена понимать, когда нужно выполнить внешнее действие (например, отправить запрос к API), и правильно формировать структурированный ответ для этого.
| Компонент | Рекомендация | Примечание |
|---|---|---|
| Raspberry Pi 5 | 4GB или 8GB RAM | 8GB предпочтительнее для работы с ИИ |
| Карта памяти | MicroSD 64GB Class 10 | Или SSD через USB3 для скорости |
| Охлаждение | Активный кулер | ИИ-модели нагружают CPU |
| Модель ИИ | FunctionGemma 2B (Q4_K_M) | Оптимальный баланс скорости/качества |
Raspberry Pi 5 с его 2.4 GHz quad-core CPU и поддержкой PCIe 2.0 (для быстрого SSD) достаточно мощён для запуска квантованных версий моделей размером 2-3 миллиарда параметров. FunctionGemma 2B в формате Q4_K_M занимает около 1.5 GB RAM и работает с приемлемой скоростью (2-5 токенов в секунду).
1 Подготовка Raspberry Pi 5 и установка базового ПО
Начнём с чистой установки Raspberry Pi OS (64-bit). Важно использовать именно 64-битную версию, так как современные ИИ-библиотеки требуют этого.
# Обновляем систему и устанавливаем ключевые пакеты
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-pip python3-venv git curl wget build-essential
# Устанавливаем Ollama — самый простой способ запускать модели
curl -fsSL https://ollama.com/install.sh | sh
# Проверяем установку
ollama --version
Важно: Если вы планируете использовать Pi 5 для других ИИ-экспериментов, рекомендую прочитать глубокий анализ форматов квантования моделей. Для нашего случая Q4_K_M — оптимальный выбор.
2 Установка и настройка FunctionGemma
Ollama уже содержит FunctionGemma в своём репозитории. Загружаем квантованную версию:
# Скачиваем модель (это займёт время, ~1.5 GB)
ollama pull functiongemma:2b-q4_K_M
# Запускаем модель в фоне как сервис
ollama serve &
# Проверяем, что модель работает
curl http://localhost:11434/api/generate -d '{
"model": "functiongemma:2b-q4_K_M",
"prompt": "Hello"
}'
Теперь у нас работает локальный ИИ, который понимает function calling. Но пока он не умеет делать ничего полезного — ему нужны инструменты (functions).
3 Создаём инструменты для работы с почтой и календарём
Мы будем использовать Google API для Gmail и Google Calendar. Это безопаснее, чем парсить почту напрямую, и даёт полный контроль над правами доступа.
- Создаём проект в Google Cloud Console
- Включаем API Gmail и Google Calendar
- Создаём OAuth 2.0 credentials (тип "Desktop app")
- Скачиваем JSON-файл с учётными данными и сохраняем как
credentials.json
Устанавливаем необходимые Python-библиотеки:
pip install google-auth google-auth-oauthlib google-auth-httplib2 \
google-api-python-client python-dotenv
Создаём файл tools.py с нашими инструментами:
import os
import pickle
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from datetime import datetime, timedelta
# Если изменяете SCOPES, удалите файл token.pickle
SCOPES = [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/calendar'
]
def get_gmail_service():
"""Аутентификация и создание сервиса Gmail"""
creds = None
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
return build('gmail', 'v1', credentials=creds)
def get_calendar_service():
"""Аутентификация и создание сервиса Calendar"""
creds = None
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
return build('calendar', 'v3', credentials=creds)
def read_unread_emails(limit=5):
"""Чтение непрочитанных писем"""
service = get_gmail_service()
results = service.users().messages().list(
userId='me', labelIds=['INBOX', 'UNREAD'], maxResults=limit).execute()
messages = results.get('messages', [])
emails = []
for msg in messages:
txt = service.users().messages().get(userId='me', id=msg['id']).execute()
subject = next(h['value'] for h in txt['payload']['headers'] if h['name'] == 'Subject')
sender = next(h['value'] for h in txt['payload']['headers'] if h['name'] == 'From')
emails.append({'subject': subject, 'from': sender})
return emails
def create_calendar_event(summary, start_time, duration_hours=1):
"""Создание события в календаре"""
service = get_calendar_service()
start = datetime.fromisoformat(start_time)
end = start + timedelta(hours=duration_hours)
event = {
'summary': summary,
'start': {'dateTime': start.isoformat(), 'timeZone': 'Europe/Moscow'},
'end': {'dateTime': end.isoformat(), 'timeZone': 'Europe/Moscow'},
}
created_event = service.events().insert(calendarId='primary', body=event).execute()
return f"Создано событие: {created_event['summary']} в {start.strftime('%H:%M %d.%m.%Y')}"
4 Создаём агента, который связывает FunctionGemma с инструментами
Теперь напишем основной скрипт, который будет принимать запросы на естественном языке, определять, какие инструменты нужны, и выполнять их.
import json
import requests
from tools import read_unread_emails, create_calendar_event
OLLAMA_URL = "http://localhost:11434/api/chat"
# Описание инструментов для модели в формате JSON Schema
TOOLS = [
{
"type": "function",
"function": {
"name": "read_unread_emails",
"description": "Читает непрочитанные письма из Gmail",
"parameters": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Количество писем (по умолчанию 5)"
}
}
}
}
},
{
"type": "function",
"function": {
"name": "create_calendar_event",
"description": "Создаёт событие в Google Calendar",
"parameters": {
"type": "object",
"properties": {
"summary": {
"type": "string",
"description": "Название события"
},
"start_time": {
"type": "string",
"description": "Время начала в формате YYYY-MM-DDTHH:MM:SS"
},
"duration_hours": {
"type": "number",
"description": "Продолжительность в часах"
}
},
"required": ["summary", "start_time"]
}
}
}
]
def run_agent(user_query):
"""Основная функция агента"""
# Первый запрос к модели с описанием инструментов
messages = [
{
"role": "user",
"content": user_query
}
]
payload = {
"model": "functiongemma:2b-q4_K_M",
"messages": messages,
"tools": TOOLS,
"stream": False
}
response = requests.post(OLLAMA_URL, json=payload)
response_data = response.json()
# Проверяем, хочет ли модель вызвать инструмент
if 'tool_calls' in response_data['message']:
tool_call = response_data['message']['tool_calls'][0]
function_name = tool_call['function']['name']
function_args = json.loads(tool_call['function']['arguments'])
# Вызываем соответствующий инструмент
if function_name == "read_unread_emails":
result = read_unread_emails(**function_args)
elif function_name == "create_calendar_event":
result = create_calendar_event(**function_args)
else:
result = "Неизвестный инструмент"
# Отправляем результат выполнения обратно модели
messages.append(response_data['message'])
messages.append({
"role": "tool",
"content": json.dumps(result),
"tool_call_id": tool_call['id']
})
# Получаем финальный ответ от модели
payload["messages"] = messages
final_response = requests.post(OLLAMA_URL, json=payload)
return final_response.json()['message']['content']
else:
return response_data['message']['content']
# Пример использования
if __name__ == "__main__":
print(run_agent("Какие у меня непрочитанные письма?"))
print(run_agent("Создай встречу 'Обсуждение проекта' на завтра 15:00"))
5 Запуск и тестирование системы
Запускаем наш агент и тестируем основные сценарии:
# В первом терминале запускаем Ollama
ollama serve
# Во втором терминале запускаем нашего агента
python3 assistant.py
При первом запуске откроется браузер для авторизации в Google. После этого создастся файл token.pickle с токенами доступа.
Предупреждение: Файл token.pickle содержит ключи доступа к вашей почте и календарю. Храните его в безопасном месте и не коммитьте в Git! Добавьте token.pickle и credentials.json в .gitignore.
Возможные ошибки и их решение
| Ошибка | Причина | Решение |
|---|---|---|
| "Out of memory" при загрузке модели | Недостаточно оперативной памяти | Используйте swap-файл: sudo fallocate -l 4G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile |
| Медленная работа модели | CPU перегревается или throttling | Установите активное охлаждение, проверьте температуру: vcgencmd measure_temp |
| Ошибка аутентификации Google | Истёк токен или неверные scope | Удалите token.pickle и перезапустите аутентификацию |
| Модель не вызывает инструменты | Неправильное описание tools в JSON | Сверьтесь с документацией Ollama Function Calling |
Куда развивать проект дальше?
- Голосовой интерфейс: Добавьте VOSK или Whisper для распознавания речи и синтеза ответов. В статье о голосовом ассистенте на n8n есть полезные идеи.
- Больше инструментов: Подключите управление умным домом (Home Assistant), проверку погоды, напоминания.
- Автоматизация сценариев: Например, «если пришло письмо от начальника с пометкой „срочно“ — создай событие в календаре на ближайшее время».
- Веб-интерфейс: Создайте простой UI на Flask или FastAPI для управления ассистентом из браузера.
Теперь у вас есть полностью локальный ИИ-ассистент, который работает на Raspberry Pi 5, уважает вашу приватность и может быть расширен под любые ваши задачи. Это не просто игрушка, а практичный инструмент для автоматизации рутины, который вы контролируете от начала до конца.