在開始進行我們的 AI 工具人的建立時,我們要先來理解一下一個東西,那就是 AI Framework,這裡我們先簡單聊聊我自已的想法 ~
首先用 Framework 不外乎有幾個好處 :
所以基本上如果我會是要用在產品,且是會迭代加會給其它人維護的情況下,我通常還是會配基本的 Framework。
然後至於我們這個 30 天要做的東西是否需要,事實上沒到一定要,因為這個只是學習範例,沒有要迭代,也沒人要維護,然後我這裡學 LangChain 主要還是因為公司用到,加上它目前應該是 AI 應用 Framework 中,最多人用的一個,因此才會以它為主題。
但也有不少人罵他,這個之後我們在來說說,再罵他之前 ~ 我們先來理解理解它。
我們這裡都會以我在撰寫時最新的 1.0.0-alpha 版本來進行說明,這個在 2025.09.02 終於正式發表是 1.0.0-alpha 了,看官網可能會在我們寫鐵人賽的期間出 stable 版,真是讓人心情不錯。
https://blog.langchain.com/langchain-langchain-1-0-alpha-releases/
然後文件是看這份:
https://docs.langchain.com/oss/javascript/langchain/overview
請別看到舊版的這份,會生氣
。
https://js.langchain.com/docs/concepts/ ( 舊版 )
🤔 然後至於為什麼要使用呢 ?
我自已是覺得,以長遠來看,用 LangChain 可以幫我們更快速的建立比較好維護的 AI Application。
為什麼說長遠呢 ? 因為我知道在 1.0.0 版本之前早期的 0.x 版本
一堆人在罵它,開發起來綁手綁腳,一堆抽象再抽象的鬼東西,真的用起來很靠腰,而且查了文件又發現他的文件又不一致,實際上使用又和文件的不一樣,嗯嗯真的很想罵髒話。
然是還在 1.0.0 版本後的文件,我自已是覺得有慢慢的收斂往好的方向來看,而且它本身的確有很多東西,可以減少我們開發 AI 應用的時間,所以整體來說我自已是覺得的使用它會有以下兩個好處 :
然後這裡我們就針對這兩個東西來說說 ~
根據官網的這份文件,它事實上提到了我們在開發應用的幾個功能,如下 :
https://docs.langchain.com/oss/javascript/langchain/overview
下面的功能我就只簡單的說明一下,因為之後的實作幾乎每一個地方都會細講到它們,然後只要記得他就是 AI 應用的功能。
事實上這上面的每一個功能我們都可以自已實作這個是沒錯,但它的確很多東西都幫我們實作好了,而且也節省了不少我們的時間。
當然 OpenAI SDK 也是可以做到這些事情,所以除非你確定只用 OpenAI 的話,用它是可以。但這裡是不太建議直接打 API 如下,然後其它東西都自已抽象化與自已手建,這樣真的太花時間了,加上後面好不好維護又是另一題。
import axios from "axios";
axios.post(
"https://api.openai.com/v1/chat/completions",
{
model: "gpt-5-mini",
messages: [
{ role: "system", content: "You are a helpful assistant" },
{ role: "user", content: "你好,可以幫我解釋什麼是 RAG 嗎?" }
],
},
{
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
},
}
)
不過我還是要備註一下,在最開始用 1.0.0 前的版本,我的確反而花了不少時間,尤其只是要做個簡單的東西,但後來有慢慢變好。
這個地方真的見人見智,因為加速與減速的人我都有聽過,但至少我看 1.0.0 後的版本,我自已覺得應該是會加速。
我覺得 LangChain 在增加 AI 產品維護性這塊,我自已覺得 1.0.0 是有加分,主要的理由有以下幾點 :
標準化
不同模型與工具的介面,並進一步抽象化常見流程(如 Prompt 管理、RAG pipeline ),讓咱們能用統一的方式組裝
複雜 AI 應用。所以整體來說,如果是多人開發,且 AI 產品會一直迭代上去的,我還是會建議用 Framework,至於要不要用 LangChain 我覺得還好,至少我自已覺得它算標準化的不錯了。
🤔 接下來我想談談他在進行標準化與組裝的核心概念 Runnable,我自已是覺得它算是整個的核心,因為你看它 source code 大部份的東西,都有實作它。
下面是官網某個地方所說。
These are core LangChain components (like LLMs, prompt templates, retrievers, etc.) that have been converted into Runnables so they can be composed in a pipeline
也就是說 Runnable 是整個 Langchain 的核心,基本上能完全理解它,那但大部份的情況下在開發 Langchain 應該都會串接的起來,接下來我們來詳細的來理解一下這個概念。
Runnable 本身不是 Langchain 才有的概念,它最早應該是在 Java,在 Langchain 中,它的 interface 如下 :
然後這個 interface 要求我們實作它時,需要有以下的方法 :
它事實上就只是統一的可執行單元的概念。
interface Runnable<In, Out, Options = any> {
//
invoke(input: In, options?: Partial<Options>): Promise<Out>;
// 批次執行,多筆輸入 → 多筆輸出
batch(
inputs: In[],
options?: Partial<Options> | Partial<Options>[],
opts?: { returnExceptions?: boolean }
): Promise<(Out | Error)[]>;
// 串流執行,逐步輸出結果
stream(
input: In,
options?: Partial<Options>
): Promise<AsyncIterable<Out>>;
// 轉換一個輸入資料流為輸出資料流
transform(
inputs: AsyncGenerator<In>,
options?: Partial<Options>
): AsyncGenerator<Out>;
// 取得名稱(方便觀測/除錯)
getName(suffix?: string): string;
}
🤔 整理一下 Runnable 的好處,我自已覺得目的有以下幾個 :
簡單串接範例
import { RunnableLambda } from "@langchain/core/runnables";
// 模擬:PromptTemplate - 將輸入組合為提示
const promptTemplate = RunnableLambda.from(async (input: { topic: string }) => {
return `請用簡單的方式解釋這個主題:${input.topic}`;
});
// 模擬:LLM - 將 prompt 回傳假設的回覆(實際應該是 ChatOpenAI / ChatAnthropic)
const fakeLLM = RunnableLambda.from(async (prompt: string) => {
return `這是針對「${prompt}」的解釋:它是很酷的技術。`;
});
// 模擬:OutputParser - 將回應轉為結構資料
const outputParser = RunnableLambda.from(async (response: string) => {
return {
summary: response,
length: response.length,
};
});
// 🧩 LCEL 組合:Prompt → LLM → Parser
const chain = promptTemplate.pipe(fakeLLM).pipe(outputParser)
const result = await chain.invoke({ topic: "AI" })
console.log(result)
然後如果要改成用實際的 AI Model 就只要改這樣。
// 真實的 OpenAI LLM
const openai = new ChatOpenAI({
model: "gpt-3.5-turbo",
temperature: 0.7,
openAIApiKey: process.env.OPENAI_API_KEY,
});
const llm = RunnableLambda.from(async (prompt: string) => {
const response = await openai.invoke(prompt);
return response;
});
// 🧩 LCEL 組合:Prompt → LLM → Parser
const chain = promptTemplate.pipe(llm).pipe(outputParser);
這是我們上面那段程式碼,然後在 invoke 的地方加上的 RunnableConfig。
// 🧩 LCEL 組合:Prompt → LLM → Parser
const chain = promptTemplate.pipe(fakeLLM).pipe(outputParser);
const result = await chain.invoke(
{ topic: "AI" },
{
// 追蹤 / 過濾用
tags: ["blog", "demo", "invoke"],
// 想記錄但不影響邏輯的上下文
metadata: { userId: "u-123", sessionId: "s-456" },
// 給 runnable 的動態參數(你自己定義要讀什麼 key)
configurable: { style: "白話解釋", tone: "活潑" },
// 這次執行的可讀名稱(在 trace/log 特別好找)
runName: "ExplainTopicInvoke",
}
);
console.log(result);
然後接下來你在你的 Observability 服務,例如 LangChain 的好朋友 LangSmith 上就會看到相對應的 tags、metadata 等,這些你在未來分析這些行為與優化你的 Agent 都會有一定的幫助。
不過不得說說,自從 1.0.0 以後,官網換了一份文件後,就沒有一份文件專門說明 Runnable 了,舊版本的文件在這,但不確定新版的文件會不會增加。
https://js.langchain.com/docs/concepts/runnables
雖然說 Chain 是整個 LangChain 的核心,但事實上很多地方都可以用 LangGraph
替換掉,不過可能 Chain 慢慢移除重心,但 Runnable 這個概念應該還是不會,因為在 LangGraph 有很多類別也都有實作到它,所以知道這個東西應該也是好的 ~ 你看下面是 LangGraph 的 Class,它裡面還是有 Runnable。
declare class Pregel<
Nodes extends StrRecord<string, PregelNode>,
Channels extends StrRecord<string, BaseChannel>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ContextType extends Record<string, any> = StrRecord<string, any>,
InputType = PregelInputType,
OutputType = PregelOutputType,
StreamUpdatesType = InputType,
StreamValuesType = OutputType,
NodeReturnType = unknown
> extends PartialRunnable<
InputType | CommandInstance | null,
OutputType,
PregelOptions<Nodes, Channels, ContextType>
> implements
PregelInterface<Nodes, Channels, ContextType>,
PregelParams<Nodes, Channels> {}
這篇文章我們簡單的理解了整個 LangChain,並且也理解了它對接下來開發 AI Application 的好處,還有就是 LangChain 的核心 Runnable 的概念。
那至於我會不會推薦用 LangChain 呢 ? 如果有以下幾個條件,我會不太推 :
AI Framework 是用自由度換成一些維護性+開發速度
所以整體來說,排除掉以上情況,我自已都會找個 AI Framework 來用用,因為我自已很看重維護度,真的看過太多自幹的東西,最後累的都是後來的維護者。然後我自已是沒有太能真的比較其它現有有 AI Framework,所以在這一塊我的結論是 :
我推薦用 AI Framework 來開發,但要不要用 LangChain 可以想一下 ~ 如果有其它更好的,沒事別自幹