CodeL
以前端为翼,以 AI 为脑,向全栈而行
2026-03-31

LangChain.js 完全指南:前端视角的 AI 应用开发

LangChain.js 完全指南:前端视角的 AI 应用开发 从零开始构建 AI Agent,JavaScript/TypeScript 开发者的实用入门手册 目录 1. 核心概念 2. 基础使用 3. 进阶用法 4....

LangChain.js 完全指南:前端视角的 AI 应用开发 #

从零开始构建 AI Agent,JavaScript/TypeScript 开发者的实用入门手册


目录 #

  1. 核心概念
  2. 基础使用
  3. 进阶用法
  4. 实战场景
  5. 常见问题
  6. 总结速记

一、核心概念 #

1.1 什么是 LangChain.js?(大白话解释) #

想象一下,你要做一个 AI 助手。最原始的方式是:直接调用 OpenAI 的 API,发一条消息,等回复。这就像打电话问客服一个问题,挂断,结束。

但真实场景要复杂得多:

  • 多轮对话 — 用户说"帮我查天气",AI 问"哪个城市?",用户说"北京",AI 再调用天气 API...
  • 需要工具 — AI 光会说话没用,还得能查数据库、调用 API、读写文件
  • 记住上下文 — 用户之前说了什么,AI 得记住,不能每次都从头问

LangChain.js 就是帮你解决这些问题的框架

打个比方:

  • 直接调用 AI API ≈ 用原生 JavaScript 写网页
  • 用 LangChain.js ≈ 用 React/Vue 写应用

它帮你把"模型调用 → 工具执行 → 状态管理 → 对话记忆"这套流程封装好了,你只需要声明式地描述"我要什么",而不是命令式地写一堆异步回调。

1.2 为什么需要 LangChain.js? #

问题 直接调用 API 用 LangChain.js
模型切换 每个提供商 API 不同,要改代码 改一个字符串就行 "openai:gpt-4""anthropic:claude"
工具调用 手写解析逻辑、处理回调、错误处理 createAgent({ tools: [getWeather] }) 一行搞定
多轮对话 自己维护 message 数组、实现记忆 内置 Memory,自动管理
结构化输出 手写 JSON 解析、校验 用 Zod 定义 schema,自动校验
调试追踪 加 console.log,没有可视化 LangSmith 一键追踪

一句话总结:LangChain.js 让你从"写 AI 调用代码"变成"配置 AI Agent"。

1.3 LangChain.js 的核心名词 #

名词 是什么 前端类比
Model LLM 模型(GPT、Claude 等) 相当于"后端服务",提供推理能力
Tool AI 能调用的函数(查天气、搜数据库) 相当于"API 封装",给 AI 用
Agent AI + 工具 + 记忆的组合体 相当于"一个完整的 App"
Prompt 给 AI 的指令(角色设定、任务描述) 相当于"组件 props",告诉 AI 干什么
Memory 对话历史、用户偏好等记忆 相当于"Redux state",持久化数据
Structured Output 强制 AI 返回 JSON 格式 相当于"TypeScript 类型定义"
LangSmith 调试/追踪工具 相当于"React DevTools"

1.4 LangChain vs LangGraph vs Deep Agents #

这是三个不同的层级:

产品 定位 什么时候用
LangChain 基础框架 快速搭建一个 Agent
LangGraph 低级编排框架 需要精细控制流程、复杂工作流
Deep Agents "开箱即用"的高级 Agent 生产级 Agent,自动压缩对话、文件系统、子 Agent

新手建议:先用 LangChain,熟练后再看 LangGraph。


二、基础使用 #

2.1 安装 #

# 核心包
npm install langchain @langchain/core
 
# 模型提供商(选你用的)
npm install @langchain/openai      # OpenAI
npm install @langchain/anthropic   # Claude
npm install @langchain/google-genai # Gemini
 
# 工具依赖
npm install zod                     # schema 定义

要求:Node.js 20+

2.2 最简单的例子:直接调用模型 #

import { initChatModel } from "langchain";
 
// 设置 API Key(实际项目中用环境变量)
process.env.OPENAI_API_KEY = "your-api-key";
 
// 初始化模型
const model = await initChatModel("gpt-4o-mini");
 
// 调用
const response = await model.invoke("为什么鹦鹉会说话?");
 
console.log(response.content);
// "鹦鹉会说话是因为它们有很强的模仿能力..."

这就是最基础的用法 —— 和直接调用 OpenAI API 差不多。

2.3 第一个 Agent:带工具的 AI #

import { createAgent, tool } from "langchain";
import * as z from "zod";
 
// 定义一个工具:查天气
const getWeather = tool(
  // 工具的执行逻辑
  ({ city }) => `今天 ${city} 天气晴朗,温度 25°C`,
  {
    name: "get_weather",              // 工具名称
    description: "查询指定城市的天气",  // AI 看到的描述
    schema: z.object({
      city: z.string().describe("城市名称,如:北京、上海")
    })
  }
);
 
// 创建 Agent
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [getWeather]
});
 
// 使用
const result = await agent.invoke({
  messages: [{ role: "user", content: "北京今天天气怎么样?" }]
});
 
console.log(result.messages[result.messages.length - 1].content);
// "根据查询结果,北京今天天气晴朗,温度 25°C。适合出门散步!"

发生了什么?

  1. 用户问"北京天气"
  2. AI 判断需要调用 get_weather 工具
  3. AI 生成工具调用参数 { city: "北京" }
  4. 工具执行,返回结果
  5. AI 根据工具结果,生成最终回复

整个过程自动完成,你只需要定义工具。

2.4 使用不同的模型提供商 #

LangChain 的核心优势:切换模型只需改字符串

// OpenAI
const agent1 = createAgent({
  model: "openai:gpt-4o-mini",
  tools: []
});
 
// Anthropic Claude
const agent2 = createAgent({
  model: "anthropic:claude-sonnet-4-6",
  tools: []
});
 
// Google Gemini
const agent3 = createAgent({
  model: "google-genai:gemini-2.0-flash",
  tools: []
});
 
// Azure OpenAI
const agent4 = createAgent({
  model: "azure_openai:gpt-4o",
  tools: []
});

对应的环境变量:

OPENAI_API_KEY=xxx
ANTHROPIC_API_KEY=xxx
GOOGLE_API_KEY=xxx
AZURE_OPENAI_API_KEY=xxx
AZURE_OPENAI_ENDPOINT=xxx

2.5 配置模型参数 #

import { initChatModel } from "langchain";
 
const model = await initChatModel("gpt-4o-mini", {
  temperature: 0.7,    // 创造性:0-1,越高越随机
  maxTokens: 1000,     // 最大输出长度
  timeout: 30,         // 超时时间(秒)
  maxRetries: 3        // 失败重试次数
});
 
const agent = createAgent({
  model,
  tools: []
});
参数 作用 推荐值
temperature 0 = 确定性回答,1 = 创造性 工具调用用 0,聊天用 0.7
maxTokens 输出上限 根据任务调整
timeout 超时 网络不稳时增大
maxRetries 重试次数 生产环境 10-15

三、进阶用法 #

3.1 定义系统提示词(System Prompt) #

系统提示词定义 Agent 的"角色"和"行为规则"。

const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [getWeather],
  systemPrompt: `你是一个专业的天气预报助手。
  
你的职责:
1. 查询用户指定城市的天气
2. 用轻松幽默的语气回复
3. 给出穿衣建议
 
如果用户没有指定城市,询问他们的位置。`
});
 
// 使用
await agent.invoke({
  messages: [{ role: "user", content: "今天要穿什么?" }]
});
// AI 会先问 "你在哪个城市?"

写提示词的技巧

  • 具体比笼统好("你是一个天气助手" > "你是一个助手")
  • 列出可用工具,AI 才知道能干什么
  • 设定边界("只回答天气相关的问题")

3.2 结构化输出(Structured Output) #

让 AI 返回 JSON,而不是自由文本。

import * as z from "zod";
 
// 定义输出格式
const WeatherReport = z.object({
  city: z.string(),
  temperature: z.number(),
  condition: z.enum(["晴", "雨", "多云", "雪"]),
  suggestion: z.string().describe("穿衣建议")
});
 
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [getWeather],
  responseFormat: WeatherReport  // 强制输出这个格式
});
 
const result = await agent.invoke({
  messages: [{ role: "user", content: "北京天气" }]
});
 
// 直接拿到结构化数据
console.log(result.structuredResponse);
// {
//   city: "北京",
//   temperature: 25,
//   condition: "晴",
//   suggestion: "建议穿短袖,带个薄外套"
// }

好处

  • 可以直接存数据库
  • 前端可以直接渲染
  • 类型安全,不会出现奇怪格式

3.3 添加对话记忆(Memory) #

没有记忆的 Agent,每次对话都是独立的,不会记住用户之前说了什么。

import { MemorySaver } from "@langchain/langgraph";
 
// 创建记忆存储
const checkpointer = new MemorySaver();
 
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [getWeather],
  checkpointer  // 启用记忆
});
 
// 第一次对话
await agent.invoke(
  { messages: [{ role: "user", content: "我叫小明" }] },
  { configurable: { thread_id: "user-123" } }  // thread_id 区分不同用户
);
 
// 第二次对话(同一个 thread_id)
const result = await agent.invoke(
  { messages: [{ role: "user", content: "我叫什么名字?" }] },
  { configurable: { thread_id: "user-123" } }
);
 
console.log(result.messages[result.messages.length - 1].content);
// "你叫小明,你刚才告诉我的。"

关键概念

  • thread_id — 会话标识符,同一个 ID 共享记忆
  • checkpointer — 记忆存储器,MemorySaver 是内存版本

生产环境:用数据库存储记忆。

import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
 
const checkpointer = PostgresSaver.fromConnString(
  "postgresql://user:pass@localhost:5432/mydb"
);

3.4 工具访问上下文(Context) #

工具可以访问用户信息、会话数据。

import { tool, type ToolRuntime } from "langchain";
 
// 定义上下文类型
type MyContext = { user_id: string; user_name: string };
 
const getUserInfo = tool(
  async (_, config: ToolRuntime<unknown, MyContext>) => {
    // 从 config.context 获取上下文
    const { user_id, user_name } = config.context;
    
    // 模拟查询数据库
    return `用户 ${user_name}(ID: ${user_id})已登录 3 天`;
  },
  {
    name: "get_user_info",
    description: "获取当前用户信息",
    schema: z.object({})
  }
);
 
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [getUserInfo],
  contextSchema: z.object({
    user_id: z.string(),
    user_name: z.string()
  })
});
 
// 调用时传入上下文
await agent.invoke(
  { messages: [{ role: "user", content: "我是谁?" }] },
  { context: { user_id: "abc123", user_name: "张三" } }
);

3.5 流式输出(Streaming) #

实时显示 AI 回复,而不是等全部生成完。

const agent = createAgent({
  model: "gpt-4o-mini",
  tools: []
});
 
const stream = await agent.stream(
  { messages: [{ role: "user", content: "讲一个笑话" }] },
  { streamMode: "values" }
);
 
// 逐块输出
for await (const chunk of stream) {
  const lastMessage = chunk.messages[chunk.messages.length - 1];
  if (lastMessage.role === "assistant") {
    console.log(lastMessage.content);  // 逐步打印
  }
}

前端应用场景:聊天界面实时显示回复。

3.6 工具返回不同类型 #

工具可以返回三种类型:

// 1. 返回字符串(最常见)
const search = tool(
  ({ query }) => `找到 3 条关于 "${query}" 的结果`,
  { name: "search", schema: z.object({ query: z.string() }) }
);
 
// 2. 返回对象(结构化数据)
const getWeatherData = tool(
  ({ city }) => ({
    city,
    temperature: 25,
    humidity: 60,
    wind: "东北风 3级"
  }),
  { name: "get_weather_data", schema: z.object({ city: z.string() }) }
);
 
// 3. 返回 Command(更新 Agent 状态)
import { Command } from "@langchain/langgraph";
import { ToolMessage } from "@langchain/core/messages";
 
const setLanguage = tool(
  async ({ language }, config) => {
    return new Command({
      update: {
        preferredLanguage: language,
        messages: [
          new ToolMessage({
            content: `语言已切换为 ${language}`,
            tool_call_id: config.toolCallId
          })
        ]
      }
    });
  },
  {
    name: "set_language",
    schema: z.object({ language: z.string() })
  }
);

四、实战场景 #

场景 1:智能客服助手 #

一个能查询订单、处理退款的客服 Agent。

import { createAgent, tool } from "langchain";
import * as z from "zod";
import { MemorySaver } from "@langchain/langgraph";
 
// 查询订单工具
const queryOrder = tool(
  async ({ orderId }) => {
    // 模拟数据库查询
    const orders = {
      "12345": { status: "已发货", items: ["iPhone 15", "AirPods"], total: 9999 },
      "67890": { status: "待支付", items: ["MacBook Pro"], total: 19999 }
    };
    const order = orders[orderId as keyof typeof orders];
    return order 
      ? `订单 ${orderId}: ${order.status}, 商品: ${order.items.join(", ")}, 总价: ¥${order.total}`
      : `未找到订单 ${orderId}`;
  },
  {
    name: "query_order",
    description: "查询订单状态和详情",
    schema: z.object({
      orderId: z.string().describe("订单号")
    })
  }
);
 
// 申请退款工具
const requestRefund = tool(
  async ({ orderId, reason }) => {
    // 模拟退款处理
    return `退款申请已提交:订单 ${orderId}, 原因: ${reason}。预计 3-5 个工作日处理。`;
  },
  {
    name: "request_refund",
    description: "申请订单退款",
    schema: z.object({
      orderId: z.string().describe("订单号"),
      reason: z.string().describe("退款原因")
    })
  }
);
 
// 创建客服 Agent
const customerServiceAgent = createAgent({
  model: "gpt-4o-mini",
  tools: [queryOrder, requestRefund],
  systemPrompt: `你是电商平台的客服助手。
 
你的职责:
1. 查询用户订单状态
2. 处理退款申请
3. 解答常见问题
 
规则:
- 用户询问订单时,先查订单状态再回复
- 退款需要用户提供订单号和原因
- 保持礼貌、专业的语气`,
  checkpointer: new MemorySaver()  // 启用记忆
});
 
// 使用示例
const config = { configurable: { thread_id: "customer-001" } };
 
// 用户查订单
await customerServiceAgent.invoke(
  { messages: [{ role: "user", content: "帮我查一下订单 12345" }] },
  config
);
 
// 用户申请退款(Agent 会记住订单号)
await customerServiceAgent.invoke(
  { messages: [{ role: "user", content: "我想退款,东西不喜欢" }] },
  config
);

场景 2:代码助手 #

一个能解释代码、生成代码、查文档的 Agent。

// 执行代码工具(模拟)
const runCode = tool(
  async ({ code, language }) => {
    // 实际项目中可以用沙箱执行
    if (language === "javascript") {
      try {
        const result = eval(code);
        return `执行结果: ${result}`;
      } catch (e) {
        return `错误: ${e.message}`;
      }
    }
    return `暂不支持 ${language}`;
  },
  {
    name: "run_code",
    description: "执行代码并返回结果",
    schema: z.object({
      code: z.string().describe("要执行的代码"),
      language: z.enum(["javascript", "python"]).describe("编程语言")
    })
  }
);
 
// 搜索文档工具(模拟)
const searchDocs = tool(
  async ({ query }) => {
    // 实际项目中调用搜索引擎
    const docs = {
      "react useState": "useState 是 React 的状态管理 Hook...",
      "vue computed": "computed 是 Vue 的计算属性..."
    };
    return docs[query as keyof typeof docs] || `未找到 "${query}" 相关文档`;
  },
  {
    name: "search_docs",
    description: "搜索技术文档",
    schema: z.object({
      query: z.string().describe("搜索关键词")
    })
  }
);
 
const codeAgent = createAgent({
  model: "gpt-4o-mini",
  tools: [runCode, searchDocs],
  systemPrompt: `你是一个代码助手。
 
职责:
1. 解释代码逻辑
2. 生成代码示例
3. 搜索技术文档
4. 执行简单代码
 
规则:
- 生成代码后,询问是否需要执行
- 解释要清晰、有注释
- 推荐最佳实践`
});
 
// 使用
await codeAgent.invoke({
  messages: [{ 
    role: "user", 
    content: "帮我写一个 React 计数器组件" 
  }]
});

场景 3:数据分析师 Agent #

从数据库提取数据、生成分析报告。

// 定义输出格式:分析报告
const AnalysisReport = z.object({
  summary: z.string().describe("数据摘要"),
  trends: z.array(z.string()).describe("发现趋势"),
  recommendations: z.array(z.string()).describe("建议"),
  confidence: z.number().min(0).max(1).describe("置信度")
});
 
// 查询数据库工具
const queryDatabase = tool(
  async ({ table, conditions }) => {
    // 模拟数据库查询
    return `查询 ${table} 表,条件: ${conditions.join(", ")}。返回 100 条记录。`;
  },
  {
    name: "query_database",
    description: "查询数据库",
    schema: z.object({
      table: z.string().describe("表名"),
      conditions: z.array(z.string()).describe("查询条件")
    })
  }
);
 
// 生成图表工具
const generateChart = tool(
  async ({ type, data, title }) => {
    // 实际项目中生成真实图表
    return `已生成 ${type} 图表:"${title}"。数据包含 ${data.length} 个点。`;
  },
  {
    name: "generate_chart",
    description: "生成数据图表",
    schema: z.object({
      type: z.enum(["bar", "line", "pie"]),
      data: z.array(z.number()),
      title: z.string()
    })
  }
);
 
const dataAnalystAgent = createAgent({
  model: "gpt-4o-mini",
  tools: [queryDatabase, generateChart],
  responseFormat: AnalysisReport,  // 强制输出结构化报告
  systemPrompt: `你是数据分析助手。
 
工作流程:
1. 理解用户分析需求
2. 查询相关数据
3. 分析数据趋势
4. 生成可视化图表
5. 输出结构化报告
 
报告必须包含:摘要、趋势、建议、置信度。`
});
 
// 使用
const result = await dataAnalystAgent.invoke({
  messages: [{ 
    role: "user", 
    content: "分析最近一周的用户注册数据" 
  }]
});
 
console.log(result.structuredResponse);

场景 4:多工具协作 Agent #

一个 Agent 同时使用多个工具完成复杂任务。

import { createAgent, tool } from "langchain";
import * as z from "zod";
 
// 天气查询
const getWeather = tool(
  ({ city }) => `${city}: 晴, 28°C`,
  { name: "get_weather", schema: z.object({ city: z.string() }) }
);
 
// 餐厅推荐
const searchRestaurants = tool(
  ({ city, cuisine }) => `${city} 有 5 家 ${cuisine} 餐厅推荐`,
  { 
    name: "search_restaurants", 
    schema: z.object({ 
      city: z.string(), 
      cuisine: z.string().optional() 
    }) 
  }
);
 
// 电影查询
const getMovies = tool(
  ({ genre }) => `推荐 3 部 ${genre} 电影`,
  { name: "get_movies", schema: z.object({ genre: z.string() }) }
);
 
// 日程安排
const scheduleEvent = tool(
  ({ date, time, event }) => `已安排:${date} ${time} - ${event}`,
  { 
    name: "schedule_event", 
    schema: z.object({ 
      date: z.string(), 
      time: z.string(), 
      event: z.string() 
    }) 
  }
);
 
// 万能助手
const superAgent = createAgent({
  model: "gpt-4o-mini",
  tools: [getWeather, searchRestaurants, getMovies, scheduleEvent],
  systemPrompt: `你是万能助手,可以帮用户:
- 查天气
- 推荐餐厅
- 推荐电影
- 安排日程
 
根据用户需求,自动选择合适的工具组合。
例如用户说"周末安排",你可以:
1. 查周末天气
2. 推荐餐厅
3. 推荐电影
4. 生成日程安排`,
  checkpointer: new MemorySaver()
});
 
// 使用:用户一句话,Agent 自动调用多个工具
const result = await superAgent.invoke({
  messages: [{ role: "user", content: "帮我安排北京这周末的活动" }]
});

场景 5:前端集成 —— React 聊天组件 #

把 LangChain Agent 接到前端 React 应用。

// backend.ts - 后端 API
import { createAgent, tool } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
 
const chatAgent = createAgent({
  model: "gpt-4o-mini",
  tools: [],
  checkpointer: new MemorySaver()
});
 
// Express API
app.post("/chat", async (req, res) => {
  const { message, threadId } = req.body;
  
  const stream = await chatAgent.stream(
    { messages: [{ role: "user", content: message }] },
    { configurable: { thread_id: threadId }, streamMode: "values" }
  );
  
  // 返回流式响应
  res.setHeader("Content-Type", "text/event-stream");
  for await (const chunk of stream) {
    const msg = chunk.messages[chunk.messages.length - 1];
    if (msg.role === "assistant") {
      res.write(`data: ${JSON.stringify({ content: msg.content })}\n\n`);
    }
  }
  res.end();
});
// frontend.tsx - React 组件
import { useState } from "react";
 
function ChatComponent() {
  const [messages, setMessages] = useState<Array<{role: string, content: string}>>([]);
  const [input, setInput] = useState("");
  const threadId = "user-" + Math.random().toString(36).slice(2);
 
  async function sendMessage() {
    setMessages(prev => [...prev, { role: "user", content: input }]);
    setInput("");
 
    // 流式接收
    const response = await fetch("/chat", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: input, threadId })
    });
 
    const reader = response.body?.getReader();
    const decoder = new TextDecoder();
    let aiMessage = "";
 
    while (reader) {
      const { done, value } = await reader.read();
      if (done) break;
      
      const chunk = decoder.decode(value);
      const lines = chunk.split("\n").filter(l => l.startsWith("data:"));
      
      for (const line of lines) {
        const data = JSON.parse(line.slice(5));
        aiMessage += data.content;
        setMessages(prev => {
          const last = prev[prev.length - 1];
          if (last?.role === "assistant") {
            return [...prev.slice(0, -1), { role: "assistant", content: aiMessage }];
          }
          return [...prev, { role: "assistant", content: aiMessage }];
        });
      }
    }
  }
 
  return (
    <div className="chat">
      {messages.map((msg, i) => (
        <div key={i} className={`message ${msg.role}`}>
          {msg.content}
        </div>
      ))}
      <input 
        value={input} 
        onChange={e => setInput(e.target.value)}
        onKeyDown={e => e.key === "Enter" && sendMessage()}
      />
      <button onClick={sendMessage}>发送</button>
    </div>
  );
}

五、常见问题 #

Q1: Agent 调用工具时报错怎么办? #

import { ToolNode } from "@langchain/langgraph/prebuilt";
 
// 默认:错误会中断执行
const toolNode = new ToolNode(tools);
 
// 捕获错误,继续执行
const toolNode = new ToolNode(tools, { 
  handleToolErrors: true  // 或传自定义消息
});
 
const toolNode = new ToolNode(tools, { 
  handleToolErrors: "工具执行失败,请稍后重试"
});

Q2: 如何控制对话长度? #

长对话会超出模型上下文限制,需要裁剪。

import { createMiddleware } from "langchain";
import { RemoveMessage, REMOVE_ALL_MESSAGES } from "@langchain/langgraph";
 
const trimMessages = createMiddleware({
  name: "TrimMessages",
  beforeModel: (state) => {
    const messages = state.messages;
    
    if (messages.length <= 5) return;
    
    // 保留第一条 + 最近 4 条
    const firstMsg = messages[0];
    const recent = messages.slice(-4);
    const newMessages = [firstMsg, ...recent];
    
    return {
      messages: [
        new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),
        ...newMessages
      ]
    };
  }
});
 
const agent = createAgent({
  model: "gpt-4o-mini",
  middleware: [trimMessages],
  checkpointer: new MemorySaver()
});

Q3: 如何在 Node.js 和浏览器中使用? #

Node.js — 正常使用,设置环境变量。

process.env.OPENAI_API_KEY = "xxx";
const agent = createAgent({ model: "gpt-4o-mini", tools: [] });

浏览器 — 需要处理 CORS 和 API Key 安全问题。

// 方案 1:通过后端代理
const response = await fetch("/api/chat", {
  method: "POST",
  body: JSON.stringify({ message })
});
 
// 方案 2:使用边缘函数(Vercel/Cloudflare)
// API Key 在边缘函数中,不暴露给前端

不建议在前端直接调用 API —— Key 会暴露。

Q4: 如何调试 Agent 执行过程? #

使用 LangSmith 追踪工具。

# 设置环境变量
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=xxx

然后在 LangSmith 网站 查看:

  • 模型调用日志
  • 工具执行过程
  • Token 使用统计
  • 错误追踪

Q5: 为什么 Agent 不调用工具? #

常见原因:

  1. 工具描述不清晰 — AI 不知道什么时候用
  2. 模型不支持工具调用 — 换支持 tool calling 的模型
  3. 提示词冲突 — 提示词里说了"不要用工具"

解决:

// 改进工具描述
const search = tool(
  ({ query }) => `结果`,
  {
    name: "web_search",
    description: "当用户询问实时信息、新闻、天气时使用此工具",  // 明确触发条件
    schema: z.object({ query: z.string() })
  }
);
 
// 确认模型支持工具调用
// OpenAI: gpt-4o, gpt-4o-mini, gpt-4-turbo
// Anthropic: claude-3.5-sonnet, claude-3-opus
// Gemini: gemini-1.5-pro, gemini-2.0-flash

Q6: 如何动态选择工具? #

根据用户权限、状态动态过滤工具。

import { createMiddleware } from "langchain";
 
const dynamicTools = createMiddleware({
  name: "DynamicTools",
  wrapModelCall: (request, handler) => {
    const userRole = request.runtime?.context?.userRole;
    
    let filteredTools = request.tools;
    
    if (userRole === "guest") {
      // 游客只能用查询工具
      filteredTools = request.tools.filter(
        t => t.name.startsWith("query_")
      );
    } else if (userRole === "admin") {
      // 管理员可以用所有工具
    }
    
    return handler({ ...request, tools: filteredTools });
  }
});
 
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [queryTool, deleteTool, updateTool],
  middleware: [dynamicTools]
});

Q7: 如何使用 Zod 定义复杂 Schema? #

import * as z from "zod";
 
// 基础类型
const BasicSchema = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().email()
});
 
// 可选字段
const OptionalSchema = z.object({
  title: z.string(),
  subtitle: z.string().optional(),
  tags: z.array(z.string()).optional()
});
 
// 嵌套对象
const NestedSchema = z.object({
  user: z.object({
    name: z.string(),
    address: z.object({
      city: z.string(),
      zip: z.string()
    })
  }),
  orders: z.array(z.object({
    id: z.string(),
    amount: z.number()
  }))
});
 
// 带描述(AI 看得到)
const DescribedSchema = z.object({
  query: z.string().describe("搜索关键词,最多 50 字"),
  limit: z.number().min(1).max(100).describe("返回结果数量,1-100")
});
 
// 枚举
const EnumSchema = z.object({
  status: z.enum(["pending", "completed", "cancelled"]),
  priority: z.enum(["low", "medium", "high"])
});

六、总结速记 #

核心概念速记表 #

概念 一句话 关键代码
Model AI 大脑 initChatModel("gpt-4o-mini")
Tool AI 的手 tool(fn, { name, schema })
Agent AI + 工具 + 记忆 createAgent({ model, tools })
Memory 对话历史 checkpointer: new MemorySaver()
Structured Output JSON 输出 responseFormat: z.object({...})
Streaming 实时输出 agent.stream({ messages }, { streamMode })

模型选择速记 #

任务 推荐 原因
工具调用 gpt-4o-mini 快、便宜、支持好
复杂推理 claude-sonnet-4-6 推理能力强
大量请求 gemini-2.0-flash 最便宜
中文场景 gpt-4o / claude 中文理解好

常用代码模板 #

// 最小 Agent
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [myTool]
});
 
// 带 Memory
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [],
  checkpointer: new MemorySaver()
});
 
// 带结构化输出
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [],
  responseFormat: z.object({ result: z.string() })
});
 
// 带提示词
const agent = createAgent({
  model: "gpt-4o-mini",
  tools: [],
  systemPrompt: "你是..."
});
 
// 调用
await agent.invoke({ messages: [{ role: "user", content: "..." }] });

附录 #

命令速查表 #

命令 作用
npm install langchain @langchain/core 安装核心包
npm install @langchain/openai 安装 OpenAI 集成
npm install zod 安装 schema 库
LANGSMITH_TRACING=true 启用追踪

API 速查 #

API 作用
initChatModel(model, options) 初始化模型
createAgent(config) 创建 Agent
tool(fn, config) 定义工具
agent.invoke(input, config) 调用 Agent
agent.stream(input, config) 流式调用

官方资源 #

资源 链接
官方文档 https://js.langchain.com/docs
GitHub https://github.com/langchain-ai/langchainjs
LangSmith https://smith.langchain.com
集成列表 https://js.langchain.com/docs/integrations

最后更新:2026-03-29