Prosta Integracja LLM z MSSQL
W dzisiejszym świecie, gdzie dane są na wagę złota, a ich efektywne przetwarzanie decyduje o przewadze konkurencyjnej, technologia Large Language Models (LLM) rewolucjonizuje podejście do zarządzania i analizy informacji. Integracja LLM z systemami baz danych, takimi jak MSSQL, otwiera nowe możliwości, pozwalając na wykraczanie poza tradycyjne ramy zapytań SQL i eksplorację danych w sposób bardziej intuicyjny i wszechstronny. Co ważne, integracja ta może być prostsza niż myślisz, dzięki wykorzystaniu standardowych protokołów API.
Ollama i MSSQL: Połączenie Potencjałów
Ollama, jako narzędzie umożliwiające lokalne uruchamianie LLM, w połączeniu z MSSQL, potężnym systemem zarządzania bazą danych, stwarza unikalne środowisko do eksperymentowania i wdrażania zaawansowanych rozwiązań analitycznych. Możliwość bezpośredniego przekazywania wyników zapytań SQL do LLM otwiera drzwi do szeregu zastosowań, które do niedawna były trudne do zrealizowania. Kluczem do tej integracji jest wykorzystanie zapytań opartych na standardowych protokołów API LLM, co eliminuje potrzebę skomplikowanych instalacji i konfiguracji.
Dlaczego to takie proste?
Większość systemów serwerowych posiada wbudowane narzędzia lub biblioteki, które umożliwiają wysyłanie zapytań HTTP do zewnętrznych API. Dzięki temu, komunikacja z LLM, takimi jak te udostępniane przez Ollama, sprowadza się do wykonywania zapytań HTTP z poziomu serwera MSSQL. Nie jest wymagane instalowanie dodatkowego oprogramowania lub uczenie się skomplikowanych języków programowania.
Przykłady Zastosowań
- Przetwarzanie i wzbogacanie danych: LLM mogą być wykorzystywane do transformacji danych pobranych z bazy danych, takich jak zmiana formatu, agregacja informacji z różnych tabel czy dodawanie kontekstu do surowych danych.
- Tłumaczenie i lokalizacja: Wyniki zapytań SQL mogą być automatycznie tłumaczone na różne języki, co ułatwia internacjonalizację aplikacji i raportów.
- Analiza sentymentu i klasyfikacja tekstu: LLM mogą analizować dane tekstowe przechowywane w bazie danych, identyfikując opinie klientów, klasyfikując dokumenty czy wykrywając anomalie.
- Generowanie raportów i podsumowań: Zamiast tworzyć skomplikowane zapytania SQL i ręcznie formatować wyniki, można wykorzystać LLM do generowania czytelnych i zrozumiałych raportów na podstawie danych z bazy danych.
- Predykcja i prognozowanie: LLM mogą być wykorzystywane do analizy danych szeregów czasowych i generowania prognoz, wspierając procesy decyjne w biznesie.
Przykładowe metody Integracji SQL: Procedury i Funkcje
W artykule omawiamy dwie przykładowe metody integracji Ollama z MSSQL: procedury składowane i funkcje zdefiniowane przez użytkownika. Obie metody pozwalają na wykonywanie zapytań do LLM bezpośrednio z poziomu SQL, ale różnią się sposobem użycia i przeznaczeniem. Co istotne, zarówno procedury, jak i funkcje mogą służyć do opakowywania requestów API, umożliwiając integrację nie tylko z Ollama, ale również z innymi serwerami LLM lub zewnętrznymi źródłami danych.
- Procedury składowane: Charakteryzują się większą elastycznością i pozwalają na wykonywanie złożonych operacji, takich jak modyfikacja danych w bazie danych, wywoływanie innych procedur składowanych, a także wykonywanie zapytań HTTP do zewnętrznych API. Dzięki temu mogą one służyć do pobierania danych z różnych źródeł, łączenia ich z danymi z MSSQL i przekazywania do LLM w celu dalszego przetwarzania.
- Funkcje zdefiniowane przez użytkownika: Są bardziej odpowiednie do prostych zapytań, które zwracają wynik na podstawie danych wejściowych. Podobnie jak procedury, mogą one wykonywać zapytania HTTP do zewnętrznych API, ale ich możliwości są bardziej ograniczone. Funkcje mogą być używane do wzbogacania danych z MSSQL o informacje z LLM lub innych źródeł zewnętrznych w ramach zapytań SELECT.
Przykładowe proste implementacje.
Poniżej znajdują się przykładowe implementacje procedury składowanej i funkcji zdefiniowanej przez użytkownika w MSSQL, które integrują się z API LLM. Należy pamiętać, że przedstawione wartości, takie jak adres URL API Ollama, są statyczne i służą jedynie jako ilustracja. W praktycznych zastosowaniach zaleca się parametryzację tych wartości.
Przed wykonaniem zapytań SQL konieczne jest rozszerzenie uprawnień serwera MSSQL:
Te ustawienia właczają obsługę OLE Automation Procedures, czyli możliwość tworzenia i uruchamiania obiektów COM z poziomu SQL Servera (np. Scripting.FileSystemObject, itp.). Nalezy mieć tego świadmość w kontekście polityki bezpieczeństwa pracy serwera SQL.
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE;
Procedura składowana:
CREATE PROCEDURE GetLLMResponse
@Prompt NVARCHAR(MAX), -- Parametr wejściowy: Prompt (zapytanie) do LLM
@ResponseText NVARCHAR(MAX) OUTPUT -- Parametr wyjściowy: Odpowiedź otrzymana z LLM
AS
BEGIN
DECLARE
@Object INT, -- Uchwyt obiektu COM dla MSXML2.ServerXMLHTTP
@hr INT, -- Zmienna przechowująca kod HRESULT z wywołań COM
@URL NVARCHAR(200) = 'http://172.244.1.5:11434/api/chat', -- Przykładowy Adres URL API LLM
@msg NVARCHAR(255), -- Zmienna przechowująca komunikaty błędów
@JSON NVARCHAR(MAX), -- Zmienna przechowująca JSON z zapytaniem do LLM
@statusVariant SQL_VARIANT, -- Zmienna przechowująca status odpowiedzi HTTP (SQL_VARIANT dla elastyczności)
@status INT, -- Zmienna przechowująca status odpowiedzi HTTP (po konwersji na INT)
@responseTextVariant SQL_VARIANT, -- Zmienna przechowująca odpowiedź tekstową z LLM (SQL_VARIANT)
@responseType NVARCHAR(MAX), -- Zmienna przechowująca typ danych odpowiedzi z LLM
@cleanedResponse NVARCHAR(MAX) -- Zmienna przechowująca przetworzoną odpowiedź tekstową z LLM
SET @ResponseText = 'BRAK ODPOWIEDZI' -- Domyślna wartość odpowiedzi w przypadku błędu
SET @JSON = '{
"model": "deepseek-r1:1.5b",
"messages": [{"role": "user", "content": "' + REPLACE(@Prompt, '"', '\"') + '"}],
"temperature": 0.7,
"stream": false
}' -- Konstruowanie JSON z zapytaniem
-- Użyj stabilniejszego COM-a
EXEC @hr = sp_OACreate 'MSXML2.ServerXMLHTTP.6.0', @Object OUT -- Utworzenie obiektu COM
IF @hr <> 0 BEGIN RAISERROR('sp_OACreate failed', 16, 1) RETURN END -- Obsługa błędu utworzenia obiektu
EXEC @hr = sp_OAMethod @Object, 'open', NULL, 'POST', @URL, false -- Otwarcie połączenia HTTP POST
IF @hr <> 0 BEGIN SET @msg = 'Open failed' GOTO EH END -- Obsługa błędu otwarcia połączenia
EXEC @hr = sp_OAMethod @Object, 'setRequestHeader', NULL, 'Content-Type', 'application/json' -- Ustawienie nagłówka Content-Type
IF @hr <> 0 BEGIN SET @msg = 'SetRequestHeader failed' GOTO EH END -- Obsługa błędu ustawienia nagłówka
EXEC @hr = sp_OAMethod @Object, 'send', NULL, @JSON -- Wysyłanie zapytania JSON do LLM
IF @hr <> 0 BEGIN SET @msg = 'Send failed' GOTO EH END -- Obsługa błędu wysłania zapytania
EXEC @hr = sp_OAGetProperty @Object, 'status', @statusVariant OUT -- Pobranie statusu odpowiedzi HTTP do zmiennej SQL_VARIANT
IF @hr <> 0 BEGIN SET @msg = 'get Status failed' GOTO EH END -- Obsługa błędu pobrania statusu
SET @status = CONVERT(INT, @statusVariant); -- Konwersja statusu HTTP na typ INT
EXEC @hr = sp_OAGetProperty @Object, 'responseText', @responseTextVariant OUT -- Pobranie odpowiedzi z LLM do zmiennej SQL_VARIANT
IF @hr = 0
BEGIN
-- Sprawdź typ danych i odpowiednio przekonwertuj
SET @responseType = CONVERT(NVARCHAR(MAX),SQL_VARIANT_PROPERTY(@responseTextVariant, 'BaseType')) -- Pobranie typu danych odpowiedzi
IF @responseType = 'NVarChar' OR @responseType = 'VarChar' -- Sprawdzenie, czy odpowiedź jest typu string
BEGIN
DECLARE @responseTextString NVARCHAR(MAX)
SET @responseTextString = CAST(@responseTextVariant AS NVARCHAR(MAX)) -- Konwersja odpowiedzi na NVARCHAR(MAX)
BEGIN TRY
-- Pobierz odpowiedź JSON
SELECT @cleanedResponse = JSON_VALUE(@responseTextString, '$.message.content')
-- Usuń znaczniki <think> i </think> oraz białe znaki
SET @cleanedResponse = REPLACE(
REPLACE(
REPLACE(
REPLACE(@cleanedResponse, '<think>', ''),
'</think>', ''
),
CHAR(10),
''
),
CHAR(13),
''
)
-- Usuń wiodące i końcowe białe znaki
SET @ResponseText = LTRIM(RTRIM(@cleanedResponse))
SET @ResponseText = CASE
WHEN LEN(@ResponseText) > 4000 THEN LEFT(@ResponseText, 4000) + N' [obcięte]'
ELSE @ResponseText
END
END TRY
BEGIN CATCH
SET @ResponseText = 'Błąd parsowania JSON' -- Obsługa błędu parsowania JSON
END CATCH
END
ELSE
BEGIN
SET @ResponseText = 'Odpowiedź nie jest typu string. Typ: ' + @responseType -- Obsługa przypadku, gdy odpowiedź nie jest stringiem
END
END
ELSE
BEGIN
SET @ResponseText = 'Odpowiedź HTTP: ' + CAST(@status AS NVARCHAR) + ' (brak ResponseText)' -- Obsługa błędu pobrania odpowiedzi
END
EXEC sp_OADestroy @Object -- Zwolnienie obiektu COM
RETURN
EH: -- Etykieta dla bloku obsługi błędów
IF @Object IS NOT NULL EXEC sp_OADestroy @Object -- Zwolnienie obiektu COM w przypadku błędu
RAISERROR(@msg, 16, 1) -- Zgłoszenie błędu
RETURN
END
go
Użycie procedury składowanej:
DECLARE @Wynik NVARCHAR(MAX);
EXEC GetLLMResponse @Prompt = N'Hello', @Response = @Wynik OUTPUT;
SELECT @Wynik;
W tym przykładzie, procedura GetLLMResponse przyjmuje zapytanie, wysyła je do API Ollama, pobiera odpowiedź i zwraca ją poprzez parametr wyjściowy @Response. Należy zauważyć, że adres URL API Ollama (http://172.244.1.5:11434/api/chat) jest zakodowany na stałe w procedurze. W praktycznych zastosowaniach zaleca się przekazywanie adresu URL jako parametru do procedury, co zwiększa jej elastyczność i umożliwia łatwiejsze dostosowanie do różnych serwerów LLM. Następnie, przykład użycia deklaruje zmienną @Wynik, wywołuje procedurę z zapytaniem i wyświetla wynik.
Po wykonaniu zapytania powinieneś otrzymać wynik zbliżony do:
Hello! How can I assist you today? 😊
Oczywiście, dokładna odpowiedź może się różnić w zależności od konkretnego modelu LLM, z którym się komunikujesz.
Funkcja zdefiniowana przez użytkownika do obsługi zapytań:
CREATE PROCEDURE GetLLMResponse
@Prompt NVARCHAR(MAX), -- Parametr wejściowy: Prompt (zapytanie) do LLM
@ResponseText NVARCHAR(MAX) OUTPUT -- Parametr wyjściowy: Odpowiedź otrzymana z LLM
AS
BEGIN
DECLARE
@Object INT, -- Uchwyt obiektu COM dla MSXML2.ServerXMLHTTP
@hr INT, -- Zmienna przechowująca kod HRESULT z wywołań COM
@URL NVARCHAR(200) = 'http://172.244.1.5:11434/api/chat', -- Przykładowy Adres URL API LLM
@msg NVARCHAR(255), -- Zmienna przechowująca komunikaty błędów
@JSON NVARCHAR(MAX), -- Zmienna przechowująca JSON z zapytaniem do LLM
@statusVariant SQL_VARIANT, -- Zmienna przechowująca status odpowiedzi HTTP (SQL_VARIANT dla elastyczności)
@status INT, -- Zmienna przechowująca status odpowiedzi HTTP (po konwersji na INT)
@responseTextVariant SQL_VARIANT, -- Zmienna przechowująca odpowiedź tekstową z LLM (SQL_VARIANT)
@responseType NVARCHAR(MAX), -- Zmienna przechowująca typ danych odpowiedzi z LLM
@cleanedResponse NVARCHAR(MAX) -- Zmienna przechowująca przetworzoną odpowiedź tekstową z LLM
SET @ResponseText = 'BRAK ODPOWIEDZI' -- Domyślna wartość odpowiedzi w przypadku błędu
SET @JSON = '{
"model": "deepseek-r1:1.5b",
"messages": [{"role": "user", "content": "' + REPLACE(@Prompt, '"', '\"') + '"}],
"temperature": 0.7,
"stream": false
}' -- Konstruowanie JSON z zapytaniem
-- Użyj stabilniejszego COM-a
EXEC @hr = sp_OACreate 'MSXML2.ServerXMLHTTP.6.0', @Object OUT -- Utworzenie obiektu COM
IF @hr <> 0 BEGIN RAISERROR('sp_OACreate failed', 16, 1) RETURN END -- Obsługa błędu utworzenia obiektu
EXEC @hr = sp_OAMethod @Object, 'open', NULL, 'POST', @URL, false -- Otwarcie połączenia HTTP POST
IF @hr <> 0 BEGIN SET @msg = 'Open failed' GOTO EH END -- Obsługa błędu otwarcia połączenia
EXEC @hr = sp_OAMethod @Object, 'setRequestHeader', NULL, 'Content-Type', 'application/json' -- Ustawienie nagłówka Content-Type
IF @hr <> 0 BEGIN SET @msg = 'SetRequestHeader failed' GOTO EH END -- Obsługa błędu ustawienia nagłówka
EXEC @hr = sp_OAMethod @Object, 'send', NULL, @JSON -- Wysyłanie zapytania JSON do LLM
IF @hr <> 0 BEGIN SET @msg = 'Send failed' GOTO EH END -- Obsługa błędu wysłania zapytania
EXEC @hr = sp_OAGetProperty @Object, 'status', @statusVariant OUT -- Pobranie statusu odpowiedzi HTTP do zmiennej SQL_VARIANT
IF @hr <> 0 BEGIN SET @msg = 'get Status failed' GOTO EH END -- Obsługa błędu pobrania statusu
SET @status = CONVERT(INT, @statusVariant); -- Konwersja statusu HTTP na typ INT
EXEC @hr = sp_OAGetProperty @Object, 'responseText', @responseTextVariant OUT -- Pobranie odpowiedzi z LLM do zmiennej SQL_VARIANT
IF @hr = 0
BEGIN
-- Sprawdź typ danych i odpowiednio przekonwertuj
SET @responseType = CONVERT(NVARCHAR(MAX),SQL_VARIANT_PROPERTY(@responseTextVariant, 'BaseType')) -- Pobranie typu danych odpowiedzi
IF @responseType = 'NVarChar' OR @responseType = 'VarChar' -- Sprawdzenie, czy odpowiedź jest typu string
BEGIN
DECLARE @responseTextString NVARCHAR(MAX)
SET @responseTextString = CAST(@responseTextVariant AS NVARCHAR(MAX)) -- Konwersja odpowiedzi na NVARCHAR(MAX)
BEGIN TRY
-- Pobierz odpowiedź JSON
SELECT @cleanedResponse = JSON_VALUE(@responseTextString, '$.message.content')
-- Usuń znaczniki <think> i </think> oraz białe znaki
SET @cleanedResponse = REPLACE(
REPLACE(
REPLACE(
REPLACE(@cleanedResponse, '<think>', ''),
'</think>', ''
),
CHAR(10),
''
),
CHAR(13),
''
)
-- Usuń wiodące i końcowe białe znaki
SET @ResponseText = LTRIM(RTRIM(@cleanedResponse))
SET @ResponseText = CASE
WHEN LEN(@ResponseText) > 4000 THEN LEFT(@ResponseText, 4000) + N' [obcięte]'
ELSE @ResponseText
END
END TRY
BEGIN CATCH
SET @ResponseText = 'Błąd parsowania JSON' -- Obsługa błędu parsowania JSON
END CATCH
END
ELSE
BEGIN
SET @ResponseText = 'Odpowiedź nie jest typu string. Typ: ' + @responseType -- Obsługa przypadku, gdy odpowiedź nie jest stringiem
END
END
ELSE
BEGIN
SET @ResponseText = 'Odpowiedź HTTP: ' + CAST(@status AS NVARCHAR) + ' (brak ResponseText)' -- Obsługa błędu pobrania odpowiedzi
END
EXEC sp_OADestroy @Object -- Zwolnienie obiektu COM
RETURN
EH: -- Etykieta dla bloku obsługi błędów
IF @Object IS NOT NULL EXEC sp_OADestroy @Object -- Zwolnienie obiektu COM w przypadku błędu
RAISERROR(@msg, 16, 1) -- Zgłoszenie błędu
RETURN
END
go
Użycie funkcji zdefiniowanej przez użytkownika:
SELECT dbo.GetLLMResponseFunction(N'Hello');
W tym przykładzie, funkcja GetLLMResponseFunction przyjmuje zapytanie, wysyła je do API Ollama i zwraca odpowiedź. Podobnie jak w przypadku procedury, adres URL API Ollama jest zakodowany na stałe. W praktycznych zastosowaniach zaleca się przekazywanie adresu URL jako parametru do funkcji. Przykład użycia pokazuje, jak wywołać funkcję w zapytaniu SELECT i wyświetlić wynik. MOdel użyty w przykładzie DeepSeek w odpiedziach przesyła wnioskowanie którego usuneliśmy w odpowiedziach aby rezultat był bardziej czytelny jednak takie podejście skomplikowało samo zaptytanie o odpowiednie jego przefiltrowanie.
Podsumowanie
Integracja z lokalnej instancji Ollama z MSSQL nieco rozszeża zakres przetwarzania danych. Możliwość wykorzystania LLM do analizy i transformacji danych bezpośrednio z poziomu bazy danych stwarza ogromny potencjał dla innowacji w różnych dziedzinach. Co najważniejsze, ta integracja jest prostsza niż mogłoby się wydawać, dzięki wykorzystaniu standardowych protokołów API, które są już dostępne w większości systemów serwerowych. Należy jednak pamiętać, że przedstawiona metoda jest jedną z wielu opcji dostępu do LLM, a API LLM mogą charakteryzować się zmiennymi czasami odpowiedzi i potencjalnymi opóźnieniami. Dlatego też, implementacja tego konceptu w środowisku produkcyjnym wymaga starannej analizy i uwzględnienia specyfiki danego zastosowania.
Zachęcamy do eksperymentowania z przedstawionymi metodami i odkrywania własnych zastosowań tej fascynującej technologii.