新闻  |   论坛  |   博客  |   在线研讨会
我为什么放弃了 LangChain?(1)
机器之心 | 2023-07-24 07:16:00    阅读:278   发布文章

「LangChain 的流行已经扭曲了围绕其本身的人工智能创业生态系统,这就是为什么我不得不坦诚自己对它的疑虑。」

如果你关注了过去几个月中人工智能的爆炸式发展,那你大概率听说过 LangChain。

图片

简单来说,LangChain 是一个 Python 和 JavaScript 库,由 Harrison Chase 开发,用于连接 OpenAI 的 GPT API(后续已扩展到更多模型)以生成人工智能文本。
更具体地说,它是论文《ReAct: Synergizing Reasoning and Acting in Language Models》的实现:该论文展示了一种提示技术,允许模型「推理」(通过思维链)和「行动」(通过能够使用预定义工具集中的工具,例如能够搜索互联网)。

图片


论文链接:https://arxiv.org/pdf/2210.03629.pdf
事实证明,这种组合能够大幅提高输出文本的质量,并使大型语言模型具备正确解决问题的能力。
2023 年 3 月,ChatGPT 的 API 因升级降价大受欢迎,LangChain 的使用也随之爆炸式增长。
这之后,LangChain 在没有任何收入也没有任何明显的创收计划的情况下,获得了 1000 万美元的种子轮融资和 2000-2500 万美元的 A 轮融资,估值达到 2 亿美元左右。
图片ReAct 论文中的 ReAct 流示例。

由 LangChain 推广的 ReAct 工作流在 InstructGPT/text-davinci-003 中特别有效,但成本很高,而且对于小型项目来说并不容易使用。
Max Woolf 是一位 BuzzFeed 的数据科学家。他也使用过 LangChain,这次经历总体来说不太好。
让我们看看他经历了什么。
「是只有我不会用吗?」
在 BuzzFeed 工作时,我有一个任务是为 Tasty 品牌创建一个基于 ChatGPT 的聊天机器人(后来在 Tasty iOS 应用中发布为 Botatouille),可以与用户聊天并提供相关食谱。
具体来说,源菜谱将被转换为嵌入式菜谱并保存在一个向量存储中:例如如果用户询问「健康食品」,查询会被转换为嵌入式菜谱,然后执行近似最近邻搜索以找到与嵌入式查询相似的菜谱,然后将其作为附加上下文提供给 ChatGPT,再由 ChatGPT 显示给用户。这种方法通常被称为检索增强生成。

图片使用检索增强生成的聊天机器人的架构示例。

「LangChain 是 RAG 最受欢迎的工具,所以我想这是学习它的最佳时机。我花了一些时间阅读 LangChain 的全面文档,以便更好地理解如何最好地利用它。」


经过一周的研究,我一无所获。运行 LangChain 的 demo 示例确实可以工作,但是任何调整它们以适应食谱聊天机器人约束的尝试都会失败。在解决了这些 bug 之后,聊天对话的整体质量很差,而且毫无趣味。经过紧张的调试之后,我没有找到任何解决方案。
总而言之,我遇到了生存危机:当很多其他 ML 工程师都能搞懂 LangChain 时,我却搞不懂,难道我是一个毫无价值的机器学习工程师吗?
我用回了低级别的 ReAct 流程,它立即在对话质量和准确性上超过了我的 LangChain 实现。
浪费了一个月的时间来学习和测试 LangChain,我的这种生存危机在看到 Hacker News 关于有人用 100 行代码重现 LangChain 的帖子后得到了缓解,大部分评论都在发泄对 LangChain 的不满:

图片


LangChain 的问题在于它让简单的事情变得相对复杂,而这种不必要的复杂性造成了一种「部落主义」,损害了整个新兴的人工智能生态系统。
所以,如果你是一个只想学习如何使用 ChatGPT 的新手,绝对不要从 LangChain 开始。
LangChain 的「Hello World」

LangChain 的快速入门,从一个关于如何通过 Python 与 LLM/ChatGPT 进行简单交互的迷你教程开始。例如,创建一个可以将英语翻译成法语的机器人:

from langchain.chat_models import ChatOpenAIfrom langchain.schema import (    AIMessage,    HumanMessage,    SystemMessage)
chat = ChatOpenAI(temperature=0)chat.predict_messages([HumanMessage(content="Translate this sentence from English to French. I love programming.")])# AIMessage(content="J'adore la programmation.", additional_kwargs={}, example=False)
使用 OpenAI ChatGPT 官方 Python 库的等效代码:
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 库的代码量大致相同,估计 LangChain 合并了更多对象类,但代码优势并不明显。 
提示模板的示例揭示了 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,一个存在于每个 Python 安装中的功能,但是有额外的步骤。为什么我们需要使用这些 PromptTemplates 来做同样的事情呢?
我们真正想做的是知道如何创建 Agent,它结合了我们迫切想要的 ReAct 工作流。幸运的是,有一个演示,它利用了 SerpApi 和另一个数学计算工具,展示了 LangChain 如何区分和使用两种不同的工具:
from langchain.agents import load_toolsfrom langchain.agents import initialize_agentfrom langchain.agents import AgentTypefrom langchain.chat_models import ChatOpenAIfrom 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?")
各个工具如何工作?AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION 到底是什么?agent.run () 的结果输出(仅在 verbose=True 时出现)更有帮助。


> 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 yearsThought: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'
文档中没有明确说明,但是在每个思想 / 行动 / 观察中都使用了自己的 API 调用 OpenAI,所以链条比你想象的要慢。另外,为什么每个动作都是一个 dict?答案在后面,而且非常愚蠢。
最后,LangChain 如何存储到目前为止的对话?
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 有必要这样做吗?将此调整为最小的 openai 实现:
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?

这样代码行数就少了,而且信息保存的位置和时间都很清楚,不需要定制对象类。你可以说我对教程示例吹毛求疵,我也同意每个开源库都有值得吹毛求疵的地方(包括我自己的)。但是,如果吹毛求疵的地方比库的实际好处还多,那么这个库就根本不值得使用。
因为,如果快速入门都已经这么复杂,那么实际使用 LangChain 会有多痛苦呢?


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客