LangChain 核心:Chain 链式调用实现复杂 AI 任务

像搭积木一样串联 AI 能力,构建智能化工作流!

为什么需要 Chain 链式调用?

在实际 AI 应用开发中,单个模型调用往往无法完成复杂任务。比如,要实现一个"代码审查助手",可能需要:

  1. 分析代码质量
  2. 识别潜在 Bug
  3. 给出优化建议
  4. 生成修复代码

如果每次都要手动处理中间结果并调用多次 API,代码会变得臃肿且难以维护。**Chain(链)**正是为了解决这个问题而生的。

Chain 的核心价值

价值点 说明
任务解耦 将复杂任务拆分为多个独立步骤,各司其职
代码复用 一个 Chain 可以在不同场景重复使用
流程可视化 调用逻辑清晰,易于理解和调试
错误隔离 单步失败不影响其他步骤(可配置)

Chain 核心原理

什么是 Chain?

Chain 是 LangChain 中最核心的抽象概念之一。简单来说,Chain 将一个或多个组件(模型、提示词模板、其他 Chain 等)串联起来,形成端到端的处理流程

text 复制代码
输入 → [组件A] → 中间结果 → [组件B] → 中间结果 → [组件C] → 输出

Chain 的工作原理

  1. 输入接收:Chain 接收一个对象(包含所有需要的参数)
  2. 组件执行:按顺序调用内部组件(模型、提示词模板等)
  3. 结果传递:上一步的输出作为下一步的输入(通过变量名匹配)
  4. 最终输出:返回处理完成的结果

变量传递机制

这是 Chain 最容易踩坑的地方:Chain 中的变量传递是通过变量名自动匹配的

typescript 复制代码
// Chain A 输出:{ output: "hello" }
// Chain B 需要:{ text: "hello" }
// ❌ 变量名不匹配,传递失败

// 解决方案:使用变量映射或统一命名

常用基础 Chain 类型详解

1. LLMChain - 最基础的链

LLMChain 是最简单的 Chain,将一个 PromptTemplate 和一个 ChatModel 组合在一起。

typescript 复制代码
import { LLMChain } from "langchain/chains";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";

const prompt = ChatPromptTemplate.fromMessages([
  ["system", "你是一个{role},回答要{style}"],
  ["human", "{question}"]
]);

const model = new ChatOpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY,
    configuration: {
      baseURL: process.env.DASHSCOPE_API_URL,
    },
    model: "qwen-plus",
    temperature: 0.7,
});

const chain = new LLMChain({
  llm: model,
  prompt: prompt,
  outputKey: "answer"  // 输出结果的 key
});

// 调用
const result = await chain.call({
  role: "前端技术专家",
  style: "通俗易懂",
  question: "什么是闭包?"
});

console.log(result.answer);

2. RunnableSequence - 替代 LLMChain

使用 RunnableSequence 配合 pipe 方法,代码更简洁、更灵活。

typescript 复制代码
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { RunnableSequence } from "@langchain/core/runnables";
import { StringOutputParser } from "@langchain/core/output_parsers";
import dotenv from "dotenv";

dotenv.config();

const prompt = ChatPromptTemplate.fromMessages([
  ["system", "你是一个{role},回答要{style}"],
  ["human", "{question}"]
]);

const model = new ChatOpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY,
    configuration: {
      baseURL: process.env.DASHSCOPE_API_URL,
    },
    model: "qwen-plus",
    temperature: 0.7,
 });

// 使用 pipe 方法构建链
const chain = RunnableSequence.from([
  prompt,
  model,
  new StringOutputParser()  // 将 AIMessage 转换为字符串
]);

// 调用
const result = await chain.invoke({
  role: "前端技术专家",
  style: "通俗易懂",
  question: "什么是闭包?"
});

console.log(result);
// 输出:闭包(Closure)是 JavaScript 中一个非常经典又容易让人困惑的概念...

更简洁的写法(使用 .pipe())

typescript 复制代码
// .pipe() 方法更加直观
const chain = prompt
  .pipe(model)
  .pipe(new StringOutputParser());

const result = await chain.invoke({
  role: "前端技术专家",
  style: "通俗易懂",
  question: "什么是闭包?"
});

3. 简单顺序链

当多个链首尾相连,前一个的输出直接作为后一个的输入时,使用 RunnableSequence 连接多个 Runnable。

typescript 复制代码
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { RunnableSequence } from "@langchain/core/runnables";
import { StringOutputParser } from "@langchain/core/output_parsers";
import dotenv from "dotenv";

dotenv.config();

const prompt = ChatPromptTemplate.fromMessages([
  ["system", "你是一个{role},回答要{style}"],
  ["human", "{question}"]
]);

const model = new ChatOpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY,
    configuration: {
      baseURL: process.env.DASHSCOPE_API_URL,
    },
    model: "qwen-plus",
    temperature: 0.7,
  });

// Chain 1:生成问题
const prompt1 = ChatPromptTemplate.fromTemplate(
  "请为'{topic}'生成一个面试题,难度{level}"
);
const chain1 = prompt1
  .pipe(model)
  .pipe(new StringOutputParser());

// Chain 2:回答问题
const prompt2 = ChatPromptTemplate.fromTemplate(
  "请回答以下面试题,并提供参考答案:\n{text}"
);
const chain2 = prompt2
  .pipe(model)
  .pipe(new StringOutputParser());

// 组合成顺序链
const overallChain = RunnableSequence.from([
  {
    topic: (input: { topic: string; level: string }) => input.topic,
    level: (input: { topic: string; level: string }) => input.level
  },
  chain1,
  (generatedQuestion) => ({ text: generatedQuestion }),
  chain2
]);

// 或者更清晰的写法
const overallChain2 = RunnableSequence.from([
  (input: { topic: string; level: string }) => 
    chain1.invoke(input),  // 第一步:生成问题
  (question) => chain2.invoke({ text: question })  // 第二步:回答问题
]);

const result = await overallChain2.invoke({
  topic: "JavaScript 闭包",
  level: "中等"
});

console.log(result);

简化版:使用 .pipe() 连接

typescript 复制代码
// 如果需要中间处理,可以自定义转换函数
const pipeline = chain1.pipe(async (question) => {
  console.log(`生成的问题:${question}`);
  return { text: question };
}).pipe(chain2);

const result = await pipeline.invoke({
  topic: "JavaScript 闭包",
  level: "中等"
});

4. 复杂顺序链

当需要更复杂的变量传递(多个输入、多个输出)时,使用 RunnableLambda 或自定义函数来处理数据流。

typescript 复制代码
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { RunnableSequence } from "@langchain/core/runnables";
import { StringOutputParser } from "@langchain/core/output_parsers";
import dotenv from "dotenv";

dotenv.config();

const prompt = ChatPromptTemplate.fromMessages([
  ["system", "你是一个{role},回答要{style}"],
  ["human", "{question}"]
]);

const model = new ChatOpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY,
    configuration: {
      baseURL: process.env.DASHSCOPE_API_URL,
    },
    model: "qwen-plus",
    temperature: 0.7,
  });

// Chain 1:分析代码复杂度
const complexityPrompt = ChatPromptTemplate.fromTemplate(`
分析以下代码的复杂度:
\`\`\`
{code}
\`\`\`
输出格式:【复杂度评级:简单/中等/复杂】【建议:xxx】
`);

const complexityChain = complexityPrompt
  .pipe(model)
  .pipe(new StringOutputParser());

// Chain 2:生成优化建议
const optimizePrompt = ChatPromptTemplate.fromTemplate(`
根据以下代码和复杂度分析,给出具体的优化建议:
【代码】
{code}
【复杂度分析】
{complexityAnalysis}

输出格式:【优化方向】【具体方案】【预期效果】
`);

const optimizeChain = optimizePrompt
  .pipe(model)
  .pipe(new StringOutputParser());

// 组合成复杂顺序链(支持多变量传递)
const codeReviewChain = RunnableSequence.from([
  // 第一步:并行处理?或者顺序处理
  async (input: { code: string }) => {
    const complexityAnalysis = await complexityChain.invoke({
      code: input.code
    });
    return {
      code: input.code,
      complexityAnalysis
    };
  },
  // 第二步:生成优化建议
  async (state) => {
    const suggestions = await optimizeChain.invoke({
      code: state.code,
      complexityAnalysis: state.complexityAnalysis
    });
    return {
      complexityAnalysis: state.complexityAnalysis,
      optimizationSuggestions: suggestions
    };
  }
]);

// 使用
const result = await codeReviewChain.invoke({
  code: `function add(a, b) { return a + b; }`
});

console.log(result.complexityAnalysis);
console.log(result.optimizationSuggestions);

更优雅的实现:使用 RunnablePassthrough 保持状态

typescript 复制代码
import { RunnablePassthrough, RunnableSequence } from "@langchain/core/runnables";

const codeReviewChain2 = RunnableSequence.from([
  // 第一步:分析复杂度,同时保留原始代码
  {
    code: new RunnablePassthrough(),  // 传递原始输入
    complexityAnalysis: complexityChain
  },
  // 第二步:使用上一步的结果生成优化建议
  {
    complexityAnalysis: ({ complexityAnalysis }) => complexityAnalysis,
    code: ({ code }) => code,
    optimizationSuggestions: optimizeChain
  }
]);

const result2 = await codeReviewChain2.invoke({
  code: `function add(a, b) { return a + b; }`
});

5. 高级用法:条件分支和并行执行

并行执行多个任务

typescript 复制代码
// 同时分析代码的多个维度
const analyzeCode = RunnableSequence.from([
  {
    code: new RunnablePassthrough(),
    quality: qualityChain,      // 质量分析
    performance: performanceChain, // 性能分析
    security: securityChain     // 安全分析
  },
  async (results) => {
    // 汇总所有分析结果
    return {
      summary: `质量:${results.quality}\n性能:${results.performance}\n安全:${results.security}`,
      details: results
    };
  }
]);

条件分支执行

typescript 复制代码
import { RunnableBranch } from "@langchain/core/runnables";

// 根据代码复杂度决定执行不同的优化策略
const conditionalChain = new RunnableBranch([
  // 条件1:如果代码复杂,使用深度优化
  (input) => input.complexity === "复杂",
  deepOptimizationChain,
  // 条件2:如果代码中等,使用标准优化
  (input) => input.complexity === "中等",
  standardOptimizationChain,
  // 默认:简单优化
  simpleOptimizationChain
]);

前端业务场景 Chain 应用案例

场景:智能表单处理助手

实现功能:用户输入自然语言描述 → 解析需求 → 生成验证规则 → 输出前端代码

创建 src/form-assistant.ts

typescript 复制代码
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { RunnableSequence } from "@langchain/core/runnables";
import { StringOutputParser } from "@langchain/core/output_parsers";
import dotenv from "dotenv";

dotenv.config();

async function formAssistant() {
  
  const model = new ChatOpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY,
    configuration: { 
      baseURL: process.env.DASHSCOPE_API_URL 
    },
    model: "qwen-turbo",
    temperature: 0.3,
  });

  // ========== Chain 1:解析需求,提取字段信息 ==========
  const parsePrompt = ChatPromptTemplate.fromMessages([
    ["system", `你是一个表单需求分析专家。从用户的自然语言描述中,提取需要收集的字段信息。
输出格式必须为 JSON 数组,每个字段包含:
- name: 字段名(英文)
- label: 显示标签(中文)
- type: 类型(text/email/tel/number/select/checkbox/radio)
- required: 是否必填(true/false)
- options: 如果是 select,给出选项数组
- placeholder: 提示文本(可选)

只输出 JSON 数组,不要其他解释。`],
    ["human", "{requirement}"]
  ]);

  const parseChain = parsePrompt
    .pipe(model)
    .pipe(new StringOutputParser());

  // ========== Chain 2:生成校验规则 ==========
  const validatePrompt = ChatPromptTemplate.fromMessages([
    ["system", `你是表单校验规则生成专家。根据字段定义,为每个字段生成前端校验规则。
输出格式为 JSON 对象,字段名作为 key,规则数组作为 value。

示例:{{"email": [{"type": "email", "message": "请输入正确的邮箱"}, {"required": true, "message": "邮箱不能为空"}]}}

只输出 JSON 对象,不要其他解释。`],
    ["human", "字段定义:{fieldsJson}"]
  ]);

  const validateChain = validatePrompt
    .pipe(model)
    .pipe(new StringOutputParser());

  // ========== Chain 3:生成前端代码 ==========
  const codePrompt = ChatPromptTemplate.fromMessages([
    ["system", `你是前端代码生成专家。根据字段定义和校验规则,生成 Vue3 + Element Plus 的表单代码。
要求:
- 使用 reactive 管理表单数据
- 完整的校验逻辑
- 提交时的数据格式
- 代码要有注释
- 使用 TypeScript

只输出完整的 Vue 组件代码。`],
    ["human", `字段定义:{fieldsJson}
校验规则:{validationRules}
用户需求:{requirement}`]
  ]);

  const codeChain = codePrompt
    .pipe(model)
    .pipe(new StringOutputParser());

  // ========== 组合成完整 Chain(使用 RunnableSequence) ==========
  const formBuilderChain = RunnableSequence.from([
    // 第一步:解析需求,提取字段
    async (input) => {
      const fieldsJson = await parseChain.invoke({ requirement: input.requirement });
      return {
        requirement: input.requirement,
        fieldsJson
      };
    },
    // 第二步:生成校验规则
    async (state) => {
      const validationRules = await validateChain.invoke({ fieldsJson: state.fieldsJson });
      return {
        requirement: state.requirement,
        fieldsJson: state.fieldsJson,
        validationRules
      };
    },
    // 第三步:生成代码
    async (state) => {
      const generatedCode = await codeChain.invoke({
        fieldsJson: state.fieldsJson,
        validationRules: state.validationRules,
        requirement: state.requirement
      });
      return {
        fieldsJson: state.fieldsJson,
        validationRules: state.validationRules,
        generatedCode
      };
    }
  ]);

  // ========== 执行测试 ==========
  const requirement = `
我需要一个用户注册表单,包含以下字段:
- 用户名:必填,3-20个字符
- 邮箱:必填,需要是有效的邮箱格式
- 手机号:选填,11位数字
- 性别:下拉选择(男/女/保密)
- 年龄:数字,18-60岁
`;

  console.log("📝 用户需求:\n", requirement);
  console.log("\n🔄 开始链式处理...\n");

  try {
    const result = await formBuilderChain.invoke({ requirement });

    console.log("\n📋 提取的字段定义:\n", result.fieldsJson);
    console.log("\n🔒 生成的校验规则:\n", result.validationRules);
    console.log("\n💻 生成的代码:\n", result.generatedCode);
  } catch (error) {
    console.error("处理出错:", error);
  }
}

formAssistant();

完整 TS 代码实现 - 代码审查流水线

创建 src/code-review-pipeline.ts

typescript 复制代码
import { PromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import dotenv from "dotenv";

dotenv.config();

class CodeReviewPipeline {
  private model: ChatOpenAI;
  
  constructor() {
    this.model = new ChatOpenAI({
      apiKey: process.env.DASHSCOPE_API_KEY,
      configuration: {
        baseURL: process.env.DASHSCOPE_API_URL,
      },
      model: "qwen-turbo",
      temperature: 0.2,
    });
  }
  
  async review(code: string) {
    // 并行执行前三个分析
    const [qualityAnalysis, performanceIssues, securityIssues] = await Promise.all([
      this.analyzeQuality(code),
      this.analyzePerformance(code),
      this.analyzeSecurity(code)
    ]);
    
    // 最后生成优化代码
    const optimizedCode = await this.generateOptimizedCode(
      code,
      qualityAnalysis,
      performanceIssues,
      securityIssues
    );
    
    return {
      qualityAnalysis,
      performanceIssues,
      securityIssues,
      optimizedCode
    };
  }
  
  private async analyzeQuality(code: string): Promise<string> {
    const prompt = PromptTemplate.fromTemplate(`
请分析以下 TypeScript 代码的质量问题:

\`\`\`typescript
{code}
\`\`\`

分析维度:
1. 命名规范(变量/函数/类名是否清晰)
2. 代码复杂度(是否过于复杂)
3. 类型安全(是否正确使用 TypeScript)
4. 错误处理(是否有遗漏的异常处理)

输出格式:【维度】【问题】【建议】
`);
    
    const chain = prompt.pipe(this.model);
    const response = await chain.invoke({ code });
    return response.content as string;
  }
  
  private async analyzePerformance(code: string): Promise<string> {
    const prompt = PromptTemplate.fromTemplate(`
分析以下代码的性能问题:

\`\`\`typescript
{code}
\`\`\`

重点关注:
- 循环嵌套
- 不必要的重渲染
- 内存泄漏风险
- 异步操作

如果无性能问题,输出"无性能问题"。
`);
    
    const chain = prompt.pipe(this.model);
    const response = await chain.invoke({ code });
    return response.content as string;
  }
  
  private async analyzeSecurity(code: string): Promise<string> {
    const prompt = PromptTemplate.fromTemplate(`
检查以下代码是否存在安全风险:

\`\`\`typescript
{code}
\`\`\`

检查项:
- XSS 风险
- SQL 注入(如涉及数据库)
- 敏感信息泄露
- 输入验证

输出格式:【风险等级:高/中/低/无】【具体说明】
`);
    
    const chain = prompt.pipe(this.model);
    const response = await chain.invoke({ code });
    return response.content as string;
  }
  
  private async generateOptimizedCode(
    code: string,
    qualityAnalysis: string,
    performanceIssues: string,
    securityIssues: string
  ): Promise<string> {
    const prompt = PromptTemplate.fromTemplate(`
基于以下分析,请对代码进行优化:

【原始代码】
{code}

【质量分析】
{qualityAnalysis}

【性能问题】
{performanceIssues}

【安全问题】
{securityIssues}

请输出优化后的完整代码,并标注主要修改点。
`);
    
    const chain = prompt.pipe(this.model);
    const response = await chain.invoke({
      code,
      qualityAnalysis,
      performanceIssues,
      securityIssues
    });
    return response.content as string;
  }
}

async function codeReviewPipeline() {
  const pipeline = new CodeReviewPipeline();
  
  const testCode = `
function getUserData(id) {
  const data = fetch('/api/user/' + id);
  return data;
}

// 组件代码
function UserList({ users }) {
  const [list, setList] = useState([]);
  
  useEffect(() => {
    setList(users);
  }, []);
  
  return (
    <div>
      {list.map(user => (
        <div>{user.name}</div>
      ))}
    </div>
  );
}
`;

  console.log("🔍 开始代码审查...\n");
  console.log("📄 原始代码:\n", testCode);
  console.log("\n" + "=".repeat(60) + "\n");

  const result = await pipeline.review(testCode);

  console.log("📊 代码质量分析:\n", result.qualityAnalysis);
  console.log("\n⚡ 性能问题:\n", result.performanceIssues);
  console.log("\n🔒 安全问题:\n", result.securityIssues);
  console.log("\n✨ 优化后的代码:\n", result.optimizedCode);
}

codeReviewPipeline();

链式调用常见问题排查

问题 1:变量名不匹配导致数据传递失败

现象:Chain 执行成功,但后续步骤收不到预期数据

解决:检查数据流中的字段名是否一致

typescript 复制代码
// ❌ 错误示例:字段名不匹配
const step1 = RunnableSequence.from([
  (input) => {
    const result = { data: "分析结果" };
    return { analysis: result };  // 返回 { analysis: ... }
  },
  (state) => {
    // 但这里期望接收 { result: ... }
    console.log(state.result);  // undefined
    return state;
  }
]);

// ✅ 正确示例:保持字段名一致
const step1 = RunnableSequence.from([
  (input) => {
    const analysis = "分析结果";
    return { analysis };  // 返回 { analysis }
  },
  (state) => {
    console.log(state.analysis);  // ✅ 正确获取
    return { suggestion: `基于${state.analysis}的建议` };
  }
]);

// 更好的方式:使用 RunnablePassthrough 保持状态
import { RunnablePassthrough } from "@langchain/core/runnables";

const pipeline = RunnableSequence.from([
  {
    analysis: analysisChain,  // 分析结果
    original: new RunnablePassthrough()  // 保留原始输入
  },
  {
    suggestion: suggestionChain,  // 生成建议
    analysis: ({ analysis }) => analysis  // 传递分析结果
  }
]);

问题 2:数据流中的参数传递错误

现象:需要传递多个参数,但链式调用中数据丢失

解决 :使用 RunnablePassthrough 或自定义转换函数

typescript 复制代码
// ❌ 错误:参数会被覆盖
const wrongChain = RunnableSequence.from([
  step1,  // 返回 { result1 }
  step2,  // 返回 { result2 },丢失了 result1
]);

// ✅ 正确:逐步累积数据
const correctChain = RunnableSequence.from([
  async (input) => {
    const result1 = await step1.invoke(input);
    return { ...input, ...result1 };  // 合并结果
  },
  async (state) => {
    const result2 = await step2.invoke(state);
    return { ...state, ...result2 };  // 继续累积
  }
]);

// ✅ 更好:使用 RunnablePassthrough
const betterChain = RunnableSequence.from([
  {
    original: new RunnablePassthrough(),
    result1: step1
  },
  {
    original: ({ original }) => original,
    result1: ({ result1 }) => result1,
    result2: step2
  }
]);

问题 3:链式调用超时或卡顿

现象:多个步骤串行执行,总耗时过长

解决

  • 添加日志监控定位耗时步骤
  • 将独立步骤并行化
  • 选择更快的模型
typescript 复制代码
import { RunnableSequence } from "@langchain/core/runnables";

// 添加性能监控的包装器
function withTiming<T extends RunnableSequence>(chain: T, name: string) {
  return RunnableSequence.from([
    async (input) => {
      console.log(`⏱️ [${name}] 开始执行...`);
      const start = Date.now();
      const result = await chain.invoke(input);
      const duration = Date.now() - start;
      console.log(`✅ [${name}] 完成,耗时 ${duration}ms`);
      return result;
    }
  ]);
}

// 使用监控
const monitoredChain = withTiming(analysisChain, "代码分析");

// 独立步骤并行执行
const parallelChain = RunnableSequence.from([
  async (input) => {
    // 并行执行独立的分析任务
    const [analysis1, analysis2, analysis3] = await Promise.all([
      qualityChain.invoke(input),
      performanceChain.invoke(input),
      securityChain.invoke(input)
    ]);
    
    return {
      ...input,
      quality: analysis1,
      performance: analysis2,
      security: analysis3
    };
  },
  // 汇总结果
  async (state) => {
    const summary = await summaryChain.invoke({
      quality: state.quality,
      performance: state.performance,
      security: state.security
    });
    return { ...state, summary };
  }
]);

问题 4:中间步骤输出格式问题

现象:后续 Chain 解析前一步输出时失败

解决:强制规定输出格式,添加格式校验和解析器

typescript 复制代码
import { StringOutputParser } from "@langchain/core/output_parsers";
import { StructuredOutputParser } from "@langchain/core/output_parsers";

// 方式1:使用结构化输出解析器
const outputParser = StructuredOutputParser.fromZodSchema(
  z.object({
    status: z.enum(["success", "error"]),
    data: z.string(),
    error: z.string().nullable()
  })
);

const chain = prompt
  .pipe(model)
  .pipe(outputParser);  // 自动解析为 JSON 对象

// 方式2:手动添加格式校验
const chainWithValidation = RunnableSequence.from([
  prompt,
  model,
  new StringOutputParser(),
  async (output) => {
    // 验证输出格式
    try {
      const parsed = JSON.parse(output);
      if (!parsed.status || !parsed.data) {
        throw new Error("缺少必要字段");
      }
      return parsed;
    } catch (error) {
      console.error("格式解析失败:", output);
      // 返回默认格式或重试
      return {
        status: "error",
        data: output,
        error: "格式不正确"
      };
    }
  }
]);

// 方式3:在 Prompt 中强制格式要求
const promptWithFormat = ChatPromptTemplate.fromMessages([
  ["system", `你是一个数据分析专家。

任务:{task}

重要:请严格按照以下 JSON 格式输出,不要添加任何其他内容:
{
  "status": "success/error",
  "data": "...",
  "error": null
}

如果处理失败,status 设为 "error" 并填写 error 字段。`],
  ["human", "内容:{content}"]
]);

Chain 复用技巧(RunnableSequence 版本)

1. 封装可复用的 Chain 工厂

typescript 复制代码
import { RunnableSequence } from "@langchain/core/runnables";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";

// 创建可复用的分析 Chain
function createAnalysisChain(analysisType: string, model: ChatOpenAI) {
  const prompt = ChatPromptTemplate.fromTemplate(`
你是一个{analysisType}分析专家。
请分析以下内容:{content}

输出格式:【分析结果】【关键发现】【建议】
`);

  return prompt
    .pipe(model)
    .pipe(new StringOutputParser());
}

// 使用
const codeAnalysis = createAnalysisChain("代码", model);
const textAnalysis = createAnalysisChain("文本", model);

const codeResult = await codeAnalysis.invoke({
  analysisType: "代码",
  content: "function add(a,b){return a+b}"
});

2. 创建可配置的 Chain 工厂

typescript 复制代码
interface ChainConfig {
  temperature: number;
  maxTokens?: number;
  modelName?: string;
}

function createCustomChain(
  template: string,
  config: ChainConfig
) {
  const prompt = ChatPromptTemplate.fromTemplate(template);
  
  const model = new ChatOpenAI({
    apiKey: process.env.BAILIAN_API_KEY,
    configuration: { 
      baseURL: process.env.BAILIAN_BASE_URL 
    },
    model: config.modelName || "qwen-turbo",
    temperature: config.temperature,
    maxTokens: config.maxTokens,
  });

  return prompt
    .pipe(model)
    .pipe(new StringOutputParser());
}

// 使用
const strictChain = createCustomChain(
  "分析:{input}",
  { temperature: 0.1, maxTokens: 500 }
);

const creativeChain = createCustomChain(
  "创作:{input}",
  { temperature: 0.9, modelName: "qwen-plus" }
);

3. 封装带缓存的 Chain

typescript 复制代码
interface CacheEntry {
  output: string;
  timestamp: number;
}

class CachedChain {
  private cache = new Map<string, CacheEntry>();
  private ttl: number;

  constructor(
    private chain: RunnableSequence,
    ttlSeconds: number = 300
  ) {
    this.ttl = ttlSeconds * 1000;
  }

  async invoke(input: any) {
    const key = JSON.stringify(input);
    const cached = this.cache.get(key);
    
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      console.log("✅ 命中缓存");
      return cached.output;
    }
    
    console.log("🔄 执行 Chain...");
    const result = await this.chain.invoke(input);
    
    this.cache.set(key, {
      output: result,
      timestamp: Date.now()
    });
    
    return result;
  }

  // 清空缓存
  clearCache() {
    this.cache.clear();
  }

  // 获取缓存统计
  getCacheStats() {
    return {
      size: this.cache.size,
      keys: Array.from(this.cache.keys())
    };
  }
}

// 使用示例
const analysisChain = createAnalysisChain("代码", model);
const cachedChain = new CachedChain(analysisChain, 600); // 缓存10分钟

// 第一次调用 - 执行 Chain
const result1 = await cachedChain.invoke({ content: "代码内容" });

// 第二次调用相同输入 - 命中缓存
const result2 = await cachedChain.invoke({ content: "代码内容" });

4. 创建可组合的 Chain 构建器

typescript 复制代码
class ChainBuilder {
  private steps: Array<(input: any) => Promise<any>> = [];
  private model: ChatOpenAI;

  constructor(model: ChatOpenAI) {
    this.model = model;
  }

  // 添加 LLM 步骤
  addLLMStep(promptTemplate: string, outputKey: string) {
    const prompt = ChatPromptTemplate.fromTemplate(promptTemplate);
    const chain = prompt
      .pipe(this.model)
      .pipe(new StringOutputParser());
    
    this.steps.push(async (input) => {
      const result = await chain.invoke(input);
      return { ...input, [outputKey]: result };
    });
    
    return this;
  }

  // 添加自定义处理步骤
  addTransformStep(transform: (input: any) => any) {
    this.steps.push(async (input) => {
      const result = await transform(input);
      return { ...input, ...result };
    });
    return this;
  }

  // 添加并行步骤
  addParallelStep(steps: Record<string, RunnableSequence>) {
    this.steps.push(async (input) => {
      const results = await Promise.all(
        Object.entries(steps).map(async ([key, chain]) => {
          const result = await chain.invoke(input);
          return [key, result];
        })
      );
      
      return {
        ...input,
        ...Object.fromEntries(results)
      };
    });
    
    return this;
  }

  // 构建最终的 Chain
  build() {
    return RunnableSequence.from(this.steps);
  }
}

// 使用示例
const builder = new ChainBuilder(model);

const pipeline = builder
  .addLLMStep("分析代码:{code}", "analysis")
  .addParallelStep({
    quality: qualityChain,
    performance: performanceChain
  })
  .addTransformStep((state) => ({
    ...state,
    summary: `${state.analysis}\n质量:${state.quality}`
  }))
  .build();

const result = await pipeline.invoke({ code: "function test() {}" });

5. 创建可重用的 Chain 模板

typescript 复制代码
// 定义通用的 Chain 类型
type ChainInput = Record<string, any>;
type ChainOutput = Record<string, any>;

class ReusableChain {
  private chain: RunnableSequence;
  
  constructor(
    name: string,
    buildChain: () => RunnableSequence
  ) {
    console.log(`🔧 构建 Chain: ${name}`);
    this.chain = buildChain();
  }
  
  async execute(input: ChainInput): Promise<ChainOutput> {
    try {
      console.log(`🚀 执行 Chain...`);
      const result = await this.chain.invoke(input);
      return { success: true, data: result };
    } catch (error) {
      console.error(`❌ Chain 执行失败:`, error);
      return { success: false, error: String(error) };
    }
  }
}

// 预定义的 Chain 模板
const ChainTemplates = {
  // 代码审查模板
  codeReview: (model: ChatOpenAI) => {
    const prompt = ChatPromptTemplate.fromTemplate(`
      审查以下代码:{code}
      输出:问题列表和建议
    `);
    return prompt.pipe(model).pipe(new StringOutputParser());
  },
  
  // 文档生成模板
  documentGeneration: (model: ChatOpenAI) => {
    const prompt = ChatPromptTemplate.fromTemplate(`
      为以下代码生成文档:{code}
      输出:JSDoc 注释格式
    `);
    return prompt.pipe(model).pipe(new StringOutputParser());
  },
  
  // 测试生成模板
  testGeneration: (model: ChatOpenAI) => {
    const prompt = ChatPromptTemplate.fromTemplate(`
      为以下函数生成单元测试:{function}
      输出:Jest 测试代码
    `);
    return prompt.pipe(model).pipe(new StringOutputParser());
  }
};

// 使用模板
const reviewChain = new ReusableChain(
  "代码审查",
  () => ChainTemplates.codeReview(model)
);

const result = await reviewChain.execute({ code: "function add(a,b){return a+b}" });

结语

通过这篇教程,我们学习了 LangChain 中 Chain 的核心概念和使用方法。Chain 是构建复杂 AI 应用的基石,掌握它就能像搭积木一样灵活组合各种 AI 能力。

对于文章中错误的地方或有任何疑问,欢迎在评论区留言讨论!

相关推荐
EdenMa1 小时前
从飞书 PRD 到代码实现:我的AI编程workflow
openai·ai编程
往上跑山1 小时前
【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读
前端
winlife_2 小时前
从一句话到可玩原型:用 funplay-unity-mcp 让 AI 搭起完整游戏循环
人工智能·游戏·unity·ai编程·mcp·游戏原型
文心快码BaiduComate2 小时前
从个人效能到组织资产:文心快码企业版Agent Hub上线,提升团队AI编程效能
前端·后端·程序员
兆。2 小时前
LangChain向量数据库集成指南:面向RAG开发者
数据库·langchain
咖啡星人k2 小时前
从需求到交付:我用MonkeyCode的AI Agent完成了一个React数据看板
前端·人工智能·react.js·monkeycode
sxlishaobin2 小时前
linux 自动清除日志 脚本
linux·服务器·前端
ZC跨境爬虫2 小时前
跟着 MDN 学CSS day_37:(从文档流到粘性定位的底层原理)
前端·javascript·css·ui·html
IccBoY2 小时前
NVM超详细全解教程:解决Node版本冲突(Win/Mac/Linux安装+使用+踩坑合集)
前端·node.js