Как стать автором
Поиск
Написать публикацию
Обновить

Соединяем AI и реляционную базу данных

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров5.6K

На статью данный текст точно не тянет, скорее это маленькая заметка. Как известно свои дети и свои идеи они всегда самые лучшие. Я давно работаю с реляционными базами и очень люблю язык SQL за его формализм, скорее всего из-за этой моей профдеформации и родилась эта мысль. На работе ко мне иногда обращались сделать выгрузку в CSV файл из базы для обучения моделей или анализа данных, и я подумал, а зачем выгружать данные, а потом иногда загружать обратно результат в базу. Почему не сделать так что бы результат запроса сразу отправлялся на обработку в AI и затем выдавался ответ на запрос. Нам всего лишь нужна SQL функция которая берет результат запроса, заворочает его в вызов к модели, а потом выдает результат. Понятно, что серебряной пули нет и данный подход не везде будет работать, например, такой подход не подразумевает асинхронность, а значит если нужна высокая производительность, то данный подход не очень подходит, с другой стороны сейчас запросы к AI не дёшевы и если вы пошлете 100 запросов в секунду, не дождавшись ответа на предыдущие то скорее всего получите ошибку. Я думаю в будущем это будет стандартная функции в базах данных.

Теперь рассмотрим простейшую реализацию данной функции. Под рукой был PostgreSQL, но можно реализовать это и для ORACLEили других баз. Для этого нам понадобится расширение. В качестве AI будем использовать Groq. Первое что нам надо это получить API ключ. Сама функция очень простая.

CREATE OR REPLACE FUNCTION ai.completions(
	role_user text, role_sys text DEFAULT '')
    RETURNS jsonb
    LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
	url text = 'https://api.groq.com/openai/v1/chat/completions';
  	j text;
  	req http_request;
  	key_header http_header;
  	http_status integer;
  	error text;
BEGIN
    key_header.field = 'Authorization';
    key_header.value = 'Bearer ' ||  ‘API key’;
    req.method = 'POST';
    req.headers	= array[key_header];
    req.uri = url;
    req.content_type = 'application/json';
    req.content = format('{
    "model": "meta-llama/llama-4-scout-17b-16e-instruct",
    "messages": [
      {"role": "system", "content": "%s"},
      {"role": "user", "content": "%s"}
    ],
    "temperature": 0.7
  }', role_sys, role_user);

	SELECT status, content INTO http_status, j FROM http(req);	
	IF (http_status != 200) THEN		
		RAISE EXCEPTION  USING  ERRCODE = 'AI002', MESSAGE = j;
	END IF;
	RETURN j::jsonb;
END;
$BODY$;

Примеры работы, перед запуском советую установить следующие параметры

select http_set_curlopt('CURLOPT_CONNECTTIMEOUT', '10');
select http_set_curlopt('CURLOPT_TIMEOUT', '10');
select * from 
ai.completions('сколько будет 2 + 2', 'ты математик, верни только ответ') t

Результат

{
  "id": "chatcmpl-ac97506b-0b35-4e4d-bc82-3142fd0d3bc3",
  "model": "meta-llama/llama-4-scout-17b-16e-instruct",
  "usage": {
    "queue_time": 0.09607076599999999,
    "total_time": 0.008472493,
    "prompt_time": 0.003623623,
    "total_tokens": 30,
    "prompt_tokens": 28,
    "completion_time": 0.00484887,
    "completion_tokens": 2
  },
  "object": "chat.completion",
  "x_groq": {
    "id": "req_01k0vr86dtfz1rfh86ba6ztd7d"
  },
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "4"
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "created": 1753278061,
  "service_tier": "on_demand",
  "usage_breakdown": null,
  "system_fingerprint": "fp_37da608fc1"
}
select * from 
ai.completions('Стоит ли сейчас шортить биткоин?', 
    'ты профессиональный помощник по криптотрейдингу. Отвечай кратко и точно.') t

Результат

{
  "id": "chatcmpl-1f78c32f-8ae9-4134-a90d-748fd1b507c2",
  "model": "meta-llama/llama-4-scout-17b-16e-instruct",
  "usage": {
    "queue_time": 0.412265067,
    "total_time": 0.062087713,
    "prompt_time": 0.003936061,
    "total_tokens": 70,
    "prompt_tokens": 45,
    "completion_time": 0.058151652,
    "completion_tokens": 25
  },
  "object": "chat.completion",
  "x_groq": {
    "id": "req_01k0vrhw0yexxavgh5p6m0z507"
  },
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Нет, сейчас не лучший момент для шорта биткоина. Лучше дождаться подтверждения нисходящего тренда."
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "created": 1753278378,
  "service_tier": "on_demand",
  "usage_breakdown": null,
  "system_fingerprint": "fp_79da0e0073"
}
select  
ai.completions('Сосчитай сумму чисел в массиве '  
               || string_agg(d.price::text, ','), 'ты математик')  
from (
select t.price  
  from crypto_bot2.binance_data t where t.pair='BTCUSDT' 
  order by t.t_date desc limit 10) d

Результат

{
  "id": "chatcmpl-dc5f9394-518f-4011-9494-0a8e88d5aff9",
  "model": "meta-llama/llama-4-scout-17b-16e-instruct",
  "usage": {
    "queue_time": 1.975420253,
    "total_time": 0.474911567,
    "prompt_time": 0.006071319,
    "total_tokens": 262,
    "prompt_tokens": 76,
    "completion_time": 0.468840248,
    "completion_tokens": 186
  },
  "object": "chat.completion",
  "x_groq": {
    "id": "req_01k0vrn55ef6rbw3ztzkk08p2v"
  },
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Чтобы найти сумму чисел в данном массиве, я сложу все числа:\n\n117763.12 + 117789.74 = 235552.86\n235552.86 + 117735.53 = 353288.39\n353288.39 + 117718.625 = 471006.015\n471006.015 + 117725.19 = 588731.205\n588731.205 + 117674.25 = 706405.455\n706405.455 + 117656.75 = 824062.205\n824062.205 + 117646.13 = 941708.335\n941708.335 + 117646.086 = 1059354.421\n1059354.421 + 117650.914 = 1177005.335\n\nСумма чисел в данном массиве равна: 1177005.335"
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "created": 1753278487,
  "service_tier": "on_demand",
  "usage_breakdown": null,
  "system_fingerprint": "fp_37da608fc1"
}

Где мы можем использовать данный подход

Наверное, эта часть самая сложная. Это как Raspberry pi или Arduino, отличные игрушки, но где их применить в реальной жизни. Я думаю вот несколько примеров где пригодится данный подход

  1. У нас есть старая система и мы хотим без переделки добавить AI в нее, и анализировать наши данные и рисовать графики. К старой системе прилагаются старые программисты, которым работать с запросами гораздо проще чем делать вызовы REST API

  2. Генерация тестовых данных

  3. Для торговых ботов подтверждение сигналов тех анализа, новостными сигналами

  4. Разбор больших текстов и заполнение нужных полей в зависимости от содержимого текста.

  5. В медицинских базах или базах автосервиса и тому подобное, постановка диагноза на основе жалоб клиента и автоматическое заполнение нужных полей.

Понятно, что реализация может быть лучше и на другом языке, можно реализовать функцию построения рисунка или графика на основе данных из базы. Это всего лишь пример. Наверное, это все, чем я хотел с вами поделится, пишите, что думаете об этой идеи, сильно прошу не бить.

Теги:
Хабы:
-1
Комментарии8

Публикации

Ближайшие события