Skip to main content

Sentences

Utilities for sentence-level text segmentation and tokenization tailored to LLM tokenizers.

This package is designed to support sentence-level (“Thought Anchor”) analyses like those in:

Bogdan, P. C.*, Macar, U.*, Nanda, N.°, & Conmy, A.° Thought anchors: Which LLM reasoning steps matter? 2025. https://arxiv.org/abs/2506.19143.

Features

  • Splits a given text into sentences
  • Avoids common issues (e.g., "Dr. Fu" shouldn't be split into two sentences)
  • Respects standard LLM tokenization patterns (e.g., leading-space tokens)
  • Given a tokenizer, returns token ranges for each sentence in the tokenized input text

Installation

pip install sentences

Sentence Splitting

Sentences split here adhere to typical LLM tokenization strategies. For example, this sentence "I love my cat. It is big." should be split with a leading space rather than a trailing one, ["I love my cat.", " It is big."]

from sentences import split_text_to_sentences

text = "Dr. Smith went to the store. They bought some milk. It cost $3.50."
sentences, positions = split_text_to_sentences(text)

for i, (sent, pos) in enumerate(zip(sentences, positions)):
    print(f"{i}: {repr(sent)}")
    # 0: 'Dr. Smith went to the store.'
    # 1: ' They bought some milk.'
    # 2: ' It cost $3.50.'

Token Range Extraction

You can use this package to get the exact token ranges for sentences. You can use this to split up a model's chain-of-thought into sentences. You can include pre_string, where you provide a string that will appear before your sentences (e.g., a chat template), and the token ranges will respect that.

Token ranges are calculated by repeatedly appending a new sentence to the pre_string, tokenizing the new string, and counting the number of tokens. This helps avoid tokenization oddities. Simply tokenizing each sentence independently can cause problems.

from sentences import get_token_ranges
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-14B-Instruct")

# Example with Qwen-2.5 chat template
pre_string = """<|im_start|>system
This system message is just for demonstration purposes.<|im_end|>
<|im_start|>user
Solve this math problem step by step.<|im_end|>
<|im_start|>assistant
<think>

"""

sentences = ["Let me think about this problem.", " First, I'll break it down."]
ranges = get_token_ranges(sentences, tokenizer, pre_string)
tokens_all = tokenizer.batch_decode(tokenizer.encode(pre_string + ''.join(sentences)))

for sent, (start, end) in zip(sentences, ranges):
    print(f"Tokens [{start}:{end}] = '{sent}'\n\t{tokens_all[start:end]}")
    # Tokens [39:46] = 'Let me think about this problem.'
    #   [' Let', ' me', ' think', ' about', ' this', ' problem', '.']
    # Tokens [46:54] = ' First, I'll break it down.'
    #   [' First', ',', ' I', "'ll", ' break', ' it', ' down', '.']

Note on CoT pre-filling

gpt-oss models don't use <think> tags but instead employ a special format:

pre_string = """<|start|>system<|message|>You are ChatGPT, a large language model trained by OpenAI.
Knowledge cutoff: 2024-06
Current date: 2025-11-22<|end|><|start|>user<|message|>Solve this math problem step by step.<|end|><|start|>assistant<|channel|>analysis<|message|>"""

Metadata

Release files for sentences 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sentences 0.1.1
File Size Uploaded
sentences-0.1.1.tar.gz 11.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sentences 0.1.1
File Interpreter ABI Platform
sentences-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 21.1 kB

Release files / sentences-0.1.1.tar.gz

Download URL sentences-0.1.1.tar.gz
Size 11.1 kB
Tags Source
SHA-256 checksum
How to use checksums
393c8cb3b0bc8318d9b09f2d9bfb16b06d03269feb9e966e0f6be87ed8ce9113
BLAKE2b-256 checksum
How to use checksums
d9dc4676179d4d163deffb8d7befadd02ea522998aa59db6b9a5596c652eb25e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.4

Release files / sentences-0.1.1-py3-none-any.whl

Download URL sentences-0.1.1-py3-none-any.whl
Size 10.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a02cd71281a38d373678923969ec96faca5bec25e7ab294435fbb6e456cb1da7
BLAKE2b-256 checksum
How to use checksums
6881a422227ae6fafa3f14eba006e6fa206eeff1ad3239e98646dcd75f81be25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.4

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page