一、先搞清楚一个核心问题
你真的需要这些库吗?
答案:80%的情况下,你不需要
// 很多时候,你只需要这样:
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ message: userInput }),
})
// 就够了!
什么时候需要这些库?
- 你要做复杂的多步骤工作流(不是简单问答)
- 你需要整合多个数据源和工具
- 你在做RAG(检索增强生成)
- 你要实现Agent(让AI自己决定调用什么工具)
二、LangChain.js - 最流行但也最复杂
它到底是干什么的?
官方说法: "用于开发由语言模型驱动的应用程序的框架"
- 用统一的接口调用不同的大模型(OpenAI、Claude、本地模型等)
- 把复杂任务拆成多个步骤(Chain)
- 管理Prompt模板
- 连接各种数据源(数据库、API、文档等)
- 实现RAG(检索增强生成)
核心概念详解
1. LLM(大语言模型)- 最基础的封装
import { ChatOpenAI } from '@langchain/openai'
// 不用LangChain的写法
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }],
}),
})
// 用LangChain的写法
const llm = new ChatOpenAI({
modelName: 'gpt-4',
temperature: 0.7,
})
const response = await llm.invoke('Hello')
好处: 切换模型只需要改一行代码
// 换成Claude
const llm = new ChatAnthropic({ model: 'claude-3-opus' })
// 换成本地模型
const llm = new ChatOllama({ model: 'llama2' })
// 其他代码不用改!
2. Prompt Templates - 模板管理
import { ChatPromptTemplate } from '@langchain/core/prompts'
// 不用LangChain:手动拼接字符串
const prompt = `你是一个${role}。
用户背景:${userContext}
请回答:${question}`
// 用LangChain:模板化管理
const promptTemplate = ChatPromptTemplate.fromMessages([
['system', '你是一个{role}。'],
['human', '用户背景:{userContext}'],
['human', '请回答:{question}'],
])
const prompt = await promptTemplate.format({
role: '专业的代码审查专家',
userContext: '3年前端经验',
question: '这段代码有什么问题?',
})
好处
- Prompt可以复用
- 变量清晰,不容易拼错
- 方便测试和迭代
3. Chains - 多步骤流程
这是LangChain的核心价值
import { RunnableSequence } from '@langchain/core/runnables'
// 场景:用户上传简历,要做3件事:
// 1. 提取关键信息
// 2. 生成职位匹配度分析
// 3. 给出改进建议
// 不用LangChain:手动串联
async function analyzeResume(resume: string) {
// 第1步
const extracted = await openai.chat.completions.create({
messages: [
{
role: 'user',
content: `提取简历关键信息:${resume}`,
},
],
})
// 第2步
const analysis = await openai.chat.completions.create({
messages: [
{
role: 'user',
content: `分析匹配度:${extracted.choices[0].message.content}`,
},
],
})
// 第3步
const suggestions = await openai.chat.completions.create({
messages: [
{
role: 'user',
content: `给出建议:${analysis.choices[0].message.content}`,
},
],
})
return suggestions
}
// 用LangChain:声明式定义流程
const extractChain = promptTemplate1.pipe(llm)
const analysisChain = promptTemplate2.pipe(llm)
const suggestionChain = promptTemplate3.pipe(llm)
const fullChain = RunnableSequence.from([
extractChain,
analysisChain,
suggestionChain,
])
// 一行调用
const result = await fullChain.invoke({ resume })
好处
- 代码更清晰,流程一目了然
- 容易修改某一步
- 可以并行执行某些步骤
- 内置错误处理和重试
4. Document Loaders - 文档加载
import { PDFLoader } from 'langchain/document_loaders/fs/pdf'
import { CSVLoader } from 'langchain/document_loaders/fs/csv'
import { WebBaseLoader } from 'langchain/document_loaders/web/cheerio'
// 加载PDF
const loader = new PDFLoader('resume.pdf')
const docs = await loader.load()
// 加载网页
const webLoader = new WebBaseLoader('https://example.com')
const webDocs = await webLoader.load()
// docs是统一的格式,都有pageContent和metadata
docs.forEach((doc) => {
console.log(doc.pageContent) // 文本内容
console.log(doc.metadata) // 元数据(来源、页码等)
})
好处: 不用自己写各种文件解析代码
5. Vector Stores - 向量数据库集成
import { OpenAIEmbeddings } from '@langchain/openai'
import { MemoryVectorStore } from 'langchain/vectorstores/memory'
// 1. 把文档切片
const docs = await loader.load()
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 1000,
chunkOverlap: 200,
})
const splits = await splitter.splitDocuments(docs)
// 2. 向量化并存储
const embeddings = new OpenAIEmbeddings()
const vectorStore = await MemoryVectorStore.fromDocuments(splits, embeddings)
// 3. 搜索相关文档
const results = await vectorStore.similaritySearch(
'用户的问题',
3 // 返回最相关的3个片段
)
// 4. 把结果塞进Prompt
const context = results.map((r) => r.pageContent).join('\n\n')
const answer = await llm.invoke(`
参考以下内容回答问题:
${context}
问题:${question}
`)
这就是RAG(检索增强生成)的完整流程
6. Agents - 让AI自己决定做什么
这是最高级的功能
import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents'
import { Calculator } from 'langchain/tools/calculator'
import { WebBrowser } from 'langchain/tools/webbrowser'
// 定义AI可以使用的工具
const tools = [
new Calculator(),
new WebBrowser(),
// 自定义工具
{
name: 'get_weather',
description: '获取指定城市的天气',
func: async (city: string) => {
const weather = await fetch(`https://api.weather.com/${city}`)
return weather.json()
},
},
]
// 创建Agent
const agent = await createOpenAIFunctionsAgent({
llm,
tools,
prompt: '你是一个助手,可以使用工具帮助用户。',
})
const executor = new AgentExecutor({
agent,
tools,
})
// 用户问:"北京明天天气怎么样,如果下雨的概率超过50%,帮我计算一下打车费用(15公里)"
const result = await executor.invoke({
input: '北京明天天气怎么样,如果下雨的概率超过50%,帮我计算一下打车费用(15公里)',
})
// Agent会自动:
// 1. 先调用get_weather工具获取天气
// 2. 判断降雨概率
// 3. 如果>50%,调用Calculator计算15*单价
// 4. 返回完整答案
好处: 你不需要写if-else判断逻辑,AI自己决定调用什么工具
三、LangGraph - 更复杂的工作流
为什么有了LangChain还要LangGraph?
LangChain的Chain是线性的
步骤1 → 步骤2 → 步骤3 → 结束
但实际业务可能是这样的
开始 → 判断 → 如果A → 步骤1 → 步骤2
↓
如果B → 步骤3 → 返回判断 → 继续
LangGraph用图的方式定义工作流
import { StateGraph } from '@langchain/langgraph'
// 定义状态
interface State {
userInput: string
category?: string
needMoreInfo?: boolean
response?: string
}
// 定义节点(每个节点是一个处理函数)
const graph = new StateGraph<State>({
channels: {
userInput: null,
category: null,
needMoreInfo: null,
response: null,
},
})
// 节点1:分类用户意图
graph.addNode('categorize', async (state) => {
const category = await llm.invoke(`分类用户意图:${state.userInput}`)
return { category }
})
// 节点2:检查是否需要更多信息
graph.addNode('check', async (state) => {
const needMore = state.category === '复杂问题'
return { needMoreInfo: needMore }
})
// 节点3:简单回答
graph.addNode('simple_answer', async (state) => {
const response = await llm.invoke(`回答:${state.userInput}`)
return { response }
})
// 节点4:复杂处理
graph.addNode('complex_process', async (state) => {
// 多步处理...
return { response: '复杂答案' }
})
// 定义边(节点之间的连接)
graph.addEdge('categorize', 'check')
graph.addConditionalEdges(
'check',
(state) => (state.needMoreInfo ? 'complex' : 'simple'),
{
simple: 'simple_answer',
complex: 'complex_process',
}
)
// 设置入口和出口
graph.setEntryPoint('categorize')
graph.addEdge('simple_answer', '__end__')
graph.addEdge('complex_process', '__end__')
// 编译并运行
const app = graph.compile()
const result = await app.invoke({ userInput: '用户问题' })
实际业务场景
// 场景:智能客服
// 流程:
// 1. 理解用户问题
// 2. 查询知识库
// 3. 如果找到答案 → 直接回复
// 如果没找到 → 转人工
// 如果答案不确定 → 追问用户
const customerServiceGraph = new StateGraph({...});
// 节点:理解问题
graph.addNode("understand", async (state) => {
const intent = await llm.invoke(`理解意图:${state.message}`);
return { intent };
});
// 节点:搜索知识库
graph.addNode("search_kb", async (state) => {
const results = await vectorStore.search(state.intent);
return {
kbResults: results,
confidence: results[0]?.score || 0,
};
});
// 节点:直接回答
graph.addNode("direct_answer", async (state) => {
const answer = await llm.invoke(`基于${state.kbResults}回答`);
return { response: answer };
});
// 节点:追问用户
graph.addNode("ask_more", async (state) => {
return { response: "您能详细说明一下吗?" };
});
// 节点:转人工
graph.addNode("to_human", async (state) => {
await notifyHumanAgent(state);
return { response: "正在为您转接人工客服..." };
});
// 条件分支
graph.addConditionalEdges(
"search_kb",
(state) => {
if (state.confidence > 0.8) return "direct";
if (state.confidence > 0.5) return "ask";
return "human";
},
{
direct: "direct_answer",
ask: "ask_more",
human: "to_human",
}
);
好处
- 可以处理复杂的分支逻辑
- 可以循环(比如多轮对话)
- 可以并行执行某些节点
- 状态管理清晰
四、其他前端AI库对比
1. Vercel AI SDK - 最推荐给前端的
import { useChat } from 'ai/react';
function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div>
{messages.map(m => <div key={m.id}>{m.content}</div>)}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
</form>
</div>
);
}
对比LangChain
- ✅ 专为前端设计,React Hooks超好用
- ✅ 自动处理流式响应
- ✅ 内置状态管理
- ✅ 代码量少,学习曲线平缓
- ❌ 功能相对简单,不支持复杂工作流
适合场景: 80%的前端AI应用(聊天、文本生成、简单的RAG)
2. LlamaIndex.js - 专注RAG
import { VectorStoreIndex, SimpleDirectoryReader } from 'llamaindex'
// 加载文档并建立索引
const documents = await new SimpleDirectoryReader().loadData('./docs')
const index = await VectorStoreIndex.fromDocuments(documents)
// 查询
const queryEngine = index.asQueryEngine()
const response = await queryEngine.query('用户问题')
对比LangChain
- ✅ RAG功能更强大
- ✅ 性能优化更好
- ✅ 文档质量高
- ❌ 只能做RAG,不像LangChain那么全能
适合场景: 专门做知识库问答、文档搜索的项目
3. ai.js (AI.JSX) - 用JSX写AI应用
import { ChatCompletion, UserMessage } from 'ai-jsx/core/completion';
function MyAI() {
return (
<ChatCompletion>
<UserMessage>写一首诗</UserMessage>
</ChatCompletion>
);
}
特点
- 用JSX语法写AI逻辑
- 概念很新颖,但社区较小
4. LangChain.js vs Python版本
| 特性 | Python版 | JS版 |
|---|---|---|
| 功能完整度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 文档质量 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 社区规模 | 大 | 中等 |
| 更新速度 | 快 | 稍慢 |
| 前端集成 | ❌ | ✅ |
结论: 如果你是纯前端项目,用JS版;如果需要复杂功能,考虑用Python做后端
五、前端大模型应用的技术选择建议
场景1:简单的聊天应用
推荐:Vercel AI SDK
// 前端
import { useChat } from 'ai/react'
// 后端API (Next.js)
import { OpenAIStream, StreamingTextResponse } from 'ai'
export async function POST(req: Request) {
const { messages } = await req.json()
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages,
stream: true,
})
const stream = OpenAIStream(response)
return new StreamingTextResponse(stream)
}
不需要: LangChain、LangGraph
场景2:文档问答(RAG)
推荐:LangChain.js 或 LlamaIndex.js
// 用LangChain实现RAG
import { RetrievalQAChain } from 'langchain/chains'
import { OpenAIEmbeddings } from '@langchain/openai'
import { MemoryVectorStore } from 'langchain/vectorstores/memory'
// 1. 加载并向量化文档
const docs = await loader.load()
const vectorStore = await MemoryVectorStore.fromDocuments(
docs,
new OpenAIEmbeddings()
)
// 2. 创建QA链
const chain = RetrievalQAChain.fromLLM(llm, vectorStore.asRetriever())
// 3. 查询
const answer = await chain.call({ query: '用户问题' })
为什么需要
- 文档加载器省事
- 向量存储封装好
- RAG流程标准化
场景3:多步骤工作流(比如:简历分析)
推荐:LangChain Chains
import { RunnableSequence } from '@langchain/core/runnables'
const chain = RunnableSequence.from([
extractionChain, // 提取信息
analysisChain, // 分析匹配度
suggestionChain, // 生成建议
])
const result = await chain.invoke({ resume })
为什么需要
- 多步骤逻辑清晰
- 错误处理方便
- 容易测试和调试
场景4:复杂的决策流程(比如:智能客服)
推荐:LangGraph
// 需要条件分支、循环、状态管理
const graph = new StateGraph({...});
graph.addNode("understand", ...);
graph.addNode("search", ...);
graph.addConditionalEdges(...);
为什么需要
- 有复杂的if-else逻辑
- 需要多轮对话
- 要根据AI的回答决定下一步
场景5:Agent(让AI使用工具)
推荐:LangChain Agents
const agent = await createOpenAIFunctionsAgent({
llm,
tools: [weatherTool, calculatorTool, databaseTool],
})
// AI会自己决定调用哪个工具
const result = await executor.invoke({ input: userMessage })
为什么需要
- 需要AI自主决策
- 工具调用逻辑复杂
- 不确定用户会问什么
六、实战建议
1. 什么时候不需要这些库?
大多数情况下,你只需要
// 前端
async function chat(message: string) {
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ message }),
})
const reader = response.body.getReader()
// 处理流式响应...
}
// 后端 (Next.js API)
export async function POST(req: Request) {
const { message } = await req.json()
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: message }],
stream: true,
})
return new Response(stream)
}
这样写的好处
- 代码简单,容易理解
- 依赖少,打包体积小
- 灵活,想怎么改就怎么改
2. 什么时候考虑用LangChain?
出现这些需求时
- ✅ 需要同时支持多个大模型(OpenAI、Claude、本地模型)
- ✅ 要做RAG,需要管理向量数据库
- ✅ 有多步骤的复杂流程
- ✅ 需要让AI使用工具(Agent)
- ✅ 团队其他人用Python版LangChain,前端要对齐
3. 学习顺序建议
第1周:不用任何库
直接调API → 理解基本原理 → 自己实现流式响应
第2周:用Vercel AI SDK
体验框架的便利性 → 对比手写代码 → 理解抽象层
第3周:用LangChain做简单RAG
加载文档 → 向量化 → 检索 → 回答
第4周:用LangChain做复杂流程
多步Chain → 条件分支 → Agent
不推荐: 一上来就学LangChain,容易被复杂的概念搞晕
4. 避坑指南
坑1:过度工程化
// ❌ 不要为了用库而用库
import { LLMChain } from 'langchain/chains'
const chain = new LLMChain({ llm, prompt })
const result = await chain.call({ input: message })
// ✅ 这种简单场景直接调用就行
const result = await llm.invoke(message)
坑2:不了解原理就用库
// 你至少要知道这个Chain内部做了什么
const chain = RetrievalQAChain.fromLLM(llm, retriever)
// 实际上是:
// 1. 用retriever搜索相关文档
// 2. 把文档塞进Prompt
// 3. 调用LLM生成答案
// 如果不知道这个流程,出bug很难调试
坑3:版本不兼容
# LangChain更新很快,文档和实际版本可能不一致
# 固定版本号,不要用^或~
npm install langchain@0.1.30 --save-exact
坑4:打包体积大
// ❌ 导入整个库
import { OpenAI } from 'langchain'
// ✅ 按需导入
import { ChatOpenAI } from '@langchain/openai'
七、完整实战案例对比
案例:企业知识库问答系统
方案A:不用任何库(纯手写)
// 优点:完全可控,轻量
// 缺点:要自己实现所有功能
// 1. 文档处理
async function processDocument(file: File) {
const text = await extractText(file) // 自己写PDF解析
const chunks = splitText(text, 1000) // 自己写分块逻辑
// 2. 向量化
const embeddings = await Promise.all(
chunks.map((chunk) => openai.embeddings.create({ input: chunk }))
)
// 3. 存储(自己管理数组)
documents.push(
...chunks.map((chunk, i) => ({
text: chunk,
embedding: embeddings[i].data[0].embedding,
}))
)
}
// 4. 查询
async function query(question: string) {
// 向量化问题
const qEmbed = await openai.embeddings.create({ input: question })
// 计算相似度(自己写余弦相似度)
const scores = documents.map((doc) =>
cosineSimilarity(qEmbed.data[0].embedding, doc.embedding)
)
// 取top-k
const topDocs = documents
.map((doc, i) => ({ doc, score: scores[i] }))
.sort((a, b) => b.score - a.score)
.slice(0, 3)
// 生成答案
const context = topDocs.map((d) => d.doc.text).join('\n')
const answer = await openai.chat.completions.create({
messages: [
{
role: 'user',
content: `参考:${context}\n\n问题:${question}`,
},
],
})
return answer
}
方案B:用Vercel AI SDK(前端)+ LangChain(后端)
// 后端 (Next.js API)
import { RetrievalQAChain } from "langchain/chains";
import { OpenAIEmbeddings } from "@langchain/openai";
import { PDFLoader } from "langchain/document_loaders/fs/pdf";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
// 初始化(启动时运行一次)
const loader = new PDFLoader("docs/company-handbook.pdf");
const docs = await loader.load();
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 1000,
chunkOverlap: 200,
});
const splits = await splitter.splitDocuments(docs);
const vectorStore = await MemoryVectorStore.fromDocuments(
splits,
new OpenAIEmbeddings()
);
const chain = RetrievalQAChain.fromLLM(
new ChatOpenAI({ modelName: "gpt-4" }),
vectorStore.asRetriever(3), // top-3
{ returnSourceDocuments: true } // 返回来源
);
// API路由
export async function POST(req: Request) {
const { question } = await req.json();
const result = await chain.call({ query: question });
return Response.json({
answer: result.text,
sources: result.sourceDocuments.map(doc => ({
content: doc.pageContent,
metadata: doc.metadata,
})),
});
}
// 前端
import { useState } from 'react';
function KnowledgeBase() {
const [question, setQuestion] = useState('');
const [answer, setAnswer] = useState('');
const [sources, setSources] = useState([]);
async function ask() {
const response = await fetch('/api/knowledge-base', {
method: 'POST',
body: JSON.stringify({ question }),
});
const data = await response.json();
setAnswer(data.answer);
setSources(data.sources);
}
return (
<div>
<input value={question} onChange={e => setQuestion(e.target.value)} />
<button onClick={ask}>提问</button>
<div>{answer}</div>
<div>
<h4>参考来源:</h4>
{sources.map((src, i) => (
<div key={i}>
<p>{src.content}</p>
<small>来源:{src.metadata.source}</small>
</div>
))}
</div>
</div>
);
}
代码量
八、总结:选择建议
如果你是前端新手做AI应用
推荐路线
- 第1个项目: 不用任何库,直接调OpenAI API
- 目的:理解流式响应、Prompt工程
- 第2个项目: 用Vercel AI SDK
- 目的:体验框架的便利性
- 第3个项目: 简单的RAG需求,试试LangChain
- 目的:理解RAG工作流
- 之后: 根据需求选择
快速决策表
| 你的需求 | 推荐方案 | 理由 |
|---|---|---|
| 简单聊天 | Vercel AI SDK | 最简单,开箱即用 |
| 多模型切换 | LangChain | 统一接口 |
| 文档问答 | LangChain/LlamaIndex | 省去RAG实现 |
| 复杂工作流 | LangChain Chains | 多步骤管理 |
| 条件分支 | LangGraph | 图状态机 |
| Agent | LangChain Agents | 工具调用封装好 |
| 只做前端 | 手写 + Vercel SDK | 不依赖Python生态 |
| 全栈项目 | LangChain (后端) + Vercel SDK (前端) | 最佳组合 |
最后建议
不要追求"完美的技术选型"
- 先快速做出来一个能用的
- 遇到问题再重构
- 技术服务业务,不要为了用新库而用新库
记住:80%的AI应用不需要LangChain
用最简单的方式,解决你的实际问题,就是最好的选择。