[LangChain] 09. Runnable接口 - 1

在 LCEL 中,几乎所有的模块:

  • 提示词模板
  • 模型
  • 解析器

都是实现了 Runnable 接口的,可以将这些模块称之为 Runnable 类型。这种类型的模块可以快速插入到链条里面。

RunnableLambda

RunnableLambda 是 LangChain.js 提供的一种轻量级工具,它能把 普通函数 封装成符合 Runnable 接口规范的实例,从而让该函数能够无缝参与到 LCEL 的链式调用与流式处理流程中。

  1. 快速上手案例

    import { RunnableLambda } from "@langchain/core/runnables";
    
    const fn = (text) => {
      return text.toUpperCase();
    };
    
    const runnableFn = RunnableLambda.from(fn);
    
    const res = await runnableFn.invoke("hello");
    
    console.log(res);
    
  2. 关键词高亮插件

    闭包 --> *&*闭包*&*

    import { ChatOllama } from "@langchain/ollama";
    import { PromptTemplate } from "@langchain/core/prompts";
    import { StringOutputParser } from "@langchain/core/output_parsers";
    import { RunnableLambda } from "@langchain/core/runnables";
    
    // 1. 创建一个提示词模板
    const pt = PromptTemplate.fromTemplate("请使用中文解释下面的概念:{topic}");
    
    // 2. 创建模型
    const model = new ChatOllama({
      model: "llama3",
      temperature: 0.7,
    });
    
    // 3. 解析器
    const parser = new StringOutputParser();
    
    // 4. 创建一个链条
    let chain = pt.pipe(model).pipe(parser);
    
    // 5. 创建一个简单的插件
    const fn = (text) => text.replace(/闭包/g, "*&*闭包*&*");
    const highlight = RunnableLambda.from(fn);
    
    chain = chain.pipe(highlight);
    
    const res = await chain.invoke({
      topic: "闭包",
    });
    
    console.log(res);
    

更多场景:

  • 插入日志收集模块
  • 插入翻译模块(调用外部 API)
  • 插入开关:判断某个条件是否中断执行
  • 格式调整、结构清洗、敏感词过滤

pipe() 方法可接受的三种类型:

  1. Runnable 实例:这是最常用的,也是最推荐的

  2. 普通函数:LCEL 内部会自动用 RunnableLambda.from(fn) 包装成一个 Runnable

  3. 对象:将上游的输入(或结果)分别传给多个 runnable,然后返回一个对象。

    import { ChatOllama } from "@langchain/ollama";
    import { PromptTemplate } from "@langchain/core/prompts";
    import { StringOutputParser } from "@langchain/core/output_parsers";
    import { RunnableLambda } from "@langchain/core/runnables";
    
    // 创建模型
    const model = new ChatOllama({
      model: "llama3",
      temperature: 0.7,
    });
    
    // 解析器
    const parser = new StringOutputParser();
    
    // 创建两个子链
    const chain1 = PromptTemplate.fromTemplate(
      "请用中文用 2-3 句概括以下主题的核心含义:{input}"
    )
      .pipe(model)
      .pipe(parser);
    
    const chain2 = PromptTemplate.fromTemplate(
      "请用中文从以下主题中提取 5 个关键词,以逗号分隔:{input}"
    )
      .pipe(model)
      .pipe(parser);
    
    let chain = RunnableLambda.from((x) => x);
    
    chain = chain.pipe({
      summary: chain1,
      keywords: chain2,
    });
    
    const res = await chain.invoke({
      input: "闭包",
    });
    console.log(res);
    

RunnableMap

RunnableMap(也叫 RunnableParallel),它可以让多个链条 并发执行,并返回一个结构化的对象结果。

RunnableMap.from({ ... }) 会并发执行多个子链,并将它们的结果组合成一个对象返回。

import { ChatOllama } from "@langchain/ollama";
import { PromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { RunnableMap } from "@langchain/core/runnables";

// 创建模型
const model = new ChatOllama({
  model: "llama3",
  temperature: 0.7,
});

// 解析器
const parser = new StringOutputParser();

const chain1 = PromptTemplate.fromTemplate("用中文讲一个关于 {topic} 的笑话")
  .pipe(model)
  .pipe(parser);
const chain2 = PromptTemplate.fromTemplate("用中文写一首关于 {topic} 的两行诗")
  .pipe(model)
  .pipe(parser);

const chain = RunnableMap.from({
  joke: chain1,
  poem: chain2,
});

const res = await chain.invoke({
  topic: "小狗",
});
console.log(res);

-EOF-

posted @ 2025-11-02 16:14  Zhentiw  阅读(7)  评论(0)    收藏  举报