)
Milvus Function Chain API 设计解析面向搜索重排的三级流水线架构L0/L1/L2 Rerank【免费下载链接】milvusMilvus is a high-performance, cloud-native vector database built for scalable vector ANN search项目地址: https://gitcode.com/GitHub_Trending/mi/milvus导读本文深度解读 Milvus 官方设计文档《MEP: Function Chain API for Search Rerank》20260624-function-chain-api.md系统阐述 Function Chain 这一类型化、有序、分阶段的搜索打分与重排流水线它如何以结构化 protobuf 而非不透明 JSON 字符串下发重排计划、如何在 L0/L1/L2 三个分布式执行边界上运行、如何通过$score系统虚拟列统一重排语义以及 SDK 如何用FunctionChain/fnDSL 把用户意图编译为可校验的算子序列。读完本文你将掌握 Function Chain 的完整设计脉络、Python DSL 与 protobuf 数据结构、各阶段算子能力边界、内置表达式decay/num_combine/round_decimal/rerank_model的参数细节以及仓库中对应的源码实现路径可直接用于设计或落地基于 Milvus 的多因子排序与模型重排方案。背景与动机为什么需要 Function ChainMilvus 此前已有function_score与 ranker 参数两类传统重排入口它们对预定义的打分公式足够有用但无法表达由多个重排步骤有序组合而成的通用计划。文档给出一个典型的多因子排序诉求基于时间戳字段计算新鲜度freshness分数将原始 ANN 分数、新鲜度、热度popularity组合可选地调用外部重排模型做文本相关性打分重写最终分数排序并裁剪候选集。把这些诉求表达为类型化算子序列typed operations后Milvus 可以获得确定的执行顺序deterministic execution order类型化的嵌套参数杜绝 JSON-in-string 编码带来的类型歧义显式的字段依赖分析explicit field dependency analysis支撑内部按需取数一致的$score语义最终分数统一通过既有 score/distance 字段回传为未来扩展更多阶段与算子预留空间。从源码结构看internal/util/function/chain包就是这套运行时的主体expr/子目录存放各内置表达式decay_expr.go、num_combine_expr.go、round_decimal_expr.go、rerank_model_expr.go 等operator_*.go文件则实现map、sort、limit等算子。阶段模型L0 / L1 / L2 三级分布式重排边界Function Chain 的核心创新在于把重排拆分到三个不同的分布式执行边界阶段执行边界首版支持的算子L0worker QueryNode 内每个 segment 结果上、跨 segment 归约之前mapL1每个 worker QueryNode完成自身跨 segment 归约之后、结果返回 shard leader 之前map、sort、limitL2Proxy完成分布式/全局归约之后校验规则允许的通用函数链运行时算子完整的分布式流水线如下segment ANN result - L0 per-segment chain - worker QueryNode cross-segment reduce / PK dedup / group-aware merge - L1 per-worker merged-candidate chain - shard-leader reduce - Proxy global reduce - L2 Proxy chain - final projection需要特别强调的是L1 只在每个 worker QueryNode 的归约结果上执行恰好一次不会在 shard leader 处重复运行。该边界使 L1 能在单个 worker 管辖的多个 segment 之间横向比较候选同时保持现有分布式 reducer 与线协议不变。从源码看l1_function_chain.go 中的applyL1Rerank正是 L1 在 worker 侧的 Go 归约实现入口。文档还明确划定了首版不包含Non-Goals的内容hybrid/advanced search 不支持function_chains不支持 insert/upsert/ingestion 阶段的函数链不在 shard-leader 归约边界或多级 QueryNode 归约层级上执行 L1L1 首版不支持filter、select、group_by算子不支持任意用户自定义表达式语言中间链变量不作为用户可见结果字段返回不替换function_score与 legacy rank 参数外部模型调用不在客户端执行。阶段枚举同时为未来的 ingestion、pre-processing、post-processing 预留了位置普通 Search 在每个L0_RERANK/L1_RERANK/L2_RERANK上至多接受一条链。源码中的阶段常量定义在 types.go如StageL0Rerank L0_rerank、StageL1Rerank L1_rerank、StageL2Rerank L2_rerank。公开接口Python DSL 与 Search APIPyMilvus DSL 构建链用户通过FunctionChain、FunctionChainStage、col以及fn下的辅助函数构建一条链。以下示例来自设计文档演示如何组合新鲜度衰减、加权分数合并、小数取整、排序与截断from pymilvus import FunctionChain, FunctionChainStage from pymilvus.function_chain import col, fn chain ( FunctionChain(FunctionChainStage.L2_RERANK, namefresh_popular_rerank) .map( freshness, fn.decay( col(published_at), functionexp, origincurrent_time, scale86400, offset0, decay0.5, ), ) .map( $score, fn.num_combine( col($score), col(freshness), col(popularity), modeweighted, weights[0.7, 0.2, 0.1], ), ) .map($score, fn.round_decimal(col($score), decimal4)) .sort(col($score), descTrue, tie_break_colcol($id)) .limit(10) ) client.search( collection_namearticles, data[query_vector], anns_fieldembedding, search_params{metric_type: IP}, limit100, output_fields[title], function_chainschain, )模型重排示例外部模型重排同样是一条 L2 链chain ( FunctionChain(FunctionChainStage.L2_RERANK, namemodel_rerank) .map( $score, fn.rerank_model( col(doc), queries[renewable energy developments], providervoyageai, model_namererank-2.5, truncationTrue, max_client_batch_size128, ), ) .sort(col($score), descTrue, tie_break_colcol($id)) )文档强调外部模型的凭据由 Milvus 服务端通过 provider 配置解析SDK 请求不应携带 API Key。Search API 与冲突校验普通 Search 通过function_chains参数接收链单个或列表均可client.search(..., function_chainschain) client.search(..., function_chains[chain])SDK 与服务端校验会拒绝以下歧义或不受支持的组合function_chains与 SDKranker/ protofunction_score同时使用普通 Search 出现 L0/L1/L2 之外的阶段hybrid 或 advanced search 使用function_chainsFunction rerank 与 Search Iterator 或order_by同时使用L1 与 search aggregation 同时使用。仓库中 function_chain_validator.go 正是 Proxy 侧校验的实现validateFunctionChainSearchRequest返回function_score and function_chains cannot be used together与function_chains is not supported for hybrid search yetsplitFunctionChainsByStage则负责按阶段把链拆分为 L2 链留在 Proxy与 L0/L1 链随物理计划下发 QueryNode。Protobuf 契约链是有序逻辑计划与“整条链编码为 JSON 字符串”的方案不同Function Chain 以结构化 protobuf 下发。核心消息结构如下enum FunctionChainStage { FunctionChainStageUnspecified 0; FunctionChainStageIngestion 1; FunctionChainStagePreProcess 2; FunctionChainStageL0Rerank 3; FunctionChainStageL1Rerank 4; FunctionChainStageL2Rerank 5; FunctionChainStagePostProcess 6; } message FunctionChain { string name 1; FunctionChainStage stage 2; repeated FunctionChainOp ops 3; } message FunctionChainOp { string op 1; FunctionChainExpr expr 2; repeated string inputs 3; repeated string outputs 4; mapstring, FunctionParamValue params 5; } message FunctionChainExpr { string name 1; repeated FunctionChainExprArg args 2; mapstring, FunctionParamValue params 3; } message FunctionChainExprArg { oneof arg { FunctionChainColumnArg column 1; FunctionParamValue literal 2; } } message FunctionChainColumnArg { string name 1; } message FunctionParamValue { oneof value { bool bool_value 1; int64 int64_value 2; double double_value 3; string string_value 4; FunctionParamArray array_value 5; FunctionParamObject object_value 6; bytes bytes_value 7; } } message FunctionParamArray { repeated FunctionParamValue values 1; } message FunctionParamObject { mapstring, FunctionParamValue fields 1; }SearchRequest通过repeated schema.FunctionChain function_chains 24;携带链hybrid request proto 虽为未来支持保留字段但首版执行会直接拒绝。内部表示ChainRepr 与依赖分析公开 proto 进入服务端后首先由 chain 包转换为与调用方无关的内部表示ChainRepr。该结构在 repr.go 中定义type ChainRepr struct { Name string Stage string Operators []OperatorRepr Info ChainReprInfo } type ChainReprInfo struct { RequiredInputs []string WrittenNames []string Ops []OperatorReprInfo } type OperatorReprInfo struct { Type string ReadNames []string WriteNames []string }关键设计是ChainRepr.Info.RequiredInputs只表达“链在某条先前算子写入之前就读取了这些名字”的结构性依赖它不决定某个名字究竟是 schema 字段、运行时系统值还是非法名称——该分类权归调用方所有。ProtoChainToRepr负责 proto→repr 转换含 nil 检查、空算子名校验、stage 枚举转换、未知算子拒绝RefreshInfo通过一次扫描重建RequiredInputs/WrittenNames并从GetOperatorFactory校验算子类型是否已知。FuncChainFromRepr/FuncChainFromReprWithContext再从ChainRepr构建可执行的FuncChain前者使用空FunctionBuildContext后者用于需要运行时上下文如模型重排的构造场景。IsFunctionChainSystemName以$前缀识别系统名。$score与$id系统虚拟列语义$score是系统虚拟列而非集合字段其运行时行为如下重排输入构建时$score从当前搜索结果 score/distance 初始化函数可通过col($score)读取它map($score, expr)覆盖当前分数寄存器sort(col($score), descTrue)按重写后的分数排序候选最终$score通过既有结果 score/distance 字段序列化SDK 用户看到的就是普通 hit distance/score 值。层级表示形式Python DSL$scoreProtoFunctionChainColumnArg.name $score运行时score register / DataFrame 列搜索结果既有 distance/score 字段$id作为只读系统值用于 tie-break。在公开的 L0/L1 链中可读的系统列只有$id与$score可写的系统列只有$score用于 segment 偏移、分组、元素元数据或 L1 provenance 的内部列不属于公开链命名空间绝不允许出现在结果字段中。Proxy 侧validateL2RerankSystemInput/validateL2RerankSystemOutput在 function_chain_validator.go 中落实了这一约束。算子语义mapmap(output, expr)计算表达式并把结果写入outputL0/L1/L2 均可写入freshness这类临时变量供链内后续算子使用L0 与 L1 还可在阶段局部 DataFrame 内覆写普通集合列output可以是可写系统值$score首版重排不允许写$id或未知$xxx值。sortsort(by, descTrue, tie_break_colNone)对当前候选块排序by编码为 op input 与参数tie_break_col可选同样编码为 input排序是显式的一旦链中出现了显式排序Milvus 不再根据向量 metric 类型推断排序方向。limitlimit(limit, offset0)在前序算子之后裁剪每个查询块。它是用户计划的一部分Search 不会隐式追加公开的limit/offset算子。对 L1 而言limit是每个 worker、每个 query-vector 块独立应用的中间候选预算并非最终客户端 Search limit。被某 worker 丢弃的候选不会在 shard leader 或 Proxy 处重现因此L1limit会降低召回率用户必须按预期的 worker 扇出与召回目标来设置它。当 L1 链同时含用户sort与limit时limit 遵循用户定义的顺序。用户整条链执行完毕后QueryNode 会追加一个非公开的规范化排序按$score降序、$id升序作为 tie-break。该内部步骤不属于公开链算子它恢复下游 shard/Proxy reducer 所需的排序契约且不会改变用户 L1limit已选出的候选集合。内置表达式decay由一个数值输入列计算数值衰减分数。参数包括functiongauss、exp或linearorigin原点scale尺度offset偏移decay衰减系数源码层面decay_expr.go 定义了GaussFunction/LinearFunction/ExpFunction常量与decayReScorer计算函数注释明确其输出为[0, 1]的纯衰减因子与$score的组合由链中后续的num_combine节点负责列映射由map算子完成。num_combine组合两个及以上数值输入支持以下模式multiplysummaxminavgweighted要求每个输入对应一个数值权重round_decimal将单个 Float32 分数列四舍五入到[0, 6]位小数。rerank_model对文本列调用外部重排模型 provider首版仅在 L2 重排阶段可运行。必填参数queries每个搜索 query 块对应一条 queryprovider 参数如provider、model_name、max_client_batch_size及 provider 专属选项。Provider 凭据与 endpoint 默认值在 Milvus 服务端通过既有 function provider 配置解析。仓库中 rerank_model_expr.go 与其测试对应此表达式模型 client 集中在internal/util/function/models/下如 voyageai、cohere、openai、tei、siliconflow 等。输入、写入与投影语义Function Chain 将链执行命名与最终结果投影分离expr-based op read names column references in FunctionChainExpr.args non-expr op read names FunctionChainOp.inputs op write names FunctionChainOp.outputs final result projection Search-owned output projection以文档示例为准FunctionChain(FunctionChainStage.L2_RERANK) \ .map(freshness, fn.decay(col(published_at), ...)) \ .map($score, fn.num_combine(col($score), col(freshness), modesum)) \ .sort(col($score), descTrue)依赖分析会得出先前写入之前必需的输入published_at、$score写入的名字freshness、$scorefreshness不会从集合 schema 取数因为它被前序算子写入published_at即使不在用户output_fields中也会为重排而内部取数最终响应只返回$id、最终$score与用户请求的输出字段。中间变量如freshness不会返回给用户。端到端执行流与集成设计高层 Search 流程SearchRequest.function_chains - SDK serialization - Proxy request validation and stage split - L0/L1 serialized into PlanNode.querynode_function_chains - L2 retained as Proxy rerank metadata - worker QueryNode exports per-segment Arrow DataFrames - L0 executes on each segment DataFrame - worker QueryNode cross-segment reduce - L1 materializes required fields and executes on the merged DataFrame - shard-leader and Proxy reductions - L2 rerankOperator builds and executes a DataFrame chain - Search-owned final projection值得注意的实现事实L1不需要新增 protobuf 传输它复用PlanNode.querynode_function_chains字段与 L0 一起下发靠FunctionChain.stage区分。L2 被当作一种 Proxy rerank source复用既有rerankOperator而非新增独立的functionChainOperatorL1 属于 worker QueryNode 的 Go 归约流程也不新增 Proxy 管线算子。文档给出的 L2 集成路径为SearchResultData - chain.FromSearchResultData(..., neededFields) - build FuncChain from rerank metadata - ExecuteWithContext - chain.ToSearchResultDataWithOptions(...)链构建器按 rerank metadata 类型分发legacy function score、legacy rank params、公开 function chainFuncChainFromRepr/FuncChainFromReprWithContext。Proxy L2 输入规划普通 Search L2 重排时Proxy 对每个必需输入分类$score与$id为运行时系统输入其他名字必须解析为受支持的集合 schema 字段未知的非系统名被拒绝不受支持的$xxx系统输入被拒绝前序算子写出的临时变量不从 schema 取数。首版受支持的 schema 输入字段类型BoolInt8 / Int16 / Int32 / Int64 / TimestamptzFloat / DoubleString / VarChar / Text不受支持的输入字段类型包括向量字段、JSON、Array、Geometry 以及 dynamic field 子键。validateFunctionChainInputField通过chain.ToArrowType校验字段类型可映射为 Arrow 类型否则拒绝。QueryNode L0/L1 准备Proxy 将 L0 与 L1 链一起序列化进物理计划。worker QueryNode 解析planpb.PlanNode一次把公开链转为ChainRepr按各自 stage 校验每条链并分别规划 L0 与 L1 的 schema 输入。Legacyfunction_score也在该准备阶段被规范化为包含其 scorer 与解析后的 score-combine 模式的 L0 prepared 配置。只有公开 L0 输入字段随每个 segment 搜索结果在归约前导出prepared legacy boost score 只需既有 segment 偏移不向导出追加集合字段。L1 输入字段在跨 segment 归约后、为幸存的 worker 候选物化。L0 保持 segment 本地行为只接受mapL1 接受map、sort、limit。两个阶段均可写普通临时列与集合列系统列中只有$score可写$id与其他$xxx只读。L1 输入物化与延迟投影late materializationworker 跨 segment reducer 产出合并 DataFrame 及并行的 source maptype segmentSource struct { InputIdx int SegOffset int64 OriginalIdx int } type mergeResult struct { DF *chain.DataFrame Sources [][]segmentSource }仅 L1 需要的普通标量字段不会随所有 segment ANN 候选导出也不在 heap merge 中复制。L1 执行前QueryNode 展平合并结果的 source map仅从源 segment 读取幸存候选Sources[query chunk][row].{InputIdx, SegOffset} - ordered segment field read for L1 required field IDs - Arrow RecordBatch in merged-row order - L1 input DataFrame with mergedDF chunk sizes物化必须保持 Arrow 类型、field ID/类型/nullability 元数据、null 值、chunk 数与行数缺失字段、非法源索引/偏移、畸形 Arrow 元数据、DataFrame/source 形状不匹配都属于内部结果契约失败而非非法请求。L1 的sort/limit会重排或裁剪mergeResult.DF直接变换会破坏行到 segment 的映射。因此 L1 执行前 QueryNode 会为每个 chunk 附加隐藏的 per-chunk source-index 列l1_function_chain.go中常量l1SourceIndexColumn $l1_source_indextoken 是该行在当前 chunkSources切片中的下标。由于所有 Function Chain 行算子都会变换每一列token 会随用户map/sort/limit及内部规范化排序跟随每一行执行后用变换后的 token 重建Sources再移除隐藏列。PK 不能作为 provenance tokenelement-level search 可能包含多条同 PK 的行按 PK 重建 source 会产生歧义。隐藏 token 仅限内部公开链不可读也绝不能出现在SearchResultData.FieldsData或最终输出投影中。延迟物化前必须满足五项不变量chunk 数一致、每行恰有一个 source 条目、token 非空且类型/范围合法、重建顺序与最终 DataFrame 一致、token 与 L1 临时输入列在序列化前移除。Requery 与字段可用性Function Chain 输入字段走既有 rerank metadatarerankMeta.GetInputFieldNames() rerankMeta.GetInputFieldIDs()需要 requery 时requery 算子会包含 rerank 必需字段名以便在重排执行前构建 DataFrame最终投影仍只使用用户 output 字段不暴露内部取来的重排输入。Proxy 的functionChainRerankMeta正是通过这两个 getter 暴露输入字段function_chain_validator.go。请求级规则与校验清单function_score冲突function_score与function_chains互斥错误信息为function_score and function_chains cannot be used together——两者都定义重排打分行为同时使用会使排序语义歧义。SDKranker映射到 legacy rerank/function-score 行为因此 SDK 在 RPC 前就拒绝rankerfunction_chains。阶段唯一性同一请求中每个FunctionChainStage至多出现一次。一条 L0、一条 L1、一条 L2 可以共存其执行顺序由阶段固定而非请求列表顺序决定。单阶段需要多步时应把多个有序算子放进该阶段的同一条链而不是发送重复链。L1 兼容性限制L1 不支持 hybrid/advanced searchL1 不支持 Search Iteratorlegacy 或 v2L1 不支持order_by两者都定义排序行为L1 不支持 search aggregationSearch 级 group-by 可与 L1map/sort/limit组合与 L2 兼容性一致Function Chain 算子可以重排或裁剪分组行无需重建原始 group count 或group_size契约。这些校验在执行前完成保证不受支持的组合不会悄悄产生不完整的分布式结果。首版校验规则汇总Function chain proto 不得为 nilstage 必须受请求类型支持拒绝重复 stage算子名非空表达式存在时表达式名非空列引用与输入/输出名非空expr 参数只能是列引用或受支持字面量参数值必须类型化且可转换为运行时值L0/L1/L2 公开输入系统名限定为$id、$score公开系统输出限定为$score非系统必需输入必须是受支持的集合字段L0 只接受mapL1 只接受map、sort、limit未知算子与函数被拒绝函数必须在其所在 stage 可运行函数专属参数须通过校验外部重排模型 query 数量必须与 query chunk 数量一致L1 与 search aggregation 组合被拒绝Function rerank 与 Search Iteratorlegacy/v2及order_by组合被拒绝。文档还指出“至多一个 sort”“sort 必须在最后”等更严格的排序约束可作为未来选项首版按用户下发顺序执行用户计划除非算子自身拒绝随后仅应用上述内部 L0/L1 reducer 规范化。可观测性QueryNode 复用milvus_querynode_function_chain_latency指标统计 L0 与 L1 执行L1 记录chain_levell1及既有 success/failure 状态标签。计时的 L1 阶段包含必需字段物化、链构建与执行、provenance 重建与内部规范化。指标标签必须保持有界字段名、表达式、集合名、链名不得作为指标标签。运行时错误走既有类型化错误路径非法用户计划与不受支持的组合是输入错误缺失内部字段、畸形 DataFrame、非法源索引、provenance 损坏、结果形状违规是系统/内部失败。为既有类型化错误追加上下文时应使用merr.Wrap/merr.Wrapf保证原始错误码存活。文档建议的后续指标方向按算子/函数类型的链执行延迟、重排内部取数字段数、外部 provider 延迟与按 provider 的错误计数、按校验类别的被拒链请求数。测试计划要点仓库中的测试覆盖与文档测试计划一一对应可直接定位验证SDK 测试builder 序列化、类型化参数序列化、col(...)校验、decay/num_combine/round_decimal/rerank_modelhelper 校验、L0/L1/L2 链编码、function_chainsranker拒绝等。Proxy/chain 规划测试function_chain_validator_test.go 覆盖function_score冲突、各 stage 重复链拒绝、L0/L1/L2 路由与共存、hybrid/advanced 拒绝、Iterator v2 与order_by冲突、L1 aggregation 拒绝等。QueryNode L1 测试l1_function_chain_test.go、search_task_go_reduce_test.go 覆盖map/sort/limit接受与filter/select/group_by拒绝、标量输入含 null物化、Int64/string PK 保真、同 PK 元素级结果、用户排序决定 limit 选择、内部规范化排序、Ragged TopKs、类型化内部错误、隐藏 provenance 列与 L1-only 输入不出现在结果字段、延迟指标恰记录一次等。归约与延迟物化测试L1 在延迟物化前执行、sort/limit 同步重排mergeResult.Sources、输出字段在重排/裁剪后仍与正确 hit 关联、混合 NQ/topK 合并后按请求切片、group-by 与元素元数据对齐、shard-leader 正确合并多 worker 的归一化 L1 输出、worker 本地 limit 语义显式化。L2 与回归测试buildChainFromMeta构建FuncChain、既有rerankOperator执行 proto 派生链、$scoremap/sort 改变结果顺序与分数、limit更新每 query TopK、requery 后必需字段可用但不出现在响应字段、L0L1L2 按阶段顺序执行、既有function_score与 legacy rank 行为不变、rerank_model可选外部 provider 测试以服务端凭据为门槛。端到端测试Python 与 REST 测试覆盖 L1 分数映射、隐藏标量输入、sortlimit、L0/L1/L2 组合、不兼容性校验、输出字段对齐、worker 本地候选预算语义。测试数据必须能区分 segment 本地 L0、worker 级 L1 与 Proxy 全局 L2以证明命中的是所选执行边界而非仅最终算术。文档给出的回归命令示例go test -tags dynamic,test -gcflagsall-N -l -count1 ./internal/util/function/chain/... go test -tags dynamic,test -gcflagsall-N -l -count1 ./internal/proxy/... -run FunctionChain|Rerank|L1 go test -tags dynamic,test -gcflagsall-N -l -count1 ./internal/querynodev2/tasks/... -run FunctionChain|L1|GoReduce由于 L1 改变了分布式排序、provenance 与延迟物化验证还包括完整 Go 测试套件与端到端失败模式追踪仅一条成功的成功路径搜索不足以证明 source 对齐或 worker 本地 limit 语义正确。SDK 测试从 PyMilvus 仓库或本地 checkout 运行。安全考虑外部模型重排会从 Milvus 服务端进程调用第三方服务安全要求如下API 凭据通过既有 provider 配置或凭据库在服务端解析SDKfunction_chains请求不应包含原始 API Keyprovider 凭据必须由既有凭据处理路径在日志中脱敏provider endpoint 应使用 HTTPS除非为可信本地测试显式配置发给外部 provider 的请求可能包含用户文本字段部署方必须将其视为数据出口data egress并相应配置 provider超时与批量上限必须防止无界的外部调用。兼容性与迁移不含function_chains的既有搜索请求行为不变既有function_score与 legacy rank 行为继续受支持公开 function chain 为 opt-in既有结果 schema 保持不变最终分数仍通过当前 score/distance 字段暴露。本 MEP 不引入任何弃用deprecation。当用户需要显式有序组合时可从function_score或 ranker API 迁移到function_chains首版不提供自动转换。被否决的备选方案在KeyValuePair中以 JSON 字符串编码参数被否决。链参数可能包含嵌套对象、数组、布尔、整数、浮点与字节JSON-in-string 会导致迟解析失败、弱类型信息、SDK 行为不一致、更弱的校验错误以及数值类型歧义。FunctionParamValue保证公开计划类型化。用function_score承载全部链行为被否决。function_score不是有序算子流水线无法自然表达带显式依赖的多步 map/sort/limit/model。为搜索管线新增独立functionChainOperator首版被否决。Function Chain 本质是另一种 rerank 实现复用rerankOperator可让 fetch/requery/最终投影与 legacy rerank 保持一致。在通用 chain 包中分类必需输入被否决。只有调用方知道某个名字是 schema 字段、请求负载字段、运行时系统值还是非法值chain 包只报告结构依赖。开放问题Hybrid search 的最佳公开 API 形态顶层 post-merge 链、每个 sub-search 各自的链还是两者兼有未来 L0/L1 阶段应允许哪些新增函数与算子L1 未来是否应支持 shard-leader 执行模式worker post-reduce 之外的第二种模式是否应强制严格算子排序规则例如至多一个sort且只能作为最后一个排序算子未来 API 是否允许用户显式返回中间变量是否应在 embedding 与 rerank 模型 provider 之间标准化 provider 专属指标进一步阅读路径设计文档原文docs/design-docs/design_docs/20260624-function-chain-api.md运行时核心包internal/util/function/chain含 repr.go、optimization_plan.go、pruning.go 与各算子/表达式实现Proxy 校验与规划internal/proxy/function_chain_validator.go、internal/proxy/search_pipeline.go、internal/proxy/task_search.goQueryNode L0/L1 执行internal/querynodev2/tasks/l0_function_chain.go、internal/querynodev2/tasks/l1_function_chain.go、internal/querynodev2/tasks/search_task_go_reduce.go、internal/querynodev2/tasks/querynode_function_chain.go内置表达式internal/util/function/chain/exprdecay、num_combine、round_decimal、rerank_model 及其测试外部模型 providerinternal/util/function/models【免费下载链接】milvusMilvus is a high-performance, cloud-native vector database built for scalable vector ANN search项目地址: https://gitcode.com/GitHub_Trending/mi/milvus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考