100 行代码 我用LangGraph+Tavily打造一个会“自主思考”的 Agent

LobeChat

LobeChat

AI应用

LobeChat 是一个开源、高性能的聊天机器人框架。支持语音合成、多模态和可扩展插件系统。支持一键式免费部署私人ChatGPT/LLM 网络应用程序。

开始

作为一名开发者,你是否曾经想过——如果能创建一个AI助手,让它自动判断什么时候该搜索实时数据,什么时候该直接回答问题,那该多酷?今天,我将手把手带你实现这个想法,从零开始构建一个真正会“思考”的智能Agent。

🎯 第一步:明确我们要解决什么问题?

普通的AI对话模型有个明显缺陷:它们要么完全依赖预训练知识(可能过时),要么盲目搜索所有问题(效率低下)。我们需要一个更聪明的方案。

我们要构建的Agent应该具备这样的能力:

  • 🧠 智能判断:自动识别问题类型
  • 🔍 按需搜索:只在需要时获取实时数据
  • 💬 智能回答:结合实时数据和知识库
  • 🔄 状态管理:记住对话上下文

🛠️ 第二步:环境准备——搭建开发基础

使用 langGraph 创建 Agent

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

安装 langGraph 必要插件

npm install @langchain/langgraph @langchain/core

使用 Tavily 搜索功能

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

注册登录 把 API key 放在代码库 .env 文件中

TAVILY_API_KEY=xxx

安装 langchain tavily 插件

npm i @langchain/tavily

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

import 'dotenv/config'
import { TavilySearch } from '@langchain/tavily'

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

选择一个大模型

langChain 集成了有很多 LLM 可供选择它默认推荐的是 OpenAI 但是在国内我们没法直接调用它的 API ,所以我当前选择的是 DeepSeek 。
注册登录 DeepSeek 创建一个 API key 并把它放在 .env 文件中。

DEEPSEEK_API_KEY=xxx

安装 langChain deepseek 插件

npm i @langchain/deepseek

然后继续写 agent.js 代码

const llm = new ChatDeepSeek({
  model: 'deepseek-chat',
  temperature: 0.7, // 控制创造性:0.1-保守,0.7-平衡,1.0-富有创造性
})

🏗️ 第三步:抛出问题——设计思考流程

想象一下:用户问了以下问题:
1、深圳今天天气怎么样?
2、南京明天会下雨吗?
3、你知道南京有什么著名景点吗?

这里有需要联网获取数据之后才能回答的问题(天气),也有大模型可以直接回答的问题(景点)。大家有没有思考过当我们输入这些问题之后,模型背后的处理过程是什么样的?让我们先用文字描述整个思考过程:

用户提问
    ↓
【决策节点】判断是否为天气问题?
    ↓
是 → 【搜索节点】获取实时天气数据 → 【回答节点】生成天气报告
    ↓
否 → 【通用回答节点】直接回答问题

💻 第四步:代码实现——从骨架到血肉

搭建基础骨架(导入和初始化)

import 'dotenv/config'
import { ChatDeepSeek } from '@langchain/deepseek'
import { TavilySearch } from '@langchain/tavily'
import { StateGraph, END, MemorySaver, MessagesAnnotation } from '@langchain/langgraph'
import { HumanMessage, AIMessage } from '@langchain/core/messages'

// 1. 初始化工具和模型
const tavilySearch = new TavilySearch({ maxResults: 1 })
const llm = new ChatDeepSeek({
  model: 'deepseek-chat',
  temperature: 0.7, // 控制创造性:0.1-保守,0.7-平衡,1.0-富有创造性
})

定义数据容器(状态结构)

const StateAnnotation = {
  messages: MessagesAnnotation,           // 对话历史记录
  step: { reducer: (x, y) => y ?? x },    // 当前执行步骤
  searchData: { reducer: (x, y) => y ?? x }, // 搜索到的数据
}

messages 记录对话历史,step 记录当前做到哪一步,searchData 记录搜集到的信息。

创建第一个节点:智能决策器

// 节点1:问题分类器
const startNode = async (state) => {
  console.log("🔍 开始分析问题类型...")
  const lastMessage = state.messages[state.messages.length - 1]
  
  // 使用LLM判断问题类型
  const isWeatherRelated = await llm.invoke([
    new HumanMessage(`请判断以下问题是否与天气相关(如天气、气温、降雨等),只需回答"是"或"否":${lastMessage.content}`)
  ])
  
  const isWeather = isWeatherRelated.content.trim().toLowerCase() === '是'
  console.log(`📊 判断结果:${isWeather ? '天气问题' : '普通问题'}`)
  
  // 决定下一步走向
  return {
    ...state,
    step: isWeather ? 'search_weather' : 'respond_general',
  }
}

创建第二个节点:实时数据搜集器

// 节点2:天气数据搜索
const searchWeatherNode = async (state) => {
  console.log("🌤️ 开始搜索实时天气数据...")
  const lastMessage = state.messages[state.messages.length - 1]
  
  try {
    // 构建搜索查询
    const searchQuery = `${lastMessage.content} 天气 实时气温`
    console.log(`🔎 搜索关键词:${searchQuery}`)
    
    // 调用Tavily API获取数据
    const searchResults = await tavilySearch.invoke({ query: searchQuery })
    console.log("✅ 天气数据获取成功")
    
    return {
      ...state,
      searchData: searchResults,
      step: 'respond_weather', // 告诉系统下一步该做什么
    }
  } catch (error) {
    console.error("❌ 天气搜索失败:", error)
    return {
      ...state,
      searchData: '天气搜索服务暂时不可用',
      step: 'respond_weather',
    }
  }
}

创建第三个节点:天气报告生成器

// 节点3: 生成天气回答(基于Tavily搜索数据)
const respondWeatherNode = async state => {
  console.log('📝 基于实时数据生成天气报告...')
  // 使用LLM基于搜索数据生成友好回答
  const lastMessage = state.messages[state.messages.length - 1]
  // 将原始数据转化为友好回答的——这体现了AI的真正价值。
  const finalResponse = await llm.invoke([
    new HumanMessage(`你是一个天气助手。请基于以下搜索数据,为用户的问题生成一个准确、友好、实用的天气回答。
    用户问题:${lastMessage.content}
    搜索数据:${state.searchData}

    要求:
    1. 如果搜索数据中有具体的天气信息,请基于数据回答
    2. 如果搜索数据不完整或没有找到信息,请诚实地告知用户
    3. 回答要简洁明了,包含温度、天气状况等关键信息
    4. 用自然的中文回答`),
  ])

  return {
    messages: [...state.messages, new AIMessage(finalResponse.content)], // 保留历史并添加新消息
    step: 'end',
  }
}

创建第四个节点:通用问题回答器

// 节点4: 生成通用回答(非天气问题,直接使用LLM)
const respondGeneralNode = async state => {
  console.log('💭 处理通用知识问题...')
  const lastMessage = state.messages[state.messages.length - 1]

  // 直接使用LLM回答所有非天气问题
  const generalResponse = await llm.invoke([
    new HumanMessage(`请回答用户的以下问题,提供准确、有用的信息:
    用户问题:${lastMessage.content}
    请用中文友好地回答,如果不知道可以诚实地告知。`),
  ])

  return {
    messages: [...state.messages, new AIMessage(generalResponse.content)],
    step: 'end',
  }
}

🔗 第五步:连接所有节点——构建完整工作流

创建流程控制器

// 条件边控制
const shouldContinue = state => {
  console.log(`🔄 检查下一步流程,当前步骤:${state.step}`)
  return state.step !== 'end' ? state.step : END
}

组装完整的工作流

// 5. 构建状态图
const graph = new StateGraph({ channels: StateAnnotation })
  .addNode('start', startNode) // 起始节点
  .addNode('search_weather', searchWeatherNode) // 天气搜索节点
  .addNode('respond_weather', respondWeatherNode) // 天气响应节点
  .addNode('respond_general', respondGeneralNode) // 通用响应节点
  .setEntryPoint('start')
  .addConditionalEdges('start', shouldContinue)
  .addConditionalEdges('search_weather', shouldContinue)
  .addConditionalEdges('respond_weather', shouldContinue)
  .addConditionalEdges('respond_general', shouldContinue)

关键特点:

  • 所有节点都连接到同一个条件判断函数 shouldContinue
  • 没有明确的边连接,完全依赖条件判断决定流向
┌─────────────┐
│   __start__ │
└──────┬──────┘
       ↓
   ┌────────┐
   │ start  │
   └───┬────┘
       ↓ (shouldContinue判断)
       ├───→┌───────────────┐ ────┐
       │    │ search_weather│     │
       │    └───────────────┘     │
       │     	↓ (shouldContinue)│
       │                          │
       ├───→ ┌───────────────┐    │
       │     │ respond_weather    │
       │     └───────────────┘    │
       │       ↓ (shouldContinue) │
       │                          │
       ├───→ ┌───────────────┐    │
       │     │respond_general│    │
       │     └───────────────┘    │
       │       ↓ (shouldContinue) │
       │                          │
       └───→ ┌─────────┐          │
             │ __end__ │          │
             └─────────┘          │
                   ↑              │
                   └──────────────┘
                    (循环回到各节点)

启用记忆功能

// 6. 配置记忆存储并编译图
const memory = new MemorySaver()
const agent = graph.compile({
  checkpointSaver: memory,
})
console.log('🎉 智能Agent创建成功!')

记忆功能的重要性: 这让Agent能够进行多轮对话,就像人类能记住之前的谈话内容一样。

🧪 第六步:测试我们的智能Agent

创建测试函数

// 7. 运行Agent的函数
async function runWeatherAgent(userInput, threadId = 'default-thread') {
  console.log(`\n👤 用户提问:${userInput}`)
  console.log('='.repeat(50))

  try {
    const finalState = await agent.invoke(
      {
        messages: [new HumanMessage(userInput)],
        step: 'start',
      },
      { configurable: { thread_id: threadId } }
    )

    const lastMessage = finalState.messages[finalState.messages.length - 1]
    console.log(`🤖 助手回答:${lastMessage.content}`)
    console.log('='.repeat(50))

    return finalState
  } catch (error) {
    console.error('❌ 运行出错:', error)
    // 出错时使用LLM直接回答
    const fallbackResponse = await llm.invoke([new HumanMessage(userInput)])
    console.log(`🆘 降级回答:${fallbackResponse.content}`)
    return {
      messages: [
        new HumanMessage(userInput),
        new AIMessage(fallbackResponse.content),
      ],
    }
  }
}

运行测试

// 8. 测试Agent
;(async () => {
  console.log('开始测试智能问答Agent...\n')
  await runWeatherAgent('深圳今天天气怎么样?')
  await runWeatherAgent('南京明天会下雨吗?')
  await runWeatherAgent('你知道南京有什么著名景点吗?')
  console.log('测试完成!')
})()

📊 第七步:分析测试结果——看看我们的Agent有多聪明

运行测试后,你应该看到类似这样的输出:

🚀 开始智能Agent测试...

👤 用户提问:深圳今天天气怎么样?
==================================================
🔍 开始分析问题类型...
📊 判断结果:天气问题
🌤️ 开始搜索实时天气数据...
🔎 搜索关键词:深圳今天天气怎么样? 天气 实时气温
✅ 天气数据获取成功
📝 基于实时数据生成天气报告...
🤖 助手回答:根据最新天气数据,深圳今天晴天,气温25-30°C...
==================================================

👤 用户提问:南京明天会下雨吗?
==================================================
🔍 开始分析问题类型...
📊 判断结果:天气问题
🌤️ 开始搜索实时天气数据...
🔎 搜索关键词:南京明天会下雨吗? 天气 实时气温
✅ 天气数据获取成功
📝 基于实时数据生成天气报告...
🤖 助手回答:南京明天预计会有降雨,建议您出门携带雨具...
==================================================

👤 用户提问:南京有什么著名景点?
==================================================
🔍 开始分析问题类型...
📊 判断结果:普通问题
💭 处理通用知识问题...
🤖 助手回答:南京是一座历史悠久、文化底蕴深厚的城市...
==================================================

您可能感兴趣的与本文相关的镜像

LobeChat

LobeChat

AI应用

LobeChat 是一个开源、高性能的聊天机器人框架。支持语音合成、多模态和可扩展插件系统。支持一键式免费部署私人ChatGPT/LLM 网络应用程序。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值