“ 新版本的Langchain就像一个半自动的汽车,既有灵活性,又有稳定性。”
最近这几天在做Langchain的版本升级,不得不说Langchain版本升级之后和之前的差别还是很大的,问题主要表现在新版本的Langchain对智能体开发很友好,但对普通开发就不那么友好了,比如说生成式任务。
在Langchain的核心组件中,智能体排在第一位,以及紧随其后的几个核心组件,如模型,消息,工具,记忆和格式化输出等。
但在大模型应用开发中,主要应用方向有两种,一是普通的大模型应用开发,即非智能体项目;另一种是智能体应用开发,虽然说智能体应用是未来的主要方向,但在某些场景中并不需要复杂的智能体,而只需要简单的模型应用,如内容补全等生成式任务。
Langchain1.x版本
Langchain在之前的版本中,一直被很多人诟病的一点就是过渡封装,导致其中很多执行过程就是一个黑盒,改起来又特别麻烦;但过渡封装虽然有很多问题,但同时也有很多好处,那就是使用起来很简单,不论是模型,消息,历史记录等只需要简单的链式组合即可使用,它就像一个自动驾驶的汽车,操作简单。
而新版本的Langchain在智能体开发方面依然像一个自动驾驶的汽车,但在普通模型应用方面却像一个手动驾驶的汽车。
总之,新版本的Langchain给人的感觉就是,既可以自动驾驶,又需要手动驾驶;举例来说,使用Langchain1.x实现一个生成式任务,需要实现格式化输出和记忆功能应该怎么做?
这一点在老版本中的Langchain中很容易实现,如下代码所示只需要很简单的代码就可以实现具备记忆功能的多轮对话功能。
prompt = ChatPromptTemplate.from_messages([("system","You're an assistant who speaks in {language}. Respond in 20 words or fewer"),MessagesPlaceholder(variable_name="history"),("human","{input}")])chain = prompt | modelchain.invoke("你是谁")
但在新版本的Langchain中,历史记录没了,链式调用也没了,或者说你感受不到,但又已经无处不在。
在新版本中,链式调用被完全弱化了,在官方文档中基本上看不到Chain和|管道操作符。
但,换个角度想想之前基于管道符的链式调用不就是把提示词,模型和格式化输出给串到一条链上嘛;我们自己手动串联也是一样的。
from pydantic import BaseModel, Fieldclass Movie(BaseModel):"""A movie with details."""title: str = Field(..., description="The title of the movie")year: int = Field(..., description="The year the movie was released")director: str = Field(..., description="The director of the movie")rating: float = Field(..., description="The movie's rating out of 10")model_with_structure = model.with_structured_output(Movie)#格式化输出response = model_with_structure.invoke("Provide details about the movie Inception")print(response) # Movie(title="Inception", year=2010, director="Christopher Nolan", rating=8.8)
新版中,与模型的交互都是通过对话实现的,也就是messages,因此从本质上来说所谓的历史记录,就是消息历史;因此,我们需要自己构建一个消息队列的存取方式,以此来保存我们的历史对话。
state = {}def add_message(self, session_id, role, content):"""添加一条对话消息Args:session_id: 会话IDrole: 角色,如 "user" 或 "assistant"content: 对话内容"""# 如果会话不存在,创建一个新的会话列表if session_id not in self.state:self.state[session_id] = []# 添加新的对话消息self.state[session_id].append({"role": role,"content": content})
def get_conversation(self, session_id):"""获取指定会话的完整对话记录Args:session_id: 会话IDReturns:该会话的对话记录列表,如果会话不存在则返回None"""return self.state.get(session_id)
总之,新版本的Langchain对智能体功能进行更合理的重构和优化,但在普通生成式任务中,其给了更灵活的开发方式,使用最原始的messages消息列表实现,这即给了我们很大的自主权,但同时也增加了很多工作量。

