在LangChain体系中,
- LangChain:主要 集成了与大语言模型交互的能力 和 进行基础功能的实现(LLM、记忆、工具)。快速原型、简单线性任务、RAG场景。
- LangGraph:对 多个Agent 和 工具 编排,实现了复杂的流程调度。
LangGraph 是一种基于状态机 的框架,专为构建复杂的 AI 工作流 而设计。它允许开发者定义图结构来表示不同的操作节点以及它们之间的流转逻辑。包含 START 初始入口、END 某个分支或者整体工作的结束节位置、自定义任务节点。
自定义任务节点:是通过**@task** 注解将普通的 Python 函数转化为具有特定行为的任务节点。一旦函数被标记为任务,就可以将其加入到工作流中,并与其他任务连接起来形成完整的业务流程。
这些任务 本质上是封装成 RunnableLambda 对象的形式,从而获得诸如批处理支持、异步执行能力等功能。
一、Graph 图(有向无环图)
主要包含三个基本元素:
- State:在整个应用中共享的一种数据结构;
- Node:一个处理数据的节点。Node通常是一个Python的函数,以State为输入,经过一些操作后,返回更新后的State;
- Edge:表示Node之间的依赖关系,根据当前State来决定接下来执行哪个Node。
二、主要步骤
python
# 创建LLM
llm = ChatTongyi(
model="qwen-plus",
api_key=load_api_key("BAILIAN_API_KEY")
)
# 定义状态
class State(TypedDict):
messages: Annotated[list[AnyMessage],add]
type: str
nodes = ["node1","node2","node3","node4","node5"]
# 定义5个任务节点
def node1(state: State):
...
# 构建Graph图
builder = StateGraph(State)
# 添加Node
builder.add_node("node1",node1)
builder.add_node("node2",node2)
builder.add_node("node3",node3)
builder.add_node("node4",node4)
builder.add_node("node5",node5)
# 路由函数
def routing_func(state: State):
if state["type"] == END:
return END
elif state["type"] == "node1":
return "node1"
elif state["type"] == "node2":
return "node2"
elif state["type"] == "node3":
return "node3"
else:
return "node5"
# 添加Edge
builder.add_edge(START,"node1")
builder.add_conditional_edges("node1",routing_func,["node2","node3","node4","node5",END])
builder.add_edge("node2","node1")
builder.add_edge("node3","node1")
builder.add_edge("node4","node1")
builder.add_edge("node5","node1")
# 编译Graph
checkpointer = InMemorySaver()
graph = builder.compile(checkpointer=checkpointer)
# 调用图
graph.invoke({"user_input":"今天"})
for chunk in graph.stream():
print(chunk)
请求的参数从固定的START传入,依次经过多个任务节点处理,最后进入到END节点结束。
python
from IPython.display import Image,display
# draw_mermaid方法可以打印出Graph的mermaid代码
display(Image(graph.get_graph().draw_mermaid_png()))
三、记忆
- 短期记忆:Agent内部的记忆,用于当前对话中的历史记忆信息,LangGraph将它封装成Checkpoint;需要配置一个单独的不同的thread_id来区分不同的对话。和⼤模型的每次交互记录,包括⼯具调⽤的信息,都保存在了短期记忆当中。
- 长期记忆:Agent外部的记忆,用于第三方存储长久的保存用户级别或者应用级别的聊天信息,LangGraph将它封装成Store。
python
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.prebuilt import create_react_agent
checkpointer = InMemorySaver()
# 指定checkpoint属性,实现短期记忆
agent = create_react_agent(
model=llm,
tools=[get_weather],
checkpointer=checkpointer
)
# 同一个对话使用同一个thread_id
config = {
"configurable":{
"thread_id":"1"
}
}
# 长期记忆
from langgraph.store.memory import InMemoryStore
from langchain_core.tools import tool
from langchain_core.runnables import RunnableConfig
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
# 定义长期存储
store = InMemoryStore()
# 添加一些测试数据(users是命名空间,user1是key,后面的json数据是value)
store.put(
("users",),
"user1",
{
"name": "ahead",
"age": "123"
}
)
# 定义工具
@tool(return_direct=True)
def get_user_info(config: RunnableConfig):
"""查找用户信息"""
# 获取长期存储
store = get_store()
# 获取配置中的用户id
user_id = config["configurable"].get("user_id")
# 获取store中的用户信息
user_info = store.get(("users",),user_id)
return str(user_info.value) if user_info else "Unknown user"
agent = create_react_agent(
model=llm,
tools=[get_user_info],
store=store
)
agent.invoke(
{"messages": "查询用户信息"},
config={"configurable":{"user_id": "user1"}}
)
LangGraph中管理短期记忆的方法:
- Summarization 总结:用大模型的方式,对短期记忆进行总结,然后再把总结的结果作为新的短期记忆;
- Trimming 删除:直接把短期记忆中最旧的消息删除掉。
四、状态管理
保存中间结果。这些状态数据,还可以在Tools工具中使用。
python
from langgraph.prebuilt.chat_agent_executor import AgentState
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from typing import Annotated
class CustomState(AgentState):
user_id: str
@tool(return_direct=True)
def get_user_info(state: Annotated[CustomState,InjectedState]):
"""查询用户信息"""
user_id = state["user_id"]
return "user1的姓名为:ahead" if user_id == "user1" else "未知用户"
agent = create_react_agent(
model=llm,
tools=[get_user_info],
# 使用自定义的 CustomState 来管理对话状态
state_schema=CustomState
)
agent.invoke({
"messages":"查询用户信息",
"user_id":"user1"
})
五、Human-in-the-loop人类干预
Agent 的⼯作过程中,要不要调⽤⼯具,却完全是由Agent ⾃⼰决定的。 这就会导致Agent 在⾯对⼀些问题时,可能会出现错误的判断。
为了解决这个问题, LangGraph 提供了 Human-in-the-loop 的功能,允许⽤户进⾏监督。这就需要通过 interruput() ⽅法中断当前的执⾏任务,等待⽤户输⼊后,再重新恢复任务。