《60天AI学习计划启动 | Day 11: LangChain 框架 - 提升 AI 开发效率》

Day 11: LangChain 框架 - 提升 AI 开发效率

学习目标


核心学习内容

1. LangChain 简介

什么是 LangChain?

  • AI 应用开发框架
  • 简化 LLM 应用构建
  • 提供组件和工具链
  • 支持多种 LLM 和工具

核心优势:

  • 模块化设计
  • 丰富的组件库
  • 易于扩展
  • 社区活跃

核心概念:

Components(组件)
  ↓
Chains(链)
  ↓
Agents(代理)
  ↓
Memory(记忆)

2. 核心组件

主要组件:

  1. LLMs:语言模型封装
  2. Prompts:提示词管理
  3. Chains:调用链
  4. Agents:智能代理
  5. Memory:记忆管理
  6. Tools:工具集成

3. Chain 概念

什么是 Chain?

  • 将多个组件串联
  • 顺序执行任务
  • 数据在链中传递

示例:

输入 → LLM → 处理 → 输出

实践作业

作业1:安装和配置 LangChain

安装依赖:

npm install langchain @langchain/openai

基础配置:

// src/config/langchain.js
import { ChatOpenAI } from '@langchain/openai';
import { OpenAIEmbeddings } from '@langchain/openai';

// 配置 LLM
export const llm = new ChatOpenAI({
  modelName: 'gpt-3.5-turbo',
  temperature: 0.7,
  openAIApiKey: process.env.OPENAI_API_KEY
});

// 配置 Embeddings
export const embeddings = new OpenAIEmbeddings({
  openAIApiKey: process.env.OPENAI_API_KEY
});

作业2:实现基础 Chain

src/chains/simple-chain.js:

import { ChatOpenAI } from '@langchain/openai';
import { PromptTemplate } from '@langchain/core/prompts';
import { LLMChain } from 'langchain/chains';

/**
 * 简单 Chain 示例
 */
export async function createSimpleChain() {
  const llm = new ChatOpenAI({
    temperature: 0.7,
    openAIApiKey: process.env.OPENAI_API_KEY
  });

  // 定义提示词模板
  const prompt = PromptTemplate.fromTemplate(
    `你是一个专业的前端开发助手。
回答以下问题:{question}

请提供:
1. 简要回答
2. 代码示例(如适用)
3. 最佳实践建议`
  );

  // 创建 Chain
  const chain = new LLMChain({
    llm: llm,
    prompt: prompt
  });

  return chain;
}

// 使用示例
export async function useSimpleChain() {
  const chain = await createSimpleChain();
  
  const result = await chain.call({
    question: '如何实现防抖函数?'
  });

  console.log(result.text);
}

作业3:实现 Sequential Chain

src/chains/sequential-chain.js:

import { ChatOpenAI } from '@langchain/openai';
import { PromptTemplate } from '@langchain/core/prompts';
import { LLMChain, SimpleSequentialChain } from 'langchain/chains';

/**
 * 顺序 Chain:先总结,再生成代码
 */
export async function createSequentialChain() {
  const llm = new ChatOpenAI({
    temperature: 0.7,
    openAIApiKey: process.env.OPENAI_API_KEY
  });

  // Chain 1: 总结需求
  const summaryPrompt = PromptTemplate.fromTemplate(
    `总结以下开发需求,提取关键信息:
需求:{requirement}

总结:`
  );

  const summaryChain = new LLMChain({
    llm: llm,
    prompt: summaryPrompt
  });

  // Chain 2: 生成代码
  const codePrompt = PromptTemplate.fromTemplate(
    `根据以下需求总结,生成 JavaScript 代码:
总结:{summary}

代码:`
  );

  const codeChain = new LLMChain({
    llm: llm,
    prompt: codePrompt
  });

  // 组合 Chain
  const chain = new SimpleSequentialChain({
    chains: [summaryChain, codeChain],
    verbose: true // 显示执行过程
  });

  return chain;
}

// 使用示例
export async function useSequentialChain() {
  const chain = await createSequentialChain();
  
  const result = await chain.run(
    '实现一个用户登录功能,包含用户名和密码验证'
  );

  console.log(result);
}

作业4:实现 RAG Chain

src/chains/rag-chain.js:

import { ChatOpenAI } from '@langchain/openai';
import { OpenAIEmbeddings } from '@langchain/openai';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';
import { RetrievalQAChain } from 'langchain/chains';
import { PromptTemplate } from '@langchain/core/prompts';

/**
 * RAG Chain:检索增强生成
 */
export class RAGChain {
  constructor() {
    this.vectorStore = null;
    this.chain = null;
  }

  /**
   * 初始化向量存储
   */
  async initializeVectorStore(documents) {
    const embeddings = new OpenAIEmbeddings({
      openAIApiKey: process.env.OPENAI_API_KEY
    });

    // 创建向量存储
    this.vectorStore = await MemoryVectorStore.fromTexts(
      documents.map(doc => doc.text),
      documents.map(doc => doc.metadata),
      embeddings
    );
  }

  /**
   * 创建 RAG Chain
   */
  async createRAGChain() {
    const llm = new ChatOpenAI({
      temperature: 0.7,
      openAIApiKey: process.env.OPENAI_API_KEY
    });

    // 自定义提示词
    const prompt = PromptTemplate.fromTemplate(
      `基于以下文档内容回答问题。如果文档中没有相关信息,请说明。

文档内容:
{context}

问题:{question}

回答:`
    );

    // 创建检索 QA Chain
    this.chain = RetrievalQAChain.fromLLM(llm, this.vectorStore.asRetriever(), {
      prompt: prompt,
      returnSourceDocuments: true
    });

    return this.chain;
  }

  /**
   * 回答问题
   */
  async answer(question) {
    if (!this.chain) {
      throw new Error('Chain 未初始化');
    }

    const result = await this.chain.call({
      query: question
    });

    return {
      answer: result.text,
      sourceDocuments: result.sourceDocuments
    };
  }
}

// 使用示例
export async function useRAGChain() {
  const ragChain = new RAGChain();
  
  // 准备文档
  const documents = [
    {
      text: 'Vue.js 是一个渐进式 JavaScript 框架',
      metadata: { source: 'vue-docs' }
    },
    {
      text: 'React 是 Facebook 开发的 UI 库',
      metadata: { source: 'react-docs' }
    }
  ];

  // 初始化
  await ragChain.initializeVectorStore(documents);
  await ragChain.createRAGChain();

  // 提问
  const result = await ragChain.answer('Vue.js 是什么?');
  console.log('回答:', result.answer);
  console.log('来源:', result.sourceDocuments);
}

作业5:实现 Agent

src/agents/simple-agent.js:

import { ChatOpenAI } from '@langchain/openai';
import { initializeAgentExecutorWithOptions } from 'langchain/agents';
import { DynamicTool } from '@langchain/core/tools';

/**
 * 简单 Agent 示例
 */
export async function createSimpleAgent() {
  const llm = new ChatOpenAI({
    temperature: 0.7,
    openAIApiKey: process.env.OPENAI_API_KEY
  });

  // 定义工具
  const tools = [
    new DynamicTool({
      name: 'get_weather',
      description: '获取指定城市的天气信息。输入:城市名称',
      func: async (input) => {
        // 模拟天气查询
        return `${input}的天气:晴天,22°C`;
      }
    }),
    new DynamicTool({
      name: 'calculate',
      description: '执行数学计算。输入:数学表达式',
      func: async (input) => {
        try {
          const result = Function(`"use strict"; return (${input})`)();
          return `计算结果:${result}`;
        } catch (error) {
          return '计算失败';
        }
      }
    }),
    new DynamicTool({
      name: 'search_web',
      description: '搜索网络信息。输入:搜索关键词',
      func: async (input) => {
        return `关于"${input}"的搜索结果:...`;
      }
    })
  ];

  // 创建 Agent
  const executor = await initializeAgentExecutorWithOptions(tools, llm, {
    agentType: 'zero-shot-react-description',
    verbose: true
  });

  return executor;
}

// 使用示例
export async function useSimpleAgent() {
  const agent = await createSimpleAgent();
  
  const result = await agent.invoke({
    input: '北京今天天气怎么样?然后计算 123 * 456'
  });

  console.log(result.output);
}

作业6:使用 LangChain 重构 RAG 服务

src/services/rag-langchain.js:

import { ChatOpenAI } from '@langchain/openai';
import { OpenAIEmbeddings } from '@langchain/openai';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';
import { RetrievalQAChain } from 'langchain/chains';
import { PromptTemplate } from '@langchain/core/prompts';
import { documentProcessor } from './document-processor.js';
import { logger } from '../utils/logger.js';

/**
 * 使用 LangChain 实现的 RAG 服务
 */
export class RAGServiceLangChain {
  constructor() {
    this.vectorStore = null;
    this.chain = null;
    this.embeddings = null;
    this.llm = null;
  }

  /**
   * 初始化
   */
  async initialize() {
    // 初始化 Embeddings
    this.embeddings = new OpenAIEmbeddings({
      openAIApiKey: process.env.OPENAI_API_KEY
    });

    // 初始化 LLM
    this.llm = new ChatOpenAI({
      modelName: 'gpt-3.5-turbo',
      temperature: 0.7,
      openAIApiKey: process.env.OPENAI_API_KEY
    });

    // 创建空的向量存储
    this.vectorStore = await MemoryVectorStore.fromTexts(
      [],
      [],
      this.embeddings
    );

    // 创建 RAG Chain
    await this.createChain();
  }

  /**
   * 添加文档
   */
  async addDocument(text, metadata = {}) {
    try {
      // 处理文档(分块)
      const chunks = documentProcessor.chunkText(text, 500, 50);
      
      const texts = chunks.map(chunk => chunk.text);
      const metadatas = chunks.map((chunk, index) => ({
        ...metadata,
        chunkIndex: index
      }));

      // 添加到向量存储
      await this.vectorStore.addTexts(texts, metadatas);
      
      logger.info(`添加了 ${texts.length} 个文档块`);
    } catch (error) {
      logger.error('添加文档失败:', error);
      throw error;
    }
  }

  /**
   * 创建 Chain
   */
  async createChain() {
    const prompt = PromptTemplate.fromTemplate(
      `你是一个智能文档助手,基于提供的文档内容回答问题。

文档内容:
{context}

问题:{question}

回答要求:
1. 只基于文档内容回答
2. 如果文档中没有相关信息,明确说明
3. 回答要准确、简洁、有条理
4. 使用 Markdown 格式化

回答:`
    );

    this.chain = RetrievalQAChain.fromLLM(
      this.llm,
      this.vectorStore.asRetriever({
        k: 5 // 返回最相关的5个文档
      }),
      {
        prompt: prompt,
        returnSourceDocuments: true
      }
    );
  }

  /**
   * 回答问题
   */
  async answerQuestion(question) {
    try {
      if (!this.chain) {
        await this.initialize();
      }

      const result = await this.chain.call({
        query: question
      });

      return {
        answer: result.text,
        sources: result.sourceDocuments.map(doc => ({
          text: doc.pageContent.substring(0, 200) + '...',
          metadata: doc.metadata
        }))
      };
    } catch (error) {
      logger.error('RAG 回答失败:', error);
      throw error;
    }
  }

  /**
   * 流式回答
   */
  async streamAnswerQuestion(question, callbacks = {}) {
    const { onChunk, onComplete, onError } = callbacks;

    try {
      if (!this.chain) {
        await this.initialize();
      }

      // 检索相关文档
      const retriever = this.vectorStore.asRetriever({ k: 5 });
      const docs = await retriever.getRelevantDocuments(question);

      // 组装上下文
      const context = docs.map(doc => doc.pageContent).join('\n\n');

      // 流式生成回答
      const stream = await this.llm.stream(
        `基于以下文档内容回答问题:\n\n${context}\n\n问题:${question}`
      );

      let fullContent = '';

      for await (const chunk of stream) {
        const content = chunk.content || '';
        if (content) {
          fullContent += content;
          if (onChunk) {
            onChunk(content);
          }
        }
      }

      if (onComplete) {
        onComplete({
          answer: fullContent,
          sources: docs.map(doc => ({
            text: doc.pageContent.substring(0, 200) + '...',
            metadata: doc.metadata
          }))
        });
      }
    } catch (error) {
      logger.error('流式 RAG 失败:', error);
      if (onError) {
        onError(error);
      }
    }
  }
}

export const ragServiceLangChain = new RAGServiceLangChain();

作业7:创建 LangChain 路由

src/routes/langchain.js:

import express from 'express';
import { ragServiceLangChain } from '../services/rag-langchain.js';
import { createSimpleAgent } from '../agents/simple-agent.js';
import { logger } from '../utils/logger.js';

export const langchainRouter = express.Router();

// 初始化 LangChain 服务
ragServiceLangChain.initialize().catch(err => {
  logger.error('LangChain 初始化失败:', err);
});

// POST /api/langchain/rag/answer
langchainRouter.post('/rag/answer', async (req, res) => {
  try {
    const { question } = req.body;

    if (!question) {
      return res.status(400).json({
        success: false,
        error: '问题不能为空'
      });
    }

    const result = await ragServiceLangChain.answerQuestion(question);

    res.json({
      success: true,
      data: result
    });
  } catch (error) {
    logger.error('LangChain RAG 错误:', error);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

// POST /api/langchain/rag/add-document
langchainRouter.post('/rag/add-document', async (req, res) => {
  try {
    const { text, metadata = {} } = req.body;

    if (!text) {
      return res.status(400).json({
        success: false,
        error: '文本内容不能为空'
      });
    }

    await ragServiceLangChain.addDocument(text, metadata);

    res.json({
      success: true,
      message: '文档添加成功'
    });
  } catch (error) {
    logger.error('添加文档错误:', error);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

// POST /api/langchain/agent
langchainRouter.post('/agent', async (req, res) => {
  try {
    const { question } = req.body;

    if (!question) {
      return res.status(400).json({
        success: false,
        error: '问题不能为空'
      });
    }

    const agent = await createSimpleAgent();
    const result = await agent.invoke({ input: question });

    res.json({
      success: true,
      data: {
        answer: result.output
      }
    });
  } catch (error) {
    logger.error('Agent 错误:', error);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

遇到的问题

问题1:LangChain 版本兼容

解决方案:

# 使用稳定版本
npm install langchain@^0.1.0 @langchain/openai@^0.0.14

问题2:Memory 使用

解决方案:

import { ConversationBufferMemory } from 'langchain/memory';

const memory = new ConversationBufferMemory();
const chain = new ConversationChain({
  llm: llm,
  memory: memory
});

学习总结

今日收获

  1. ✅ 理解 LangChain 核心概念
  2. ✅ 掌握 Chain 和 Agent
  3. ✅ 实现工具链集成
  4. ✅ 使用 LangChain 重构项目
  5. ✅ 学习最佳实践

关键知识点

  • LangChain 简化开发,提供丰富的组件
  • Chain 串联组件,实现复杂流程
  • Agent 智能决策,自动选择工具
  • 模块化设计,易于扩展和维护

LangChain 优势

  • ✅ 代码更简洁
  • ✅ 功能更强大
  • ✅ 易于扩展
  • ✅ 社区支持好

明日计划

明天将学习:

期待明天的学习! 🚀


参考资源


代码仓库

项目已更新:

  • ✅ LangChain 集成
  • ✅ Chain 实现
  • ✅ Agent 实现
  • ✅ RAG 重构

GitHub 提交: Day 11 - LangChain 框架学习


标签: #AI学习 #LangChain #框架学习 #Chain #Agent #学习笔记


写在最后

今天学习了 LangChain 框架,这是一个强大的 AI 应用开发工具。
通过 LangChain,可以更高效地构建 AI 应用,代码更简洁,功能更强大。
明天将学习本地模型部署,实现离线 AI 功能!

继续加油! 💪


快速检查清单

完成这些,第十一天就达标了!

posted @ 2025-12-16 15:54  XiaoZhengTou  阅读(4)  评论(0)    收藏  举报