向量匹配丨分类
Free text into a fixed category list, via embeddings — and the setup it quietly demands
- 类目
- 分数
- 状态
- 匹配层级
- 匹配ID
- 总类目
- 调试信息
Here's the problem VectorMatcher solves: you have a fixed list of categories - say a storefront taxonomy with levels like 餐饮行业 → 中式正餐 → 高端酒楼 - and users keep typing free-form text that doesn't match any of them exactly. "我晚上想吃个高端点的粤菜馆" is not equal to any category name. VectorMatcher embeds both sides, measures semantic similarity, and maps the loose text onto your whitelist with a confidence score.
It's the most ambitious node in this pack's data tools, and the one that demands the most setup. Be warned up front: unlike the rest of QING, this node will not just work out of the box.
How it works
At runtime, three things have to exist:
- A sentence-transformers model (default
bge-base-zh-v1.5) to embed the query. The node looks for it in ComfyUI'smodels/embeddingsdirectory, or hands the name to sentence-transformers, which downloads it from HuggingFace on first use. - A precomputed index:
vectors.npy(embedding vectors, one per category) plusmeta.json(the category rows). By default these are read from the pack'sdata/vectors.npyanddata/meta.json. - The rules config (optional) that powers query fusion.
The query gets a Chinese retrieval-instruction prefix (the standard BGE usage pattern: "为这个句子生成表示以用于检索相关文章:"), gets embedded, and the node computes cosine similarity against every category vector. Then it makes a hierarchical decision - it checks the best category, then aggregates up to level 3, level 2, level 1 - and each level must clear two bars to be accepted: a top-1 score at or above top1_threshold (default 0.38) and a gap between the best and second-best candidate at or above a gap threshold (default 0.03, with tighter per-level values). Output status reflects the outcome: 命中 (ok), 未命中 (no_match), 模糊 (ambiguous), or 错误 (error).
Query fusion (on by default) builds three weighted query variants - raw, keyword, and industry - from the rules profile and blends their scores, so a storefront-style query matches on category and on its industry/keyword aliases. If no rules file exists, it silently falls back to a single raw query (and warns in the console).
The honest setup cost
This is where people get burned. The pack ships only data/storefront_categories.json.example - an example taxonomy, not a built index. There is no vectors.npy and no meta.json in the repo. So for VectorMatcher to return anything but an error, you need to:
- Install
sentence-transformersyourself - it is not in the pack'srequirements.txt(that lists Pillow, opencv, scipy, scikit-image, cairosvg, openai). - Build your index from your own category list using the companion
ConvertDataToVectorsnode (which turns a category JSON like the example into vectors + meta). - Have the embedding model reachable - either in
models/embeddingsor via a working HuggingFace download.
The error output is actually decent about this: a failure returns empty 类目, score 0, status 错误 (error), and the 调试信息 output with the traceback and the resolved file paths. Read that output before anything else.
Inputs and outputs
user_text(required) - the free text to classify.model_name_or_path- the embedding model (dynamically lists models found in your embeddings dirs).vectors_path/meta_path- where your built index lives; defaults to the pack'sdata/paths.top1_threshold,gap_threshold,level1/2/3_gap_threshold- the acceptance bars. Lowertop1_thresholdif matches keep coming back "no match".return_topk- how many candidates feed the decision (default 3).enable_query_fusion,raw_query_weight,keyword_query_weight,industry_query_weight- blending weights for the three query variants.rules_path,rules_profile- optional rules config and profile for query fusion.- Outputs:
类目(category name),分数(score),状态(status text),匹配层级(category/level3/level2/level1),匹配ID(category id),总类目(full joined level path),调试信息(JSON debug).
Installing it
VectorMatcher ships in ComfyUI-QING:
cd ComfyUI/custom_nodes
git clone https://github.com/GAO-SHIQING/ComfyUI-QING
cd ComfyUI-QING
python install_dependencies.py
Then, separately, the node's real dependency:
cd ComfyUI-QING
pip install sentence-transformers
Restart ComfyUI. ComfyUI Manager users: install "ComfyUI-QING" from the GUI, then add sentence-transformers manually.
Troubleshooting
- Status
错误 (error)and调试信息mentions "sentence-transformers 导入失败". That's the missing package above. - Debug shows missing
vectors.npy. You haven't built an index. Run your category list throughConvertDataToVectorsfirst; the example file shows the expected schema. - Everything returns
未命中. Yourtop1_threshold(0.38 default) is probably too high for your category set - cosine scores for weak categories sit lower. Drop it to ~0.25–0.3 and re-test. 模糊 (ambiguous). Best score cleared the bar but the gap to the runner-up didn't. Tighten your taxonomy so categories are more distinct, or lowergap_threshold.
This is genuinely the right tool for "classify loose text into a fixed list" - the kind of job an LLM does sloppily and expensively per call. Just budget the setup time, because the node assumes you read its companion ConvertDataToVectors and built an index first.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| user_text | STRING | — | |
| model_name_or_pathopt | COMBO | bge-base-zh-v1.5 | 1 options: bge-base-zh-v1.5 |
| vectors_pathopt | STRING | — | |
| meta_pathopt | STRING | — | |
| top1_thresholdopt | FLOAT | 0.380–1 | — |
| gap_thresholdopt | FLOAT | 0.030–1 | — |
| level3_gap_thresholdopt | FLOAT | 0.0100–1 | — |
| level2_gap_thresholdopt | FLOAT | 0.0080–1 | — |
| level1_gap_thresholdopt | FLOAT | 0.0050–1 | — |
| return_topkopt | INT | 31–20 | — |
| enable_query_fusionopt | BOOLEAN | true | — |
| raw_query_weightopt | FLOAT | 0.200–1 | — |
| keyword_query_weightopt | FLOAT | 0.500–1 | — |
| industry_query_weightopt | FLOAT | 0.300–1 | — |
| rules_pathopt | STRING | — | |
| rules_profileopt | STRING | — |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| 类目 | STRING | — |
| 分数 | FLOAT | — |
| 状态 | STRING | — |
| 匹配层级 | STRING | — |
| 匹配ID | STRING | — |
| 总类目 | STRING | — |
| 调试信息 | STRING | — |