ai 精选推荐

LangChain.js 入门与实践:构建 LLM 应用的瑞士军刀

HTMLPAGE 团队
20 分钟阅读

系统讲解 LangChain.js 核心概念和使用方法,包括链式调用、Agent、Memory 等关键模块

#LangChain #LLM #AI 应用 #链式调用

LangChain 是什么

LangChain 是构建 LLM 应用的开发框架,它提供了:

  • 统一的模型接口:一套代码适配多个 LLM 提供商
  • 链式组合:像乐高一样组装 AI 能力
  • 内置模块:记忆、检索、工具调用开箱即用

LangChain.js 是 LangChain 的 JavaScript/TypeScript 版本,适合前端和 Node.js 开发者。

安装与配置

# 核心包
npm install langchain @langchain/core

# 模型提供商(按需安装)
npm install @langchain/openai
npm install @langchain/anthropic
npm install @langchain/google-genai

环境配置

// .env
OPENAI_API_KEY=sk-xxx
ANTHROPIC_API_KEY=sk-ant-xxx

核心概念

1. Models(模型)

import { ChatOpenAI } from '@langchain/openai'
import { ChatAnthropic } from '@langchain/anthropic'

// OpenAI
const openai = new ChatOpenAI({
  modelName: 'gpt-4-turbo-preview',
  temperature: 0.7,
  maxTokens: 1000
})

// Anthropic
const claude = new ChatAnthropic({
  modelName: 'claude-3-opus-20240229',
  temperature: 0.7
})

// 使用方式完全相同
const response = await openai.invoke('你好,请介绍一下自己')

2. Prompts(提示模板)

import { ChatPromptTemplate, HumanMessagePromptTemplate } from '@langchain/core/prompts'

// 简单模板
const simplePrompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个{role}专家'],
  ['human', '{question}']
])

const formatted = await simplePrompt.format({
  role: '前端开发',
  question: 'Vue 和 React 有什么区别?'
})

// 带示例的模板
const fewShotPrompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个代码翻译器,将自然语言转换为代码'],
  ['human', '创建一个数组'],
  ['assistant', 'const arr = []'],
  ['human', '给数组添加元素1'],
  ['assistant', 'arr.push(1)'],
  ['human', '{input}']
])

3. Chains(链)

链是 LangChain 的核心抽象——把多个操作组合成一个可复用的流程。

import { RunnableSequence, RunnablePassthrough } from '@langchain/core/runnables'
import { StringOutputParser } from '@langchain/core/output_parsers'

// 构建链
const chain = RunnableSequence.from([
  {
    context: (input) => input.context,
    question: (input) => input.question
  },
  ChatPromptTemplate.fromMessages([
    ['system', '基于以下上下文回答问题:\n{context}'],
    ['human', '{question}']
  ]),
  new ChatOpenAI(),
  new StringOutputParser()
])

// 调用链
const result = await chain.invoke({
  context: 'Vue 是一个渐进式 JavaScript 框架...',
  question: 'Vue 的核心特点是什么?'
})

4. Output Parsers(输出解析)

import { StructuredOutputParser } from 'langchain/output_parsers'
import { z } from 'zod'

// 定义输出结构
const parser = StructuredOutputParser.fromZodSchema(
  z.object({
    name: z.string().describe('产品名称'),
    price: z.number().describe('价格'),
    features: z.array(z.string()).describe('特性列表')
  })
)

// 获取格式化指令
const formatInstructions = parser.getFormatInstructions()

// 在 prompt 中使用
const prompt = ChatPromptTemplate.fromMessages([
  ['system', '分析产品信息并输出 JSON\n{format_instructions}'],
  ['human', '{product_description}']
])

const chain = prompt.pipe(model).pipe(parser)
const result = await chain.invoke({
  format_instructions: formatInstructions,
  product_description: 'iPhone 15 Pro,售价 7999 元,支持灵动岛、USB-C、A17 芯片'
})
// { name: 'iPhone 15 Pro', price: 7999, features: ['灵动岛', 'USB-C', 'A17 芯片'] }

高级功能

Memory(记忆)

让对话具有上下文记忆:

import { BufferMemory, ConversationSummaryMemory } from 'langchain/memory'
import { ConversationChain } from 'langchain/chains'

// 缓冲记忆(保存完整历史)
const bufferMemory = new BufferMemory({
  memoryKey: 'history',
  returnMessages: true
})

// 摘要记忆(大语言模型总结历史)
const summaryMemory = new ConversationSummaryMemory({
  memoryKey: 'history',
  llm: new ChatOpenAI({ modelName: 'gpt-3.5-turbo' })
})

// 在链中使用记忆
const conversation = new ConversationChain({
  llm: new ChatOpenAI(),
  memory: bufferMemory
})

await conversation.call({ input: '我叫张三' })
await conversation.call({ input: '我是一名前端工程师' })
const result = await conversation.call({ input: '你还记得我的信息吗?' })
// AI 会记住之前的对话内容

Vector Stores(向量存储)

存储和检索向量化的文档:

import { OpenAIEmbeddings } from '@langchain/openai'
import { MemoryVectorStore } from 'langchain/vectorstores/memory'
import { Document } from '@langchain/core/documents'

// 创建文档
const docs = [
  new Document({ pageContent: 'Vue 是一个渐进式框架', metadata: { source: 'vue.md' } }),
  new Document({ pageContent: 'React 使用虚拟 DOM', metadata: { source: 'react.md' } }),
  new Document({ pageContent: 'Angular 是一个完整的框架', metadata: { source: 'angular.md' } })
]

// 创建向量存储
const embeddings = new OpenAIEmbeddings()
const vectorStore = await MemoryVectorStore.fromDocuments(docs, embeddings)

// 相似性搜索
const results = await vectorStore.similaritySearch('什么是渐进式?', 2)
// 返回最相关的 2 个文档

Retrievers(检索器)

// 从向量存储创建检索器
const retriever = vectorStore.asRetriever({
  k: 4,                     // 返回数量
  searchType: 'similarity'  // 搜索类型
})

// 检索相关文档
const relevantDocs = await retriever.invoke('Vue 有什么特点?')

Tools(工具)

让 AI 能够调用外部工具:

import { DynamicStructuredTool } from '@langchain/core/tools'
import { z } from 'zod'

// 定义工具
const weatherTool = new DynamicStructuredTool({
  name: 'get_weather',
  description: '获取指定城市的天气信息',
  schema: z.object({
    city: z.string().describe('城市名称')
  }),
  func: async ({ city }) => {
    // 调用真实的天气 API
    const response = await fetch(`https://api.weather.com?city=${city}`)
    const data = await response.json()
    return JSON.stringify(data)
  }
})

const calculatorTool = new DynamicStructuredTool({
  name: 'calculator',
  description: '进行数学计算',
  schema: z.object({
    expression: z.string().describe('数学表达式,如 2+3*4')
  }),
  func: async ({ expression }) => {
    return String(eval(expression)) // 注意:生产环境需要安全的计算方式
  }
})

Agents(智能体)

Agent 能自主决定使用哪些工具:

import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents'
import { ChatOpenAI } from '@langchain/openai'
import { pull } from 'langchain/hub'

// 获取 Agent 提示模板
const prompt = await pull('hwchase17/openai-functions-agent')

// 创建 Agent
const agent = await createOpenAIFunctionsAgent({
  llm: new ChatOpenAI({ modelName: 'gpt-4-turbo-preview' }),
  tools: [weatherTool, calculatorTool],
  prompt
})

// 创建执行器
const executor = new AgentExecutor({
  agent,
  tools: [weatherTool, calculatorTool],
  verbose: true  // 输出推理过程
})

// 执行
const result = await executor.invoke({
  input: '北京今天天气怎么样?另外帮我算一下 15 * 37'
})
// Agent 会自动调用天气工具和计算器工具

实战案例

案例 1:文档问答系统

import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai'
import { MemoryVectorStore } from 'langchain/vectorstores/memory'
import { createStuffDocumentsChain } from 'langchain/chains/combine_documents'
import { createRetrievalChain } from 'langchain/chains/retrieval'

async function createDocQA(documents: Document[]) {
  // 1. 创建向量存储
  const embeddings = new OpenAIEmbeddings()
  const vectorStore = await MemoryVectorStore.fromDocuments(documents, embeddings)
  
  // 2. 创建检索器
  const retriever = vectorStore.asRetriever({ k: 4 })
  
  // 3. 创建问答链
  const llm = new ChatOpenAI({ modelName: 'gpt-4-turbo-preview' })
  
  const prompt = ChatPromptTemplate.fromMessages([
    ['system', `基于以下上下文回答问题。如果上下文中没有相关信息,请说明。

上下文:
{context}`],
    ['human', '{input}']
  ])
  
  const documentChain = await createStuffDocumentsChain({ llm, prompt })
  const retrievalChain = await createRetrievalChain({
    retriever,
    combineDocsChain: documentChain
  })
  
  return retrievalChain
}

// 使用
const chain = await createDocQA(myDocuments)
const result = await chain.invoke({ input: '项目的技术栈是什么?' })

案例 2:代码生成助手

import { ChatOpenAI } from '@langchain/openai'
import { HumanMessage, SystemMessage } from '@langchain/core/messages'

const codeAssistant = new ChatOpenAI({
  modelName: 'gpt-4-turbo-preview',
  temperature: 0.2  // 低温度提高确定性
})

async function generateCode(requirement: string, language: string) {
  const messages = [
    new SystemMessage(`你是一个${language}专家。
根据需求生成高质量的代码,包含:
1. 完整的类型定义(如适用)
2. 详细的注释
3. 错误处理
4. 示例用法`),
    new HumanMessage(requirement)
  ]
  
  const response = await codeAssistant.invoke(messages)
  return response.content
}

// 使用
const code = await generateCode(
  '实现一个防抖函数,支持立即执行选项',
  'TypeScript'
)

案例 3:多轮对话客服

import { ChatOpenAI } from '@langchain/openai'
import { BufferWindowMemory } from 'langchain/memory'
import { ConversationChain } from 'langchain/chains'

const customerService = new ConversationChain({
  llm: new ChatOpenAI({ modelName: 'gpt-4-turbo-preview' }),
  memory: new BufferWindowMemory({ k: 10 }),  // 保留最近 10 轮对话
  prompt: ChatPromptTemplate.fromMessages([
    ['system', `你是一个电商平台的客服助手。
- 态度友好专业
- 回答简洁明了
- 如需要人工服务,引导用户联系人工客服

对话历史:
{history}`],
    ['human', '{input}']
  ])
})

// 多轮对话
await customerService.call({ input: '我想退货' })
await customerService.call({ input: '买了 3 天了' })
await customerService.call({ input: '还没拆封' })
// AI 会根据上下文理解完整的退货需求

流式输出

import { ChatOpenAI } from '@langchain/openai'

const model = new ChatOpenAI({
  modelName: 'gpt-4-turbo-preview',
  streaming: true
})

// 方式 1:回调
await model.call('写一首诗', {
  callbacks: [{
    handleLLMNewToken(token) {
      process.stdout.write(token)
    }
  }]
})

// 方式 2:流迭代器
const stream = await model.stream('写一首诗')
for await (const chunk of stream) {
  process.stdout.write(chunk.content as string)
}

最佳实践

1. 错误处理

import { RunnableRetry } from '@langchain/core/runnables'

// 添加重试逻辑
const chainWithRetry = chain.withRetry({
  stopAfterAttempt: 3,
  onFailedAttempt: (error, attempt) => {
    console.log(`尝试 ${attempt} 失败:`, error.message)
  }
})

2. 成本控制

import { ChatOpenAI } from '@langchain/openai'
import { BaseCallbackHandler } from '@langchain/core/callbacks/base'

class TokenCounter extends BaseCallbackHandler {
  totalTokens = 0

  handleLLMEnd(output) {
    const usage = output.llmOutput?.tokenUsage
    if (usage) {
      this.totalTokens += usage.totalTokens
      console.log(`本次消耗: ${usage.totalTokens}, 累计: ${this.totalTokens}`)
    }
  }
}

const counter = new TokenCounter()
const model = new ChatOpenAI({
  callbacks: [counter]
})

3. 缓存

import { InMemoryCache } from '@langchain/core/caches'

const cache = new InMemoryCache()
const model = new ChatOpenAI({ cache })

// 相同输入会命中缓存
await model.invoke('你好')
await model.invoke('你好')  // 从缓存返回

总结

LangChain.js 核心模块:

模块用途
Models统一的模型接口
Prompts提示模板管理
Chains链式组合逻辑
Memory对话记忆
Retrievers文档检索
Tools工具调用
Agents自主决策

记住:LangChain 是脚手架,不是银弹。理解底层原理,按需使用。


相关文章推荐: