LangGraph.js - 快速入门¶
简介¶
在本快速入门指南中,你将快速了解并运行一个简单的 Reason + Act 代理(通常称为 ReAct 代理),它可以使用 Tavily Search API。代码是完全可配置的。你可以
- 替换组件
- 定制执行流程
- 使用自定义代码或工具进行扩展
- 更改使用的大型语言模型 (LLM) 和提供商
前提条件¶
要跟着操作,你需要准备以下内容
- NodeJS 版本 18 或更新
- 一个 Tavily 账户和 API 密钥
- 一个 OpenAI 开发者平台 账户和 API 密钥
首先为项目创建一个新文件夹。打开终端并运行以下代码
你还需要安装一些依赖项来创建一个代理
- langchain/langgraph 包含用于组装代理的构建块
- langchain/openai 使你的代理能够使用 OpenAI 的 LLM
- langchain/community 包含 Tavily 集成,为你的代理提供搜索功能
你可以通过在终端中运行以下 npm 命令来安装这些依赖项
LangSmith¶
可选:设置 LangSmith 以获得一流的可观测性。设置很简单 - 将以下变量添加到你的环境中,并将 LANGCHAIN_API_KEY
值更新为你的 API 密钥。
// Optional, add tracing in LangSmith
// process.env.LANGCHAIN_API_KEY = "ls__...";
// process.env.LANGCHAIN_CALLBACKS_BACKGROUND = "true";
// process.env.LANGCHAIN_TRACING_V2 = "true";
// process.env.LANGCHAIN_PROJECT = "Quickstart: LangGraphJS";
使用 LangGraph 构建你的第一个代理¶
创建一个名为 agent.ts
(Reason + Act 代理的缩写)的文件,并将下面的 TypeScript 代码添加到其中。
确保更新文件顶部的环境变量以包含你的 API 密钥。如果未更新,OpenAI 和 Tavily API 调用将产生错误,你的代理将无法正常工作。
添加 API 密钥后,保存文件并使用以下命令运行代码
// agent.ts
// IMPORTANT - Add your API keys here. Be careful not to publish them.
process.env.OPENAI_API_KEY = "sk-...";
process.env.TAVILY_API_KEY = "tvly-...";
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
import { ChatOpenAI } from "@langchain/openai";
import { MemorySaver } from "@langchain/langgraph";
import { HumanMessage } from "@langchain/core/messages";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
// Define the tools for the agent to use
const agentTools = [new TavilySearchResults({ maxResults: 3 })];
const agentModel = new ChatOpenAI({ temperature: 0 });
// Initialize memory to persist state between graph runs
const agentCheckpointer = new MemorySaver();
const agent = createReactAgent({
llm: agentModel,
tools: agentTools,
checkpointSaver: agentCheckpointer,
});
// Now it's time to use!
const agentFinalState = await agent.invoke(
{ messages: [new HumanMessage("what is the current weather in sf")] },
{ configurable: { thread_id: "42" } },
);
console.log(
agentFinalState.messages[agentFinalState.messages.length - 1].content,
);
const agentNextState = await agent.invoke(
{ messages: [new HumanMessage("what about ny")] },
{ configurable: { thread_id: "42" } },
);
console.log(
agentNextState.messages[agentNextState.messages.length - 1].content,
);
The current weather in San Francisco is as follows:
- Temperature: 82.0°F (27.8°C)
- Condition: Sunny
- Wind: 11.9 mph from the NW
- Humidity: 41%
- Pressure: 29.98 in
- Visibility: 9.0 miles
- UV Index: 6.0
For more details, you can visit [Weather in San Francisco](https://www.weatherapi.com/).
The current weather in New York is as follows:
- Temperature: 84.0°F (28.9°C)
- Condition: Sunny
- Wind: 2.2 mph from SSE
- Humidity: 57%
- Pressure: 29.89 in
- Precipitation: 0.01 in
- Visibility: 9.0 miles
- UV Index: 6.0
For more details, you can visit [Weather in New York](https://www.weatherapi.com/).
工作原理¶
createReactAgent
构造函数可以让你用一行代码创建一个简单的工具使用 LangGraph 代理。这是图的视觉表示
// Note: tslab only works inside a jupyter notebook. Don't worry about running this code yourself!
import * as tslab from "tslab";
const graph = agent.getGraph();
const image = await graph.drawMermaidPng();
const arrayBuffer = await image.arrayBuffer();
await tslab.display.png(new Uint8Array(arrayBuffer));
此外,你可以使用以下方法将图保存为本地 PNG 文件
import { writeFileSync } from "node:fs";
const graphStateImage = await drawableGraphGraphState.drawMermaidPng();
const graphStateArrayBuffer = await graphStateImage.arrayBuffer();
const filePath = "./graphState.png";
writeFileSync(filePath, new Uint8Array(graphStateArrayBuffer));
定制代理行为¶
createReactAgent
对于简单的代理来说非常有用,但有时你需要更强大的功能。
当你需要对代理行为进行细粒度控制时,LangGraph 就会大放异彩。以下代码创建了一个与上面示例具有相同行为的代理,但你可以清楚地看到执行逻辑以及如何对其进行定制。
更新你的 agent.ts
文件中的代码以匹配下面的示例。请再次确保更新顶部的环境变量。
更新环境变量并保存文件后,你可以使用与之前相同的命令运行它
// agent.ts
// IMPORTANT - Add your API keys here. Be careful not to publish them.
process.env.OPENAI_API_KEY = "sk-...";
process.env.TAVILY_API_KEY = "tvly-...";
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, AIMessage } from "@langchain/core/messages";
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { StateGraph, MessagesAnnotation } from "@langchain/langgraph";
// Define the tools for the agent to use
const tools = [new TavilySearchResults({ maxResults: 3 })];
const toolNode = new ToolNode(tools);
// Create a model and give it access to the tools
const model = new ChatOpenAI({
model: "gpt-4o-mini",
temperature: 0,
}).bindTools(tools);
// Define the function that determines whether to continue or not
function shouldContinue({ messages }: typeof MessagesAnnotation.State) {
const lastMessage = messages[messages.length - 1] as AIMessage;
// If the LLM makes a tool call, then we route to the "tools" node
if (lastMessage.tool_calls?.length) {
return "tools";
}
// Otherwise, we stop (reply to the user) using the special "__end__" node
return "__end__";
}
// Define the function that calls the model
async function callModel(state: typeof MessagesAnnotation.State) {
const response = await model.invoke(state.messages);
// We return a list, because this will get added to the existing list
return { messages: [response] };
}
// Define a new graph
const workflow = new StateGraph(MessagesAnnotation)
.addNode("agent", callModel)
.addEdge("__start__", "agent") // __start__ is a special name for the entrypoint
.addNode("tools", toolNode)
.addEdge("tools", "agent")
.addConditionalEdges("agent", shouldContinue);
// Finally, we compile it into a LangChain Runnable.
const app = workflow.compile();
// Use the agent
const finalState = await app.invoke({
messages: [new HumanMessage("what is the weather in sf")],
});
console.log(finalState.messages[finalState.messages.length - 1].content);
const nextState = await app.invoke({
// Including the messages from the previous run gives the LLM context.
// This way it knows we're asking about the weather in NY
messages: [...finalState.messages, new HumanMessage("what about ny")],
});
console.log(nextState.messages[nextState.messages.length - 1].content);
我们的 ReAct 代理的这个版本有一些新的东西。
一个 ToolNode
使 LLM 能够使用工具。在此示例中,我们创建了一个 shouldContinue
函数并将其传递给 addConditionalEdge
,以便我们的 ReAct 代理可以调用工具或响应请求。
Annotations 是 LangGraph 中图状态的表示方式。我们正在使用 MessagesAnnotation
,这是一个实现了常见模式的助手:将消息历史记录保存在数组中。
下一步¶
恭喜你使用 LangGraph 创建了你的第一个 AI 代理!如果你准备构建更复杂的内容,请查看我们的其他 教程 学习如何实现其他端到端的代理工作流程,例如
- 检索增强生成 (RAG)
- 多代理协作
- 反思,即代理评估其工作
如果你想改进你的代理,我们有 操作指南 提供帮助,包括
- 工具调用 使代理能够与 API 交互
- 为你的代理提供 持久内存 以继续对话并调试意外行为
- 设置 人机协作 对于需要人工验证的操作
- 流式输出代理的输出 使你的应用程序响应更及时
- 一行代码更改 AI 模型