2 Using Large Language Models from Clojure
ns llms
(:require
(:as hk-client]
[org.httpkit.client :as json])) [cheshire.core
LLMs often come as APIs, as they require computing power (GPUs), which most users do not have locally. OpenAI offers their models behind an (paid) API for example. In the following we will see three different ways to use the GPT-4 model from OpenAI
Get the openai API key either from environment or a specific file
def open-ai-key
(or (System/getenv "OPEN_AI_KEY")
(slurp "open_ai_secret.txt")
(
) )
2.1 Use OpenAI API directly
OpenAI offers a rather simple API, text-in text-out for “chatting” with GPT
The following shows how to ask a simple question, and getting the answer using an http library, http-kit. The API is based on JSON, so easy to use from Clojure
->
("https://api.openai.com/v1/chat/completions"
@(hk-client/post :headers
{"content-type" "application/json"
{"authorization" (format "Bearer %s" open-ai-key)}
:body
(json/encode:model "gpt-4"
{:messages [{:role "system",
:content "You are a helpful assistant."},
:role "user",
{:content "What is Clojure ?"}]})})
:body
keyword)) (json/decode
:id "chatcmpl-AjW6ECkx9x4cjSmxs2St2xHCI4JHS",
{:object "chat.completion",
:created 1735411514,
:model "gpt-4-0613",
:choices
:index 0,
[{:message
:role "assistant",
{:content
"Clojure is a compiled, dynamic, general-purpose programming language that combines the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. It is a dialect of the Lisp programming language that runs on the Java Virtual Machine (JVM), JavaScript engines, and the CLR (.NET platform).\n\nClojure promotes immutability and immutable data structures. Being a functional programming language, it emphasizes recursive iteration instead of looping, and treats functions as first-class objects. \n\nIt also provides easy access to Java frameworks, with optional type hints and type inference, to ensure that calls to Java can avoid reflection and enable fast performance.",
:refusal nil},
:logprobs nil,
:finish_reason "stop"}],
:usage
:prompt_tokens 22,
{:completion_tokens 133,
:total_tokens 155,
:prompt_tokens_details {:cached_tokens 0, :audio_tokens 0},
:completion_tokens_details
:reasoning_tokens 0,
{:audio_tokens 0,
:accepted_prediction_tokens 0,
:rejected_prediction_tokens 0}},
:system_fingerprint nil}
2.2 use Bosquet
Bosquet abstracts some of the concepts of LLMs on a higher level API. Its has further notions of “memory” and “tools” and has other features we find for example in python “LangChain”
Bosque wants the API key in a config file
"secrets.edn"
(spit pr-str
(:openai {:api-key open-ai-key}})) {
nil
require '[bosquet.llm.generator :refer [generate llm]]) (
Call GPT from Bosquet
(generate:user "What is Clojure"]
[[:assistant (llm :openai
[:llm/model-params {:model :gpt-4
})]])
:bosquet{:conversation
#:user "What is Clojure"]
[[:assistant
["Clojure is a dynamic, general-purpose programming language that runs on the Java Virtual Machine (JVM). It is a dialect of the Lisp programming language and focuses on providing a simple and holistic approach to programming. Clojure’s key features include immutability, functional programming, concurrency, and polymorphism. It was designed by Rich Hickey and was first released in 2007."]],
:completions
nil
{"Clojure is a dynamic, general-purpose programming language that runs on the Java Virtual Machine (JVM). It is a dialect of the Lisp programming language and focuses on providing a simple and holistic approach to programming. Clojure’s key features include immutability, functional programming, concurrency, and polymorphism. It was designed by Rich Hickey and was first released in 2007."},
:usage
nil {:prompt 11, :completion 78, :total 89},
{:bosquet/total {:prompt 11, :completion 78, :total 89}},
:time 3830}
2.3 Use langchain4j
We can use LLMs as well via a Java Interop and the library lnagchain4j which aims to be a copy of the python library langchain, and offers support or building blocks for several concepts around LLMs (model, vector stores, document loaders, etc.) We see it used in the following chapters
import '[dev.langchain4j.model.openai OpenAiChatModel OpenAiChatModelName]) (
dev.langchain4j.model.openai.OpenAiChatModelName
For now just the simplest call to an GPT model, asking it the same question:
def open-ai-chat-model
(
(.. (OpenAiChatModel/builder)
(apiKey open-ai-key)
(modelName OpenAiChatModelName/GPT_4) build))
"What is Clojure ?") (.generate open-ai-chat-model
"Clojure is a modern, dynamic, and functional dialect of the Lisp programming language on the Java platform. It is designed to be a general-purpose language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is predominantly a functional programming language and features a rich set of immutable, persistent data structures."