ArticutAPI: Rule-Based Chinese Word Segmentation and POS Tagging via HTTP
API for Articut, a Chinese word-segmentation tool with part-of-speech tagging. Word segmentation is fundamental to Chinese NLP. Articut uses no machine learning or trained models, only modern vernacular Chinese grammar rules, yet achieves over 94% F1 and over 96% recall on SIGHAN 2005.
At a glance
- What is it?
- ArticutAPI is a Python client for Droidtown's Articut service, which segments Chinese text and tags each word with a semantic part of speech using grammar rules rather than a trained model. It is a thin HTTP wrapper, so the quality of your results depends on the remote service and your network, not on anything installed locally.
- Who is it for?
- ArticutAPI suits Python teams that need Chinese segmentation with semantic POS tags and are willing to depend on a remote service for it. It is the wrong choice if you need offline processing, if your text is not Modern Standard Chinese, or if your budget cannot absorb per-character billing beyond the public quota.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 130 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem ArticutAPI addresses, and who it is for
Chinese text arrives without spaces. Any downstream task, from search indexing to intent classification, needs boundaries between words before it can do anything useful. The usual answer is a statistical segmenter trained on a labelled corpus. ArticutAPI takes the opposite route. The README states the design as computing segmentation from grammatical structure rather than statistical methods, and claims F1-measure above 94% and recall above 96% on SIGHAN 2005 without a data model. That claim is the project's own, published in its README, and it is the thing a prospective user should try to falsify on their own corpus rather than accept.
The library is for Python developers working with Modern Standard Chinese who want part-of-speech information attached to each segment, not just the boundaries. The tags are semantic rather than purely syntactic: parse output in the README shows labels such as ENTITY_pronoun, ACTION_lightVerb, MODAL and ENTITY_nouny. A tag like ENTITY_nouny tells you the word behaves as a noun without a fixed noun class, which is more than a generic NN label gives you. If your pipeline needs that distinction, this is the reason to look here. If you only need character offsets, a lighter segmenter will do.
How the parse call actually works
There is no local model. ArticutAPI.py wraps HTTP requests to api.droidtown.co, and the pyproject.toml dependency list is short: Python 3.6 or later, requests, and emoji. Nothing in the package performs segmentation on your machine. Every parse() call sends text to the service and returns a dictionary.
The returned dictionary carries the fields you build on: result_pos, a list of tagged strings, one per sentence; result_segmentation, the slash-delimited word string; exec_time; level; status; version; and word_count_balance. The version field is worth noticing. It reports something like v118, meaning the segmentation output is tied to a server-side engine version. Two calls a month apart can return different segmentations for the same input if the service has moved on, and the client code will not warn you. Pinning behaviour means recording the version field alongside your results.
The level parameter controls granularity. The README describes lv1 as the finest cut, suited to NLU or machine translation, and lv2 as the default, grouping into meaningful minimal units for text analysis and keyword extraction. The documented example is 小紅帽: at lv1 it becomes three tokens, 小 / 紅 / 帽, tagged MODIFIER, MODIFIER_color and ENTITY_nounHead; at lv2 it stays as one token tagged ENTITY_nouny. That single example is the clearest statement of the trade-off in the whole README. Choosing lv1 gives a model more pieces to reason over and more chances to lose the phrase-level meaning.
On top of parse, the client exposes helper methods that filter the parse output by tag family: getContentWordLIST, getVerbStemLIST, getNounStemLIST and getLocationStemLIST. Each returns lists of (start, end, word) tuples per sentence. In the documented example for 你計劃過地球人類補完計劃, the verb list contains 計劃 and 補 while the noun list contains 人類 and 計劃, so the same surface form appears in two lists with different offsets. That is the mechanism working as intended: the tag, not the string, decides membership.
Installing ArticutAPI and running a first parse
The README gives one install command. It pulls the client from PyPI; the service itself is not installed.
pip3 install ArticutAPIThe basic usage example constructs an Articut object with a username and API key. The README states that leaving both as empty strings falls back to a public quota of 2000 characters per hour, which is enough to evaluate the output on a few sentences. Credentials come from an account at api.droidtown.co.
from ArticutAPI import Articut
from pprint import pprint
username = "" # email used at https://api.droidtown.co; empty uses the 2000-char/hour public quota
apikey = "" # api Key from https://api.droidtown.co; empty uses the public quota
articut = Articut(username, apikey)
inputSTR = "會被大家盯上,才證明你有實力。"
resultDICT = articut.parse(inputSTR)
pprint(resultDICT)The response includes result_segmentation as a slash-separated string and result_pos as tagged strings. The README's own output for this sentence shows word_count_balance at 9985, which is how the remaining quota is reported back to you. Watch that field in development; it is the only quota signal the response carries.
To filter by tag rather than read the raw string, call the helper methods on the parse result. The README example requests lv1 explicitly before filtering.
inputSTR = "你計劃過地球人類補完計劃"
resultDICT = articut.parse(inputSTR, level="lv1")
contentWordLIST = articut.getContentWordLIST(resultDICT)
verbStemLIST = articut.getVerbStemLIST(resultDICT)
pprint(contentWordLIST)
pprint(verbStemLIST)Each helper returns a list of lists of (start, end, word) tuples, one inner list per sentence. The offsets are what you would use to slice the original string. Finally, articut.versions() returns the available engine versions with their levels and release dates, which is the cheapest way to confirm what the service currently offers before you build against a level.
The user-defined dictionary, and the boundary it draws
Articut handles language knowledge, not encyclopedic knowledge. The README states this directly and offers a user-defined dictionary as the remedy. The dictionary is a JSON file mapping a canonical term to a list of aliases.
{"雷姆":["小老婆"],
"艾蜜莉亞":["大老婆"],
"初音未來": ["初音", "只是個軟體"],
"李敏鎬": ["全民歐巴", "歐巴"]}Pass the path through the userDefinedDictFILE argument. The README's example contrasts the two runs on 我的最愛是小老婆,不是初音未來。 Without the dictionary, 初音 and 未來 are split and 未來 is tagged TIME_justtime, a plausible reading of the characters that is wrong in context. With the dictionary, 初音未來 is one token tagged UserDefined. Note the tag: matched entries get a dedicated UserDefined label rather than a linguistic one, so downstream code that filters on ENTITY_ or ACTION_ tags will not see them unless you handle that case. That is a real integration detail, not a footnote.
The repository also contains a Public_UserDefinedDict/ directory and an opendata_place option that, per the README, marks place names from a government tourism open-data set as KNOWLEDGE_place. The README's request example includes opendata_place set to true alongside version and level. The documentation does not describe how that dataset is refreshed or what happens when it changes, so treat place tagging as a convenience rather than a stable contract.
Throughput, batching, and where the client stops helping
The README publishes three clients with different transport strategies. ArticutAPI uses HTTP requests and is described as simple to use, for any scenario. MP_ArticutAPI uses multiprocessing and a bulk_parse(bulkSize=20) method for batch text analysis. WS_ArticutAPI uses WebSockets for real-time work such as chatbots. The published timing table, measured on a 4-core CPU with 4 processes, lists 1K sentences at 155 seconds through ArticutAPI, 8 seconds through MP_ArticutAPI and 18 seconds through WS_ArticutAPI; 3K sentences at 455, 17 and 43 seconds respectively. Those are the project's figures from its own README, not an independent measurement.
The shape of the numbers is the useful part. The naive serial client scales linearly, so a corpus of any size becomes a scheduling problem rather than a segmentation problem. bulk_parse exists precisely because the single-call path does not amortize well. If you adopt ArticutAPI for anything beyond interactive use, plan on the multiprocessing path from the start.
One thing the README does not document is failure behaviour. There is no described retry policy, no rate-limit response format, no statement about what happens when the service is unreachable mid-batch, and no rollback mechanism for a partially completed bulk run. For a client whose entire function is a network call, that silence is the largest gap in the documentation. You will be writing your own retry and checkpointing logic, and you should budget for it.
When ArticutAPI is the wrong tool
The remote dependency is the first disqualifier. If your text cannot leave your infrastructure, this library cannot process it, because the segmentation happens on Droidtown's servers. There is no local segmentation path in the package. An air-gapped deployment, a regulated data pipeline, or a latency-sensitive loop that cannot tolerate a round trip all rule this out.
The second is language scope. The README frames the system around Modern Standard Chinese grammar rules. Nothing in the README suggests coverage of Classical Chinese, Cantonese-specific vocabulary, or mixed-script text beyond what the rules happen to handle. If your corpus is not Modern Standard Chinese, the rule-based premise works against you: there is no training step that would let you adapt the model to your data. The user-defined dictionary is a term list, not an adaptation mechanism.
The third is determinism across time. Because the engine version is server-side, reproducibility requires you to record the version field with every result. A pipeline that needs byte-identical output from a fixed input over months cannot get that guarantee from a hosted service whose segmentation rules are still being revised.
Finally, the public quota of 2000 characters per hour will not carry a production workload. Anything at scale means credentials and billing, and the README does not state the pricing or the request rate limits.
How this differs from jieba and from fine-tuned transformer taggers
jieba is the obvious comparison for a Python user. It is a local library: you install it and it segments on your machine with no account, no quota and no network. Its dictionary-based approach means you can add words by editing a dictionary file, and you can run it inside a container with no egress. The difference in approach is exactly the difference the Articut README claims as its advantage: jieba's segmentation comes from dictionary matching and statistics, while Articut's comes from grammar rules evaluated server-side. In practice the trade is local control and zero marginal cost against semantic tag depth. jieba gives you boundaries and a coarse POS tag; Articut gives you labels like ACTION_lightVerb and ENTITY_nouny plus helper methods that filter on them. If you need the semantic categories, jieba will not give you them without extra work.
The other comparison is a fine-tuned transformer tagger, whether a multilingual BERT variant or a Chinese-specific model. That approach requires labelled data, GPU time for training or inference, and a model artifact you version and serve yourself. ArticutAPI requires none of that: a pip install and an HTTP call. The cost is that you cannot inspect or modify the rules, you cannot fine-tune on your domain, and you inherit whatever the service does next. For a team without labelled Chinese data and without GPU capacity, the hosted rule-based route is a shorter path to a working pipeline. For a team that already has annotation budget and needs full control, it is a detour.
Licence, maintenance and upgrade cost
The client is MIT licensed, stated in both the LICENSE file and pyproject.toml. That covers the Python code in this repository. It does not cover the Articut service, which is a separate hosted product with its own account terms, and the README does not state what those terms are. Do not read the MIT licence on the client as a licence for the segmentation engine.
The dependency surface is small, which keeps upgrade cost low: requests and emoji, with Python 3.6 through 3.x declared in pyproject.toml. The repository's last push was on 2026-06-04, and the most recent release listed is v1.3.9 on 2026-02-10, following v1.3.7 in November 2024 and v1.3.6 in January 2024. Note that pyproject.toml and setup.py both declare version 1.4.0 while the release list stops at v1.3.9, so the repository state and the release tags do not line up. Check which version pip actually resolves before assuming you have the code in the working tree.
The upgrade risk is not in the client, which changes rarely. It is on the server. Since segmentation output is versioned by the engine and the client does not pin it, an upgrade can change your results without a code change on your side. If you need stable output, record the version field and re-run a fixed evaluation set after any dependency bump.
Editorial conclusion
ArticutAPI suits Python teams that need Chinese segmentation with semantic POS tags and are willing to depend on a remote service for it. It is the wrong choice if you need offline processing, if your text is not Modern Standard Chinese, or if your budget cannot absorb per-character billing beyond the public quota. Before adopting, run articut.versions() to confirm which levels the service currently exposes, check the word_count_balance field in a parse result to understand how quota is reported, and test your own domain vocabulary against the userDefinedDictFILE mechanism, since Articut deliberately excludes encyclopedic knowledge.
Frequently asked questions
What does ArticutAPI do for Chinese text?
It sends Chinese text to the Articut service and returns word segmentation plus semantic part-of-speech tags, along with a slash-delimited segmentation string and helper methods that filter words by tag family such as noun, verb or location.
How do I install ArticutAPI?
The README gives a single command, pip3 install ArticutAPI, which installs the Python client. The segmentation itself runs on the remote service, so no model is installed locally.
Can I use ArticutAPI without an account?
Yes, the README states that passing empty strings for username and apikey falls back to a public quota of 2000 characters per hour. Beyond that you need credentials from api.droidtown.co.
What is the difference between lv1 and lv2 in ArticutAPI?
The README describes lv1 as the finest cut, suited to NLU or machine translation, and lv2 as the default, grouping into meaningful minimal units for text analysis and keyword extraction. The documented example splits 小紅帽 into three tokens at lv1 and keeps it as one at lv2.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/droidtown-articutapi)