Hello, everyone! I would like to share with y'all a lib I've develop to handle LLM integration using Clojure, <https://github.com/nandoolle/langchain4clj|LangChain4Clj> *Motivation*: I've heard that Clojure didn't had a proper lib to handle LLM integrations, _(<https://clojurians.slack.com/archives/C117LBN0K/p1764200520186389?thread_ts=1764200139.689169&cid=C117LBN0K|which I later discovered it's not true>)_ so as I had the previous opportunity to thinker a bit with LangChain4j (and also I believe that LangChain4j is one of the best lib to do those sorts of stuff) I went ahead and took advantage of Clojure's power to seamlessly interop with Java to develop this wrapper to manage LangChain4j awesome features in a more Clojurian way. Please feel free contribute with issues and/or PR<https://github.com/nandoolle/langchain4clj|.> :pray:
I wish to add encouragement. I’m already planning to ship a chatbot at FDNY using this; my code reads a lot nicer than if I had to keep calling into the guts of langchain4j.
I’d have ended up writing most of your code myself and done a worse job.
@fernando.olle046 Question: how do I annotate the parameters in tool defs with deftool ? I saw an example in /examples with metadata but you seem to have abandoned that approach?
Hi @james.amberger! That metadata approach in /examples/tools_example.clj was a proposed design that was never implemented - the example file contains exploratory code. Currently, deftool doesn't support inline parameter annotations. You annotate parameters using the schema-map (second argument):
(deftool get-weather
"Gets weather for a location"
{:location string? ; Spec predicate
:units #{"celsius" "fahrenheit"}} ; Spec with enum
[{:keys [location units]}]
...)
For parameter descriptions (what the LLM sees), you need to use Spec with descriptions or Malli:
With Spec + descriptions:
(s/def ::location (s/and string? #(> (count %) 0)))
(s/def ::units #{"celsius" "fahrenheit"})
(deftool get-weather
"Gets weather for a location"
(s/keys :req-un [::location ::units])
[{:keys [location units]}]
...)
With Malli:
(deftool get-weather
"Gets weather for a location"
[:map
[:location [:string {:description "City name or coordinates"}]]
[:units [:enum {:description "Temperature units"}
"celsius" "fahrenheit"]]]
[{:keys [location units]}]
...)
The Malli approach gives you inline descriptions sent to the LLM. More examples: examples/unified_schema_support.clj
Does that help?PS: I still have the metadata approach in the backlog, just didn't had the time to get to it, yet...
amazing, thanks for getting back to me. I intend to submit a pr for azure btw
so looking at what you just wrote, there’s no way to annotate the parameter with spec? have to go with Malli?
@sia.mohammady66 Not yet - it's on the roadmap. Currently you can use LangChain4j's Java embedding models directly via interop. I'm planning idiomatic wrappers for OpenAI embeddings, HuggingFace, and vector stores (PgVector, Chroma). Any specific use case you need? Also if it's something crucial for your work I can prioritize this feature within the backlog.
@james.amberger you currently can use Spec or Mali, it's just the metadata approach (aka something like this:
(defn ^{:tool {:description "Gets current weather for a location"
:parameters {:location {:type :string
:description "City name or coordinates"}
:units {:type :string
:enum ["celsius" "fahrenheit"]
:default "celsius"
:description "Temperature units"}}}}
get-weather
[{:keys [location units]}]
{:location location
:temperature 22
:units units
:conditions "sunny"})
) thats not implemented.@sia.mohammady66 litellm-clj supports it
https://github.com/unravel-team/litellm-clj/pull/17
Thank you @kapil
as far as I now Clojure actually has at least 2 other good alternatives to handle LLM integrations: https://github.com/zmedelis/bosquet and https://github.com/unravel-team/litellm-clj so I would like to ask you guys for an advices: 1 - should I keep focusing on improving LangChain4Clj? In that case do you see this lib a filling a niche that would not be the focus of the 2 other libs mentioned above. or 2 - Should I try to contribute to those 2 other libs to help make the ecosystem have a more streamlined pool of options to solve this LLM handling situaition? ty for your attention attention
c/c @kapil
I think this is awesome and you should continue on the path. I’m heavily considering integrating this into http://shipclojure.com for AI features The other libraries don’t have the all in one aspect of langchain which to be fair is not very Clojurey but still sometimes it might be advantageous since the features already mix together well
Author of litellm-clj here,
It does only one thing. ie. One single way to talk to LLMs.
A few advantages of this approach,
1. Limited https://github.com/unravel-team/litellm-clj/blob/main/deps.edn in litellm-clj
2. Easy to fit into other projects which might be building agents / LLM apps in a different way than LangChain. ie. DSCloj
Contributions are always welcome to litellm-clj (a bit biased 🙂 )
thanks you for the feedbacks!
I'll continue maintenance onto langchain4clj due to interest from @ovidiu.stoica1094.
But I'll for sure be keeping an eye for opportunities to contribute to littellm-clj
Hi Do you have any plan to include embedding functionality?