Skip to content

perf: _estimate_tokens 在离线/受限网下每次重试下载 tiktoken,导致 token 估算秒级阻塞 #8

Description

@weed33834

背景

doctoragent/model/agent.py 里的 _estimate_tokenstiktoken.get_encoding("cl100k_base") 估算 token 数,失败才回退 len(text) // 4

现象

tests/test_agent_react_loop.py::TestParallelToolDispatch::test_independent_tools_run_in_parallel 时,两个各 0.15s 的工具竟然耗了 25s。插桩后定位:25s 全部消耗在 _dispatch_tool_calls 内部、且发生在两次工具执行(各 0.15s)之外——也就是估算/记录阶段,不是工具本身慢。

根因

tiktoken 首次调用 get_encoding 会从 OpenAI 的 CDN 下载 BPE 编码文件。在离线或受限网络(院内隔离网、CI 受限出口)下,下载每次都要重试 ~5s 才失败;更要命的是失败没有被缓存——get_encoding 每次调用都重新尝试联网下载。完整测试集里 token 估算被高频触发,一次次重试累加成 25s 的硬阻塞。

影响(这是真 bug,不是测试问题)

  • DoctorAgent 部署在院内离线/隔离网络时,每一次 token 估算(轨迹记录、上下文窗口管理、审计日志)都可能被多秒的网络重试拖垮,严重时让响应"假死"。
  • 它还会把自己的锅甩给别的逻辑:上面那个"并发分派"测试,看起来像并发慢了,其实是估算在后台默默重试下载(详见 chore(deps): bump docker/setup-qemu-action from 3 to 4 #3)。

建议 / 已做的修复

  • 已本地把 tiktoken 的可用性(成功 or 失败)缓存到进程生命周期:加 _TIKTOKEN_CACHE = {"enc": None, "failed": False}get_encoding 只在 try 内解析并缓存一次;一旦失败就打标记,之后所有调用直接走 len // 4 兜底,不再碰网络。修复后并发测试从 25s 回到亚秒级。
  • 进一步建议:把 tiktoken 的 BPE 文件随包内置(离线优先),彻底去掉下载依赖;或者在配置里允许显式指定编码缓存路径。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions