拓冰建站拓冰建站
首页 / 资讯中心 / 正文

LangChain.js Redis 集成演进:FluentRedisVectorStore 类型安全过滤 API 与迁移实战(@langchain/redis)

LangChain.js Redis 集成演进FluentRedisVectorStore 类型安全过滤 API 与迁移实战langchain/redis【免费下载链接】langchainjsThe agent engineering platform项目地址: https://gitcode.com/GitHub_Trending/la/langchainjslangchain/redis是 LangChain.js 官方提供的 Redis 集成包当前版本 1.1.3覆盖向量存储、聊天历史与缓存三大能力。本文以该包的 CHANGELOG.md 版本演进为主线结合 README.md 迁移指南与 源码实现 深入讲解新版FluentRedisVectorStore的类型安全过滤 APITag/Num/Text/Geo/Timestamp/Custom、MetadataFieldSchema数组式 schema 定义、查询转义安全机制并给出从旧版RedisVectorStore平滑迁移的完整六步实操。读完本文你将能直接上手构建支持 AND/OR 嵌套、多类型元数据预过滤的 Redis 向量检索应用。一、包定位与版本演进主线langchain/redis位于 libs/providers/langchain-redis/其 package.json 表明它直接依赖redis^6.2.1官方 SDK并以langchain/core作为 peer dependency要求 Node.js 20。包内源码结构清晰vectorstores.ts旧版RedisVectorStore字符串数组/原始查询过滤已标记 deprecatedvectorstores_fluent.ts新版FluentRedisVectorStore类型安全过滤推荐使用filters.ts全部过滤表达式类与便捷函数schema.ts元数据字段 schema 定义、序列化与推断工具query_safety.tsRediSearch 查询转义与字段名校验chat_histories.ts/caches.ts聊天历史与缓存集成从 CHANGELOG 可以梳理出三条清晰的演进主线1. 与 LangChain v1.0 对齐1.0.0版本CHANGELOG.md将整个包更新为兼容 LangChain v1.0随后1.0.1修复了moduleResolution: node场景下的兼容问题。这意味着使用旧版 TypeScript 模块解析配置的项目也能正常导入该包。2. 过滤能力从字符串拼接走向类型安全表达式这是最核心的演进1.1.0引入了FluentRedisVectorStore配套新增Tag、Num、Text、Geo、Timestamp、Custom六个过滤表达式类以及MetadataFieldSchema数组式 schema 定义支持 AND/OR 逻辑与任意层级的嵌套组合同时保留旧版RedisVectorStore以维持向后兼容。1.1.1进一步补上了查询转义escaping与字段名校验从源头杜绝了恶意/畸形过滤输入引发的查询错误。3. 依赖与安全治理1.1.2移除了对uuid的直接使用转向langchain/core/utils/uuid修复了已知的 uuid 安全漏洞1.1.3继续清理了多余的types/uuid声明并刷新 lockfile。0.1.3则曾将内部缓存 key 生成器替换为更安全的keyEncoder。早期能力积累同样值得关注0.1.2为RedisVectorStore增加了按文档 ID 删除的能力0.1.4支持在向量存储中定义自定义 schema。二、FluentRedisVectorStore类型安全的高级向量存储1. 配置项全解FluentRedisVectorStoreConfig定义于 vectorstores_fluent.ts是构造该存储的核心配置各字段作用如下配置项类型默认值说明redisClientcreateClient/createCluster返回值必填Redis 客户端或集群客户端indexNamestring必填RediSearch 索引名indexOptionsCreateSchemaFlatVectorField/CreateSchemaHNSWVectorFieldHNSW COSINE向量索引算法与距离度量createIndexOptions索引创建选项不含 PREFIX见源码ON: HASH、语言、停用词等PREFIX 必须通过keyPrefix设置keyPrefixstringdoc:${indexName}:Redis key 前缀同时作为索引 PREFIXcontentKeystringcontent文档正文所在字段名metadataKeystringmetadata元数据字段名vectorKeystringcontent_vector向量字段名filterFilterExpression无构建时即绑定的默认过滤条件ttlnumber无文档过期时间秒customSchemaMetadataFieldSchema[]无必需元数据字段索引 schema不提供会直接抛错两个值得注意的默认行为见构造函数 vectorstores_fluent.ts向量索引默认采用SCHEMA_VECTOR_FIELD_ALGORITHM.HNSWDISTANCE_METRIC: COSINE。若数据量小且要求精确检索可在indexOptions中显式切换为 FLAT 算法。索引创建选项固定注入ON: HASH与PREFIX: this.keyPrefix即所有文档以 Hash 结构存储且必须带前缀避免createIndexOptions中重复设置PREFIX造成冲突。2. 索引创建与状态检测createIndexvectorstores_fluent.ts要求必须配置customSchema否则抛出 FluentRedisVectorStore requires a customSchema to be defined 错误。创建前会通过checkIndexState检测索引状态返回三态legacy索引存在且带有metadata字段标识——这通常意味着该索引由旧版RedisVectorStore创建default索引存在且为新格式none索引不存在随后执行ft.create。同时createIndex会用inferMetadataSchema(documents)从待写入文档推断 schema并与自定义 schema 比对若类型不一致则打印警告checkForSchemaMismatch提示可能配置了错误的 schema。向量字段统一以FLOAT32类型创建维度来自首次写入的向量长度默认 1536。3. 元数据存储方式的根本差异这是新旧两版最本质的区别也是迁移时必须理解的一点详见 README.md 迁移指南 Step 5旧版RedisVectorStore将整个 metadata 对象JSON.stringify后作为一个 JSON blob 塞进单个metadata字段再额外把自定义 schema 字段复制成metadata.field供索引见 vectorstores.ts。新版FluentRedisVectorStore不再存储 JSON blob而是把每个 schema 字段作为独立的 Hash 字段写入配合序列化规则保证类型正确见 vectorstores_fluent.ts。因此两种实现的数据布局互不兼容。CHANGELOG 与 README 都明确建议迁移时新建索引、按新 schema 重新灌入数据避免混用产生歧义结果。三、类型安全过滤 API 深度拆解1.1.0引入的过滤体系全部定义在 filters.ts核心是抽象基类FilterExpression它提供两个组合方法and(other)生成AndFilterRediSearch 中表现为括号内空格分隔(cond1 cond2)or(other)生成OrFilterRediSearch 中表现为括号内|分隔(cond1|cond2)AndFilter对通配符做了特殊处理任一侧为*时直接返回另一侧OrFilter则相反任一侧为*时整体坍缩为*。这样空过滤条件组合时不会产生无效查询。1. Tag分类精确匹配适用于低基数的分类字段如品类、状态。支持字符串、字符串数组与Setstring多值之间是 OR 语义import { Tag, Num, Text, Geo, Timestamp, Custom } from langchain/redis; Tag(category).eq(electronics); // category:{electronics} Tag(category).eq([electronics, books]); // category:{electronics|books} Tag(status).ne(archived); // (-status:{archived})TagFilter对空数组/空 Set 返回通配符*避免空过滤破坏查询。测试用例见 filters.test.ts。2. Num数值区间与比较支持eq、ne、gt、gte、lt、lte、between七种运算符。RediSearch 数值区间用方括号表示闭区间、圆括号表示开区间Num(price).eq(99.99); // price:[99.99 99.99] Num(price).gt(50); // price:[(50 inf] —— 开区间下界 Num(price).gte(4.5); // price:[4.5 inf] —— 闭区间下界 Num(price).lt(100); // price:[-inf (100] Num(price).lte(100); // price:[-inf 100] Num(price).between(50, 200);// price:[50 200]3. Text全文检索针对 TEXT 类型字段提供四种匹配模式Text(title).exact(wireless headphones); // title:(wireless headphones) Text(title).match(bluetooth wireless); // title:(bluetooth wireless) —— 分词匹配 Text(title).wildcard(*phone*); // title:(head*) —— 通配符 Text(description).fuzzy(blutooth); // title:(%%blutooth%%) —— 模糊匹配其中fuzzy通过 RediSearch 的%%前缀/后缀实现拼写容错wildcard模式下*、?不会被转义。4. Geo地理半径检索按经纬度 半径过滤单位支持km、mi、m、ftGeo(location).within(-122.4194, 37.7749, 10, km); // location:[-122.4194 37.7749 10 km] Geo(store_location).outside(-74.006, 40.7128, 5, mi); // 半径外取反Geo 字段存储格式为longitude,latitude字符串或[lon, lat]数组serializeMetadataField会自动完成数组到字符串的转换见 schema.ts。5. Timestamp时间范围检索Redis 并没有独立的时间戳字段类型时间戳本质上是存储 Unix 纪元秒的 NUMERIC 字段。TimestampFilter是方便的包装器自动把Date对象转成秒级 epochTimestamp(created_at).gt(new Date(2023-01-01)); // created_at:[(1672531200 inf] Timestamp(created_at).between( new Date(2023-01-01), new Date(2023-12-31) ); // created_at:[1672531200 1703980800] Timestamp(updated_at).gte(1672531200); // 也可直接传 epoch 秒对应 schema 定义时仍要使用type: numeric{ name: created_at, type: numeric, options: { sortable: true } }6. Custom原始 RediSearch 语法逃生舱当内置过滤器无法覆盖高级语法时可原样传入 RediSearch 查询串不做任何修改Custom((category:{electronics} price:[0 100])); Custom(title:(wireless|bluetooth) price:[50 200]).and(Num(price).lt(100));注意Custom 查询串的正确性完全由使用者负责语法错误会导致搜索失败。7. 复杂组合示例得益于and/or的链式调用可以构建任意嵌套的过滤条件const filter Tag(category) .eq(electronics) .and(Num(price).between(100, 1000)) .and( Geo(location).within(-122.4194, 37.7749, 50, km) .or(Geo(location).within(-74.006, 40.7128, 100, mi)) );将表达式传给similaritySearchVectorWithScore即可完成混合检索const results await vectorStore.similaritySearchVectorWithScore( queryVector, 5, Tag(category).eq(electronics).and(Num(price).between(100, 1000)) );如果同时传入过滤参数又配置了this.filter会抛出 cannot provide bothfilterandthis.filter 错误vectorstores_fluent.ts保证过滤语义不会产生歧义。四、查询安全转义与字段名校验1.1.1是 CHANGELOG 中一次重要的安全修复为 Redis 过滤器构建器补充了共享的查询转义与字段校验工具并将其应用到buildCustomQuery的 tag/text/numeric 各路径同时新增了覆盖转义值、通配符处理与非法过滤输入的回归测试。这些工具位于 query_safety.tsassertSafeRedisearchFieldName(fieldName)字段名必须匹配/^[a-zA-Z0-9_.-]$/否则抛出Unsafe field name。测试中new TagFilter(tenant_id:{*}, tenant_a)即因此被拒绝。escapeRedisearchValue(value, options)对 RediSearch 全部特殊字符,.{}[]:;!#$%^()-~|?及空白符逐个加反斜杠转义。preserveWildcard时保留/?preserveWhitespace 时保留空白用于精确短语与分词匹配。例如测试用例中恶意输入tenant_a} tenant_id:{*会被正确转义为tenant_a\}\,\ \tenant_id\:\{\*见 filters.test.ts从根本上阻断通过过滤器注入查询语法的攻击路径。这与旧版RedisVectorStore在写入侧对-、:、的escapeSpecialChars/unEscapeSpecialChars处理vectorstores.ts共同构成了写入转义 查询转义的双层防护。五、MetadataFieldSchema数组式 Schema 体系1. 字段类型与选项MetadataFieldSchemaschema.ts以{ name, type, options }数组定义元数据字段type支持tag | text | numeric | geoconst customSchema [ { name: userId, type: tag }, { name: price, type: numeric, options: { sortable: true } }, { name: description, type: text, options: { weight: 2.0 } }, { name: location, type: geo }, { name: created_at, type: numeric, options: { sortable: true } }, // 时间戳字段 ];各类型可选选项及底层映射选项适用类型映射到 RediSearch默认值separatortagSEPARATOR,DEFAULT_TAG_SEPARATORcaseSensitivetagCASESENSITIVE: true关闭weighttextWEIGHT1.0noStemtextNOSTEM: true关闭sortablenumeric / textSORTABLE: true关闭noindex全部NOINDEX: true关闭即默认建立索引buildMetadataSchema负责将这些定义合并进默认的向量 content 索引 schema未知类型会回退为 TEXT。2. 序列化与反序列化serializeMetadataField写入侧tag 数组按分隔符 joinnumeric 的Date自动转 Unix 秒geo 数组转lon,lat字符串。deserializeMetadataField读取侧tag 含分隔符的字符串还原为数组numeric 还原为 number不会自动转回Date需要时手动new Date(epoch * 1000)geo 字符串还原为[lon, lat]。3. 自动推断与一致性校验inferMetadataSchema根据文档元数据自动推断 schema推断规则schema.ts所有值均为lon,lat格式字符串 →geo所有值为 number 或 Date →numeric所有值为数组 →tag其余 →textcheckForSchemaMismatch则以名称 类型为准、与顺序无关地比对自定义 schema 与推断 schema在createIndex时用于输出不一致警告。此外convertLegacySchema可将旧版Recordstring, CustomSchemaField格式自动转换为新数组格式转换时会打印弃用警告降低存量代码的迁移成本。六、从 RedisVectorStore 到 FluentRedisVectorStore 的完整迁移官方 README.md 明确将FluentRedisVectorStore定位为新项目的推荐选择。两版能力对比如下特性RedisVectorStoreFluentRedisVectorStore元数据 Schema 定义Recordstring, CustomSchemaFieldMetadataFieldSchema[]Schema 自动推断不支持仅自定义 schema支持基于写入文档的元数据推断预过滤定义字符串数组或原始查询串类型安全的FilterExpression对象预过滤嵌套条件全部条件以单一 AND 连接支持 AND、OR 与嵌套预过滤条件类型Numeric、Tag、TextNumeric、Tag、Text、Geo、Timestamp元数据存储JSON blob 可选索引字段独立索引字段无 JSON blob迁移六步Step 1更新导入// Before import { RedisVectorStore } from langchain/redis; // After import { FluentRedisVectorStore, Tag, Num, Text, Geo } from langchain/redis;Step 2转换元数据 Schema// Before对象式 SCHEMA_FIELD_TYPE 枚举 const customSchema { userId: { type: SchemaFieldTypes.TAG, required: true }, price: { type: SchemaFieldTypes.NUMERIC, SORTABLE: true }, description: { type: SchemaFieldTypes.TEXT }, location: { type: SchemaFieldTypes.GEO }, }; // After数组式 字符串类型 options const customSchema [ { name: userId, type: tag }, { name: price, type: numeric, options: { sortable: true } }, { name: description, type: text }, { name: location, type: geo }, ];Step 3更新配置const vectorStore await FluentRedisVectorStore.fromDocuments( documents, embeddings, { redisClient: client, indexName: products, customSchema: [ { name: category, type: tag }, { name: price, type: numeric, options: { sortable: true } }, ], } );Step 4重构查询过滤// Before元数据对象或字符串数组 const results await vectorStore.similaritySearchVectorWithScoreAndMetadata( queryVector, 5, { category: electronics, price: { min: 100, max: 1000 } } ); // After流畅表达式 const results await vectorStore.similaritySearchVectorWithScore( queryVector, 5, Tag(category).eq(electronics).and(Num(price).between(100, 1000)) );Step 5数据库 Schema 迁移新版仅支持独立索引字段布局与旧版JSON blob布局不兼容。为避免歧义结果必须新建索引并按新 schema 重灌数据不要直接复用旧索引。Step 6更新业务代码将RedisVectorStore全部替换为FluentRedisVectorStore并用可选过滤器链改写条件逻辑async function searchProducts(query: string, category?: string) { const filter category ? Tag(category).eq(category) : undefined; const results await vectorStore.similaritySearchVectorWithScore( await embeddings.embedQuery(query), 5, filter ); return results; }七、安装、开发与测试安装npm install langchain/redis langchain/core本地开发仓库采用 pnpm turbo 工作区在 libs/providers/langchain-redis/ 下开发时pnpm install # 安装依赖 pnpm build # 构建包或在仓库根目录按过滤器构建pnpm build --filter langchain/redis测试按单元/集成分层源码src/下以.test.ts结尾为单元测试、.int.test.ts结尾为集成测试需要可连接的 Redis 实例pnpm test # 单元测试vitest run pnpm test:int # 集成测试vitest run --mode int配套的静态检查与格式化pnpm lint pnpm format若新增对外导出的文件需在src/index.ts中导入并再导出或补充进package.json的exports字段后重新构建生成新入口点。八、总结与版本选用建议从0.1.x的自定义 schema、keyEncoder、按 ID 删除到1.0.x的 LangChain v1.0 对齐再到1.1.x的FluentRedisVectorStore、查询转义加固与依赖安全治理langchain/redis的演进清晰地指向更类型安全、更可组合、更安全的过滤体验。参考当前源码与文档给出的建议新项目一律使用FluentRedisVectorStoreMetadataFieldSchema[]FilterExpression存量项目按本文第六节的六步走迁移注意索引布局不兼容、需重建索引复杂过滤需求Geo 半径、时间区间、AND/OR 嵌套旧版RedisVectorStore无法满足必须升级运行前提向量检索依赖 RediSearch 模块若连接非 RediSearch 的 Redis 实例FT.INFO会返回 unknown command源码会抛出明确的错误提示引导检查部署环境。【免费下载链接】langchainjsThe agent engineering platform项目地址: https://gitcode.com/GitHub_Trending/la/langchainjs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门