在本文中,我们将介绍如何在 LangGraph 中构建链。构建链使我们能够组合 LangChain 的各种组件,例如:
聊天信息
首先,我们来了解一下LangGraph中的聊天信息是什么。聊天信息是LangGraph中用于表示不同类型对话交流的结构化对象。这些包括来自人类的信息、来自AI助手的回复以及系统级信息。每种信息类型在管理和组织应用程序内的对话流方面都起着特定的作用。
以下是我们在LangChain中使用Python创建聊天信息的方法,
from langchain_core.messages import HumanMessage, AIMessage
from pprint import pprint
messages = [AIMessage(content="Hello, how are you?", name="LLM")]
messages.extend([HumanMessage(content="I'm fine, thank you.", name="Human")])
messages.extend([AIMessage(content="I'm fine too. How is work going on your end?", name="LLM")])
messages.extend([HumanMessage(content="Work is going well, thank you for asking.", name="Human")])
for m in messages:
m.pretty_print()
聊天模型
聊天模型帮助我们向大型语言模型(LLM)发送包含一系列消息(就像我们在聊天信息中所拥有的那样)的调用。
聊天模型其实就是大型语言模型,它们允许我们以双方正常聊天的方式进行对话。从之前提到的聊天信息中,我们可以看到一个人类(HumanMessage)与一个AI大型语言模型(AIMessage)之间的聊天对话。
通过聊天模型(这些模型已经过微调,可以进行聊天对话),我们可以传入这种聊天信息,并让大型语言模型以AIMessage类的形式(至少在LangChain中是这样)向我们做出回应。
让我们使用之前创建的聊天信息列表来看一个简短的示例。
from langchain_openai import ChatOpenAI
# Creating chat model
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
results = model.invoke(messages)
print(results)
print("====================================")
print(results.response_metadata)
工具
在AI代理方面,工具是代码块,它们赋予AI代理在现实世界中采取行动的能力,比如调用外部API、执行代码等等。基本上,工具为代理提供了行动的能力,即AI代理的“行动”部分。
大型语言模型(LLM)运行这些工具的能力被称为工具调用。如今,大多数LLM都提供了这种能力。
在LangGraph中,我们可以将工具绑定到我们的LLM或聊天模型上。
以下是在LangChain中将一个简单的工具(Python函数)添加到聊天模型中的示例。
def addition(a: int, b: int) -> int:
"""This tool is to be used to add two numbers together"""
return a + b
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
llm_with_tool = model.bind_tools([addition])
llm_with_tool_response = llm_with_tool.invoke([HumanMessage(content="What is 2 + 2?", name="Human")])
print(llm_with_tool_response)
print("=============================")
print(llm_with_tool_response.additional_kwargs["tool_calls"])
使用消息作为状态
以下是我们如何实现这一点的方法:
from langchain_core.messages import AnyMessage
from typing import TypedDict, List
class MessageState(TypedDict):
messages: List[AnyMessage]
Reducer 函数
在前面的部分中,我们讨论了默认情况下每个节点的先前状态是如何覆盖图状态的。这可能会阻止我们在聊天消息(在这种情况下即我们的图状态,因为我们使用消息作为图状态)中保留较早的消息。
幸运的是,我们有 reducer 函数;这些函数帮助我们指定状态更新的方式。如果没有指定 reducer 函数,那么默认情况下,每次我们将状态传递给给定节点时,都会假设应该覆盖所有先前的状态。
在我们的情况下,我们希望保留所有消息,因此我们可以使用内置的 add_messages reducer 来实现这一点。这将确保发送到图状态的新状态只是附加到现有的图状态上,而不是用来覆盖先前的状态。
以下是我们可以如何实现这一点:
from langchain_core.messages import AnyMessage
from langgraph.graph.message import add_messages
from typing import TypedDict, List, Annotated
# With reducers
class MessageState(TypedDict):
messages: Annotated[List[AnyMessage], add_messages]
# Test out the reducer
messages = [HumanMessage(content="Hello, how are you?", name="Human"),
AIMessage(content="I'm fine, thank you.", name="LLM")]
additional_msg = [HumanMessage(content="I'm fine too. How is work going on your end?", name="Human")]
print(add_messages(messages, additional_msg))
我们上面执行的功能非常常见,以至于LangGraph已经内置了一些类来帮助我们完成这些任务。
接下来,让我们来探索这个类:
from langgraph.graph import MessagesState
class MessageState(MessagesState):
pass
将所有内容整合到一个简单的图中
既然我们已经了解了基础知识,现在就可以将所学内容付诸实践了。
def tool_calling_llm(state: MessageState) -> MessageState:
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
llm_with_tool = model.bind_tools([addition])
llm_with_tool_response = llm_with_tool.invoke(state["messages"])
return {"messages": [llm_with_tool_response]}
from langgraph.graph import MessagesState, START, END, StateGraph
from IPython.display import Image, display
builder = StateGraph(MessageState)
builder.add_node("tool_calling_llm", tool_calling_llm)
builder.add_edge(START, "tool_calling_llm")
builder.add_edge("tool_calling_llm", END)
graph = builder.compile()
display(Image(graph.get_graph().draw_mermaid_png()))
我们也可以调用这个图:
# Invocation 1
result = graph.invoke({"messages": HumanMessage(content="What is 2 + 2?", name="Human")})
print(result)
# Invocation 2
result = graph.invoke({"messages": [HumanMessage(content="How are you doing today?", name="Human")]})
print(result)
结论
恭喜你完成了对LangGraph链的全面介绍!
这些基本技能在你继续使用AI模型开发应用时将证明是非常宝贵的。你现在已经拥有了构建更复杂、更精细的AI驱动解决方案的基础。