逑美(皮肤健康咨询)
89.22M · 2025-09-29
作为前端开发者,你是否也有这样的纠结:想入门 AI,却被一堆 Python 教程劝退?用过 ChatGPT、Stable Diffusion,却觉得只是 “用工具” 而非 “懂原理”?尝试过 RAG、Agent 这些概念,却不知道如何用 JavaScript 落地?
今天就从前端视角出发,用 LangGraph(JS 版)手把手实现一个 ReAct 智能体 —— 这是 AI Agent 的基础模式,也是掌握复杂智能体的第一步。哪怕你只懂基础 JS,跟着步骤走也能做出来。
前端学 AI 应该学什么?
学 AI 最痛苦的是 “找不到方向”:到底该从哪入手?学完怎么算 “真懂”?我刚开始接触 AI 时,走了不少弯路:先玩 Stable Diffusion 生成图片,再用各种大模型聊天,甚至用 AI 插件写代码。看似学了很多,却总觉得 “没抓住核心”—— 因为这些都是 “用工具”,没搞懂背后的逻辑,换个场景就懵了。
直到接触 RAG(检索增强生成)、MCP(多智能体协作)、LangChain 这些技术,才慢慢明白:前端学 AI,核心要学 “如何开发 Agent(智能体)”。
Agent 是 AI 的 “应用形态”—— 比如能自动查资料写报告的 AI 助手、能帮你处理重复工作的智能工具,本质都是 Agent。而网上关于 Agent 的教程,90% 以上用 Python,前端开发者想入门难上加难。
所以接下来,我会用 JS 语言,基于 LangGraph 做一系列 AI 项目,从基础到进阶,帮前端同学真正 “落地 AI 开发”,而不是停留在 “用工具” 的层面。
开发 Agent 一定要用 LangGraph 吗?
答案是:完全不用!
你可以用纯 JS 写逻辑(比如用循环实现 “思考 - 行动” 流程),也可以用 Coze、百度千帆这些云平台(拖拖拽拽搭 Agent),甚至能用纯提示词(比如给 ChatGPT 写指令,让它模拟智能体)。
那为什么推荐 LangGraph?有两个核心原因:
简单说:LangGraph 不是 “唯一选择”,却是前端入门 Agent 的 “最优选择”—— 它帮你把精力放在 “理解 AI 逻辑” 上,而不是 “写重复代码”。
ReAct 智能体:前端最易上手的 Agent 模式
为什么先学 ReAct?
对前端开发者来说,ReAct 是最 “接地气” 的 Agent 模式 —— 它的逻辑和 “人解决问题的思路” 几乎一样:
比如你想知道 “今天上海天气要不要带伞”,会先 “思考”(要不要查实时天气?),再 “行动”(打开天气 APP),最后 “总结”(多云,不用带伞)。
ReAct 的核心就是 “推理(Reason)+ 行动(Act)” 的循环,源自论文《ReAct: Synergizing Reasoning and Acting in Language Models》。它没有复杂的数学公式,全是 “逻辑判断”,用 JS 就能轻松实现。
更重要的是:所有复杂 Agent(比如能写报告、能处理业务的 AI),底层都是 ReAct 的延伸。学会它,后续学多智能体、长记忆智能体,都会像 “搭积木” 一样简单。
项目概述:技术栈与效果预览
用什么技术?
核心技术栈:LangGraph(JS 版)+ LangStudio(调试工具)+ LangSmith(日志追踪)
这些工具都有免费额度,个人开发完全够用,不用担心收费问题。
最终效果是什么样?
你不用写复杂代码,启动项目后会自动打开 LangStudio,输入问题就能看到:
整个过程不用你手动干预,智能体自己完成 “思考 - 行动 - 输出”,像个 “迷你 AI 助手”。
目录结构:3 分钟看懂文件分工
项目叫 “react-agent”,文件不多,每个文件的职责都很明确,前端同学一看就懂:
react-agent/
├─ graph.ts // 核心!定义智能体的工作流(节点、边、循环逻辑)
├─ configuration.ts// 配置参数(用什么模型、系统提示词是什么)
├─ prompts.ts // 系统提示模板(告诉智能体“该怎么思考、怎么行动”)
├─ tools.ts // 工具定义(比如搜索工具、计算器工具)
├─ utils.ts // 辅助函数(比如加载模型、处理错误)
└─ README.md // 启动步骤(复制命令就能跑,不用配置环境)
不用怕文件多,核心逻辑全在graph.ts
里,其他文件都是 “配置或辅助”,改改参数就能用。
核心实现:从流程到代码,前端能看懂的细节
先记住一个核心逻辑:整个智能体就是 “循环做 3 件事”—— 思考→判断要不要用工具→用工具 / 输出答案。
下面拆成 “状态管理、工作流、节点函数” 三部分,每个部分都附 “前端能懂的解释” 和 “可复制的代码”。
前端同学都懂 “组件状态”(比如 React 的 useState),智能体的 “状态” 其实就是它的 “记忆”—— 比如用户问了什么、之前思考了什么、工具返回了什么,都存在这里。
LangGraph 用MessagesAnnotation管理状态,简单说就是 “一个存消息的数组”,类似前端的 “聊天记录数组”。
在graph.ts
里,状态的使用方式如下:
// graph.ts
import { MessagesAnnotation } from "@langchain/langgraph";
import { RunnableConfig } from "@langchain/core/runnables";
import { ensureConfiguration } from "./configuration";
import { loadChatModel } from "./utils";
import { TOOLS } from "./tools";
// callModel:智能体的“思考节点”,输入状态,返回新的状态(新增思考结果)
async function callModel(
state: typeof MessagesAnnotation.State, // 当前状态(比如聊天记录)
config: RunnableConfig, // 配置参数(比如用什么模型)
): Promise<typeof MessagesAnnotation.Update> { // 返回更新后的状态
// 1. 获取配置(用什么模型、系统提示词)
const configuration = ensureConfiguration(config);
// 2. 加载模型,并告诉模型“能用哪些工具”
const model = (await loadChatModel(configuration.model)).bindTools(TOOLS);
// 3. 给模型发消息:系统提示 + 历史聊天记录
const response = await model.invoke([
{
role: "system",
content: configuration.systemPromptTemplate.replace(
"{system_time}",
new Date().toISOString(), // 注入当前时间,方便模型处理“时效性问题”
),
},
...state.messages, // 带上之前的聊天记录,避免智能体“失忆”
]);
// 4. 返回更新后的状态:把模型的思考结果加入“记忆本”
return { messages: [response] };
}
前端视角解读:
state
就像 React 组件的state
,存着所有 “历史数据”;Update
就像setState
的参数,告诉 LangGraph “要更新哪些数据”;智能体的 “思考 - 行动” 流程,用 LangGraph 的StateGraph
定义,就像用 Visio 画流程图,前端同学很容易理解。
核心代码在graph.ts
里:
// graph.ts
import { StateGraph } from "@langchain/langgraph";
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { ConfigurationSchema } from "./configuration";
// 1. 定义“决策函数”:思考后该做什么?(用工具还是输出答案?)
function routeModelOutput(state: typeof MessagesAnnotation.State): string {
// 取最新的模型回复
const lastMessage = state.messages[state.messages.length - 1];
// 如果模型说“要用工具”(返回了tool_calls),就去工具节点;否则结束
if ((lastMessage as any)?.tool_calls?.length > 0) {
return "tools"; // 去执行工具
} else {
return "__end__"; // 结束流程,输出答案
}
}
// 2. 构建工作流
const workflow = new StateGraph(MessagesAnnotation, ConfigurationSchema)
// 加“思考节点”:调用模型分析问题
.addNode("callModel", callModel)
// 加“行动节点”:执行工具(用LangGraph的ToolNode,不用自己写逻辑)
.addNode("tools", new ToolNode(TOOLS))
// 起点→先思考:用户提问后,第一步是让模型分析问题
.addEdge("__start__", "callModel")
// 思考后→决策:根据模型回复,决定去工具节点还是结束
.addConditionalEdges("callModel", routeModelOutput)
// 行动后→再思考:用工具获取数据后,回到模型继续分析
.addEdge("tools", "callModel");
// 3. 导出智能体,供外部调用
export const reactAgent = workflow.compile();
用流程图简化理解:
前端同学应该很熟悉这种逻辑:就像 “组件间跳转”,用 “条件判断” 决定下一步去哪,完全不用写复杂的循环和分支。
智能体自己不会 “查天气、算数学题”,需要靠 “工具” 实现。就像前端项目需要 “调用接口” 获取数据,智能体需要 “调用工具” 扩展能力。
在tools.ts
里,我们定义一个 “搜索工具”(用 Tavily,类似百度搜索):
// tools.ts
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
import dotenv from "dotenv";
dotenv.config();
// 1. 初始化搜索工具,设置最多返回3条结果
const searchTavily = new TavilySearchResults({
maxResults: 3,
// 填入申请到的API key
apiKey: process.env.TAVILY_API_KEY,
});
// 2. 导出工具列表,供其他文件使用
export const TOOLS = [searchTavily];
前端视角解读:
TOOLS
数组即可,不用改核心流程,符合 “开闭原则”。想让智能体按你的要求工作,需要两个关键配置:“用什么模型” 和 “系统提示词”。
在configuration.ts
里定义配置项:
// configuration.ts
import { Annotation } from "@langchain/langgraph";
import { SYSTEM_PROMPT_TEMPLATE } from "./prompts";
// 1. 定义配置 schema(类似前端的PropTypes)
export const ConfigurationSchema = Annotation.Root({
// 系统提示词模板(告诉智能体“该怎么思考、怎么行动”)
systemPromptTemplate: Annotation.string({
default: SYSTEM_PROMPT_TEMPLATE,
}),
// 选用的大模型(默认用deepseek,免费且支持中文)
model: Annotation.string({
default: "deepseek/deepseek-chat",
}),
});
// 2. 工具函数:确保配置有默认值,避免报错
export function ensureConfiguration(
config: { configurable?: Record<string, any> } = {}
) {
const configurable = config.configurable ?? {};
return {
systemPromptTemplate: configurable.systemPromptTemplate ?? SYSTEM_PROMPT_TEMPLATE,
model: configurable.model ?? "deepseek/deepseek-chat",
};
}
在prompts.ts
里写系统提示词(核心是 “告诉智能体规则”):
// prompts.ts
// 系统提示词:明确智能体的“角色、规则、思考方式”
export const SYSTEM_PROMPT_TEMPLATE = `
你是一个前端开发者助手,擅长用ReAct模式解决问题。请按以下规则工作:
1. 先思考:用户的问题需要调用工具吗?如果需要,用什么工具?
2. 再行动:如果需要工具,必须调用TOOLS里的工具,不要自己编答案;
3. 后总结:工具返回结果后,整理成自然语言回答,不要遗漏关键信息;
4. 注意:如果问题不需要工具(比如“1+1等于几”),直接回答,不用调用工具。
当前系统时间:{system_time}
`;
前端视角解读:
Annotation
定义,类似前端用TypeScript
做类型校验,避免传错参数。完整运行流程:一步一步看智能体工作
以 “用户问:今天上海天气怎么样?” 为例,整个流程如下:
用户输入问题:调用reactAgent.invoke({ messages: [{ role: "user", content: "今天上海天气怎么样?" }] })
;
第一步:思考(callModel):
tool_calls: [{ name: "tavily_search_results", parameters: { query: "2024年上海今日天气" } }]
;第二步:决策(routeModelOutput):
检测到tool_calls
,决定跳转到 “tools” 节点;
第三步:行动(tools):
调用 Tavily 搜索,获取结果:“上海今日多云转晴,气温 22-28℃,风力 3 级”;
第四步:再思考(callModel):
模型分析搜索结果,判断 “不需要再调用工具,可直接整理答案”;
第五步:结束(end):
模型返回自然语言回答:“今天上海多云转晴,气温 22-28℃,适合外出,不用带伞~”;
输出结果:前端拿到回答,展示给用户。
整个过程不用你手动干预,智能体自己完成 “思考 - 行动 - 总结”,和人解决问题的逻辑完全一致。
如何启动项目?3 步搞定(附命令)
第一步:准备环境
git clone [你的仓库地址]
(如果没有仓库,可直接新建文件夹,复制上面的代码);npm install @langchain/langgraph @langchain/core @langchain/community dotenv
。第二步:配置 API key(可选)
.env
文件,写入:TAVILY_API_KEY=你的API key
;tools.ts
里引入 dotenv:import dotenv from "dotenv"; dotenv.config();
,并给TavilySearchResults
加apiKey: process.env.TAVILY_API_KEY
。第三步:启动项目并调试
index.ts
,写入调用智能体的代码(复制即可用):// index.ts
import { reactAgent } from "./graph";
import readline from "readline";
// 初始化命令行交互,方便输入问题
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: "请输入你的问题(比如“今天上海天气怎么样?”):n"
});
// 启动LangStudio调试(会自动打开浏览器)
async function startAgent() {
rl.prompt();
for await (const line of rl) {
if (line.trim() === "exit") {
console.log("退出智能体~");
rl.close();
break;
}
// 调用智能体,传入用户问题
const result = await reactAgent.invoke(
{
messages: [
{
role: "user",
content: line.trim()
}
]
},
{
// 启用LangStudio调试,会自动打开http://localhost:3000
streamMode: "debug"
}
);
// 输出智能体的回答
console.log("n智能体回答:");
console.log(result.messages[result.messages.length - 1].content + "n");
rl.prompt();
}
}
// 启动项目
startAgent().catch(err => {
console.error("启动失败:", err.message);
});
配置运行脚本:打开package.json
,在scripts
里加启动命令:
"scripts": {
"start": "ts-node index.ts"
}
(如果没装ts-node
,先执行npm install ts-node typescript -D
,并新建tsconfig.json
,用默认配置即可)
启动并调试:
要是遇到报错(比如 “模型连接失败”),先看 LangStudio 的 “Logs” 面板,里面会显示具体错误原因(比如 API key 无效、网络问题),按提示修改即可。
npm start
;callModel
节点,输出 “需要调用搜索工具”;tools
节点,显示搜索过程和结果;callModel
节点,整理结果并输出回答。如何扩展?3 个前端能落地的方向
学会基础 ReAct 智能体后,你可以轻松扩展功能,把它变成 “实用工具”,比如:
在tools.ts
里新增计算器工具,让智能体能算加减乘除:
// tools.ts 新增代码
import { Tool } from "@langchain/core/tools";
// 定义计算器工具
class CalculatorTool extends Tool {
name = "calculator"; // 工具名称,模型会用这个名称调用
description = "用来计算数学问题,比如加减乘除、平方、开方等,输入格式为数学表达式(如“2+3*4”)";
// 工具执行逻辑
async _call(input: string): Promise<string> {
try {
// 用eval计算(实际项目可换更安全的计算库,如math.js)
const result = eval(input);
return `计算结果:${input} = ${result}`;
} catch (err) {
return `计算失败:${(err as Error).message},请输入正确的数学表达式(如“2+3*4”)`;
}
}
}
// 把计算器工具加入工具列表
export const TOOLS = [searchTavily, new CalculatorTool()];
启动后输入 “3.14 乘以 5 的平方是多少”,智能体会自动调用计算器工具,返回正确结果。
把智能体集成到 React/Vue 项目里,做一个可嵌入的 AI 助手组件:
这样你就能拥有一个 “自己开发的 AI 助手”,嵌入到个人项目或作品集里,比单纯写 Demo 更有亮点。
目前的智能体 “聊完就忘”,你可以用 LangGraph 的Memory
模块,让它记住历史对话:
graph.ts
里引入MemorySaver
;import { MemorySaver } from "@langchain/langgraph";
// 编译智能体时加入记忆
export const reactAgent = workflow.compile({
checkpointer: new MemorySaver()
});
调用时传入configurable: { sessionId: "用户唯一ID" }
,智能体就会按用户 ID 保存历史对话。
后续就能实现 “连续对话”,比如先问 “上海天气怎么样”,再问 “那明天适合穿什么衣服”,智能体能结合前一个问题的答案回答。
常见问题:踩过的坑帮你避开
lsof -i:3000
(Mac)或netstat -ano | findstr "3000"
(Windows),找到占用端口的进程并关闭;sessionId
(随便填,比如 “test123”),再点击 “Load” 即可。deepseek/deepseek-chat
,先检查网络(需能访问外网,或用国内模型如 “通义千问”);configuration.ts
里把model
改成 “qwen-max”(通义千问),并安装对应的依赖npm install @langchain/aliyun
;.env
文件里的 key 是否正确,或重新申请一个。routeModelOutput
函数,确保tool_calls
的判断逻辑正确(比如是否漏了as any
类型断言);动手试试,你已经超过 80% 的前端!
很多前端同学对 AI 望而却步,其实不是技术难,而是没找到 “适合前端的入门路径”。
你现在已经掌握了:
这些能力已经能帮你落地很多小项目:比如自动查资料的脚本、个人 AI 助手、嵌入项目的交互组件。
接下来,你可以:
下一篇,我们会深入 “多智能体协作”—— 让多个智能体分工合作(比如一个负责搜索,一个负责写报告,一个负责校对),实现更复杂的任务。关注不迷路,前端学 AI,咱们一步一个脚印来~
互动时间
你已经用 JS 实现了 ReAct 智能体,接下来最想给它加什么功能?是 “计算器”“长期记忆”,还是集成到前端项目里?
评论区聊聊你的想法,抽 1 位同学送【LangGraph 官方中文文档 + 前端 AI 开发手册】(整理了我踩坑的所有笔记)~
“需要完整代码 + 启动视频教程的同学,评论区扣 1,我私发给你~”
如果你想更深入地学习大模型,以下是一些非常有价值的学习资源,这些资源将帮助你从不同角度学习大模型,提升你的实践能力。