langchain-rag-chat
v1.0.0
Published
A RAG chat library built with LangChain
Readme
langchain-rag-chat
一个基于 LangChain 生态的 TypeScript RAG(检索增强生成)聊天库。它将文档加载、向量检索、问题扩展、分类检索和答案生成整合到一个 RAGChat 类中。
特性
- 支持从网页、PDF 或纯文本加载文档,并自动进行结构感知分块(保留 Markdown 标题层级,标题与其内容不分离)
- 可插拔的向量存储(默认为内存存储)
- 问题扩展(Multi-Query)以提升检索召回率
- 可选的问题分类 + 按元数据过滤的检索
- 多问题输入的自动拆分(问题分解)
- 检索结果的去重与压缩
- 支持流式和非流式答案生成
- 通过
onStep提供生命周期回调,便于观察运行过程 - 通过
RAGOptions提供完整的类型化配置 - 模型无关:自行传入 LangChain 的聊天模型与 embedding 模型
安装
npm install langchain-rag-chat @langchain/classic @langchain/core langchain自行选择模型提供方。下面的示例使用 @langchain/openai,但任意实现了
LangChain BaseChatModel / Embeddings 的模型都可以:
npm install @langchain/openai本包同时提供 ESM 与 CommonJS 两种构建产物,可兼容 import 与 require。
快速开始
import { RAGChat } from "langchain-rag-chat";
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
const rag = new RAGChat({
model: new ChatOpenAI({
model: "gpt-4o-mini",
apiKey: process.env.OPENAI_API_KEY,
}),
embeddings: new OpenAIEmbeddings({
model: "text-embedding-3-small",
apiKey: process.env.OPENAI_API_KEY,
}),
category: ["biology", "physics"] as const,
enhancePrompt: 3,
});
// 加载并索引文档。每个资源会打上对应的分类标签。
await rag.load({
resource: [
{ url: "https://example.com/biology.html", type: "biology" },
{ url: "https://example.com/physics.pdf", type: "physics" },
],
});
// 提问并获取最终答案(非流式)。
const answer = await rag.invoke({ question: "什么是光合作用?" });
console.log(answer);
// 或流式输出答案。
for await (const chunk of rag.stream("什么是光合作用?")) {
process.stdout.write(chunk);
}配置项
所有配置项都通过 RAGOptions 接口传入 RAGChat 构造函数。
export interface RAGOptions<Q extends string> {
model: BaseChatModel;
vectorStore?: VectorStoreFactory;
embeddings: Embeddings;
enhancePrompt?: number;
retrieverOptions?: RetrieverOptions;
category?: Q[];
enableClassification?: boolean;
questionCategory?: [Q, string][];
onStep?: (step: RAGStep, payload?: any) => void;
preRetrieve?: RunnableLike;
postRetrieve?: RunnableLike;
loader?: CustomLoader<Q>;
}配置项说明
| 配置项 | 类型 | 必填 | 默认值 | 作用 |
| ---------------------- | -------------------------- | ---- | ------------------- | ---------------------------------------------------------------------- |
| model | BaseChatModel | ✅ | — | 已创建好的 LangChain 聊天模型,用于问题分类、问题扩展和答案生成。 |
| vectorStore | VectorStoreFactory | ❌ | MemoryVectorStore | 自定义向量存储工厂 (embeddings) => VectorStore。 |
| embeddings | Embeddings | ✅ | — | 已创建好的 LangChain embedding 模型,用于向量化文档与查询。 |
| enhancePrompt | number | ❌ | 3 | 由原始问题生成的扩展查询数量(Multi-Query)。小于 1 时不进行扩展。 |
| retrieverOptions | RetrieverOptions | ❌ | { k: 3 } | 传给底层向量存储检索器的选项(如 { k, filter, searchType })。 |
| category | Q[] | ❌ | [] | 允许的问题分类数组,用于问题分类。为空时,load() 会从加载的资源类型中推断。 |
| enableClassification | boolean | ❌ | true | 是否在检索前对问题进行分类。关闭后检索将不再按分类过滤。 |
| questionCategory | [Q, string][] | ❌ | [] | [分类, 描述] 的配对数组,为分类提示词描述每个分类的含义。 |
| onStep | (step, payload?) => void | ❌ | — | 生命周期回调,在各阶段携带当前 payload 触发(见 RAGStep)。 |
| preRetrieve | RunnableLike | ❌ | — | 在检索之前应用的 runnable,例如重写查询或注入上下文。 |
| postRetrieve | RunnableLike | ❌ | — | 在检索/压缩之后应用的 runnable,例如重排或转换文档。 |
| loader | CustomLoader<Q> | ❌ | — | 按文件后缀(如 .txt)注册的自定义文档加载器,可覆盖内置加载器。 |
ℹ️
model与embeddings均为必填。本库与模型提供方无关:可传入任意实现了 LangChainBaseChatModel/Embeddings的模型(OpenAI、Anthropic、本地模型等), 不再与 OpenAI 深度绑定。
RAGStep
onStep 回调会收到以下某个阶段名称:
export type RAGStep =
| "classification" // 问题分类
| "vectorStore" // 文档已写入向量存储(load 之后)
| "retrieve" // 检索完成
| "compress" // 去重/压缩完成
| "answer"; // 开始生成答案相关类型
LoadOptions
RAGChat.load() 加载与索引文档时使用的配置。
export interface LoadOptions<Q extends string> {
resource: Resource<Q>[];
concurrencyCount?: number; // 默认 3
splitterOptions?: Partial<RecursiveCharacterTextSplitterParams>;
loader?: CustomLoader<Q> | null;
}Resource
描述单个文档来源。
export interface Resource<Q extends string = string> {
url: string; // 网页或 PDF 的 http(s) URL;其他后缀作为纯文本来源(非 http 的 PDF 需自定义 loader)
type?: Q; // 写入文档元数据的分类标签(用于分类过滤)
selector?: string; // 网页 CSS 选择器(默认 "body")
text?: string; // 纯文本内容(当 url 无对应加载器时使用)
}CustomLoader
后缀 → 加载函数 的映射,键为文件后缀(如 .md)。
export interface CustomLoader<Q extends string = string> {
[suffix: string]: (resource: Resource<Q>) => Promise<Document<any>[]>;
}VectorStoreFactory / RetrieverOptions / InputQuestion
export type VectorStoreFactory = (embeddings: Embeddings) => VectorStore;
export type RetrieverOptions<
V extends VectorStoreInterface = VectorStoreInterface,
> = Exclude<Parameters<V["asRetriever"]>[0], number | undefined>;
export interface InputQuestion {
question: string;
retrieverOptions?: RetrieverOptions; // 每次查询的检索器覆盖项
}API
constructor(options: RAGOptions<Q>)
创建 RAGChat 实例,并准备检索链与答案生成链。
load(loadOptions: LoadOptions<Q>)
加载资源、将每个资源的 type 写入文档的 metadata._type、分块(结构感知,保留标题层级)并写入向量存储。当 category 为空时,会从加载的资源类型中推断。
retrieveDocuments(question: string[], kOrFields?)
在向量存储中检索给定问题,返回匹配的 Document[]。
invoke(input: string | InputQuestion, options?)
执行完整 RAG 流程并返回生成的答案字符串。
stream(input: string | InputQuestion, options?)
执行 RAG 流程并以异步生成器流式输出答案。
classification(question, category?, questionCategory?)
将问题分类到某个已配置的分类(或 "other")。
splitQuestion(question)
使用语言模型将一个包含多个问题的问题拆分为子问题,每个子问题独立检索与回答。
expandQuestion(question, queryCount?)
从原始问题生成 queryCount 个扩展查询(Multi-Query)。原始问题始终作为第一个结果保留,确保日期、ID 等精确词不会被改写丢失。
执行流程
问题
→ 问题拆分(拆成子问题)
→ 问题分类(可选)
→ 问题扩展
→ preRetrieve
→ 检索(按分类过滤)
→ 去重与压缩
→ postRetrieve
→ 答案生成许可证
MIT
