多轮对话 Token 爆炸的根因:全量历史塞回 Prompt
做 Agent 系统的同学大概率都踩过这个坑:对话轮数一多,Token 消耗就像脱缰的野马。你以为是模型变贵了,其实是你的 Prompt 结构出了问题。
Gliding Horse(流马)是一个用 Rust 写的 Agent 操作系统,我在里面管理着 200 多个 Skill。早期版本我用 Markdown 组织所有数据——提示词、Skill 定义、对话历史、记忆块,全是 Markdown。简单、直观、人类可读。但跑到 30 轮以上的多轮对话时,问题集中爆发了:
- 每轮请求都要把完整历史塞回 Prompt,Token 数随轮数线性增长,50 轮对话轻松突破上下文窗口;
- 为了省 Token 做截断,LLM 立刻“失忆”,前面确认过的参数、决策、约束全丢;
- 多个 Skill 之间参数命名不统一,
input_file、source_url、data_path指向同一个业务概念却互不识别,调用链一长就炸。
这不是模型能力问题,是数据组织方式的问题。Markdown 是给人看的,不是给机器做语义寻址的。我最终把整个系统的“语言”从 Markdown 换成了 JSON-LD,配合图数据库做记忆存储,Token 消耗从 O(n) 降到了 O(1)。
这篇从排障视角出发,先解决模型通道的配置问题——很多人卡在 Key 和 Base URL 上,根本跑不到验证那一步。TaoToken 官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 注册后创建 Key,把 Gliding Horse 的 LLM Base URL 指向 https://taotoken.net/api,模型通道先稳定下来,再去调 JSON-LD 的数据组织逻辑。TaoToken 只负责通道层,不参与你的 JSON-LD 结构设计。
TaoToken 前置:Key 与 Base URL 的配置位置
Gliding Horse 的模型调用层支持自定义 Base URL。你需要做两件事:
第一,在 TaoToken 控制台创建 API Key。打开 https://taotoken.net/api 对应的控制台入口,进入 API Keys 页面生成一个 Key,格式形如YOUR_API_KEY。这个 Key 是你所有模型请求的凭证。
第二,把 Gliding Horse 的 LLM 通道配置指向 TaoToken 的 API 端点。Base URL 填https://taotoken.net/api,不要带尾部斜杠,不要带多余路径。模型 ID 根据你在 TaoToken 控制台看到的可用模型列表填写。
如果你用的是 Claude Code 作为编码辅助工具来调试 Gliding Horse 的 Rust 代码,配置方式是在settings.json里设置ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY。如果你用的是 Codex 类工具,对应改config.toml。核心逻辑一样:Base URL 指向 TaoToken,Key 用你创建的YOUR_API_KEY。
这一步看起来简单,但我见过太多人卡在这里:Base URL 多写了/v1、Key 复制时带了空格、模型 ID 写成了展示名称而不是实际 ID。这些都会导致 401 或 404,让你误以为是 JSON-LD 方案本身有问题。
可复制配置:Gliding Horse 的模型通道与 JSON-LD 结构
模型通道配置
在 Gliding Horse 的配置文件里,LLM 通道部分这样写:
[llm] base_url = "https://taotoken.net/api" api_key = "YOUR_API_KEY" model_id = "your-model-id" max_tokens = 4096 temperature = 0.7如果你用 CLI 方式启动调试,命令是:
npm i -g @taotoken/taotoken taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m your-model-idJSON-LD 记忆结构
Gliding Horse 的核心设计是:LLM 只输出普通 JSON,由 Rust 引擎自动加上@context和@id。LLM 完全不需要理解 JSON-LD 的语法。
每次 LLM 回答时,系统强制要求它输出三个字段:
{ "thought": "详细推理过程,存进图数据库,不占上下文", "content": "正式回答内容,也存进图数据库", "summary": "本轮决策摘要,塞进上下文历史" }Rust 引擎拿到这个 JSON 后,做三件事:
- 给
thought和content分配唯一的@id,例如memory:session-042/block-017,写入 Oxigraph 图数据库; - 把
summary追加到 LLM 的上下文历史中; - 在
@context中注册语义映射,让不同 Skill 的参数名指向同一个 IRI。
Skill 定义中的参数映射这样写:
{ "@context": { "skill:sourceDataURI": "https://my-agent-os.com/skill#sourceDataURI" }, "input_file": { "@id": "skill:sourceDataURI" } }无论 Skill 作者把参数叫input_file、source_url还是data_path,系统内部统统映射到skill:sourceDataURI这个 IRI。调用时不再需要记住每个 Skill 的参数命名,语义层自动对齐。
验证请求:50 轮后 Token 是否真的从 O(n) 变 O(1)
配置完成后,你需要验证两件事:模型通道是否通,以及 Token 消耗是否真的降下来了。
通道验证
先发一个最小请求,确认 TaoToken 通道正常:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "your-model-id", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 10 }'返回 200 且带有正常 completion 内容,说明通道没问题。如果返回 401,检查 Key;返回 404,检查 Base URL 和模型 ID。
Token 消耗验证
在 Gliding Horse 里跑一个 50 轮的对话测试。每轮结束后记录两个指标:
- 当前上下文窗口中的 Token 数(即发给 LLM 的 Prompt 长度);
- 图数据库中累积的
@id节点数。
Markdown 方案下,第 50 轮的 Prompt Token 数大约是第 1 轮的 50 倍。JSON-LD 方案下,第 50 轮的 Prompt 里只有 50 条摘要,每条摘要十几个 Token,总 Token 数稳定在几百的量级,不随轮数增长。
当 LLM 需要查历史细节时,它输出一个 IRI 引用,例如memory:session-042/block-003,Rust 引擎拿这个 IRI 去 Oxigraph 查询,瞬间返回那轮的完整thought和content。LLM 的上下文里始终只有摘要和 IRI,完整数据按需拉取。
这就是 O(1) 的含义:Token 消耗不随对话轮数增长,只与你当前需要查询的细节数量有关。
本篇常见错排查
错误一:Base URL 写成了https://taotoken.net/api/v1
TaoToken 的 Base URL 是https://taotoken.net/api,不要自己加/v1。OpenAI 兼容层的路径拼接由客户端库处理,你多写一段路径会导致 404。
错误二:Key 复制时带了换行或空格
从控制台复制YOUR_API_KEY时,很容易把末尾的换行符也复制进去。在 TOML 或 JSON 配置文件里,这会导致 Authorization 头格式错误,返回 401。用echo -n "YOUR_API_KEY" | wc -c检查一下字符数。
错误三:LLM 输出的 JSON 被 Markdown 代码块包裹
Gliding Horse 要求 LLM 输出纯 JSON,但模型有时会习惯性加上```json和```。Rust 引擎在解析前需要先剥离代码块标记,否则@id分配会失败。在 Prompt 里明确要求“只输出 JSON,不要用代码块包裹”。
错误四:@context映射冲突
两个 Skill 定义了不同的@context,但映射到了同一个 IRI 的不同属性上。这会导致图数据库写入时出现属性覆盖。解决方法是统一在系统级@context中注册所有语义映射,Skill 只引用不定义。
错误五:Oxigraph 查询超时
50 轮对话后图数据库节点数增长,SPARQL 查询如果没有加索引会变慢。确保@id字段建了索引,查询时用VALUES限定 IRI 范围,不要全图扫描。
错误六:模型通道正常但 JSON-LD 解析报错
这通常说明 TaoToken 通道没问题,问题出在 Rust 引擎的 JSON-LD 处理逻辑。检查json-ldcrate 的版本,确认@context的展开和压缩配置正确。LLM 本身不参与 JSON-LD 处理,所以不要怀疑模型输出格式。
语义一致 CTA
排障和接入阶段的核心是两件事:模型通道稳定,以及 JSON-LD 结构正确。通道层的问题——Key、Base URL、模型 ID——统一在 TaoToken 的 API Keys 页面和接入文档里解决。打开 https://taotoken.net/api 对应的控制台,创建 Key,把 Base URL 填成https://taotoken.net/api,通道先跑通。
如果你需要验证模型在 JSON-LD 摘要生成上的表现,用模型对话功能直接测试不同模型对“摘要 + IRI 引用”格式的遵循程度。如果你打算长期跑 Agent 编码任务,Coding Plan 提供了更稳定的通道配额,适合 Gliding Horse 这种需要持续多轮对话的场景。
通道是通道,数据是数据。TaoToken 解决前者,JSON-LD 和图数据库解决后者。两者配合,50 轮对话的 Token 消耗才能真正从 O(n) 降到 O(1)。