之前在《使用 llama.cpp 自己架一個 OpenAI 相容伺服器》介紹了怎麼用 llama.cpp 來架設一個輕量化的 OpenAI API 相容伺服器,而接下來呢,則是來簡單介紹一下怎麼透過 LangChain 這個框架、來使用這個 LLM 的伺服器吧。
首先,LangChain 的官網是:https://www.langchain.com/,他的概念基本上有點像是提供了許多不同的功能模組(也有不少社群提供的)、讓開發者透過把各種功能模組串起來、組成自己需要的 LLM 應用程式。理論上透過 LangChain 提供的功能,可以快速地組出自己需要的功能;像是官方就有提供 RAG、agent 等功能的範例可以參考(能不能弄出自己想要的結果就是另一回事了)。
不過另一方面,目前 LangChain 也還在開發中,版本還在 0.2 版而已,所以之後的 API 可能都會有變動,現在寫的程式之後能不能用也不知道。 XD
所以如果是要拿來開發服務或是產品的話,這點可能是要考量的。
另外,對於只是想要測試的人來說,其實有不少模組實際上都需要使用第三方的雲端服務、需要有 API key 才能用,所以其實使用上不見得可以真的很方便地上手。 :p
接下來,就來先看 LangChain 的架構吧~
在架構圖裡面,LangChain 是左下角的一塊,實質上包括了核心(Core)和社群(community)兩個部分(感覺上社群的東西好像還比較多?);而這部分都有提供 Python 和 JavaScript 兩種語言的套件,對於不會 Python 的人算是提供了另一種選擇。
而除了 LangChain 外,其實他的框架外還有 LangSmith 和 LangServe 這些東西,不過這邊暫時都不會去使用就是了;另外,雖然架構圖裡沒有,但是他後來還有一個 LangGraph,這部分倒是之後可能會拿來用的東西了。
而由於 Heresy 個人對於 Python 完全不熟,所以這邊就是拿相對熟悉一點的 JavaScript 來玩看看了~
LangChain JavaScript 版的文件是在 https://js.langchain.com/,裡面有 Tutorials 和 How-To Guides,算是相對容易上手的了~
而 Heresy 這邊的測試環境,則是使用 deno 這個 JavaScript 的執行環境(官網),為了能使用相對乾淨的環境來測試,這邊是使用 docker 的版本,使用的映象檔是 denoland/deno,執行的指令是:
docker run -it --rm --network host denoland/deno bash
進入容器後,為了安裝套件,這邊還是會先去安裝 npm 這個套件管理工具(也可以用別的):
apt update && apt upgrade -y
apt install npm -y
之後,則是建立一個工作用的資料夾「llm_test
」,之後要在裡面安裝需要的套件。
mkdir llm_test
cd llm_test
接下來,則是來寫一個最簡單的測試程式,來確認可以成功地連上之前自己架設的 llama.cpp 伺服器了!
這邊在進入 deno 的環境前,會先需要透過 npm 安裝套件:
npm install langchain @langchain/openai
接下來就可以執行 deno
、進入 JavaScript 的互動環境,然後執行下面的指令:
const conf = {apiKey: "na", configuration: {baseURL: http://127.0.0.1:8080/v1}}; import { ChatOpenAI } from "@langchain/openai"; const llm = new ChatOpenAI(conf); await llm.invoke("what is llama 3?");
這邊的內容很簡單,只有四行:
-
第一行是定義一個
conf
、用來設定 OpenAI API Server 的參數。
由於自己自架設的,所以需要指定baseURL
來指到自己架設的伺服器,網址的部分要視狀況修改;而如果伺服器的部分有設定需要 API key 的話,這邊的apiKey
也要修改,沒有的話亂打就可以了(但是可能一定要給)。 -
把 LangChain 的 OpenAI 模組匯入使用。
如果是使用 node.js 的話,可能得改成用 require 的。 -
建立
ChatOpenAI
的物件llm
,這邊要把之前的設定參數傳進去。 -
透過
invoke()
來送出提示(prompt)。
之後,如果都正常的話,就會得到 OpenAI API 伺服器的推論結果了。它的結果應該會是像下面的形式:
lc_serializable: true,
lc_kwargs: {
content: “# What is LLaMA\n” +
“\n” +
“LLaMA is a large language model developed by Meta Research in 2022. It was trained “… 691 more characters,
tool_calls: [],
invalid_tool_calls: [],
additional_kwargs: { function_call: undefined, tool_calls: undefined },
response_metadata: {}
},
lc_namespace: [ “langchain_core”, “messages” ],
content: “# What is LLaMA\n” +
“\n” +
“LLaMA is a large language model developed by Meta Research in 2022. It was trained “… 691 more characters,
name: undefined,
additional_kwargs: { function_call: undefined, tool_calls: undefined },
response_metadata: {
tokenUsage: { completionTokens: 201, promptTokens: 19, totalTokens: 220 },
finish_reason: “stop”
},
tool_calls: [],
invalid_tool_calls: [],
usage_metadata: { input_tokens: 19, output_tokens: 201, total_tokens: 220 }
}
如果要想要看到完整的內容的回覆內容的話,則可以寫成:
let res = await llm.invoke("what is LLaMA 3?"); console.log(res.content);
而如果想要詢問其他內容的話,就只要替換 invoke()
的內容就可以了。
最基本的使用大概就是這樣了。
當然啦,由於這是最為簡單的操作,所以功能也相當有限;他理所當然地不會去找模型外的資料,同時也沒有前後文的記憶能力。
在這樣簡單的操作的狀況下,Heresy 試過幾個大語言模型給的回覆其實常常都還滿糟糕的,直接去 ChatGPT 或 Copilot 玩的效果都好很多。
而且不知道是相容性、或是參數設定的問題還是怎樣,在產生回復的時候常常後面會出現很多重複的文字,直到長度到達上限,變成在無謂地浪費時間…
感覺上,真的要玩到「能用」可能還得研究好一段時間了。 XD