《60天AI学习计划启动 | Day 16: LangChain 深入学习 - 高级 Chain 与 Memory》

Day 16: LangChain 深入学习 - 高级 Chain 与 Memory

学习目标


核心学习内容

1. LangChain 高级 Chain

Chain 类型:

  • Sequential Chain:顺序执行
  • Parallel Chain:并行执行
  • Router Chain:路由选择
  • Transform Chain:数据转换

2. Memory 管理

Memory 类型:

  • Buffer Memory:简单记忆
  • Summary Memory:摘要记忆
  • Conversation Buffer Window:窗口记忆
  • Entity Memory:实体记忆

3. 自定义 Chain

实现方式:

  • 继承 Chain
  • 实现 _call 方法
  • 定义输入输出

实践作业

作业1:实现自定义 Chain

src/chains/custom-chain.js:

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

/**
 * 自定义 Chain:代码审查链
 */
export class CodeReviewChain extends BaseChain {
  constructor(llm) {
    super();
    this.llm = llm;
    this.chainName = 'code_review';
  }

  _chainType() {
    return 'code_review';
  }

  get inputKeys() {
    return ['code', 'language'];
  }

  get outputKeys() {
    return ['review', 'suggestions', 'score'];
  }

  async _call(inputs) {
    const { code, language } = inputs;

    // 步骤1:代码分析
    const analysisPrompt = PromptTemplate.fromTemplate(
      `分析以下{language}代码,识别潜在问题:

代码:
\`\`\`{language}
{code}
\`\`\`

请分析:
1. 代码质量问题
2. 性能问题
3. 安全问题
4. 最佳实践

分析:`
    );

    const analysisChain = new LLMChain({
      llm: this.llm,
      prompt: analysisPrompt
    });

    const analysis = await analysisChain.call({ code, language });

    // 步骤2:生成建议
    const suggestionPrompt = PromptTemplate.fromTemplate(
      `基于以下分析,生成具体的改进建议:

分析:
{analysis}

请提供:
1. 具体改进建议
2. 优化后的代码示例
3. 评分(1-10)

建议:`
    );

    const suggestionChain = new LLMChain({
      llm: this.llm,
      prompt: suggestionPrompt
    });

    const suggestions = await suggestionChain.call({
      analysis: analysis.text
    });

    // 步骤3:评分
    const scorePrompt = PromptTemplate.fromTemplate(
      `为以下代码评分(1-10分):

代码:
{code}

分析:
{analysis}

建议:
{suggestions}

请返回 JSON:
{
  "score": 分数,
  "reason": "评分理由"
}

评分:`
    );

    const scoreChain = new LLMChain({
      llm: this.llm,
      prompt: scorePrompt
    });

    const scoreResult = await scoreChain.call({
      code,
      analysis: analysis.text,
      suggestions: suggestions.text
    });

    // 解析评分
    let score = 5;
    try {
      const scoreData = JSON.parse(scoreResult.text);
      score = scoreData.score || 5;
    } catch (e) {
      // 默认分数
    }

    return {
      review: analysis.text,
      suggestions: suggestions.text,
      score: score
    };
  }

  serialize() {
    return {
      _type: this._chainType(),
      llm: this.llm.serialize()
    };
  }
}

作业2:实现 Memory 管理

src/services/memory-manager.js:

import { 
  ConversationBufferMemory,
  ConversationSummaryMemory,
  ConversationBufferWindowMemory,
  ConversationSummaryBufferMemory
} from 'langchain/memory';
import { ChatOpenAI } from '@langchain/openai';

/**
 * Memory 管理器
 */
export class MemoryManager {
  constructor() {
    this.memories = new Map();
    this.llm = new ChatOpenAI({
      temperature: 0.7,
      openAIApiKey: process.env.OPENAI_API_KEY
    });
  }

  /**
   * 获取或创建 Memory
   */
  getMemory(sessionId, type = 'buffer') {
    const key = `${sessionId}_${type}`;
    
    if (this.memories.has(key)) {
      return this.memories.get(key);
    }

    let memory;

    switch (type) {
      case 'buffer':
        // 简单记忆:保存所有对话
        memory = new ConversationBufferMemory({
          returnMessages: true,
          memoryKey: 'history'
        });
        break;

      case 'summary':
        // 摘要记忆:总结历史对话
        memory = new ConversationSummaryMemory({
          llm: this.llm,
          returnMessages: true,
          memoryKey: 'history'
        });
        break;

      case 'window':
        // 窗口记忆:只保留最近N轮对话
        memory = new ConversationBufferWindowMemory({
          k: 5, // 保留最近5轮
          returnMessages: true,
          memoryKey: 'history'
        });
        break;

      case 'summary_buffer':
        // 摘要+缓冲:结合摘要和窗口
        memory = new ConversationSummaryBufferMemory({
          llm: this.llm,
          maxTokenLimit: 2000,
          returnMessages: true,
          memoryKey: 'history'
        });
        break;

      default:
        memory = new ConversationBufferMemory({
          returnMessages: true,
          memoryKey: 'history'
        });
    }

    this.memories.set(key, memory);
    return memory;
  }

  /**
   * 保存对话
   */
  async saveMessage(sessionId, role, content, type = 'buffer') {
    const memory = this.getMemory(sessionId, type);
    
    if (role === 'user') {
      await memory.saveContext(
        { input: content },
        { output: '' }
      );
    } else {
      // 更新最后一条消息的输出
      const messages = await memory.chatHistory.getMessages();
      if (messages.length > 0) {
        const lastMessage = messages[messages.length - 1];
        if (lastMessage._getType() === 'human') {
          await memory.saveContext(
            { input: lastMessage.content },
            { output: content }
          );
        }
      }
    }
  }

  /**
   * 获取对话历史
   */
  async getHistory(sessionId, type = 'buffer') {
    const memory = this.getMemory(sessionId, type);
    const messages = await memory.chatHistory.getMessages();
    return messages;
  }

  /**
   * 清空记忆
   */
  clearMemory(sessionId, type = 'buffer') {
    const key = `${sessionId}_${type}`;
    this.memories.delete(key);
  }

  /**
   * 获取记忆摘要
   */
  async getSummary(sessionId) {
    const memory = this.getMemory(sessionId, 'summary');
    const summary = await memory.loadMemoryVariables({});
    return summary;
  }
}

export const memoryManager = new MemoryManager();

作业3:实现并行 Chain

src/chains/parallel-chain.js:

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

/**
 * 并行 Chain:同时执行多个任务
 */
export class ParallelChain {
  constructor() {
    this.llm = new ChatOpenAI({
      temperature: 0.7,
      openAIApiKey: process.env.OPENAI_API_KEY
    });
  }

  /**
   * 并行执行多个分析
   */
  async parallelAnalysis(code, language) {
    // 创建多个 Chain
    const chains = {
      // Chain 1: 代码质量分析
      quality: new LLMChain({
        llm: this.llm,
        prompt: PromptTemplate.fromTemplate(
          `分析以下{language}代码的质量:

代码:
\`\`\`{language}
{code}
\`\`\`

从代码规范、可读性、可维护性角度分析。`
        )
      }),

      // Chain 2: 性能分析
      performance: new LLMChain({
        llm: this.llm,
        prompt: PromptTemplate.fromTemplate(
          `分析以下{language}代码的性能:

代码:
\`\`\`{language}
{code}
\`\`\`

从时间复杂度、空间复杂度、优化建议角度分析。`
        )
      }),

      // Chain 3: 安全分析
      security: new LLMChain({
        llm: this.llm,
        prompt: PromptTemplate.fromTemplate(
          `分析以下{language}代码的安全性:

代码:
\`\`\`{language}
{code}
\`\`\`

从安全漏洞、数据保护、输入验证角度分析。`
        )
      })
    };

    // 并行执行
    const [quality, performance, security] = await Promise.all([
      chains.quality.call({ code, language }),
      chains.performance.call({ code, language }),
      chains.security.call({ code, language })
    ]);

    return {
      quality: quality.text,
      performance: performance.text,
      security: security.text
    };
  }

  /**
   * 综合报告
   */
  async generateReport(analyses) {
    const reportPrompt = PromptTemplate.fromTemplate(
      `基于以下分析,生成综合报告:

质量分析:
{quality}

性能分析:
{performance}

安全分析:
{security}

请生成:
1. 总体评价
2. 关键问题
3. 改进建议
4. 优先级排序

报告:`
    );

    const reportChain = new LLMChain({
      llm: this.llm,
      prompt: reportPrompt
    });

    const report = await reportChain.call(analyses);
    return report.text;
  }
}

作业4:实现 Router Chain

src/chains/router-chain.js:

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

/**
 * 路由 Chain:根据输入选择不同的处理链
 */
export class RouterChain {
  constructor() {
    this.llm = new ChatOpenAI({
      temperature: 0.7,
      openAIApiKey: process.env.OPENAI_API_KEY
    });

    this.destinationChains = new Map();
    this.initializeChains();
  }

  /**
   * 初始化目标链
   */
  initializeChains() {
    // 代码相关链
    this.destinationChains.set('code', new LLMChain({
      llm: this.llm,
      prompt: PromptTemplate.fromTemplate(
        `你是代码专家,回答代码相关问题。
问题:{input}
回答:`
      )
    }));

    // 文档相关链
    this.destinationChains.set('document', new LLMChain({
      llm: this.llm,
      prompt: PromptTemplate.fromTemplate(
        `你是文档专家,回答文档相关问题。
问题:{input}
回答:`
      )
    }));

    // 通用链
    this.destinationChains.set('general', new LLMChain({
      llm: this.llm,
      prompt: PromptTemplate.fromTemplate(
        `你是通用助手,回答各种问题。
问题:{input}
回答:`
      )
    }));
  }

  /**
   * 路由决策
   */
  async route(input) {
    const routingPrompt = PromptTemplate.fromTemplate(
      `根据用户问题,选择最合适的处理链。

可用链:
- code: 代码相关问题
- document: 文档相关问题
- general: 通用问题

问题:{input}

请返回 JSON:
{
  "destination": "链名称",
  "reason": "选择理由"
}

路由:`
    );

    const routingChain = new LLMChain({
      llm: this.llm,
      prompt: routingPrompt,
      outputParser: new RouterOutputParser()
    });

    const result = await routingChain.call({ input });
    
    try {
      const route = JSON.parse(result.text);
      return route.destination || 'general';
    } catch (e) {
      return 'general';
    }
  }

  /**
   * 执行路由
   */
  async execute(input) {
    // 1. 路由决策
    const destination = await this.route(input);
    
    // 2. 执行对应的链
    const chain = this.destinationChains.get(destination) || 
                  this.destinationChains.get('general');
    
    const result = await chain.call({ input });
    
    return {
      answer: result.text,
      destination: destination
    };
  }
}

作业5:实现 Transform Chain

src/chains/transform-chain.js:

import { BaseChain } from 'langchain/chains';

/**
 * 转换 Chain:数据预处理和后处理
 */
export class TransformChain extends BaseChain {
  constructor(transformFn) {
    super();
    this.transformFn = transformFn;
  }

  _chainType() {
    return 'transform';
  }

  get inputKeys() {
    return ['input'];
  }

  get outputKeys() {
    return ['output'];
  }

  async _call(inputs) {
    const transformed = await this.transformFn(inputs.input);
    return {
      output: transformed
    };
  }

  serialize() {
    return {
      _type: this._chainType()
    };
  }
}

/**
 * 数据清理 Chain
 */
export class DataCleaningChain extends TransformChain {
  constructor() {
    super(async (input) => {
      // 清理数据
      let cleaned = input.trim();
      
      // 移除多余空格
      cleaned = cleaned.replace(/\s+/g, ' ');
      
      // 移除特殊字符(保留基本标点)
      cleaned = cleaned.replace(/[^\w\s.,!?;:()\-]/g, '');
      
      return cleaned;
    });
  }
}

/**
 * 数据格式化 Chain
 */
export class DataFormattingChain extends TransformChain {
  constructor() {
    super(async (input) => {
      // 格式化数据
      const lines = input.split('\n');
      const formatted = lines
        .map(line => line.trim())
        .filter(line => line.length > 0)
        .join('\n');
      
      return formatted;
    });
  }
}

作业6:创建高级 Chain API

src/routes/advanced-chains.js:

import express from 'express';
import { CodeReviewChain } from '../chains/custom-chain.js';
import { ParallelChain } from '../chains/parallel-chain.js';
import { RouterChain } from '../chains/router-chain.js';
import { ChatOpenAI } from '@langchain/openai';
import { memoryManager } from '../services/memory-manager.js';
import { logger } from '../utils/logger.js';

export const advancedChainsRouter = express.Router();

// 初始化 LLM
const llm = new ChatOpenAI({
  temperature: 0.7,
  openAIApiKey: process.env.OPENAI_API_KEY
});

// POST /api/chains/code-review - 代码审查
advancedChainsRouter.post('/code-review', async (req, res) => {
  try {
    const { code, language = 'javascript' } = req.body;

    if (!code) {
      return res.status(400).json({
        success: false,
        error: '代码不能为空'
      });
    }

    const chain = new CodeReviewChain(llm);
    const result = await chain.call({ code, language });

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

// POST /api/chains/parallel-analysis - 并行分析
advancedChainsRouter.post('/parallel-analysis', async (req, res) => {
  try {
    const { code, language = 'javascript' } = req.body;

    if (!code) {
      return res.status(400).json({
        success: false,
        error: '代码不能为空'
      });
    }

    const chain = new ParallelChain();
    const analyses = await chain.parallelAnalysis(code, language);
    const report = await chain.generateReport(analyses);

    res.json({
      success: true,
      data: {
        analyses,
        report
      }
    });
  } catch (error) {
    logger.error('并行分析错误:', error);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

// POST /api/chains/route - 路由 Chain
advancedChainsRouter.post('/route', async (req, res) => {
  try {
    const { question } = req.body;

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

    const chain = new RouterChain();
    const result = await chain.execute(question);

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

// POST /api/chains/chat-with-memory - 带记忆的聊天
advancedChainsRouter.post('/chat-with-memory', async (req, res) => {
  try {
    const { message, sessionId, memoryType = 'buffer' } = req.body;

    if (!message || !sessionId) {
      return res.status(400).json({
        success: false,
        error: '消息和会话ID不能为空'
      });
    }

    // 获取记忆
    const memory = memoryManager.getMemory(sessionId, memoryType);
    const history = await memory.loadMemoryVariables({});

    // 构建消息
    const messages = [
      ...(history.history || []),
      { role: 'user', content: message }
    ];

    // 调用 LLM
    const response = await llm.invoke(messages);

    // 保存记忆
    await memoryManager.saveMessage(sessionId, 'user', message, memoryType);
    await memoryManager.saveMessage(sessionId, 'assistant', response.content, memoryType);

    res.json({
      success: true,
      data: {
        message: response.content,
        sessionId: sessionId
      }
    });
  } catch (error) {
    logger.error('带记忆聊天错误:', error);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

遇到的问题

问题1:Memory 序列化

解决方案:

// 保存 Memory 状态
const memoryState = await memory.saveContext(
  { input: 'user message' },
  { output: 'ai response' }
);

// 加载 Memory 状态
await memory.loadMemoryVariables({});

问题2:Chain 错误处理

解决方案:

try {
  const result = await chain.call(inputs);
  return result;
} catch (error) {
  logger.error('Chain 执行错误:', error);
  // 降级处理
  return { error: error.message };
}

学习总结

今日收获

  1. ✅ 掌握高级 Chain 类型
  2. ✅ 实现自定义 Chain
  3. ✅ 理解 Memory 机制
  4. ✅ 实现并行和路由 Chain
  5. ✅ 优化工具链

关键知识点

  • 自定义 Chain,扩展功能
  • Memory 管理,保持上下文
  • 并行执行,提高效率
  • 路由选择,智能分发

Chain 类型对比

Sequential: 顺序执行,适合步骤化任务
Parallel: 并行执行,适合独立分析
Router: 路由选择,适合多场景
Transform: 数据转换,适合预处理

明日计划

明天将学习:

期待明天的学习! 🚀


参考资源


代码仓库

项目已更新:

  • ✅ 自定义 Chain
  • ✅ Memory 管理
  • ✅ 并行 Chain
  • ✅ 路由 Chain
  • ✅ 高级 API

GitHub 提交: Day 16 - LangChain 深入学习


标签: #AI学习 #LangChain #高级Chain #Memory #学习笔记


写在最后

今天深入学习了 LangChain 的高级功能,包括自定义 Chain 和 Memory 管理。
这些功能让 AI 应用更加强大和灵活。明天将继续学习 Agents 的深入应用!

继续加油! 💪


快速检查清单

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

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