nikhil8725/TokenLens

GitHub: nikhil8725/TokenLens

一个纯本地运行的 LLM token 效率诊断中间件,通过一行代码封装 SDK 即可检测并指导开发者消除 token 浪费。

Stars: 0 | Forks: 0

# token-lens **本地 LLM token 效率中间件。** 只需一行代码即可封装你现有的 LLM 客户端。它能检测 token 浪费模式,并在开发过程中向终端输出可操作的建议 —— 全程零云端依赖,且没有任何数据离开你的设备。 ``` ⚠ [token-lens TL006] No max_tokens set on call to 'openai/gpt-4o-mini'. → Without a cap, a misbehaving prompt can generate thousands of tokens and spike costs. ⚠ [token-lens TL001] System prompt is identical across 3+ consecutive calls (~120 tokens each). → Use prompt caching. Potential saving: ~80% of system prompt tokens. ── token-lens session summary ── calls: 3 prompt tokens: 612 completion tokens: 187 total tokens: 799 openai/gpt-4o-mini: 3 call(s), 799 tokens ``` ## 为什么选择 token-lens? 现有工具 —— Helicone、AgentOps、LangSmith、PromptLayer —— 都是可观测性平台:它们通过云服务来**统计** token。token-lens 在以下三个方面与众不同: | | token-lens | 云端工具 | |---|---|---| | **数据离开你的设备** | 绝不 | 会 | | **设置** | 一行代码 | 账号 + API key + 代理/SDK | | **功能** | 检测*为什么* token 会被浪费 | 统计已经消耗的 token | | **离线可用** | 是 | 否 | | **企业级部署** | 在你的服务器上 `pip install` | 需要签订商业协议 | ## 支持的提供商 token-lens 兼容**任何暴露了 `chat.completions.create()` 接口的 SDK**,并为原生 Anthropic SDK 提供了专用适配器。 | 提供商 | SDK | 封装器 | |---|---|---| | OpenAI | `openai` | `TokenLens` | | OpenRouter | `openai` (兼容模式) | `TokenLens` | | Groq | `groq` | `TokenLens` | | Together AI | `openai` (兼容模式) | `TokenLens` | | Azure OpenAI | `openai` | `TokenLens` | | Ollama | `openai` (兼容模式) | `TokenLens` | | Perplexity | `openai` (兼容模式) | `TokenLens` | | Mistral | `openai` (兼容模式) | `TokenLens` | | Anthropic | `anthropic` (原生) | `AnthropicTokenLens` | | LangGraph / LangChain | 通过回调支持任何 SDK | `TokenLensCallbackHandler` | ## 安装 ### 从 PyPI 安装(推荐) ``` pip install llm-token-lens ``` 如需实现准确的 token 统计(强烈推荐): ``` pip install "token-lens[accurate-counting]" ``` 如需支持 LangGraph / LangChain 回调: ``` pip install "token-lens[langgraph]" ``` 一次性安装所有组件: ``` pip install "token-lens[accurate-counting,langgraph]" ``` ### 从源码安装 ``` git clone https://github.com/nikhilbahalkar/llm-token-lens.git cd llm-token-lens pip install -e ".[accurate-counting,dev]" ``` ## 快速开始 ### OpenAI / 兼容 OpenAI 的提供商 只需修改一行代码 —— 其余部分保持不变: ``` from openai import OpenAI from token_lens import TokenLens # ← add this import # 之前: # client = OpenAI(api_key="...", base_url="...") # 之后: client = TokenLens(OpenAI(api_key="...", base_url="...")) # ← wrap it # 所有现有的调用点保持不变: response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "Hello!"}], max_tokens=256, ) ``` 对于 **Groq、OpenRouter、Together AI、Azure OpenAI、Ollama** 以及任何其他提供兼容 OpenAI 的 SDK 的提供商,工作方式完全相同 —— 只需封装客户端即可。 ### Anthropic ``` import anthropic from token_lens import AnthropicTokenLens # ← use the dedicated adapter client = AnthropicTokenLens(anthropic.Anthropic(api_key="...")) response = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=256, messages=[{"role": "user", "content": "Hello!"}], ) ``` ### LangGraph / LangChain 如果你使用的是 `ChatOpenAI` 或 `init_chat_model`(而不是原始的 OpenAI SDK),请使用回调处理器: ``` from token_lens import TokenLensCallbackHandler handler = TokenLensCallbackHandler() # 作为 callback 传递给任何 LangGraph 或 LangChain 调用: result = app.invoke(state, config={"callbacks": [handler]}) # 手动打印 session 摘要(或者在进程退出时自动触发): handler.session_report() ``` ## 配置 传入 `Config` 对象即可调整或屏蔽任何规则: ``` from token_lens import TokenLens, Config client = TokenLens( OpenAI(...), Config( # Raise the system-prompt-repeat threshold from 3 to 5 static_prompt_repeat_threshold=5, # Disable specific rules by ID disabled_rules={"TL007"}, # Turn off ANSI colors (e.g. in CI) no_color=True, # Disable the automatic session summary at process exit auto_report_on_exit=False, # Turn off all analysis entirely (e.g. in production) enabled=False, ), ) ``` ### 配置参考 | 字段 | 默认值 | 描述 | |---|---|---| | `enabled` | `True` | 主开关 —— 在生产环境中设置为 `False` | | `no_color` | `False` | 在输出中禁用 ANSI 颜色 | | `auto_report_on_exit` | `True` | 进程退出时输出会话摘要 | | `static_prompt_repeat_threshold` | `3` | 触发 TL001 前的调用次数 | | `history_message_threshold` | `20` | 触发 TL002 前的非系统消息数 | | `high_tier_models` | (见下文) | 被视为“高级别”以触发 TL004 的模型名称 | | `simple_task_completion_token_threshold` | `80` | 触发 TL004 的补全 token 数下限 | | `system_prompt_token_threshold` | `500` | 触发 TL005 的 token 数上限 | | `redundant_context_jaccard_threshold` | `0.70` | 触发 TL007 的重叠率比例 | | `redundant_context_min_words` | `50` | 应用 TL007 的最小消息长度 | | `pii_check_roles` | `{"user","system","tool"}` | 将扫描以检测 PII (TL008) 的消息角色 | | `tool_result_token_threshold` | `500` | 触发 TL011 的 token 数量阈值 | | `max_tools_per_call` | `15` | 触发 TL012 的工具数量阈值 | | `spike_min_calls` | `5` | 激活 TL014 前所需的最小基线调用次数 | | `spike_multiplier` | `3.0` | 触发 TL014 所需的会话平均值倍数 | | `disabled_rules` | `set()` | 要跳过的规则 ID 集合(例如 `{"TL004", "TL007"}`) | ### 环境变量 | 变量 | 效果 | |---|---| | `NO_COLOR` | 禁用 ANSI 颜色(社区标准) | | `TOKEN_LENS_NO_COLOR` | 同上,token-lens 专用 | ## 检测规则 | ID | 名称 | 阶段 | 触发条件 | 建议 | |---|---|---|---|---| | **TL001** | 静态系统提示词 | post | 连续调用使用相同系统提示词 ≥ N 次 | 使用提示词缓存(OpenAI 自动缓存 >1024 个 token;Anthropic:`cache_control`) | | **TL002** | 无限制的历史记录 | post | 非系统消息超过 20 条且持续增加 | 使用 `trim_messages()` 或添加摘要节点 | | **TL003** | 重复的提示词 | post | 发送完全相同的消息列表 ≥ 2 次 | 添加以提示词哈希为键的结果缓存 | | **TL004** | 模型过剩 | post | 高级别模型,补全 token < 80,单条消息 | 对于简单任务,切换到更小/更便宜的模型 | | **TL005** | 冗长的系统提示词 | post | 系统提示词超过 500 个 token | 将静态事实移至检索;精简提示词 | | **TL006** | 缺失 max_tokens | pre | 既没有设置 `max_tokens` 也没有设置 `max_completion_tokens` | 添加 `max_tokens=<预期的上限>` | | **TL007** | 冗余的上下文 | post | 两条消息的词汇重叠度 >70%(各 >50 个词) | 对其进行去重并整合到系统提示词中 | | **TL008** | 提示词中包含 PII | pre | 在 user/system/tool 消息中检测到电子邮件、电话号码、信用卡、社会安全代码或 IP 地址 | 在发送给提供商之前移除或匿名化 PII (GDPR/CCPA) | | **TL009** | 提示词中包含密钥 | pre | 在任何消息中检测到 API key、Bearer token 或 PEM 密钥 | 立即移除凭据;轮换任何已暴露的密钥 | | **TL010** | 未固定版本的模型 | post | 使用了未固定版本的模型别名(例如 `gpt-4o`、`claude-3-5-sonnet`) | 固定到带有日期的版本,以防止行为发生隐蔽变更 | | **TL011** | 工具结果臃肿 | post | 工具/函数返回结果超过 token 阈值 | 在将结果返回给模型之前进行摘要或过滤 | | **TL012** | 过多的工具 | pre | 单次调用中注册了超过 N 个工具 | 过滤工具,仅保留与当前上下文相关的工具 | | **TL013** | 缺失 response_format | pre | 系统提示词要求返回 JSON,但未设置 `response_format` | 添加 `response_format={"type": "json_object"}` 以保证输出有效的 JSON | | **TL014** | 成本激增 | post | 调用 token 数 ≥ 会话平均值的 3 倍(在至少 5 次基线调用后) | 排查庞大的工具结果、无限制的历史记录或失控的提示词 | | **TL015** | n>1 次补全 | pre | 在 kwargs 中传入了 `n > 1` | 使用 `n=1`;通过改变 temperature 或提示词来获取多样性 | 所有规则仅输出到 **stderr** —— 你的 `stdout` 管道永远不会被中断。 ## 隐私与数据处理 **token-lens 绝不会向任何地方发送任何数据。** - 所有分析均在进程内和内存中运行。 - token-lens 本身不会发起任何网络连接。 - 不会向磁盘写入任何日志。 - 没有遥测、没有分析、没有向外部服务的回调。 - 你的提示词、补全内容和 API key 永远不会受到 token-lens 的干涉 —— 它们会原封不动地直接传递给你的 SDK。 这使得 token-lens 可以安全地部署在企业服务器和物理隔离环境中。 ## 企业级 / 服务器部署 适用于希望在所有服务中推行 token 效率标准的团队: 1. 将 `token-lens` 添加到你共享的 `requirements.txt` 或 `pyproject.toml` 中 2. 使用 `TokenLens` 封装你共享的 LLM 客户端工厂 3. 通过 `Config(enabled=os.getenv("TOKEN_LENS_ENABLED", "true") == "true")` 进行配置,以便在生产环境中禁用,同时在预发布/开发环境中保持开启状态 ``` # shared_llm.py — 你的团队的核心 LLM 客户端模块 import os from openai import OpenAI from token_lens import TokenLens, Config _base_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"]) client = TokenLens( _base_client, Config(enabled=os.getenv("ENV", "dev") != "prod"), ) ``` 从该模块导入 `client` 的每个服务都会自动获得 token-lens 的监控 —— 无需针对单个服务进行修改。 ## 运行测试 ``` # 安装 dev 依赖 pip install -e ".[accurate-counting,dev]" # 运行完整的测试套件 pytest # 包含覆盖率 pytest --cov=token_lens --cov-report=term-missing ``` ## 项目结构 ``` token_lens/ ├── __init__.py # Public API: TokenLens, AnthropicTokenLens, Config, TokenLensCallbackHandler ├── _wrapper.py # TokenLens — OpenAI-compatible SDK wrapper ├── _anthropic_wrapper.py # AnthropicTokenLens — native Anthropic SDK wrapper ├── _chat.py # Intercepts chat.completions.create() ├── _anthropic_messages.py # Intercepts messages.create() ├── _session.py # Session state, CallRecord, NormalizedUsage ├── _analyzer.py # Runs detection rules pre- and post-call ├── _reporter.py # ANSI terminal output and session summary ├── _tokenizer.py # Token counting (tiktoken or 4-char fallback) ├── _config.py # Config dataclass ├── langgraph_integration.py # TokenLensCallbackHandler for LangGraph/LangChain └── rules/ ├── _base.py # Rule ABC, Finding dataclass, Severity enum ├── static_system_prompt.py # TL001 ├── unbounded_history.py # TL002 ├── duplicate_prompt.py # TL003 ├── model_overkill.py # TL004 ├── long_system_prompt.py # TL005 ├── missing_max_tokens.py # TL006 ├── redundant_context.py # TL007 ├── pii_in_prompt.py # TL008 ├── secret_in_prompt.py # TL009 ├── unversioned_model.py # TL010 ├── tool_result_bloat.py # TL011 ├── excessive_tools.py # TL012 ├── missing_response_format.py # TL013 ├── cost_spike.py # TL014 └── n_completions.py # TL015 ``` ## 许可证 MIT —— 详情见 [LICENSE](LICENSE)。
标签:DLL 劫持, SOC Prime, 中间件, 人工智能, 大语言模型, 开发工具, 成本优化, 本地部署, 用户模式Hook绕过, 逆向工具