
澄清一个Langgraph中的bug——在智能体中获取到工具节点中的流式输出 原创
“ Langgraph对模型功能进行了适度封装,有些可能乍一看很不合理,因此我们要多看其官网说明。”
前一段时间在学习使用Langgraph开发框架时,由于对框架理解不够深刻,以为发现了一个bug,然后今天才发现这不是bug,而是框架本身就是这么设计的。
这个bug就是,在智能体的流式输出的时候,会一块输出工具节点调用模型结果;之所以发现这个问题就是在具体的工具中又调用了模型进行数据处理,但在打印输出的时候发现工具的执行过程也被输出了出来。
如下图所示,在工具chat中调用了模型:
Langgraph流式输出问题
查看Langgraph官网介绍发现,其本身提供了从任何地方捕获令牌流等流式输出。
这种设计哲学有好处也有坏处,好处就是在最上层可以捕获到所有子节点的输出流;坏处就是,我们可能并不需要子节点的输出流。
所以怎么解决这个问题呢?
就是使用标签过滤,在Langgraph中提供了元数据(metadata)的功能,可以通过给模型添加标签数据,以此来区分不同功能的流式输出,防止数据污染。
代码案例如下:
from langchain.chat_models import init_chat_model
llm_1 = init_chat_model(model="openai:gpt-4o-mini", tags=['joke'])
llm_2 = init_chat_model(model="openai:gpt-4o-mini", tags=['poem'])
graph = ... # define a graph that uses these LLMs
async for msg, metadata in graph.astream(
{"topic": "cats"},
stream_mode="messages",
):
if metadata["tags"] == ["joke"]:
print(msg.content, end="|", flush=True)
文档地址如下: https://github.langchain.ac.cn/langgraph/how-tos/streaming/#messages
或者也可以按照节点名称进行筛选:
from typing import TypedDict
from langgraph.graph import START, StateGraph
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4o-mini")
class State(TypedDict):
topic: str
joke: str
poem: str
def write_joke(state: State):
topic = state["topic"]
joke_response = model.invoke(
[{"role": "user", "content": f"Write a joke about {topic}"}]
)
return {"joke": joke_response.content}
def write_poem(state: State):
topic = state["topic"]
poem_response = model.invoke(
[{"role": "user", "content": f"Write a short poem about {topic}"}]
)
return {"poem": poem_response.content}
graph = (
StateGraph(State)
.add_node(write_joke)
.add_node(write_poem)
# write both the joke and the poem concurrently
.add_edge(START, "write_joke")
.add_edge(START, "write_poem")
.compile()
)
for msg, metadata in graph.stream(
{"topic": "cats"},
stream_mode="messages",
):
if msg.content and metadata["langgraph_node"] == "write_poem":
print(msg.content, end="|", flush=True)
通过这种方式就可以对不同节点的模型输出进行过滤,实现节点之间的数据分隔。
当然,Langgraph还提供了自定义数据,使用Langgraph提供的输出类型会对模型输出进行一定的限制;因此,如果用对灵活性要求较高的情况下,就可以使用自定义数据类型。
总之,Langgraph对大模型的流式输出进行了适度的封装,如果没搞明白其封装的特性,可能会出现一些意想不到的问题。
本文转载自AI探索时代 作者:DFires
