跳到主要内容

使用agent-chat-ui 调试 langgraph

· 阅读需 7 分钟

在之前的文章中,使用langgraph 创建的agent,在进行调试时,都是写 python 代码来自己调用,今天介绍一种更加方便的在线调试langgraph 应用的方案,使用 agent-chat-ui 进行调试。

Agent Chat UI 是一个 Next.js 应用程序,它可以通过聊天界面使用 messages 键与任何 LangGraph 服务器进行聊天。

agent-chat-ui 项目地址 https://github.com/langchain-ai/agent-chat-ui

初始化项目,安装依赖

uv init langgraphui --python 3.11
cd langgraphui
uv sync
uv add langgraph-cli[inmem]

使用 LangGraph 构建 chatbot

使用langgraph 创建一个chatbot, 只有一个大模型调用节点,创建 chatbot 文件夹,在 chatbot 文件夹下创建chatbot.py

from typing import Annotated, Type

from typing_extensions import TypedDict
from pydantic import Field
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI


# 定义state
class State(TypedDict):
messages: Annotated[list, add_messages]

# 创建大模型对象
llm = ChatOpenAI(
model_name="qwen-plus",
temperature=0.7,
max_tokens=1024,
top_p=1
)

# 定义大模型节点函数
def chatbot(state: State):
return {"messages": [llm.invoke(state["messages"])]}


graph_builder = StateGraph(State)

# 添加节点
graph_builder.add_node("chatbot", chatbot)

# 添加边
graph_builder.add_edge(START, "chatbot")
graph_builder.add_edge("chatbot", END)

# 编译图
graph = graph_builder.compile(name="chatbot")

上面的代码和之前文章介绍的使用langgraph 没有区别,下面是图的可视化展示

image.png

以往我们要调试这个应用,需要自己写代码来调用

inputs = {
"messages": [{"role": "user", "content": "你好"}]
}
graph.invoke(input=inputs)

这种在console 中展示的信息虽然可以进行调试,但是总体来讲交互还不算太好,接下来看下如何使用agent-chat-ui 在浏览器中运行调试。

使用 agent-chat-ui 运行 langgraph

将langgraph 部署起来

这一步是将刚才写的chatbot 应用在本地部署起来,可以通过http接口进行调用

创建langgraph.json, 写入以下内容

{
"dependencies": ["."],
"graphs": {
"chatbot": "./chatbot/chatbot.py:graph"
},
"env": ".env",
"image_distro": "wolfi"
}
  • graphs: 定义langgraph 应用,这里给上面的应用起名为 chatbot, 对象路径为 ./chatbot/chatbot.py:graph, 这个路径需要根据实际情况进行配置,能够在路径中访问到
  • env: 配置环境变量文件路径,上面使用了千问大模型,需要将api_key 和 base_url 配置一下

创建 .env 文件,将大模型信息配置进来

OPENAI_API_KEY=xxxx
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1

此时的文件树为

.
├── chatbot
│ ├── chatbot.py
│ ├── __init__.py
├── langgraph.json
├── main.py
├── pyproject.toml
├── README.md
└── uv.lock

在langgraph.json 目录下运行 langgraph dev 命令启动 langgraph 应用

image.png

运行成功以后,会监听本地2024 端口用于api调用。

运行 agent-chat-ui

下载 agent-chat-ui

git clone https://github.com/langchain-ai/agent-chat-ui.git

cd agent-chat-ui

安装依赖

npm install

启动应用

npm dev

程序启动以后,会监听本地3000端口, 使用浏览器打开 http://127.0.0.1:3000

image.png

首次打开会有个弹框

  • Deployment URL: 填写上面使用 langgraph dev 运行的应用监听地址 http://127.0.0.1:2024
  • Assistant/Graph ID: 助手的名称,这里填写上面 langgraph.json 文件中 graphs 对象的名称,上面只定义了一个 chatbot, 所以这里填写 chatbot 即可 。
  • LangSmith API Key: 这个是填写langsmith 的 api key, 可以记录 langgraph 运行过程中的数据,这个不是必填了,空着就行

点击 Continue 按钮,进入对话页面

image.png

我们就可以和chatbot 进行对话了,同时也可以调试langgraph 应用

image.png

通过对话可以看出它是带有短时记忆功能的。

带有工具调用的 graph

我们来创建一个稍微复杂一点的应用,让大模型绑定工具,进行工具调用,工具还是使用天气查询,代码也是用之前文章中的代码

在chatbot目录下创建 graph.py 文件,写入以下代码

from typing import Annotated, Type

from typing_extensions import TypedDict
import requests
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI
from langchain_core.messages import ToolMessage, HumanMessage, AIMessage
from langgraph.prebuilt import ToolNode
import json
import operator
import os

class GaoDeWeatherInput(BaseModel):
city: str = Field(description="要查询天气的城市名称")

class GaoDeWeather(BaseTool):
"""
高德天气查询
"""
name: str = "高德天气查询"
description: str = "高德天气查询,输入城市名,返回该城市的天气情况,例如:北京"
args_schema: Type[BaseModel] = GaoDeWeatherInput
api_key: str

def _run(self, city):
s = requests.session()
api_domain = 'https://restapi.amap.com/v3'
# 代码省略,调用高德地图接口返回城市气象信息,可以参考之前文章


weather_tool = GaoDeWeather(api_key=os.getenv("GAODE_API_KEY"))



class State(TypedDict):
messages: Annotated[list, add_messages]
counter: Annotated[int, operator.add]

llm = ChatOpenAI(
model_name="qwen-plus",
temperature=0.7,
max_tokens=1024,
top_p=1
)

tools = [weather_tool]
llm_with_tools = llm.bind_tools(tools)
toolnode = ToolNode(tools)

def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])], "counter": 1}

def condition_tools(state: State):
ai_message = state["messages"][-1]
if ai_message.tool_calls:
print(json.dumps(ai_message.tool_calls, indent=4, ensure_ascii=False))
return "tools"
return END


graph_builder = StateGraph(State)

# 添加节点
graph_builder.add_node("chatbot", chatbot)
graph_builder.add_node("tools", toolnode)

# 添加边
graph_builder.add_edge(START, "chatbot")
graph_builder.add_conditional_edges("chatbot", condition_tools, {"tools": "tools", END: END})
graph_builder.add_edge("tools", "chatbot")

graph = graph_builder.compile(name="New Graph")

这个应用的可以化图为

image.png

修改 langgraph.json 文件

{
"dependencies": ["."],
"graphs": {
"agent": "./chatbot/graph.py:graph",
"chatbot": "./chatbot/chatbot.py:graph"
},
"env": ".env",
"image_distro": "wolfi"
}

在 graphs 中将刚才定义的 graph 添加进去, 在 .env 文件中配置上高德的key。

重新启动 langgraph dev, 重新进入 http://127.0.0.1:3000 , 在 Assistant/Graph ID 处填写 agent

image.png

可以看到,agent-chat-ui 可以将工具调用输出很好的展示出来。

局限性

agent-chat-ui 前端传过来的数据只能是 messages, 并且是列表形式,意味着只能放到 state 中的 messages 字段

class State(TypedDict):
messages: Annotated[list, add_messages]
counter: Annotated[int, operator.add]

如果state 中没有 messags 字段,则前端页面传过来的数据是接收不到的,像上面的State 中还有一个counter,也是无法通过前端传过来的。

不过这个问题,可以用官方的调试页面, 在使用 langgraph dev 启动langgraph 应用以后,会显示一个 Studio UI 的url

image.png

这个是langchain 官方的studio地址,如果你可以正常访问langchain.com 的话也可以使用这个URL进行调试,这个studio 功能更加丰富一些。

image.png

在Input 表单处,会根据 state 中定义的字段,在这里显示不同的表单,如上面agent 中我定义的state 如下

class State(TypedDict):
messages: Annotated[list, add_messages]
counter: Annotated[int, operator.add]
  • messages: list 类型
  • counter: int 类型

counter 在 agent-chat-ui 界面上是没法展示出来的,默认只有 messages 字段。

langchain studio 展示的字段也更加丰富完善。

image.png

统一图片