30 行代码 langChain.js 开发你的第一个 Agent

大家好,我是双越老师,也是 wangEditor 作者。

我正开发一个 Node 全栈 AIGC 知识库 划水AI,包括 AI 写作、多人协同编辑。复杂业务,真实上线,大家可以去注册试用,围观项目研发过程。

文章同时被发布到【划水AI】欢迎点赞 www.huashuiai.com/pub/langcha...

开始

LangChain 是一个开发 LLM 应用的框架,是目前 LLM 开发最流行的解决方案之一。最早是 Python 开发的,后来也出来 JS 语言的,现在已经更新到 v0.3 版本。

本文将使用 LangChain 开发一个简单的 AI Agent,可使用自然语言来查询天气。再使用 LangGraph 进行自定义流程。

开发第一个 Agent

首先创建一个 nodejs 项目,并安装 langchain 和 dotenv ,后面我们需要使用环境变量。

css 复制代码
npm i langchain dotenv

使用 Tavily 搜索功能

Tavily 是一个搜索引擎,可以让你的 LLM 和 Agent 有联网搜索的能力,例如搜索天气。

你需要注册登录并创建一个 API key ,Tavily 可免费使用 1000 次,足够学习使用。

把 API key 放在代码库 .env 文件中

env 复制代码
TAVILY_API_KEY=xxx

安装 langchain tavily 插件

css 复制代码
npm i @langchain/tavily

然后创建一个 agent.js 文件,代码如下

js 复制代码
import 'dotenv/config'
import { TavilySearch } from '@langchain/tavily'

// 定义 tools
const agentTools = [
    new TavilySearch({
        maxResults: 3 // 最多查询 3 个结果
    })
]

选择一个大模型

langChain 集成了有很多 LLM 可供选择 js.langchain.com/docs/integr...

它默认推荐的是 OpenAI 但是在国内我们没法直接调用它的 API ,所以我当前选择的是 DeepSeek 。

注册登录 DeepSeek 创建一个 API key 并把它放在 .env 文件中

env 复制代码
DEEPSEEK_API_KEY=xxx

安装 langChain deepseek 插件

css 复制代码
npm i @langchain/deepseek

然后继续写 agent.js 代码

javascript 复制代码
import { ChatDeepSeek } from '@langchain/deepseek'


// 定义 llm
const agentModel = new ChatDeepSeek({ model: 'deepseek-chat', temperature: 0 })

使用 langGraph 创建 Agent

langGraph 是基于 langChain 的框架,用于构建可控制的 Agent ,是现代开发 Agent 最流行的解决方案之一。

安装 langGraph 必要插件

bash 复制代码
npm install @langchain/langgraph @langchain/core

然后继续写 agent.js 代码

js 复制代码
import { MemorySaver } from '@langchain/langgraph'
import { createReactAgent } from '@langchain/langgraph/prebuilt'

// Initialize memory to persist state between graph runs
const agentCheckpoint = new MemorySaver()

// Create agent
const agent = createReactAgent({
  llm: agentModel, // 使用之前创建的 llm
  tools: agentTools, // 使用之前创建的 tools
  checkpointSaver: agentCheckpoint, // 记忆,保存状态数据
})

使用 createReactAgent 来创建一个 Re-Act Agent 智能体。Re-Act 即 Reason + Act 推理和执行,它可以使用 llm 自主推理并选择调用哪个 tool 获取结果。这也是 Agent 的特点之一。

agentCheckpoint 可以存储近期对话记录,让 llm 有记忆能力。否则你刚说自己叫张三,再问它我的名字,它就忘了。

调用 Agent

继续写 agent.js 代码,使用 agent.invoke 方法调用 agent ,传入 HumanMessage 即 prompt 提示词

js 复制代码
import { HumanMessage } from '@langchain/core/messages'

// test1
const agentFinalState = await agent.invoke(
  { messages: [new HumanMessage('what is the current weather in sf')] },
  { configurable: { thread_id: '1' } }
)
console.log(
  agentFinalState.messages[agentFinalState.messages.length - 1].content
)

// test2
const agentNextState = await agent.invoke(
  { messages: [new HumanMessage('what about Beijing')] },
  { configurable: { thread_id: '1' } }
)
console.log(agentNextState.messages[agentNextState.messages.length - 1].content)

执行 node agent.js 可以看到控制台打印结果,可以查询到 San Francisco 和 Beijing 的天气。

这里的 { thread_id: '1' } 是 Memory 存储记忆的索引, thread_id 相同的才是同一个对话记录,才能共享记忆。例如这里第二次调用时 prompt 是 'what about Beijing' 并没有问天气,但是 llm 也能根据上一次对话判断出这里是问天气,所以才能给出正确答案。

还可以使用 agent.stream 方式流式输出,配合前端可实现打字效果

javascript 复制代码
// streaming
const stream = await agent.stream(
  { messages: [new HumanMessage('what is the current weather in sf')] },
  { configurable: { thread_id: '1' }, streamMode: 'updates' }
)
for await (const step of stream) {
  console.log(JSON.stringify(step))
}

以上就是一个最基本的 AI ReAct Agent,核心代码不到 30 行。它包含三个要素:llm + tools + memory ,可以根据自然语言自主推理并调用 tool 获取结果,最后组合为自然语言,返回给用户。

自定义 Agent 行为

ReAct Agent 可以自主推理并执行,但如果你想自己控制这个流程呢? LangGraph 可以让你自定义 Agent 行为。

定义 toolNode

继续修改你的 agent.js代码。定义一个 toolNode ,并且在创建 model 时绑定 tools 。

js 复制代码
import { ToolNode } from '@langchain/langgraph/prebuilt'

// Define the tools for the agent to use
const tools = [new TavilySearch({ maxResults: 3 })]
const toolNode = new ToolNode(tools)

// Create a model and give it access to the tools
const model = new ChatDeepSeek({
  model: 'deepseek-chat',
  temperature: 0,
}).bindTools(tools)

定义节点函数

然后定义一个函数 shouldContinue 用于判断 llm 是否要发起一个 tool 调用?

js 复制代码
// Define the function that determines whether to continue or not
function shouldContinue({ messages }) {
  const lastMessage = messages[messages.length - 1]

  // 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__'
}

再定义一个函数 callModel 用于调用 llm 并返回结果

js 复制代码
// Define the function that calls the model
async function callModel(state) {
  const response = await model.invoke(state.messages)

  // We return a list, because this will get added to the existing list
  return { messages: [response] }
}

定义工作流

最后定义工作流 workflow ,并编译为一个 app 。这个 app 可以被触发执行。

js 复制代码
// Define a new graph
const workflow = new StateGraph(MessagesAnnotation)
  .addNode('agent', callModel) // 添加节点 agent ,对应 callModel 函数
  .addEdge('__start__', 'agent') // 添加"边",流程开始就指向 agent 节点
  .addNode('tools', toolNode) // 添加节点 tools ,对应 toolNode
  .addEdge('tools', 'agent') // 添加边,tools 节点指向 agent 节点
  .addConditionalEdges('agent', shouldContinue) // 添加条件边,根据 shouldContinue 函数里的逻辑,有 tool_calls 返回 'tools' 即指向 tools 节点,否则返回 '__end__' 即流程结束

// Finally, we compile it into a LangChain Runnable.
const app = workflow.compile()

工作流的定义过程看以上代码的注释,整体的流程图如下:开始,先执行 agent,再执行 shouldContinue 判断,然后要么结束、要么去执行 tools ,tools 再到 agent 。

arduino 复制代码
/* workflow diagram
           ┌──────────┐
           │ __start__│
               ↓
          ┌──────────┐
          │  agent   │ ←────────┐
          └────┬─────┘          │
               ↓                │
        ┌───────────  ─┐        │
        │shouldContinue│── tools│
        └────┬───────  ┘        │
             ↓                  ↓
         __end__        ┌──────────┐
                        │  tools   │
                        └──────────┘

*/

调用工作流

同样可以使用 invoke 方法触发工作流,传入 HumanMessage 即用户 prompt 信息

js 复制代码
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)

控制台执行 node agent.js 返回结果如下

最后

使用 ReAct Agent 会更加灵活,使用 StateGraph 可以自定义控制 Agent 行为,langChain 提供了强大的 LLM 开发能力。

最后,前端想学全栈 + AI 开发,可以看看我做的 划水AI 项目,AI 写作、多人协同编辑。复杂业务,真实上线,可注册试用。

相关推荐
普通程序员4 分钟前
Gemini CLI 新手安装与使用指南
前端·人工智能·后端
视觉语言导航5 分钟前
ICCV-2025 | 复杂场景的精准可控生成新突破!基于场景图的可控 3D 户外场景生成
人工智能·深度学习·具身智能
whaosoft-14312 分钟前
51c自动驾驶~合集6
人工智能
我叫黑大帅14 分钟前
Sequelize:让你和数据库唠嗑像聊微信一样简单 😎
后端·node.js
tonngw27 分钟前
Manus AI与多语言手写识别
人工智能
love530love36 分钟前
Docker 稳定运行与存储优化全攻略(含可视化指南)
运维·人工智能·windows·docker·容器
HeartException1 小时前
量子计算+AI芯片:光子计算如何重构神经网络硬件生态
人工智能
摸鱼仙人~1 小时前
Minstrel:多智能体协作生成结构化 LangGPT 提示词
人工智能·提示词
AI街潜水的八角2 小时前
深度学习图像分类数据集—濒危动物识别分类
人工智能·深度学习
程序员陆通2 小时前
独立开发A/B测试实用教程
人工智能·ai编程