文本按分隔符分割
Cut the thinking out of a model's output before it reaches your prompt
- ALL
- LIST
- SEGMENT
If you've wired an LLM into a ComfyUI graph to rewrite prompts - and plenty of people have, because a local model beats retyping your idea into shape - you've met the failure mode where the model hands you its working out along with the answer. The KB describes this precisely: a chat model emits role delimiters, preambles, markdown scaffolding, and if you're unlucky a <think> block full of deliberation, and all of it goes straight into your conditioning. 文本按分隔符分割 (QG_TextSplit) is the cheap fix: split on the junk, keep the part you wanted.
The default delimiter is <think>, which tells you exactly who this node was built for.
How it works
input_source picks where the text comes from - 文本框 uses the multiline text box below it, 外部列表 uses whatever list is wired into texts. delimiter is the split string, and with use_regex on it's interpreted as a regular expression instead of a literal. Empty pieces are dropped after trimming whitespace, so a split that leaves blanks around the seams doesn't produce phantom empty segments.
Then there are three outputs, and the three index knobs that drive them - this is the part that needs reading twice:
- ALL - every segment from every input text, concatenated into one list. Controlled by
total_index:0means "give me everything",Nmeans "from each input, take only segment N". - LIST - the full split of one chosen input text, controlled by
list_index(1-based;0gives you an empty list). - SEGMENT - a single string, controlled by
segment_index(1-based;0gives an empty string).
There's a wrinkle in SEGMENT that isn't obvious from the tooltips: in 文本框 mode it indexes into the full segment pool of your typed text, while in 外部列表 mode it indexes into the segments of the text selected by list_index. Same knob, two different pools. Once you know, it's logical - you need to pick a text before you can pick its segment - but the first time it bites.
A delimiter that doesn't appear in the text produces one segment: the whole thing. Splitting is not filtering.
Inputs and outputs
Required: input_source, text, delimiter (default <think>), use_regex (default off), segment_index, list_index, total_index. Optional: texts (the external list).
Outputs: ALL (list), LIST (list), SEGMENT (single string).
The realistic wiring for the thinking-block case: LLM output → texts, delimiter left at <think>, regex off, take ALL and read segment 2, or take SEGMENT with segment_index: 2. Then straight into a converted prompt input. That's a two-node guard against an entire class of contaminated prompt.
Other uses it's genuinely good at: pulling the second paragraph out of a multi-paragraph document loaded with 加载文档, splitting a CSV-ish line into fields, or reaching into a batch of generated captions and grabbing the first sentence of each via total_index: 1.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/live1617/ComfyUI-QG-tools
Full restart; console should print [QG-tools] v0.9.2 加载完成 | 节点数 24. Manager search ComfyUI-QG-Tools where the registry listing exists. Nothing to pip install - the pack's requirements file is deliberately comments-only so Manager skips its pip step entirely.
Ported from ComfyUI_Muye (MIT), itself an enhanced version of a simpler splitter. Search split, delimiter, segment or 文本分割.
Where people get burned
<think> isn't the only wrapper. Different models use different tags, and some don't tag at all - a reasoning model that just leaks its scratch work into prose gives you nothing to split on. The KB's advice on in-graph LLMs is blunt here: the job wants small and obedient models, and a reasoner is more likely to leak. Splitting is a safety net, not a cure.
Regex mode swallows more than expected. A delimiter like . as a regex matches every character and shreds your text into single letters. Escape it. If you can't remember whether something is special, put \ in front and check the result.
Indexes are 1-based, and 0 means something different per output. total_index: 0 is "all", list_index: 0 is "nothing", segment_index: 0 is "empty string". Three different meanings for zero on one node is a design that will catch you once.
Out-of-range indexes return nothing, without complaint. Ask for segment 7 of a 3-segment text and you get an empty string, which then flows happily downstream and produces a prompt that's silently blank. Check with a preview node when a generation comes out unprompted-looking.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| input_source | COMBO | 文本框 | 文本框:用下面的单段文本;外部列表:用接进来的 texts |
| text | STRING | 要分割的多行文本(仅在「文本框」模式下使用) | |
| delimiter | STRING | <think> | 分隔符;打开「使用正则」后按正则解释(默认值适合切掉模型的思考块) |
| use_regex | BOOLEAN | false | 开:分隔符按正则表达式处理;关:按普通字符串切 |
| segment_index | INT | 10–100 | SEGMENT 输出取第几段(从 1 开始;0 = 输出空字符串) |
| list_index | INT | 10–100 | LIST 输出取第几条输入文本的完整分割(从 1 开始;0 = 输出空列表) |
| total_index | INT | 00–100 | ALL 输出:0 = 列出所有段落;N = 每条文本只取第 N 段 |
| textsopt | STRING | 外部文本列表(仅在「外部列表」模式下使用) |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| ALL | STRING | 所有输入文本分割后的段落合集(受 total_index 影响)。 |
| LIST | STRING | 选定那条输入文本的完整分割结果(受 list_index 影响)。 |
| SEGMENT | STRING | 选定的单个段落(受 segment_index 影响)。 |