章节 01
导读 / 主楼:clj-llm:Clojure生态中优雅的LLM交互方案
探索clj-llm如何以函数式编程理念重新定义大语言模型调用,提供纯数据配置、流式响应、工具调用等完整功能,让LLM集成回归Clojure的简洁哲学。
正文
探索clj-llm如何以函数式编程理念重新定义大语言模型调用,提供纯数据配置、流式响应、工具调用等完整功能,让LLM集成回归Clojure的简洁哲学。
章节 01
探索clj-llm如何以函数式编程理念重新定义大语言模型调用,提供纯数据配置、流式响应、工具调用等完整功能,让LLM集成回归Clojure的简洁哲学。
章节 02
Clojure社区向来推崇简单性、组合性和数据驱动设计。传统的LLM SDK往往带有浓重的面向对象或命令式编程风格,与Clojure的哲学格格不入。开发者不得不编写大量的适配代码,将外部API的响应转换为Clojure数据结构,处理状态管理,以及应对异步操作的复杂性。
clj-llm的诞生正是为了解决这些痛点。它的核心理念可以用一句话概括:"提供者是纯映射,结果是纯映射,所有操作都与标准Clojure无缝组合。"这种设计让LLM调用真正成为Clojure程序中的一等公民。
章节 03
clj-llm的架构设计体现了Clojure社区对"数据即代码"理念的坚持。每一个LLM提供商都被表示为一个简单的Clojure映射(map),而不是复杂的对象实例。
(def openai (openai/backend {:api-key "sk-..."}))
(def claude (anthropic/backend {:api-key "sk-ant-..."}))
(def ollama (openai/backend {:api-base "http://localhost:11434/v1"
:api-key false}))
这种设计的优雅之处在于其可组合性。开发者可以使用标准的Clojure映射操作来构建和修改配置,无需学习新的API或面对复杂的构建器模式。通过简单的assoc、update或merge操作,就能创建出针对不同场景的定制化配置。
章节 04
无论底层是哪个提供商,clj-llm都提供统一的generate函数。这种一致性大大降低了在多提供商环境中切换的成本。
(:text (llm/generate ai "What is the capital of France?"))
;; => "The capital of France is Paris."
结果同样是一个纯映射,包含:text、:usage等标准字段,便于后续处理和监控。
章节 05
现代LLM应用常常需要从模型输出中提取结构化数据。clj-llm与Malli(Clojure生态中流行的数据验证库)深度集成,支持通过模式定义来约束和解析模型输出。
(llm/generate ai
{:schema [:map [:name :string] [:age :int] [:occupation :string]]}
"Marie Curie was a 66 year old physicist")
;; => {:text "{...}" :structured {:name "Marie Curie" :age 66 :occupation "physicist"} ...}
这种集成不仅确保了数据格式的正确性,还提供了一种声明式的方式来定义期望的输出结构。
章节 06
clj-llm完整支持函数调用(Tool Calling)功能。工具被定义为带有Malli函数模式的普通Clojure函数,无需额外的注解或元数据。
(defn get-weather
{:malli/schema [:=> [:cat [:map {:name "get_weather"
:description "Get current weather"}
[:city {:description "City name"} :string]]]
:string]}
[{:keys [city]}]
(str "Sunny, 22°C in " city))
库提供了两种调用模式:单次调用的generate(模型决定是否使用工具)和持续循环的run-agent(自动处理多轮工具调用直到任务完成)。这种分层设计让开发者可以根据应用场景灵活选择。
章节 07
对于需要实时反馈的场景,clj-llm支持通过回调函数处理流式输出。:on-text选项允许在接收每个文本块时执行自定义操作,同时仍然返回完整的结果映射。
对于推理模型(如o1、o3系列),:on-reasoning回调可以捕获模型的内部思考过程,为调试和优化提供宝贵的洞察。
章节 08
clj-llm内置了对图像和PDF文档的支持。通过content/image和content/pdf函数,开发者可以轻松地将多媒体内容纳入LLM对话。
(:text (llm/generate ai ["What's in this image?" (content/image "photo.jpg")]))
(:text (llm/generate ai ["Describe this" (content/image "https://example.com/chart.png")]))
(:text (llm/generate claude-ai ["Summarize" (content/pdf "invoice.pdf")]))
库还提供了图像处理选项,如调整尺寸、格式转换和质量控制,帮助开发者优化成本和性能。