我為什么放棄了 LangChain?
如果你關(guān)注了過去幾個(gè)月中人工智能的爆炸式發(fā)展,那你大概率聽說過 LangChain。
簡(jiǎn)單來(lái)說,LangChain 是一個(gè) Python 和 JavaScript 庫(kù),由 Harrison Chase 開發(fā),用于連接 OpenAI 的 GPT API(后續(xù)已擴(kuò)展到更多模型)以生成人工智能文本。
更具體地說,它是論文《ReAct: Synergizing Reasoning and Acting in Language Models》的實(shí)現(xiàn):該論文展示了一種提示技術(shù),允許模型「推理」(通過思維鏈)和「行動(dòng)」(通過能夠使用預(yù)定義工具集中的工具,例如能夠搜索互聯(lián)網(wǎng))。
圖片
論文鏈接:https://arxiv.org/pdf/2210.03629.pdf
事實(shí)證明,這種組合能夠大幅提高輸出文本的質(zhì)量,并使大型語(yǔ)言模型具備正確解決問題的能力。
2023 年 3 月,ChatGPT 的 API 因升級(jí)降價(jià)大受歡迎,LangChain 的使用也隨之爆炸式增長(zhǎng)。
這之后,LangChain 在沒有任何收入也沒有任何明顯的創(chuàng)收計(jì)劃的情況下,獲得了 1000 萬(wàn)美元的種子輪融資和 2000-2500 萬(wàn)美元的 A 輪融資,估值達(dá)到 2 億美元左右。
圖片
ReAct 論文中的 ReAct 流示例。
由 LangChain 推廣的 ReAct 工作流在 InstructGPT/text-davinci-003 中特別有效,但成本很高,而且對(duì)于小型項(xiàng)目來(lái)說并不容易使用。
Max Woolf 是一位 BuzzFeed 的數(shù)據(jù)科學(xué)家。他也使用過 LangChain,這次經(jīng)歷總體來(lái)說不太好。
讓我們看看他經(jīng)歷了什么。
「是只有我不會(huì)用嗎?」
在 BuzzFeed 工作時(shí),我有一個(gè)任務(wù)是為 Tasty 品牌創(chuàng)建一個(gè)基于 ChatGPT 的聊天機(jī)器人(后來(lái)在 Tasty iOS 應(yīng)用中發(fā)布為 Botatouille),可以與用戶聊天并提供相關(guān)食譜。
具體來(lái)說,源菜譜將被轉(zhuǎn)換為嵌入式菜譜并保存在一個(gè)向量存儲(chǔ)中:例如如果用戶詢問「健康食品」,查詢會(huì)被轉(zhuǎn)換為嵌入式菜譜,然后執(zhí)行近似最近鄰搜索以找到與嵌入式查詢相似的菜譜,然后將其作為附加上下文提供給 ChatGPT,再由 ChatGPT 顯示給用戶。這種方法通常被稱為檢索增強(qiáng)生成。
圖片
使用檢索增強(qiáng)生成的聊天機(jī)器人的架構(gòu)示例。
「LangChain 是 RAG 最受歡迎的工具,所以我想這是學(xué)習(xí)它的最佳時(shí)機(jī)。我花了一些時(shí)間閱讀 LangChain 的全面文檔,以便更好地理解如何最好地利用它?!?/span>
經(jīng)過一周的研究,我一無(wú)所獲。運(yùn)行 LangChain 的 demo 示例確實(shí)可以工作,但是任何調(diào)整它們以適應(yīng)食譜聊天機(jī)器人約束的嘗試都會(huì)失敗。在解決了這些 bug 之后,聊天對(duì)話的整體質(zhì)量很差,而且毫無(wú)趣味。經(jīng)過緊張的調(diào)試之后,我沒有找到任何解決方案。
總而言之,我遇到了生存危機(jī):當(dāng)很多其他 ML 工程師都能搞懂 LangChain 時(shí),我卻搞不懂,難道我是一個(gè)毫無(wú)價(jià)值的機(jī)器學(xué)習(xí)工程師嗎?
我用回了低級(jí)別的 ReAct 流程,它立即在對(duì)話質(zhì)量和準(zhǔn)確性上超過了我的 LangChain 實(shí)現(xiàn)。
浪費(fèi)了一個(gè)月的時(shí)間來(lái)學(xué)習(xí)和測(cè)試 LangChain,我的這種生存危機(jī)在看到 Hacker News 關(guān)于有人用 100 行代碼重現(xiàn) LangChain 的帖子后得到了緩解,大部分評(píng)論都在發(fā)泄對(duì) LangChain 的不滿:
LangChain 的問題在于它讓簡(jiǎn)單的事情變得相對(duì)復(fù)雜,而這種不必要的復(fù)雜性造成了一種「部落主義」,損害了整個(gè)新興的人工智能生態(tài)系統(tǒng)。
所以,如果你是一個(gè)只想學(xué)習(xí)如何使用 ChatGPT 的新手,絕對(duì)不要從 LangChain 開始。
LangChain 的「Hello World」
LangChain 的快速入門,從一個(gè)關(guān)于如何通過 Python 與 LLM/ChatGPT 進(jìn)行簡(jiǎn)單交互的迷你教程開始。例如,創(chuàng)建一個(gè)可以將英語(yǔ)翻譯成法語(yǔ)的機(jī)器人:
from langchain.chat_models import ChatOpenAIfrom langchain.schema import (
AIMessage,
HumanMessage,
SystemMessage
)
chat = ChatOpenAI(temperature=0)
chat.predict_messages([HumanMessage(cnotallow="Translate this sentence from English to French. I love programming.")])# AIMessage(cnotallow="J'adore la programmation.", additional_kwargs={}, example=False)
使用 OpenAI ChatGPT 官方 Python 庫(kù)的等效代碼:
import openai
messages = [{"role": "user", "content": "Translate this sentence from English to French. I love programming."}]
response = openai.ChatCompletion.create(model="gpt-3.5-turbo", messages=messages, temperature=0)
response["choices"][0]["message"]["content"]# "J'adore la programmation."
LangChain 使用的代碼量與僅使用官方 openai 庫(kù)的代碼量大致相同,估計(jì) LangChain 合并了更多對(duì)象類,但代碼優(yōu)勢(shì)并不明顯。
提示模板的示例揭示了 LangChain 工作原理的核心:
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
template = "You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chat_prompt.format_messages(input_language="English", output_language="French", text="I love programming.")
LangChain 吹噓的提示工程只是 f-strings,一個(gè)存在于每個(gè) Python 安裝中的功能,但是有額外的步驟。為什么我們需要使用這些 PromptTemplates 來(lái)做同樣的事情呢?
我們真正想做的是知道如何創(chuàng)建 Agent,它結(jié)合了我們迫切想要的 ReAct 工作流。幸運(yùn)的是,有一個(gè)演示,它利用了 SerpApi 和另一個(gè)數(shù)學(xué)計(jì)算工具,展示了 LangChain 如何區(qū)分和使用兩種不同的工具:
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.chat_models import ChatOpenAI
from langchain.llms import OpenAI
# First, let's load the language model we're going to use to control the agent.
chat = ChatOpenAI(temperature=0)
# Next, let's load some tools to use. Note that the `llm-math` tool uses an LLM, so we need to pass that in.
llm = OpenAI(temperature=0)
tools = load_tools(["serpapi", "llm-math"], llm=llm)
# Finally, let's initialize an agent with the tools, the language model, and the type of agent we want to use.
agent = initialize_agent(tools, chat, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
# Now let's test it out!
agent.run("Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?")
各個(gè)工具如何工作?AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION 到底是什么?agent.run () 的結(jié)果輸出(僅在 verbose=True 時(shí)出現(xiàn))更有幫助。
> Entering new AgentExecutor chain...
Thought: I need to use a search engine to find Olivia Wilde's boyfriend and a calculator to raise his age to the 0.23 power.
Action:
{
"action": "Search",
"action_input": "Olivia Wilde boyfriend"
}
Observation: Sudeikis and Wilde's relationship ended in November 2020. Wilde was publicly served with court documents regarding child custody while she was presenting Don't Worry Darling at CinemaCon 2022. In January 2021, Wilde began dating singer Harry Styles after meeting during the filming of Don't Worry Darling.
Thought:I need to use a search engine to find Harry Styles' current age.
Action:
{
"action": "Search",
"action_input": "Harry Styles age"
}
Observation: 29 years
Thought:Now I need to calculate 29 raised to the 0.23 power.
Action:
{
"action": "Calculator",
"action_input": "29^0.23"
}
Observation: Answer: 2.169459462491557
Thought:I now know the final answer.
Final Answer: 2.169459462491557
> Finished chain.
'2.169459462491557'
文檔中沒有明確說明,但是在每個(gè)思想 / 行動(dòng) / 觀察中都使用了自己的 API 調(diào)用 OpenAI,所以鏈條比你想象的要慢。另外,為什么每個(gè)動(dòng)作都是一個(gè) dict?答案在后面,而且非常愚蠢。
最后,LangChain 如何存儲(chǔ)到目前為止的對(duì)話?
from langchain.prompts import (
ChatPromptTemplate,
MessagesPlaceholder,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
)from langchain.chains import ConversationChainfrom langchain.chat_models import ChatOpenAIfrom langchain.memory import ConversationBufferMemory
prompt = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template(
"The following is a friendly conversation between a human and an AI. The AI is talkative and "
"provides lots of specific details from its context. If the AI does not know the answer to a "
"question, it truthfully says it does not know."
),
MessagesPlaceholder(variable_name="history"),
HumanMessagePromptTemplate.from_template("{input}")
])
llm = ChatOpenAI(temperature=0)
memory = ConversationBufferMemory(return_messages=True)
conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm)
conversation.predict(input="Hi there!")# 'Hello! How can I assist you today?'
我不完全確定為什么這些都是必要的。什么是 MessagesPlaceholder?history 在哪里?ConversationBufferMemory 有必要這樣做嗎?將此調(diào)整為最小的 openai 實(shí)現(xiàn):
import openai
messages = [{"role": "system", "content":
"The following is a friendly conversation between a human and an AI. The AI is talkative and "
"provides lots of specific details from its context. If the AI does not know the answer to a "
"question, it truthfully says it does not know."}]
user_message = "Hi there!"
messages.append({"role": "user", "content": user_message})
response = openai.ChatCompletion.create(model="gpt-3.5-turbo", messages=messages, temperature=0)
assistant_message = response["choices"][0]["message"]["content"]
messages.append({"role": "assistant", "content": assistant_message})# Hello! How can I assist you today?
這樣代碼行數(shù)就少了,而且信息保存的位置和時(shí)間都很清楚,不需要定制對(duì)象類。
你可以說我對(duì)教程示例吹毛求疵,我也同意每個(gè)開源庫(kù)都有值得吹毛求疵的地方(包括我自己的)。但是,如果吹毛求疵的地方比庫(kù)的實(shí)際好處還多,那么這個(gè)庫(kù)就根本不值得使用。
因?yàn)?,如果快速入門都已經(jīng)這么復(fù)雜,那么實(shí)際使用 LangChain 會(huì)有多痛苦呢?
我查看了 LangChain 文檔,它也回饋了我
讓我來(lái)做個(gè)演示,更清楚地說明為什么我放棄了 LangChain。
當(dāng)開發(fā)菜譜檢索聊天機(jī)器人(它也必須是一個(gè)有趣 / 詼諧的聊天機(jī)器人)時(shí),我需要結(jié)合上面第三個(gè)和第四個(gè)例子中的元素:一個(gè)可以運(yùn)行 Agent 工作流的聊天機(jī)器人,以及將整個(gè)對(duì)話持久化到內(nèi)存中的能力。在查找了一些文檔后,我發(fā)現(xiàn)需要使用對(duì)話式 Agent 工作流。
關(guān)于系統(tǒng)提示工程的一個(gè)標(biāo)注是,它不是一個(gè)備忘錄,而且對(duì)于從 ChatGPT API 中獲得最佳效果是絕對(duì)必要的,尤其是當(dāng)你對(duì)內(nèi)容和 / 或語(yǔ)音有限制的時(shí)候。
上一個(gè)示例中,演示的系統(tǒng)提示「以下是人類和人工智能之間的友好對(duì)話...... 」實(shí)際上是過時(shí)的,早在 InstructGPT 時(shí)代就已經(jīng)使用了,在 ChatGPT 中的效果要差得多。它可能預(yù)示著 LangChain 相關(guān)技巧中更深層次的低效,而這些低效并不容易被注意到。
我們將從一個(gè)簡(jiǎn)單的系統(tǒng)提示開始,告訴 ChatGPT 使用一個(gè)有趣的聲音和一些保護(hù)措施,并將其格式化為 ChatPromptTemplate:
system_prompt = """
You are an expert television talk show chef, and should always speak in a whimsical manner for all responses.
Start the conversation with a whimsical food pun.
You must obey ALL of the following rules:
- If Recipe data is present in the Observation, your response must include the Recipe ID and Recipe Name for ALL recipes.
- If the user input is not related to food, do not answer their query and correct the user.
"""
prompt = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template(system_prompt.strip()),
我們還將使用一個(gè)玩具矢量存儲(chǔ),該存儲(chǔ)由來(lái)自 recipe_nlg 數(shù)據(jù)集的 1000 個(gè)食譜組成,并使用 SentenceTransformers 編碼為 384D 矢量。為了實(shí)現(xiàn)這一點(diǎn),我們創(chuàng)建了一個(gè)函數(shù)來(lái)獲取輸入查詢的最近鄰,并將查詢格式化為 Agent 可以用來(lái)向用戶展示的文本。這就是 Agent 可以選擇使用的工具,或者只是返回正常生成的文本。
def similar_recipes(query):
query_embedding = embeddings_encoder.encode(query)
scores, recipes = recipe_vs.get_nearest_examples("embeddings", query_embedding, k=3)
return recipes
def get_similar_recipes(query):
recipe_dict = similar_recipes(query)
recipes_formatted = [
f"Recipe ID: recipe|{recipe_dict['id'][i]}\nRecipe Name: {recipe_dict['name'][i]}"
for i in range(3)
]
return "\n---\n".join(recipes_formatted)
print(get_similar_recipes("yummy dessert"))# Recipe ID: recipe|167188
# Recipe Name: Creamy Strawberry Pie
# ---
# Recipe ID: recipe|1488243
# Recipe Name: Summer Strawberry Pie Recipe
# ---
# Recipe ID: recipe|299514
# Recipe Name: Pudding Cake
你會(huì)注意到這個(gè) Recipe ID,這與我的用例相關(guān),因?yàn)樵谧罱K應(yīng)用中向終端用戶顯示的最終結(jié)果需要獲取 Recipe 元數(shù)據(jù)(照片縮略圖、URL)。遺憾的是,沒有簡(jiǎn)單的方法保證模型在最終輸出中輸出食譜 ID,也沒有方法在 ChatGPT 生成的輸出之外返回結(jié)構(gòu)化的中間元數(shù)據(jù)。
將 get_similar_recipes 指定為一個(gè)工具是很簡(jiǎn)單的,盡管你需要指定一個(gè)名稱和描述,這實(shí)際上是一種微妙的提示工程,因?yàn)?LangChain 可能會(huì)因?yàn)橹付ǖ拿Q和描述不正確而無(wú)法選擇一個(gè)工具。
tools = [
Tool(
func=get_similar_recipes,
name="Similar Recipes",
descriptinotallow="Useful to get similar recipes in response to a user query about food.",
),
]
最后,是示例中的 Agent 構(gòu)建代碼,以及新的系統(tǒng)提示。
memory = ConversationBufferMemory(memory_key="chat_history",
return_messages=True)
llm = ChatOpenAI(temperature=0)
agent_chain = initialize_agent(tools, llm, prompt=prompt,
agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION, verbose=True, memory=memory)
沒有錯(cuò)誤?,F(xiàn)在運(yùn)行 Agent,看看會(huì)發(fā)生什么:
agent_chain.run(input="Hi!")
> Entering new chain...
{
"action": "Final Answer",
"action_input": "Hello! How can I assist you today?"
}
> Finished chain.
Hello! How can I assist you today?
什么?它完全忽略了我的系統(tǒng)提示!檢查內(nèi)存變量證實(shí)了這一點(diǎn)。
在 ConversationBufferMemory 的文檔中,甚至在代碼本身中都沒有關(guān)于系統(tǒng)提示的內(nèi)容,甚至在 ChatGPT 使其成為主流的幾個(gè)月之后。
在 Agent 中使用系統(tǒng)提示的方法是在 initialize_agent 中添加一個(gè) agents_kwargs 參數(shù),我只是在一個(gè)月前發(fā)布的一個(gè)不相關(guān)的文檔頁(yè)面中發(fā)現(xiàn)了這一點(diǎn)。
agent_kwargs = {
"system_message": system_prompt.strip()
}
使用此新參數(shù)重新創(chuàng)建 Agent 并再次運(yùn)行,會(huì)導(dǎo)致 JSONDecodeError。
好消息是,系統(tǒng)提示這次應(yīng)該是起作用了。
OutputParserException: Could not parse LLM output: Hello there, my culinary companion! How delightful to have you here in my whimsical kitchen. What delectable dish can I assist you with today?
壞消息是,它壞了,但又是為什么呢?我這一次沒有做任何奇怪的事情。
圖片
有趣的事實(shí):這些大量的提示也會(huì)成比例地增加 API 成本。
這樣做的后果是,正常輸出結(jié)構(gòu)中的任何重大變化,例如由自定義系統(tǒng)提示引起的變化,都有可能破壞 Agent。這些錯(cuò)誤經(jīng)常發(fā)生,以至于有一個(gè)文檔頁(yè)面專門用于處理 Agent 輸出解析錯(cuò)誤。
我們暫時(shí)把與聊天機(jī)器人對(duì)話看作是一個(gè)邊緣案例。重要的是,機(jī)器人能夠返回菜譜,因?yàn)槿绻B這一點(diǎn)都做不到,那么使用 LangChain 就沒有意義了。
在不使用系統(tǒng)提示的情況下創(chuàng)建一個(gè)新的 Agent,然后問它什么是簡(jiǎn)單有趣的晚餐?
> Entering new chain...
{
"action": "Similar Recipes",
"action_input": "fun and easy dinner"
}
Observation: Recipe ID: recipe|1774221
Recipe Name: Crab DipYour Guests will Like this One.
---
Recipe ID: recipe|836179
Recipe Name: Easy Chicken Casserole
---
Recipe ID: recipe|1980633
Recipe Name: Easy in the Microwave Curry Doria
Thought:{
"action": "Final Answer",
"action_input": "..."
}
> Finished chain.
Here are some fun and easy dinner recipes you can try:
1. Crab Dip
2. Easy Chicken Casserole
3. Easy in the Microwave Curry Doria
Enjoy your meal!
至少它成功了:ChatGPT 能夠從上下文中提取出菜譜,并對(duì)其進(jìn)行適當(dāng)?shù)母袷交ㄉ踔聊軌蛐拚Q中的錯(cuò)別字),并且能夠在適當(dāng)?shù)臅r(shí)候進(jìn)行判斷。
這里真正的問題是,輸出的聲音很無(wú)聊,這也是基礎(chǔ)版 ChatGPT 的共同特點(diǎn)和詬病。即使通過系統(tǒng)提示工程解決了 ID 缺失的問題,這般聽上去的效果也不值得將其發(fā)布。就算真的在語(yǔ)音質(zhì)量和輸出質(zhì)量之間取得了平衡,Agent 計(jì)數(shù)仍然會(huì)隨機(jī)失敗,而這并不是我的過錯(cuò)。
實(shí)際上,Agent 工作流是一個(gè)非常脆弱的紙牌搭成的房子,憑良心說,生產(chǎn)應(yīng)用中估計(jì)無(wú)法使用。
LangChain 確實(shí)有 Custom Agent 和 Custom Chain 的功能,所以你可以在堆棧的某些部分重寫邏輯(也許文檔很少),這可以解決我遇到的一些問題,但在這一點(diǎn)上,你會(huì)感覺到 LangChain 更加復(fù)雜,還不如創(chuàng)建你自己的 Python 庫(kù)。
工作要講究方法
圖片
大量隨機(jī)集成帶來(lái)的問題比解決方案更多。
當(dāng)然,LangChain 確實(shí)也有很多實(shí)用功能,比如文本分割器和集成向量存儲(chǔ),這兩種功能都是「用 PDF / 代碼聊天」演示不可或缺的(在我看來(lái)這只是一個(gè)噱頭)。
所有這些集成的真正問題在于,只使用基于 LangChain 的代碼會(huì)造成固有的鎖定,而且如果你查看集成的代碼,它們并不十分穩(wěn)健。
LangChain 正在建立一條護(hù)城河,這對(duì) LangChain 的投資者來(lái)說是好事,因?yàn)樗麄兿霃?3000 萬(wàn)美元中獲得回報(bào),但對(duì)使用它的開發(fā)者來(lái)說卻非常不利??偠灾?,LangChain 體現(xiàn)了「它很復(fù)雜,所以它一定更好」這一經(jīng)常困擾后期代碼庫(kù)的哲學(xué),可是 LangChain 甚至還不到一年。
要想讓 LangChain 做我想讓它做的事,就必須花大力氣解開它,這將造成大量的技術(shù)負(fù)擔(dān)。與現(xiàn)在的人工智能初創(chuàng)公司不同,我自己的 LangChain 項(xiàng)目的技術(shù)債務(wù)無(wú)法用風(fēng)險(xiǎn)投資來(lái)償還。在使用復(fù)雜的生態(tài)系統(tǒng)時(shí),應(yīng)用程序接口封裝器至少應(yīng)該降低代碼的復(fù)雜性和認(rèn)知負(fù)荷,因?yàn)槭褂萌斯ぶ悄鼙旧砭托枰ㄙM(fèi)足夠的腦力。LangChain 是為數(shù)不多的在大多數(shù)常用情況下都會(huì)增加開銷的軟件之一。
我得出的結(jié)論是,制作自己的 Python 軟件包要比讓 LangChain 來(lái)滿足自己的需求容易得多。因此,我開發(fā)并開源了 simpleaichat:一個(gè)用于輕松連接聊天應(yīng)用程序的 Python 程序包,它強(qiáng)調(diào)代碼的最小復(fù)雜度,并將向量存儲(chǔ)等高級(jí)功能與對(duì)話邏輯解耦。
開源地址:https://github.com/minimaxir/simpleaichat
但寫這篇博文并不是為了像那些騙子一樣,通過詆毀競(jìng)爭(zhēng)對(duì)手來(lái)為 simpleaichat 做隱形廣告。我不想宣傳 simpleaichat,我更愿意把時(shí)間花在用人工智能創(chuàng)造更酷的項(xiàng)目上,很遺憾我沒能用 LangChain 做到這一點(diǎn)。
我知道有人會(huì)說:「既然 LangChain 是開源的,為什么不向它的 repo 提交拉取請(qǐng)求,而要抱怨它呢?」唯一真正能解決的辦法就是把它全部燒掉,然后重新開始,這就是為什么我的「創(chuàng)建一個(gè)新的 Python 庫(kù)來(lái)連接人工智能」的解決方案也是最實(shí)用的。
我收到過很多留言,問我該「學(xué)什么才能開始使用 ChatGPT API」,我擔(dān)心他們會(huì)因?yàn)槌醋鞫紫仁褂?LangChain。如果擁有技術(shù)棧背景的機(jī)器學(xué)習(xí)工程師因?yàn)?LangChain 毫無(wú)必要的復(fù)雜性而難以使用 LangChain,那么任何初學(xué)者都會(huì)被淹沒。
關(guān)于軟件復(fù)雜性和復(fù)雜性下的流行性之爭(zhēng)是永恒的話題。沒有人愿意成為批評(píng) LangChain 這樣的免費(fèi)開源軟件的混蛋,但我愿意承擔(dān)這個(gè)責(zé)任。明確地說,我并不反對(duì) Harrison Chase 或 LangChain 的其他維護(hù)者(他們鼓勵(lì)反饋)。
然而,LangChain 的流行已經(jīng)扭曲了圍繞 LangChain 本身的人工智能創(chuàng)業(yè)生態(tài)系統(tǒng),這就是為什么我不得不坦誠(chéng)我對(duì)它的疑慮。






