feat(inference): CJK 保守 token 估算(T9 架构审查整改)

- Issue11: approximate_token_count 重写
  - 新增 _is_cjk_char(CJK 统一表意/扩展A/假名/韩文/兼容/全角六大 Unicode 范围)
  - CJK 字符按 1.5 token/字符(旧 4 字符 1 token 严重低估,裁剪失效致 API 超限)
  - 其余字符仍 4 字符 1 token;最少 1 token
- 同步 config-design.md token_estimation 注释
- 新增 4 用例,全量 186 passed / 100.00%(995 stmts/252 br)
This commit is contained in:
lhl
2026-08-12 09:54:20 +08:00
parent 8239a37a99
commit 8febc50eb8
4 changed files with 53 additions and 3 deletions
+24 -2
View File
@@ -1,11 +1,33 @@
from __future__ import annotations
import unicodedata
from typing import Callable
# CJK 每字符保守 token 数(T9 整改:cl100k/4字符1token 对中文/日文严重低估)
# 日文/中文实际每字符 1~3 token,取保守 1.5 防止上下文裁剪失效导致 API 超限
_CJK_TOKENS_PER_CHAR = 1.5
def _is_cjk_char(ch: str) -> bool:
"""判断字符是否属于 CJK 密集区(中文/日文假名/韩文/全角符号)。"""
cp = ord(ch)
return (
0x4E00 <= cp <= 0x9FFF # CJK 统一表意文字
or 0x3040 <= cp <= 0x30FF # 平假名/片假名
or 0xAC00 <= cp <= 0xD7AF # 韩文音节
or 0xF900 <= cp <= 0xFAFF # CJK 兼容表意文字
or 0xFF00 <= cp <= 0xFFEF # 全角形式(全角标点/字母)
or 0x3400 <= cp <= 0x4DBF # CJK 扩展 A
)
def approximate_token_count(text: str) -> int:
"""内置近似估算:每 4 字符 ≈ 1 token(无外部依赖,可离线)。"""
return max(1, (len(text) + 3) // 4)
"""内置近似估算(T9 CJK 保守):CJK 字符按 1.5 token/字符,
其余字符按 4 字符 ≈ 1 token;最少 1 token(无外部依赖,可离线)。"""
cjk_chars = sum(1 for ch in text if _is_cjk_char(ch))
other_chars = len(text) - cjk_chars
tokens = cjk_chars * _CJK_TOKENS_PER_CHAR + (other_chars + 3) // 4
return max(1, int(tokens))
def _tiktoken_estimator(text: str) -> int | None: