- LangGraph中State状态模式及相关操作
- 状态定义与图构建:
- 知识点:使用 TypedDict 定义状态,通过
StateGraph
类实例化图,构建对话交互式程序时添加节点、设置启动点和边并编译图。 - 代码对应:
- 知识点:使用 TypedDict 定义状态,通过
- 状态定义与图构建:
# 定义图的状态模式
class State(TypedDict):
messages: Annotated[List[str], operator.add]
# 创建图的实例
builder = StateGraph(State)
这里定义了State
类型,其中messages
使用Annotated
和operator.add
表示消息列表的更新方式为追加 。接着创建StateGraph
实例builder
,为后续构建图结构做准备。
- 节点功能实现:
- 知识点:
chat_with_model
节点接收用户输入,调用大模型实例的invoke
方法生成响应并更新共享状态;convert_messages
节点对上一节点的模型回复进行数据提取和格式化处理,转化为JSON格式输出。 - 代码对应:
# 实例化大模型
llm = ChatOpenAI(model='gpt-40')
# 定义处理模型对话的节点函数
def chat_with_model(state):
print(state)
print("-----")
messages = state['messages']
response = llm.invoke(messages)
return {"messages": [response]}
# 定义数据提取节点函数
def convert_messages(state):
EXTRACTION_PROMPT = """
You are a data extraction specialist tasked with retrieving key information from the provided text.
Extract such information for the provided text and output it in JSON format. Outline the key data points you extract.
"""
print(state)
print("-------")
messages = state['messages'][-1]
messages = [
SystemMessage(content=EXTRACTION_PROMPT),
HumanMessage(content=state['messages'][-1].content)
]
response = llm.invoke(messages)
return {"messages": [response]}
实例化ChatOpenAI
模型llm
。chat_with_model
函数从输入的state
中获取messages
,调用llm.invoke
生成响应,再将响应包装成新的messages
返回 。convert_messages
函数构建特定的提示信息,结合上一节点的回复,调用llm.invoke
进行数据提取和格式化,最后返回处理后的消息。
- 消息流转与状态更新:
- 知识点:消息在图中按节点顺序流转,每次流转更新共享状态中的消息列表,通过
operator.add
实现消息追加,运行图逻辑时需按state
定义规范传递数据。 - 代码对应:在添加节点、边、设置启动点及编译图的过程中体现消息流转与状态更新。
# 添加节点
builder.add_node("chat_with_model", chat_with_model)
builder.add_node("convert_messages", convert_messages)
# 设置启动点
builder.set_entry_point("chat_with_model")
# 添加边
builder.add_edge("chat_with_model", "convert_messages")
builder.add_edge("convert_messages", END)
# 编译图
graph = builder.compile()
# 运行图,输入问题
query = "你好,请你介绍一下你自己"
input_message = {"messages": [HumanMessage(content=query)]}
result = graph.invoke(input_message)
print(result)
添加chat_with_model
和convert_messages
节点到图中 ,设置chat_with_model
为启动点,定义消息从chat_with_model
到convert_messages
再到END
的流转路径,编译图后传入问题运行图逻辑,在这个过程中消息不断流转并更新状态。
- MessageGraph源码功能解析
- 继承关系与初始化:
- 知识点:
MessageGraph
是StateGraph
的子类,使用Annotated[list[AnyMessage], add_messages]
初始化基类,状态由消息列表组成,通过add_messages
函数管理消息列表更新。 - 代码对应:在
MessageGraph
相关代码中体现继承和初始化关系。
from langgraph.graph.message import MessageGraph
class MessageGraph(StateGraph):
def __init__(self) -> None:
super().__init__(Annotated[list[AnyMessage], add_messages])
MessageGraph
继承自StateGraph
,在__init__
方法中调用父类的初始化方法,传入Annotated[list[AnyMessage], add_messages]
,表明状态由消息列表组成且用add_messages
管理更新。
- add_messages函数机制:
- 知识点:
add_messages
函数合并两个消息列表,按ID更新现有消息,默认状态为“仅附加”,新消息与现有消息ID相同则替换,否则追加。 - 代码对应:在
add_messages
函数定义中明确其功能逻辑。
def add_messages(left: Messages, right: Messages) -> Messages:
if not isinstance(left, list):
left = [left]
if not isinstance(right, list):
right = [right]
left = [message_chunk_to_message(m) for m in convert_to_messages(left)]
right = [message_chunk_to_message(m) for m in convert_to_messages(right)]
for m in left:
if m.id is None:
m.id = str(uuid.uuid4())
for m in right:
if m.id is None:
m.id = str(uuid.uuid4())
left_idx_by_id = {m.id: i for i, m in enumerate(left)}
merged = left.copy()
ids_to_remove = set()
for m in right:
if (existing_idx := left_idx_by_id.get(m.id)) is not None:
if isinstance(m, RemoveMessage):
ids_to_remove.add(m.id)
else:
merged[existing_idx] = m
else:
if isinstance(m, RemoveMessage):
raise ValueError(
f"Attempting to delete a message with an ID that doesn't exist ({m.id})"
)
merged.append(m)
merged = [m for m in merged if m.id not in ids_to_remove]
return merged
函数先对输入的消息列表进行类型和格式处理,为无ID的消息生成ID,然后根据消息ID合并两个列表,存在相同ID时按规则替换或删除,最后返回合并后的消息列表。
- 消息图构建与操作示例:
- 知识点:可单独构建
MessageGraph
,添加节点并定义功能,设置启动点和终止点,编译后通过invoke
方法传入用户问题实现交互,消息会生成唯一ID。 - 代码对应:
# 创建MessageGraph实例
builder = MessageGraph()
# 添加节点
builder.add_node("chatbot", lambda state: [("assistant", "你好,最帅气的人!")])
# 设置启动点和终止点
builder.set_entry_point("chatbot")
builder.set_finish_point("chatbot")
# 编译图
graph = builder.compile()
# 运行图,输入问题
query = "你好,请你介绍一下你自己"
input_message = [("user", query)]
result = graph.invoke(input_message)
print(result)
创建MessageGraph
实例builder
,添加chatbot
节点,设置启动点和终止点为chatbot
,编译图后传入问题运行,展示了MessageGraph
的构建和交互过程。
- 构建对话交互式聊天机器人
- 代码实现流程:
知识点:理解state
的定义模式和消息传递机制是构建应用的关键,高阶功能依赖于state
的管理和使用。整个代码中state
贯穿始终,节点函数通过操作state
中的messages
实现功能,消息传递在节点间进行,体现了state
管理和消息传递的重要性。
- LangSmith基础使用入门
- 工具作用:
- 知识点:LangSmith为基于大语言模型构建的应用程序提供全面的监控、调试和可观察性支持,能跟踪运行状态和结果。
- 代码对应:
import langsmith
from langsmith.tracing import start_trace, end_trace
# 启动LangSmith追踪
start_trace(project="my_project")
# 执行对话交互程序相关代码(这里简化,仅示意)
query = "你好,请你介绍一下你自己"
input_message = {"messages": [HumanMessage(content=query)]}
result = graph.invoke(input_message)
# 结束LangSmith追踪
end_trace()
通过start_trace
启动追踪,在执行对话交互代码前后分别调用start_trace
和end_trace
,可记录和观察应用程序在这段代码执行过程中的各种信息。
- 知识点:在构建复杂AI Agent应用程序时,用于观察和调试中间交互流程,通过Web可视化页面了解节点运行情况。
- 代码对应:在实际复杂项目中,结合上述代码,在多个关键节点前后添加追踪代码,在LangSmith的Web可视化页面查看每个节点的输入、输出、执行时间等信息,辅助调试和优化。