I built OmniToken, a pure-Go tokenizer library for local token counting, encoding, and decoding in Go services.
It supports OpenAI-compatible BPE encodings:
- cl100k_base
- o200k_base
- o200k_harmony
Why I built it:
I wanted local prompt sizing, context-window planning, and cache-boundary analysis in Go without requiring Python, Rust, CGO, or a hosted API call.
Benchmarked on Windows 11 / Intel i7-1250U / Go 1.24.2:
- CountTokens vs tiktoken-go: 15.84x faster geomean
- EncodeOrdinary vs tiktoken-go: 13.09x faster geomean
- Decode vs tiktoken-go: 2.29x faster geomean
- CountTokens vs OpenAI Rust tiktoken: 0.96x, near parity
- EncodeOrdinary vs OpenAI Rust tiktoken: 0.75x, competitive pure Go
The CountTokens path avoids materializing the token slice and hits 0 B/op / 0 allocs/op on supported OpenAI BPE workloads.
Correctness:
For supported OpenAI ordinary-text encodings, OmniToken includes parity tests, including a deterministic 50,000-case reference corpus.
It also includes:
- CountTokens / EncodeOrdinary / Decode APIs
- prompt-cache alignment planner
- benchmark harness comparing against tiktoken-go and OpenAI Rust tiktoken
- optional adapters for Gemini, Llama 3, Mistral, Hugging Face tokenizer.json, OSS SentencePiece models, and Anthropic message counting
The repo is public on GitHub under:
ron2111 / omnitoken
The Go package is available on pkg.go.dev as:
github.com/ron2111/omnitoken
I’d appreciate feedback from Go developers using OpenAI APIs:
- Are the model mappings useful?
- Any tokenization edge cases I should add?
- Should special-token-aware encode be next?
- Would streaming token counting help your workflows?