乐于分享
好东西不私藏

七个藏在源码里的 Token 机制:从 Claude Code 泄露看 AI Agent 的成本真相

七个藏在源码里的 Token 机制:从 Claude Code 泄露看 AI Agent 的成本真相

  • 引言
  • 七个藏在源码里的 Token 机制
    • Token 估算:五个工具用了同一个魔法数字——它有多不准?
    • 隐形起步价:你开口之前,工具已经替你花了多少?
    • 服务商陷阱:工具显示的用量,为什么不能直接信?
    • 自动压缩:你以为省了钱,但账单是这么算的
    • Prompt 缓存:能省 90% 的机制,为什么你没用上?
    • 思考模式:"自适应思考"不等于省钱,真相是?
    • 命令输出洪水:一条命令,怎么把后续对话全拖慢了?
    • 两类 Agent 的本质差异:能做 ≠ 适合做
  • 结语
  • 可操作参考清单

引言


2026 年 3 月 31 日,Claude Code v2.1.88 发布时,一个 60MB 的 source map 文件被意外打包进了 npm 发布包。

1906 个源文件、51 万行代码,完整暴露,Claude Code 被开源。

全网炸了。备份仓库数小时内冲到 50K star,登上 GitHub 热榜第一。公众号、抖音、X 全在讨论。有人扒出了 8 大隐藏功能、26 个未公开指令、6 级安全架构,还有一个愚人节电子宠物彩蛋。

激动冷静下来,我觉得真正有意思的,不是彩蛋,是这个——

Agent 的核心引擎,其实只有三行伪代码:

while true:    response = LLM(context)        // 调模型    if no tool_calls: break        // 纯文本回复 → 结束    result = execute(tool_calls)   // 执行工具,结果塞回 context

没有什么神秘框架。五个工具,三种语言,核心循环大体都可以抽象为这个结构。

但围绕 context 的管理代码,比引擎本身多出不止一个量级。token 怎么估算、什么时候压缩、怎么让缓存命中、工具输出怎么管控……这些决策,才是每一分钱花在哪里的真正关键。

我们翻了五个开源 AI Agent 的源码,想看看它们各自是怎么管理 Context 的。结果发现——

它们围绕同一类约束,给出了高度相似的应对。

同样在主要路径上用"字符数 ÷ 4"估算 token——TypeScript 这样写,Rust 这样写,Python 也这样写。同样的固定底座在每次请求里隐形计费。同样的上下文压缩权衡——压缩本身也要花钱。同样的 Prompt Cache 分段设计——前缀不变才能命中缓存。

这不是某家公司的技术选择,是整个行业围绕"Context 总会用完"这个约束做出的相同应答。你每天在用的各类AI编程助手同样在这套机制下精心设计——了解这些约束,能帮你把它们用得更好。

本文的目的:用源码把这些约束讲清楚,让你在日常使用中做出更聪明的选择——用更少的 token,把事情做得更好。前文《万字干货|AI Token 消耗深度认知:原理 + 实验 + 最佳实践,一篇全搞定!》建立了理论框架,本文用五个开源仓库的真实代码逐条验证,并补充了几个理论层面难以发现的实现细节——两篇互为补充,先读哪篇都完整。

五个参照工具(均开源、跨语言,结论相互印证):

  • Claude Code(社区重写版,仓库名 claw-code,Rust + Python):Claude Code 架构的社区逆向重写,你可以理解为被开源的 Claude Code,2 小时破 50K star。本文中"Claude Code(社区重写版)"特指此仓库;"Claude Code"单独出现时指 Anthropic 官方产品(TypeScript)。
  • OpenClaw(就是你的"龙虾",近期火了好久的消息平台 AI 代理):接入 WeChat / WhatsApp / Telegram(TypeScript)
  • OpenCode:同类开源编码 Agent,面向终端编码场景(TypeScript / Bun)
  • Codex CLI:OpenAI 官方开源编码 Agent,Apache 2.0(Rust + TypeScript)
  • Deep Agents:LangChain 官方 Python Agent 框架(Python / LangGraph)

不需要会看代码。源码片段只是用来说明"这是真的,不是猜的"。


┌─────────────────────────────────────────────────────────────────────┐│                        工具关系定位图                                 │├──────────────────────┬──────────────────────────────────────────────┤│  主力参照             │  Claude Code(社区重写版,Rust)  Claude Code 架构社区重写  ││  (源码开放,         │             ↑ 与官方 Claude Code 最接近的公开实现            ││   重点解析)          │  OpenClaw   即"龙虾",消息平台 Agent,TS       ││                      │             ↑ 多 Provider / 多用户并发场景     │├──────────────────────┼──────────────────────────────────────────────┤│  辅助参照             │  OpenCode   CLI 编码 Agent,TypeScript        ││                      │             ↑ 面向终端编码场景的开源参照         │├──────────────────────┼──────────────────────────────────────────────┤│  次要验证             │  Codex CLI      OpenAI 官方,Rust + TS        ││  (第三方独立印证)    │  Deep Agents    LangChain 官方,Python        │└──────────────────────┴──────────────────────────────────────────────┘

两个主力工具的核心差异:

维度
Claude Code(社区重写版)
OpenClaw
使用场景
终端编码(单用户)
消息平台(多用户并发)
实现语言
Rust + Python(官方 Claude Code 为 TypeScript)
TypeScript
上下文底座
System Prompt + 指令文件(指令文件单文件上限 4,000 字符,总底座约 2,000~3,000 token)
System Prompt + Bootstrap 文件(单文件上限 20,000 字符,总上限 150,000 字符,约 37,500 token)
Thinking 控制
无内置旋钮,Thinking 参数直接透传 API
七级 ThinkLevel 旋钮(off → adaptive,adaptive 表示沿用 Gateway 会话默认级别)
压缩策略
删旧消息 + 纯 Rust 规则摘要(不调用 LLM,默认保留最近 4 条;结构化信息完整保留,每条消息截断至 160 字符)
调用 LLM 生成摘要,支持配置独立的 Compaction 专用模型
工具输出截断
指令文件有截断(单文件 4,000 字符上限,总计 12,000 字符),通用工具输出无独立上限
硬上限 400,000 字符,动态上限不超过上下文窗口的 30%
缓存前缀设计
SYSTEM_PROMPT_DYNAMIC_BOUNDARY
 显式分界
多模式 Cache Retention + Cache Trace 诊断
定时任务 / 心跳
内置 Heartbeat(默认 30 分钟,保持缓存温热)+ Cron Job 工具

这张表只涵盖了 token 维度的差异——两类 Agent 在工具集、权限模型、编码专属优化等方面还有更深层的设计分歧,后文“两类 Agent 的本质差异”一节会展开。


七个藏在源码里的 Token 机制

围绕 Context 管理,这五个工具共同暴露了七个反直觉的 token 机制——从估算偏差到压缩成本,从缓存陷阱到工具洪水。每一条都有对应源码,每一条都有可操作的用户含义。

下图是 Agent 完整运行流程,标注了七个机制各自的触发节点——可作为阅读后文的索引图。最后,我们还会从编码 Agent 和消息 Agent 的设计哲学差异出发,串联这些机制在不同场景下的实际影响:


Token 估算:五个工具用了同一个魔法数字——它有多不准?

你可能遇到过这样的情况: 工具显示"上下文还有空间",但账单已经比预期高很多;或者压缩触发得比你预想的晚,对话已经很重了才开始处理。

背后的原因是:工具在判断上下文是否"满"的时候,用的是估算,不是精确计数。

而估算的方式,五个工具高度一致——

Claude Code(社区重写版,rust/crates/runtime/src/compact.rs,第 326–338 行,Rust):

fn estimate_message_tokens(message: &ConversationMessage) -> usize {    message.blocks.iter().map(|block| match block {        ContentBlock::Text { text } => text.len() / 4 + 1,        ContentBlock::ToolUse { name, input, .. } => (name.len() + input.len()) / 4 + 1,        ContentBlock::ToolResult { tool_name, output, .. }            => (tool_name.len() + output.len()) / 4 + 1,    }).sum()}

做得最细——逐 block 拆分,每种内容块(文本 / 工具调用 / 工具结果)单独估算,每个 block 还加了 +1 作为基础开销补偿。这是五个工具里精度最高的实现。

OpenClawsrc/agents/compaction.ts,第 14 行;ui/src/ui/views/usage-metrics.ts,第 9–12 行,TypeScript):

// compaction.tsexport const SAFETY_MARGIN = 1.2// 20% buffer for estimateTokens() inaccuracy// usage-metrics.tsconst CHARS_PER_TOKEN = 4;function charsToTokens(charsnumber): number {  return Math.round(chars / CHARS_PER_TOKEN);}

同样用 chars/4,但在 compaction 触发逻辑里乘以 1.2 倍安全系数,注释明确写明"补偿 estimateTokens() 的低估"——承认了估算的系统性误差,并在压缩决策层做了补偿。

OpenCodepackages/opencode/src/util/token.ts,辅助验证,TypeScript):

const CHARS_PER_TOKEN = 4export function estimate(input: string) {  return Math.max(0Math.round((input || "").length / CHARS_PER_TOKEN))}

Codex CLIcodex-rs/utils/string/src/truncate.rs,次要验证,Rust):

const APPROX_BYTES_PER_TOKEN: usize = 4;pub fn approx_token_count(text: &str) -> usize {    text.len().saturating_add(APPROX_BYTES_PER_TOKEN.saturating_sub(1))        / APPROX_BYTES_PER_TOKEN}

Deep Agentsdeepagents/middleware/filesystem.py,次要验证,Python):

# Using 4 chars per token as a conservative approximation (actual ratio varies by content)NUM_CHARS_PER_TOKEN = 4

五个工具,三大语言,五个团队——同一个魔法数字:4

这不是巧合。调用 tokenizer 精确计数,每次要几毫秒;用字符数除以 4 估算,只需几微秒。轻量估算是整个行业在精度和性能之间做出的统一权衡。

这个数字也和前文理论框架的分词器描述直接对应:Claude 等模型使用的 BPE(Byte Pair Encoding)分词器,对英文文本平均每个 token 约 3.5 个字符——chars/4 是对这个比例的近似取整。工具开发者没有更好的办法:精确 tokenize 要依赖外部库且有性能损耗,所以这个估算本身就是行业对"分词器精度无法廉价获取"的现实应对,而非懒惰。

补偿方式各有侧重:Claude Code(社区重写版)做得最细,逐 block 单独估算,加基础补偿;OpenClaw 加了 1.2 倍安全系数,在压缩决策层兜底;OpenCode 裸用;Codex 向上取整;Deep Agents 注释说是"保守估算"。

这个估算值直接控制着 Compaction 的触发时机——估算偏低,就意味着压缩比你预期的保守,上下文实际比工具显示的更满。

精度误差速查表(经验估算,供参考):

内容类型
实际 chars/token 近似值
chars/4 估算偏差方向
英文代码
~3.5
低估约 13%
中文文本
~1.5
低估幅度明显
(可超 50%)
JSON 结构
~3.0
低估约 25%
混合内容
~2.5
低估约 38%

注:上表为基于常用 tokenizer 经验整理的参考值,不同模型和分词器下实际偏差有所不同,仅供方向性参考。

对用户的意义: 大量使用中文时,chars/4 会明显低估实际 token 消耗。当工具显示"上下文还有空间"但响应已经明显变慢时,中文内容造成的估算偏差是常见原因之一。


隐形起步价:你开口之前,工具已经替你花了多少?

你可能遇到过这样的情况: 明明只发了一句"帮我看看这个函数",token 消耗远超预期。打开计费明细,输入 token 里有大量"说不清楚是什么"的消耗。

这是工具在每次请求里注入的固定底座——在你开口之前就已确定。

Claude Code(社区重写版,rust/crates/runtime/src/prompt.rs,第 37–40 行,Rust)——最接近官方 Claude Code 原始架构的公开实现:

pub const SYSTEM_PROMPT_DYNAMIC_BOUNDARY: &str = "__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__";const MAX_INSTRUCTION_FILE_CHARS: usize = 4_000;    // 单个 CLAUDE.md ≈ 1,000 tokenconst MAX_TOTAL_INSTRUCTION_CHARS: usize = 12_000;  // 所有指令文件合计 ≈ 3,000 token

指令文件(CLAUDE.md 等)按顺序消耗预算,超出 12,000 字符后的内容会被截断并标注 [truncated](第 374 行)。底座极为克制——把上下文空间最大程度留给对话。

OpenClaw 的底座更重,额外多了 Bootstrap 文件(src/agents/pi-embedded-helpers/bootstrap.ts,第 85–87 行,TypeScript):

export const DEFAULT_BOOTSTRAP_MAX_CHARS = 20_000;        // 单文件 ≈ 5,000 tokenexport const DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS = 150_000// 总计 ≈ 37,500 tokenexport const DEFAULT_BOOTSTRAP_PROMPT_TRUNCATION_WARNING_MODE = "once";

Bootstrap 文件就是项目级 AI 配置文件(AGENTS.md、CLAUDE.md 等),总预算上限 37,500 token。注意截断策略:先到先得,文件按顺序消耗预算,靠后的文件可能被完全跳过——超出时会发一次警告("once" 模式),不是每次都提示。

OpenCodepackages/opencode/src/session/prompt.ts,辅助验证,TypeScript):

// 每个工具的 description + JSON Schema 被序列化注入每次请求for (const item of await ToolRegistry.tools(...)) {  const schema = ProviderTransform.schema(input.model, z.toJSONSchema(item.parameters))  tools[item.id] = tool({ description: item.descriptioninputSchemajsonSchema(schema) })}// MCP 工具与内置工具完全对等注入,全量注入,不管本轮用不用for (const [key, item] of Object.entries(await MCP.tools())) {  tools[key] = item}

关键在最后一行:MCP 工具是全量注入的,不管本轮对话用不用。接入的 MCP server 越多,每次请求的底座就越高。

此外,OpenCode 还支持把远程 URL 写入 instructions 配置作为指令源(packages/opencode/src/session/instruction.ts,第 127–141 行):

// 每次对话启动时实时 fetch 远端指令,5 秒超时fetch(url, { signalAbortSignal.timeout(5000) })  .then((res) => res.ok ? res.text() : "")  .then((x) => x ? "Instructions from: " + url + "\n" + x : "")

这意味着 instructions 里配置一个 HTTPS URL,每次对话都会实时拉取并拼进底座——远端文件越大,底座越重,而且是随时可能悄悄变重的底座,不像本地文件能直接看到大小。

起步成本对比:

Claude Code(社区重写版)起步成本          OpenClaw 起步成本─────────────────────────────            ─────────────────────────────────────System Prompt    ~2,000 tok              System Prompt     ~2,000 tok指令文件          最多 ~3,000 tok         Tool Defs         ~2,500 tok                                         Bootstrap Files   最多 ~37,500 tok─────────────────────────────            ─────────────────────────────────────小计             最多 ~5,000 tok         小计              最多 ~42,000 tok

对用户的意义: 底座的钱在你开口之前就花出去了——所以简单的问题也不便宜。AGENTS.md / CLAUDE.md 写得越长,底座越重;用不到的 MCP server 断开连接,起步成本立刻降低。

附:指令文件的加载时机——底座不是一次性的

上面说的"底座"还只是起步成本。五个工具在指令文件的加载时机上有一个关键分歧,直接决定了上下文是否会在对话过程中悄悄增长:

Claude Code(社区重写版,rust/crates/runtime/src/prompt.rs,第 192–213 行,Rust)——启动时全量加载

fn discover_instruction_files(cwd: &Path) -> std::io::Result<Vec<ContextFile>> {    let mut cursor = Some(cwd);    whileletSome(dir) = cursor {        // 向上逐级扫描 CLAUDE.md / CLAUDE.local.md / .claude/instructions.md        directories.push(dir.to_path_buf());        cursor = dir.parent();    }    Ok(dedupe_instruction_files(files))  // 去重后全部加入底座}

启动时一次性扫描完毕,之后不再变化——底座大小在第一句话前就确定了。

OpenCodepackages/opencode/src/session/instruction.ts,第 144–191 行;packages/opencode/src/tool/read.ts,第 118 行,TypeScript)——Read 工具触发,按需增量注入

// instruction.ts 第144-159行:先查哪些已经注入过了export function loaded(messages) {  const paths = new Set<string>()  for (const part of msg.parts) {    if (part.type === "tool" && part.tool === "read" && !part.state.time.compacted)      if (part.state.metadata?.loadedfor (const p of loaded) paths.add(p)  }  return paths  // ← 已注入过的路径集合}// instruction.ts 第168-191行:每次 read 触发,向上逐级找,首次才注入export async function resolve(messages, filepath, messageID) {  const already = loaded(messages)  while (current.startsWith(root) && current !== root) {    const found = await find(current)          // 找 AGENTS.md / CLAUDE.md    if (found && !already.has(found))          // ← 没见过的才注入      results.push({ filepath: found, ... })    current = path.dirname(current)  }}// read.ts 第118行:每次 Read 工具调用时触发const instructions = await InstructionPrompt.resolve(ctx.messages, filepath, ctx.messageID)

Agent 每读一个新目录下的文件,就可能触发该目录及所有上层目录的 AGENTS.md 注入——且彩蛋是:OpenCode 还会尝试加载 ~/.claude/CLAUDE.mdinstruction.ts 第 26–28 行),如果你同时装了 Claude Code,其全局配置会被一并读入。

OpenClawsrc/auto-reply/reply/post-compaction-context.ts,第 58–145 行,TypeScript)——Compaction 后重新注入关键 section

// post-compaction-context.ts 第58-87行// Read critical sections from workspace AGENTS.md for post-compaction injection.const agentsPath = path.join(workspaceDir, "AGENTS.md")// 提取配置的关键 Section(默认:Session Startup + Red Lines)// 每次 Compaction 之后重新注入,确保 Agent 不会因为历史被压缩而忘掉关键规则

这是一个有趣的设计:Compaction 删掉了历史,但 AGENTS.md 里标记为"每次启动必看"的 section 会在 Compaction 后自动重新注入。既防止遗忘,又控制了重注入的内容范围(只注入指定 section,不是全文)。

Codex CLIcodex-rs/instructions/src/fragment.rs,第 4 行;codex-rs/core/src/codex.rs,第 532 行,Rust)——启动时加载 AGENTS.md,Skill 按用户 @mention 触发

// fragment.rs 第4行:AGENTS.md 注入的标记前缀pub(crate) const AGENTS_MD_START_MARKER: &str = "# AGENTS.md instructions for ";// codex.rs 第532行:启动时加载用户指令let user_instructions = get_user_instructions(&config).await;

AGENTS.md 在启动时作为 UserInstructions 注入;Skill(@skill-name)则在用户消息里显式 mention 后才触发注入(codex-rs/core-skills/src/injection.rs,第 24–57 行)。

Deep Agentslibs/deepagents/deepagents/middleware/skills.py,第 560–579 行,Python)——真正的渐进式披露(metadata first)

# skills.py 第560-579行:SKILLS_SYSTEM_PROMPT 模板# Skills follow a **progressive disclosure** pattern:# - 底座里只注入 skill 的名称 + 描述(metadata)# - 需要使用某个 skill 时,再 read 其 SKILL.md 获取完整指令# 1. Recognize when a skill applies# 2. Read the skill's full instructions (path shown in skill list)# 3. Follow the skill's instructions

五个工具里唯一在系统层面实现"按需加载全文"的——底座只放 skill 的名称和描述,等 Agent 判断需要用某个 skill 时再读完整的 SKILL.md,避免一次性把所有 skill 的全文都塞进上下文。

五种加载策略对比:

Claude Code(社区重写版):  启动时全量扫描,底座固定,对话中不变OpenCode:   Read 工具触发增量注入,底座随对话"生长"(去重保护防重复)OpenClaw:   启动加载 + Compaction 后重注入关键 section,动态但有范围限制Codex CLI:  启动加载 AGENTS.md;Skill 需用户显式 @mention 触发Deep Agents:底座只放 skill metadata,完整内容按需 read(最节省上下文)

对用户的多一层意义: OpenCode 的底座会随对话"生长"——Agent 读的目录越多,注入的 AGENTS.md 就越多。如果你的项目目录层级很深、每层都有 AGENTS.md,这个增量注入带来的隐性消耗可能超过你的预期。


服务商陷阱:工具显示的用量,为什么不能直接信?

同一个字段名 inputTokens,在 Anthropic 里不包含缓存 token,在 OpenRouter 里包含——这不是文档措辞的差异,是两个完全不同的数字。

这不是工具 bug,也不是你算错了。根本原因是:不同 Provider 对同一个字段的定义不一样,工具侧只能做归一化处理,最终扣费逻辑由 Provider 决定。

OpenClaw 在 normalizeUsage() 里构建了一个多 Provider 兼容层(src/agents/usage.ts,第 88–136 行,TypeScript)——光是"缓存读取"这一个字段,就有五种命名方式:

export function normalizeUsage(raw?: UsageLike | null): NormalizedUsage | undefined {  // 某些 provider(OpenAI 格式)会把 cached_tokens 从 prompt_tokens 里预先扣除  // 当 cached_tokens > prompt_tokens 时结果为负数——Clamp 到 0  const rawInput = asFiniteNumber(    raw.input ?? raw.inputTokens ?? raw.input_tokens ?? raw.promptTokens ?? raw.prompt_tokens,  );  const input = rawInput !== undefined && rawInput < 0 ? 0 : rawInput;  const cacheRead = asFiniteNumber(    raw.cacheRead ??    raw.cache_read ??    raw.cache_read_input_tokens ??         // Anthropic 官方    raw.cached_tokens ??                   // Moonshot / Kimi    raw.prompt_tokens_details?.cached_tokens,  // Kimi K2 嵌套字段  );}

负数保护和五路字段兼容——某些 Provider 在返回 prompt_tokens 时已经扣除了缓存 token,如果工具再减一次,就会变成负数。这不是极端情况,而是真实发生在生产环境的问题。

OpenCode 源码里有一段注释直接承认了这个跨 Provider 问题(packages/opencode/src/session/index.ts,第 816–823 行,辅助验证,TypeScript):

// OpenRouter provides inputTokens as the total count of input tokens (including cached).// Anthropic does it differently though - inputTokens doesn't include cached tokens.// It looks like OpenCode's cost calculation assumes all providers return inputTokens// the same way Anthropic does... so it's causing incorrect cost calculation for// OpenRouter and others.const excludesCachedTokens = !!(input.metadata?.["anthropic"] || input.metadata?.["bedrock"])const adjustedInputTokens = safe(  excludesCachedTokens ? inputTokens : inputTokens - cacheReadInputTokens - cacheWriteInputTokens,)

OpenRouter 的 inputTokens 包含缓存 token,Anthropic 的 inputTokens 不包含——同一个字段名,两个完全不同的语义。OpenCode 的注释自己都说"这会造成 OpenRouter 的成本计算不正确"——这不是 bug,是行业没有统一规范造成的。

对用户的意义: 对账时,以 Provider 后台的账单为准,工具内显示的用量只做参考。切换 Provider 或走中转路由时,两个数字之间的差异往往来自字段语义不同,不是计算错误。


自动压缩:你以为省了钱,但账单是这么算的

你可能遇到过这样的情况: 对话进行到后期,每一步响应都比前面慢、而且更贵;触发了"上下文压缩"之后,以为能省钱,但账单反而更高。

这两个现象背后是两件事:雪球机制,以及"压缩本身也要花钱"。

雪球机制的根源在于工具调用的数据结构。每次 Agent 调用一个工具(读文件、写代码、执行命令),会产生一对:tool-call(调用请求)+ tool-result(执行结果)。这一对会永久留在上下文,后续每一轮对话都要重新把它们发给模型。任务越复杂,工具调用越多,每一轮的输入就越重——这是雪球效应的本质。

这不是某一家工具的设计选择——五个仓库的主循环代码,语言各不相同,但结构完全一致:每轮开始时取出完整历史,拼上新结果,整包发给 LLM。

Claude Code(社区重写版,rust/crates/runtime/src/conversation.rs,Rust):

loop {    let response = client.send_message(&self.session.messages, ...).await?;    self.session.messages.push(result_message); // 工具结果追加,下轮连同完整历史一起重发    if response.stop_reason == StopReason::EndTurn { break; }}

OpenCodepackages/opencode/src/session/prompt.ts,第 296 行,TypeScript):

while (true) {  let msgs = await MessageV2.filterCompacted(MessageV2.stream(sessionID))  // 每轮从数据库 stream 出全部消息(含所有历史工具调用和结果)  if (!["tool-calls","unknown"].includes(lastAssistant.finish)) break}

Codex CLIcodex-rs/core/src/codex.rs,第 5877、5929 行,Rust):

loop {    let sampling_request_input: Vec<ResponseItem= sess.clone_history();    // clone_history():把完整历史克隆进本次请求,工具结果追加后下轮再次 clone}

OpenClawsrc/agents/compaction.ts + pi-embedded-helpers,TypeScript):工具调用和结果作为 { type: "toolCall" } / { type: "toolResult", toolCallId } 成对追加进 messages 数组——Compaction 之前不会离开上下文。

Deep Agentslibs/deepagents/deepagents/graph.py,Python / LangGraph):基于 LangGraph 的 AgentState.messages,工具调用和结果分别作为 AIMessage(含 tool_calls)和 ToolMessageappend 进状态,每次 LLM 调用时完整传入。

五种语言、三个框架,指向同一件事:工具结果写进去就不出来了,直到 Compaction 把它删掉(而那意味着信息损失)。这正是前文 §4 雪球效应呈现"平方级增长"的代码级根因。

当上下文接近上限时,工具会触发 Compaction(压缩)。但五个工具选择了不同的策略:

Claude Code(社区重写版)的策略:删旧消息 + 本地摘要rust/crates/runtime/src/compact.rs,第 75–113 行,Rust)

pub fn compact_session(session: &Session, config: CompactionConfig) -> CompactionResult {    // 把超出 max_estimated_tokens 的旧消息移除    // 对被移除的消息生成本地摘要,插入 session 开头    let summary = summarize_messages(removed);    ...}fn summarize_messages(messages: &[ConversationMessage]) -> String {    // 纯本地摘要,不调用 LLM,直接提取文件名 / 操作关键词    let key_files = collect_key_files(messages);    ...}

关键:摘要是本地生成的,零额外 API 成本。summarize_messages() 函数会提取被压缩消息的范围统计(user / assistant / tool 条数)、出现过的工具名、最近 3 条用户请求首段文字、关键词匹配出的 pending work(todo / next / pending 等关键词触发)、以及文件路径列表(最多 8 个)——是纯 Rust 规则提取,不调用任何 LLM。结构化信息(工具列表、时间线骨架、关键文件)保留完整,但每条消息内容截断至 160 字符(summarize_block() 第 214 行),长代码输出和工具结果的具体细节会丢失。

OpenClaw 的策略:调用 LLM 生成摘要src/agents/compaction.ts,第 133 行,TypeScript)

export const SUMMARIZATION_OVERHEAD_TOKENS = 4096;// 摘要生成本身也消耗 token:指令 + system prompt + 历史摘要 + 包装标签

不是删,而是"读完历史 → 调用 LLM 生成摘要 → 用摘要替代原始历史"。信息保留更完整,但:

  1. 每次压缩 = 一次额外 API 调用,有 4096 token 的基础开销(以 Claude Sonnet 为例,约 0.01~0.02 美元/次)
  2. 上下文越大,摘要本身越贵
  3. OpenClaw 还有三级降级策略:正常摘要 → 跳过超大消息(标注"[Large role omitted]")→ "Summary unavailable due to size limits."

OpenCode 的策略:两阶段压缩packages/opencode/src/session/compaction.ts,辅助验证,TypeScript)

// compaction.ts 第31行:isOverflow() 用——计算可用空间时预留给输出的安全边距const COMPACTION_BUFFER = 20_000// compaction.ts 第51-52行:prune() 用——控制工具结果删除的边界const PRUNE_MINIMUM    = 20_000   // 至少削减这么多才执行const PRUNE_PROTECT    = 40_000   // 保留最近 40K tokens 的工具调用不动

向后遍历,找旧 tool-result 直接删除,可删量超过 20K 才执行。

但 OpenCode 同时也支持 LLM 摘要式 Compaction——且 Compaction 有独立的专属 Agent,可以单独配置使用更便宜的模型packages/opencode/src/session/compaction.ts 第 132–135 行;packages/opencode/src/provider/provider.ts 第 1333–1358 行):

// compaction.ts:优先用 compaction agent 自己配置的 modelconst agent = await Agent.get("compaction")const model = agent.model  ? await Provider.getModel(agent.model.providerID, agent.model.modelID)  : await Provider.getModel(userMessage.model.providerID, userMessage.model.modelID)// provider.ts:getSmallModel() 的候选优先级(精简展示,实际含7个候选)let priority = [  "claude-haiku-4-5""claude-haiku-4.5",  "3-5-haiku""3.5-haiku",  "gemini-3-flash""gemini-2.5-flash",  "gpt-5-nano",]

这意味着:只要在配置里把 compaction Agent 的 model 指向一个便宜的小模型(如 Haiku),压缩任务就会用小模型完成,主对话继续用大模型。这是一个有实际效果、但几乎没人知道的系统性降本手段。

Codex CLI 的第三条路:Remote Compactcodex-rs/core/src/compact.rs,次要验证,Rust)

// OpenAI provider 走云端压缩,其他 provider 走本地摘要pub(crate) fn should_use_remote_compact_task(provider: &ModelProviderInfo) -> bool {    provider.is_openai()}

OpenAI 官方工具有一个独特选项:把历史消息发回 OpenAI 服务端做云端压缩。压缩质量最高——但也是一次额外 API 调用,成本最高。

五种策略对比:

工具
策略
成本
信息质量
触发方式
Claude Code(社区重写版)
删旧消息 + 纯规则摘要
零(无额外API调用)
结构完整,细节截断至160字符
自动(超过max_estimated_tokens)
OpenClaw
LLM生成摘要
有(每次~4096 token起)
较好(LLM理解上下文)
自动(context overflow时)
OpenCode
两阶段压缩(prune+LLM摘要)
第一阶段零,第二阶段有(可配置小模型)
第一阶段有损失,第二阶段较好
每轮后自动prune,overflow时LLM摘要
Deep Agents
LLM摘要 + 历史offload
有(调用LLM+写入后端)
好(摘要+完整历史可按需读取)
自动(超过170,000 token)/ 手动
Codex CLI
云端Remote Compact(OpenAI专属)
最高(一次完整API调用)
最好(云端处理)
自动 / 手动

反直觉的结论:压缩不是免费的安全网。 智能压缩策略本身有成本,而且上下文越大,压缩本身越贵。

附:Compaction 的触发阈值和开关——五个工具都可以干预

每个工具的 Compaction 不是铁板一块,都暴露了配置接口:

Claude Code(社区重写版,rust/crates/runtime/src/compact.rs,第 4–15 行,Rust):

pub struct CompactionConfig {    pub preserve_recent_messages: usize,  // 保留最近几条消息不压缩,默认 4    pub max_estimated_tokens: usize,      // token 估算超过此值才触发,默认 10_000}

两个参数直接控制触发时机——max_estimated_tokens 调大,压缩触发更晚;preserve_recent_messages 调大,保留更多近期消息不被摘要。

OpenCodepackages/opencode/src/session/compaction.ts,第 33–48 行,TypeScript):

export async function isOverflow(input: ...) {  const config = await Config.get()  if (config.compaction?.auto === falsereturn false   // ← 完全关闭自动压缩  const reserved =    config.compaction?.reserved                         // ← 用户自定义预留量    ?? Math.min(COMPACTION_BUFFERProviderTransform.maxOutputTokens(input.model))  return count >= (input.model.limit.input - reserved)}

compaction.auto = false 完全关闭;compaction.reserved 调大,让压缩更早触发,为模型输出预留更多空间。

OpenClawsrc/agents/pi-embedded-runner/compact.ts,第 402 行;src/config/types.agent-defaults.ts,第 316 行,TypeScript):

// compact.ts 第402行:Compaction 可以单独指定模型const compactionModelOverride = params.config?.agents?.defaults?.compaction?.model?.trim()// 格式:"provider/model-id",例如 "anthropic/claude-haiku-4-5"// types.agent-defaults.ts 第316行reserveTokensFloor?: number  // 压缩预留 token 下限,0 表示禁用下限保护

OpenClaw 的 Compaction 配置项最丰富:可以单独指定压缩用的模型(用便宜的小模型做摘要)、调整预留 token 下限。这和 OpenCode 的 compaction agent 配置思路相同——把摘要任务交给小模型,主对话用大模型。

Codex CLIcodex-rs/core/src/codex.rs,第 5667、5963、6164 行;codex-rs/app-server-protocol/src/protocol/v2.rs,第 720–721 行,Rust)——有两个独立可配置的 Token 阈值:

// codex.rs 第5667行:auto_compact_token_limit 是独立于上下文窗口上限之外的压缩触发点let auto_compact_limit = model_info.auto_compact_token_limit().unwrap_or(i64::MAX);// codex.rs 第5963行:total_usage_tokens 达到该阈值即触发自动压缩let token_limit_reached = total_usage_tokens >= auto_compact_limit;// v2.rs 第720-721行:两个阈值均可通过 API 协议独立配置pub model_context_window: Option<i64>,pub model_auto_compact_token_limit: Option<i64>,

还有一个 effective_context_window_percentcodex-rs/codex-api/tests/models_integration.rs,第 93 行),默认值为 95——实际上下文上限 = context_window × 95%,预留 5% 给输出。此外有一个特殊触发场景:切换到上下文窗口更小的模型时,若当前 token 用量超过新模型的 auto_compact_token_limit,立即触发压缩——换个更便宜的小模型来处理子任务,可能瞬间触发一次额外的压缩 API 调用。

Deep Agents 未在源码里发现用户侧的 Compaction disable 或阈值配置项。

对用户的意义: 文件读写多的任务(读代码、写代码、反复修改),后期每一步都会比前面慢。大任务拆成多个短对话——雪球没机会滚大,每轮成本从底座重新开始。如果你在用 OpenCode 或 OpenClaw,把 Compaction 专用模型配置为 Haiku 级别的小模型,是一个几乎零副作用的系统性降本手段。使用 Codex CLI 时注意:在同一任务中途切换到上下文窗口较小的模型,可能触发预期外的自动压缩,产生额外 API 调用成本。


Prompt 缓存:能省 90% 的机制,为什么你没用上?

Anthropic 的缓存读取价格约为正常输入价格的 1/10——但五个工具的源码告诉我们,这个折扣不是默认生效的。它能不能命中,完全取决于工具有没有专门设计。

Claude Code(社区重写版,rust/crates/runtime/src/prompt.rs,第 37 行 + 第 143 行,Rust)——用最显式的方式声明缓存分界:

pub const SYSTEM_PROMPT_DYNAMIC_BOUNDARY: &str = "__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__";// build() 方法(第 143 行附近):sections.push(get_simple_intro_section(..));     // 固定前缀 ← 缓存命中区sections.push(get_simple_system_section());sections.push(get_actions_section());sections.push(SYSTEM_PROMPT_DYNAMIC_BOUNDARY.to_string());  // ← 分界标记sections.push(self.environment_section());       // 动态部分(cwd, date, git status...)sections.push(render_project_context(..));sections.push(render_instruction_files(..));

__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ 让缓存系统明确知道"这之前的内容不会变"——固定前缀可缓存,动态部分每次重新计费。

OpenClaw 走的是另一条路(多模式 Cache Retention + 诊断工具,TypeScript):在 src/agents/pi-embedded-runner/extra-params.ts 第 73 行声明了三档 Cache Retention 配置:"none" / "short"(5 分钟)/ "long"(1 小时),同时配合 docs/concepts/session-pruning.md 里的 cache-ttl 上下文修剪机制——在 Cache TTL 过期时自动修剪对话历史,避免重新缓存整个上下文带来的写入成本。还内置了 Cache Trace 诊断工具,通过 SHA-256 对比相邻两轮消息摘要,让你验证缓存是否真的命中——其他工具几乎都做不到这一点。

OpenCodepackages/opencode/src/session/llm.ts,第 88–93 行,辅助验证,TypeScript):

// rejoin to maintain 2-part structure for caching if header unchangedif (system.length > 2 && system[0] === header) {  const rest = system.slice(1)  system.length = 0  system.push(header, rest.join("\n"))}

把 System Prompt 拆成两部分——header(固定)+ 动态内容。每次检查 header 是否变化,没变则保持结构,让第一段作为稳定前缀命中缓存。和 Claude Code(社区重写版)的 DYNAMIC_BOUNDARY 本质相同,实现方式更隐式。

但 OpenCode 的缓存设计不止于此。provider/transform.ts 的 applyCaching() 函数(第 174–176 行)还额外对最后 2 条非 System 消息打上缓存标记:

const system = msgs.filter((msg) => msg.role === "system").slice(02)  // 前 2 条 systemconst final  = msgs.filter((msg) => msg.role !== "system").slice(-2)    // 最后 2 条对话// 两组消息都打上 cacheControl: { type: "ephemeral" }

Anthropic 最多支持 4 个缓存断点,这个实现精确利用了这一上限:System 前缀 2 个 + 对话尾部 2 个。对用户的实际意义是:对话轮次越多,每次请求里"最后 2 条之前的全部历史"越大,缓存覆盖面就越广——长对话的缓存收益比短对话高得多。

Codex CLI(次要验证,Rust):未看到独立的 Prompt Caching 结构性处理代码;conversation_idcodex-rs/app-server-protocol/src/protocol/v1.rs,第 78 行)是会话线程标识符,用于历史管理和恢复,不是直接作用于 Provider 侧缓存前缀的结构性设计。Deep Agents(次要验证,Python):configurable_model.py 保留了 Anthropic 专属 cache_control 字段(_ANTHROPIC_ONLY_SETTINGS,第 46 行),切换到非 Anthropic provider 时自动剥除,缓存由 Anthropic SDK 层处理,开发者基本零感知。

五种思路对比:

Claude Code(社区重写版):  DYNAMIC_BOUNDARY  → 显式标记分界,最直观OpenClaw:   多模式 + 诊断工具  → 手工配置 + 可验证命中率(唯一能验证的)OpenCode:   2-part + 尾部标记  → 前缀稳定 + 对话历史大量命中缓存Codex CLI:  会话 ID 驱动历史管理 → 缓存由 Provider 侧自主处理Deep Agents:Anthropic cache_control 字段透传 → SDK 层兜底,切其他 provider 自动剥除

共同揭示的真相:缓存命中不是"默认有",是工具专门设计的结果。前缀内容稳定,是所有策略的核心前提。

附:Cache Write 也有成本——缓存不是纯赚

Prompt Caching 的完整账单由两部分组成:写入(cache write) 和 读取(cache read)

  • 读取约为正常输入价格的 1/10——这是大家熟知的"省 90%"
  • 写入约为正常输入价格的 1.25 倍——比普通输入还贵 25%

也就是说,第一轮对话(写入缓存那一次)不仅不省,还会多花。收益要从第二轮开始用 cache read 抵回来。在 OpenClaw 的 session-pruning.md 里提到的 cache-ttl 修剪机制,核心动机正是这里:如果会话长时间空闲、缓存 TTL 过期,下一次请求就需要重新写入缓存——这次写入是真实的费用支出,而不是省钱。所以 OpenClaw 在 TTL 接近过期时主动修剪对话历史,就是为了减小"重新写入"那一次的 cacheWrite token 量。

OpenClaw Heartbeat 的隐性成本与"空跳过"优化src/auto-reply/heartbeat.ts,第 8、23 行,TypeScript):

// heartbeat.ts 第8行:默认每 30 分钟触发一次export const DEFAULT_HEARTBEAT_EVERY = "30m";// heartbeat.ts 第23-52行:检测 HEARTBEAT.md 是否"实质为空"export function isHeartbeatContentEffectivelyEmpty(contentstring | undefined | null): boolean {  // 文件仅含空行 / 注释行(# ...)/ 空列表项(- [ ])时视为空  // 返回 true → 跳过本次 Heartbeat API 调用,零 token 消耗}

Heartbeat 每 30 分钟发一次 API 调用,目的是让 system prompt(含所有工具定义)保持在 Provider 的 Prompt Cache 里——避免缓存 TTL 过期后重新写入的高额费用。但设计了一个精妙的成本优化:如果 HEARTBEAT.md 检测为"实质为空"(只有空行或注释),则跳过 API 调用,保活成本为零。也就是说:HEARTBEAT.md 内容越精简,30 分钟的"缓存保活"越不花钱——这是 OpenClaw 里少数做到"不调用就不计费"的机制之一。此外,Heartbeat 的 HEARTBEAT_PROMPT 明确要求 Agent "Do not infer or repeat old tasks from prior chats"——防止 Agent 在保活请求里重复历史上下文,也是一层 token 节省设计。

前文 §8 重点讲了"缓存命中可省 90%",但 Cache Write 的成本(比正常输入贵 25%)在理论层面较难直接观测——OpenClaw 的 Heartbeat 机制恰好是这个成本在代码层面最清晰的体现:之所以要每 30 分钟主动 ping 一次,就是因为让缓存自然过期后重新写入是真实的额外支出,Heartbeat 本质上是在用小代价(一次保活请求)换掉大代价(完整 cacheWrite 重新计费)。

对用户的意义: 如果你的工具提供了 cache 统计,查看 cache.read 占总输入 token 的比例——如果接近 0,说明缓存基本没有命中,值得关注。频繁修改项目级配置文件(如 .cursorrulesAGENTS.md)可能会改变 System Prompt 的固定前缀,进而影响缓存命中率。短暂离开再回来继续对话时,如果空闲时间超过了缓存 TTL(Anthropic 默认约 5 分钟 / 1 小时),你会为重新写入缓存多付一次成本——这正是 OpenClaw cache-ttl 修剪机制设计的背景。


思考模式:"自适应思考"不等于省钱,真相是?

在 OpenClaw 的源码里,adaptive(自适应思考)的实现只有一行:return "medium"。它不会根据任务难度调整,每次都是 medium 级别的思考消耗。

Thinking Token(也叫 Reasoning Token)是模型"想一想再回答"产生的消耗。它和正常输出 token 分开计算,但很多工具把它合并进 output 字段显示——所以你在账单里看到 output 很高,不一定是"输出了很多内容",可能很大一部分是思考消耗。

OpenClaw 提供了七级 ThinkLevel 旋钮(src/agents/pi-embedded-runner/utils.ts,第 4–17 行,TypeScript):

// ThinkLevel:off / minimal / low / medium / high / xhigh / adaptive(7 级)export function mapThinkingLevel(level?: ThinkLevel): ThinkingLevel {  // "adaptive" 在 pi-agent-core 层映射为 "medium"  // Pi SDK provider 会将其转译为 thinking.type: "adaptive" + output_config.effort: "medium"  // 仅对支持该模式的模型(Opus 4.6 / Sonnet 4.6)生效  if (level === "adaptive") {    return "medium";  // adaptive 固定映射为 medium  }  return level ?? "off";}

注意:adaptive 不是"按需思考",而是固定映射为 medium——名字容易误解,实际是固定档位的思考消耗,不会根据任务难度动态升降。

Claude Code(社区重写版)未在源码中看到类似 OpenClaw 那样显式暴露的 Thinking 档位控制逻辑——Thinking 参数直接透传 Anthropic API,由调用层决定。不提供手动的 ThinkLevel 旋钮,因而也没有额外的 thinking budget 分配开销。

OpenCode 对思考 token 做了动态上限控制(packages/opencode/src/provider/transform.ts,辅助验证,TypeScript):

// 根据模型输出上限动态计算 thinking budgetbudgetTokensMath.min(16_000Math.floor(model.limit.output / 2 - 1)),// 或对更大上限的模型:budgetTokensMath.min(31_999, model.limit.output - 1),

这个 budget 防止模型无限"想"下去——设定了思考 token 的天花板。

OpenCode 的计费细节packages/opencode/src/session/index.ts,第 849–862 行,TypeScript)——Reasoning Token 和超 200K 分层计费:

// index.ts 第849-852行:上下文超过 200K 时切换到更高费率const costInfo =  input.model.cost?.experimentalOver200K && tokens.input + tokens.cache.read > 200_000    ? input.model.cost.experimentalOver200K   // ← 超 200K token:启用高费率    : input.model.cost// index.ts 第861-862行:Reasoning Token 按输出价格计费,合并进 output 字段// charge reasoning tokens at the same rate as output tokens.add(new Decimal(tokens.reasoning).mul(costInfo?.output ?? 0).div(1_000_000))

两件事叠在一起:第一,某些 Claude 模型(如 Claude 3.7 Sonnet)超过 20 万 token 上下文后输入单价会有阶梯涨价,OpenCode 源码里通过 experimentalOver200K 字段明确处理了这个分层。第二,Reasoning Token 在代码里被按输出价格计费,且合并进 output 字段统一显示——这就是为什么账单里 output 数字看起来异常高时,很可能有相当一部分是思考消耗而不是实际输出。

这里的计费代码(.mul(costInfo?.output ?? 0))正是前文 §7 所论述的"Thinking Token 按输出价格计费"在源码层面的直接实现——Reasoning Token 和真实输出内容共用同一个单价变量,没有任何折扣。

对用户的意义: Thinking Token 合并在 output 字段里,是账单里最难追踪的一项消耗。别把 adaptive 当省钱开关——它每次都在用 medium 级别的思考消耗。长对话还要额外注意:超过 20 万 token 上下文后,每轮的输入单价可能悄悄跳涨一档。


命令输出洪水:一条命令,怎么把后续对话全拖慢了?

一条 git log,几千行输出进了上下文——从此以后,对话的每一轮都要把这几千行重新发给模型。就像往背包里塞了一本百科全书,之后每次出门都要把它一起扛着走。

这不是你的错,也不是工具的 bug。是工具调用结果进了上下文,而上下文的内容再也出不去(除非 Compaction 把它删掉,但那也意味着信息丢失)。

对于这个"工具输出洪水"问题,五个工具选择了不同的哲学:

Claude Code(社区重写版)的策略:指令文件截断 + 告知rust/crates/runtime/src/prompt.rs,第 366–376 行,Rust)

fn truncate_instruction_content(content: &str, remaining_chars: usize) -> String {    let hard_limit = MAX_INSTRUCTION_FILE_CHARS.min(remaining_chars);    let trimmed = content.trim();    if trimmed.chars().count() <= hard_limit {        return trimmed.to_string();    }    let mut output = trimmed.chars().take(hard_limit).collect::<String>();    output.push_str("\n\n[truncated]");    output}

截断的对象是指令文件(CLAUDE.md 等),超出单文件 4,000 字符上限后追加 [truncated] 标记,让 Agent 知道内容被裁剪了。值得注意的是:在已核到的 claw-code 源码中,这个截断保护是针对 system prompt 构建阶段的指令文件,并非所有工具调用结果的通用上限——通用工具输出的大小控制由调用层按需处理。

OpenClaw 的策略:截断 + 详细提示src/agents/pi-embedded-runner/tool-result-truncation.ts,第 19–34 行,TypeScript)

export const HARD_MAX_TOOL_RESULT_CHARS = 400_000;  // 单条工具结果上限 ≈ 100K tokenconst TRUNCATION_SUFFIX =  "\n\n⚠️ [Content truncated — original was too large for the model's context window. " +  "The content above is a partial view. If you need more, request specific sections or use " +  "offset/limit parameters to read smaller chunks.]";

不仅截断,还用详细的 ⚠️ 提示告诉 Agent"内容被截了,请用 offset/limit 读小块"——这样 Agent 不会基于不完整信息做出错误结论。同时还保留"重要尾部"的逻辑(检测错误信息 / JSON 结构 / 摘要行)。

OpenCode 的策略:截断 + 本地卸载packages/opencode/src/tool/truncation.ts,辅助验证,TypeScript)

MAX_BYTES  = 50 * 1024   // ≈ 50 KiB(51,200 bytes)MAX_LINES  = 2_000       // 2000 行

超限后完整内容写入本地磁盘(~/.opencode/data/tool-output/),上下文里保留截断预览 + 文件路径,并附上提示:

const hint = hasTaskTool(agent)  ? `The tool call succeeded but the output was truncated. Full output saved to: ${filepath}\n` +    `Use the Task tool to have explore agent process thisfilewith Grep andRead (with offset/limit). ` +    `Do NOT read the full file yourself - delegate to save context.`  : `The tool call succeeded but the output was truncated. Full output saved to: ${filepath}\n` +    `Use Grep to search the full content or Read with offset/limit to view specific sections.`

与 Deep Agents 的卸载哲学相同——信息完整保留,Agent 可按需读取;落点是本地磁盘而非虚拟文件系统。

Deep Agents 的策略:双阈值卸载 + 工具参数截断deepagents/middleware/filesystem.py,第 577–578 行;deepagents/middleware/summarization.py,第 631–655 行,次要验证,Python)

# filesystem.py 第577-578行:两个独立的驱逐阈值tool_token_limit_before_evict: int | None = 20000,      # 工具结果超过 2 万 token 驱逐human_message_token_limit_before_evict: int | None = 50000,  # 用户消息超过 5 万 token 驱逐# 超出阈值时,把内容写入后端文件系统,上下文里只保留引用file_path = f"/large_tool_results/{sanitized_id}"# 模型收到的是:# "Result was too large. Saved to /large_tool_results/<call_id>. Use read_file to inspect."

Deep Agents 还有一个更精细的工具参数截断机制:不等到整体压缩,而是当对话超过阈值(默认 20 条消息时)就对早期消息里的大型工具调用参数单独截断——只保留前 20 个字符加省略标记("...(argument truncated)"),工具结果本身不动。这相当于在不丢弃信息结构的前提下,把已经不再需要的旧参数细节抹掉,属于"外科手术式"的 token 回收,比整体压缩的代价小得多。

不是丢弃,而是"搬走"。原始内容完整保留在虚拟文件系统里,上下文里只放一个路径引用。Agent 可以按需读取,不读就不占用上下文。

五种策略的本质对比:

工具
触发阈值
处理方式
信息完整性
源码位置
Claude Code(社区重写版)
指令文件单文件4,000字符/总计12,000字符
截断+插入[truncated]标记
针对指令文件,有损但Agent知情
prompt.rs:39-40
OpenClaw
超过400K字符或上下文窗口30%
截断+⚠️提示建议读小块
有损,但Agent有明确指引
tool-result-truncation.ts:19
OpenCode
超过50KB或2000行
完整内容写入本地磁盘,上下文放截断预览+路径
完整保留,Agent可按需读取
truncation.ts:13-14
Deep Agents
超过20K token
offload到后端,上下文只放路径引用
完整保留,可能产生额外读取步骤
utils.py:66 / filesystem.py:319
Codex CLI
超过10,000 token/内存缓冲1MiB
保留头部+尾部,中间插入截断标记
有损,但头尾均保留,优于纯头部截断
unified_exec/mod.rs:64-65

没有绝对最优的策略。 最危险的场景是:Agent 不知道自己"没看全",就做出了结论——这也是 Claude Code(社区重写版)和 OpenClaw 都选择在截断时明确告知 Agent 的原因。

对用户的意义: 对于需要处理大量文本的任务(日志分析、代码搜索、文件读取),提前在提示词里限定范围("只看最近 50 条"、"只搜 src/ 目录"、"先列出文件结构再精读"),比让工具的截断或卸载机制来兜底,能让 Agent 在更干净的上下文里工作。


两类 Agent 的本质差异:能做 ≠ 适合做

OpenClaw 能读写文件、能跑 bash、能编辑代码——那还要编码 Agent 干什么?

这个问题很多人问过。答案藏在源码里:两类 Agent 面对的不是同一个优化目标,代码层面的差异比你想象的大。

一、底座差一个数量级:同一句话,起步价相差 8 倍

前文已经算过账:Claude Code(社区重写版)底座最多约 5,000 token,OpenClaw 底座最多约 42,000 token

根源不是谁写得臃肿。看 system prompt 的内容结构就清楚了——

Claude Code(社区重写版)的 system prompt 只有四个 section(rust/crates/runtime/src/prompt.rs,第 134–156 行,Rust):

pub fnbuild(&self) -> Vec<String{    sections.push(get_simple_intro_section(..));    // ① 身份(编码助手)    sections.push(get_simple_system_section());      // ② 系统规则    sections.push(get_simple_doing_tasks_section()); // ③ 编码任务守则    sections.push(get_actions_section());            // ④ 操作安全    // 然后是动态边界 + 环境信息 + 指令文件}

四个 section,全部围绕"怎么写好代码"。

OpenClaw 的 system prompt 有十几个 section(src/agents/system-prompt.ts,第 423–678 行,TypeScript):

const lines = [    "You are a personal assistant running inside OpenClaw.",    "## Tooling",           // 24+ 个工具定义    "## Tool Call Style",   // 调用规范    "## Safety",            // 安全守则    "## OpenClaw CLI Quick Reference",  // CLI 指令    "## Skills",            // 技能系统    "## Memory Recall",     // 记忆检索    "## OpenClaw Self-Update",  // 自更新    "## Workspace",         // 工作区    "## Sandbox",           // 沙箱指导    "## Reply Tags",        // 消息回复标签    "## Messaging",         // 多渠道消息路由    "## Voice (TTS)",       // 语音    "## Silent Replies",    // 静默回复协议    "## Heartbeats",        // 心跳保活    "## Runtime",           // 运行时信息    // ... 还有 Reactions、Reasoning Format、Project Context 等];

多出来的每一个 section 都不是冗余——Messaging 是为了多渠道消息路由,Heartbeat 是为了缓存保温,Memory Recall 是为了长期记忆,Silent Replies 是为了消息平台不发多余消息。但对一个编码任务来说,这些全是"不需要但必须付费"的底座。

二、工具集差异:10 个 vs 24+,定义本身就是 token

Claude Code(社区重写版)内置 10 个工具(rust/crates/tools/src/lib.rs,第 53–250 行):

pub fn mvp_tool_specs() -> Vec<ToolSpec> {    vec![        // 文件操作:bash、read_file、write_file、edit_file        // 代码搜索:glob_search、grep_search        // 信息获取:WebFetch、WebSearch        // 任务管理:TodoWrite        // 子Agent:Agent    ]}

全部围绕代码读写。没有 message、cron、browser、canvas、image_generate、memory_search。

OpenClaw 有 24+ 个核心工具(src/agents/system-prompt.ts,第 239–300 行):

const coreToolSummaries = {    readwrite, edit, apply_patch, grep, find, ls,  // 文件操作(7 个)    exec, process,                                     // 命令执行(2 个)    web_search, web_fetch, browser,                    // 网络(3 个)    canvas, nodes, cron, message, gateway,             // 平台能力(5 个)    agents_list, sessions_list, sessions_history,      // 会话管理(6 个)    sessions_send, sessions_spawn, subagents,    session_status, image, image_generate,             // 其他(3 个)};

前文说过——工具定义是全量注入的,不管本轮用不用。每个工具定义(name + description + JSON Schema)约 100–300 token,10 个 vs 24+ 个,仅工具定义就差约 2,000–4,000 token

三、编码 Agent 有而消息 Agent 没有的专属优化

这是最关键的差异。编码 Agent 不只是"功能少",而是在编码路径上做了消息 Agent 没做的优化:

① git 状态作为底座的一部分(零额外调用)

Claude Code(社区重写版,rust/crates/runtime/src/prompt.rs,第 73–80 行):

pub fndiscover_with_git(cwd, current_date) -> Self{    context.git_status = read_git_status(&context.cwd);  // git status --short    context.git_diff = read_git_diff(&context.cwd);      // staged + unstaged diff    // 启动时自动注入 system prompt,Agent 开口前就知道代码当前状态}

OpenClaw 没有这个机制。在 OpenClaw 里,Agent 要知道代码状态需要先调一次 execgit status),再调一次 execgit diff)——两轮额外工具调用,两轮额外 token。

② 项目类型自动检测 + 编码规则生成

Claude Code(社区重写版,rust/crates/rusty-claude-cli/src/init.rs,第 63–78 行、219–239 行):

struct RepoDetection {    rust_workspace: bool, rust_root: bool,    python: bool, package_json: bool, typescript: bool,    nextjs: bool, react: bool, vite: bool, nest: bool,    // ...}// 检测后自动生成 CLAUDE.md,包含编译/lint/测试命令// Rust 项目 → "cargo fmt, cargo clippy --workspace, cargo test --workspace"// TypeScript → "npm run build, npm run lint, npm run test"

初始化时扫描项目结构,自动生成包含语言、框架、验证命令的 CLAUDE.md。OpenClaw 没有项目感知初始化——它的初始化面向的是消息渠道配置(Telegram token、Signal 号码等)。

③ edit_file 返回结构化 patch

Claude Code(社区重写版,rust/crates/runtime/src/file_ops.rs,第 60–78 行):

pub struct EditFileOutput {    pub old_stringString,    pub new_stringString,    pub original_fileString,        // 完整原文保留    pub structured_patchVec<StructuredPatchHunk>,  // 精确 hunk    pub git_diffOption<Value>,      // git diff 格式}

编辑后返回结构化的 patch(old_start/old_lines/new_start/new_lines),Agent 后续引用改动时不需要重新读整个文件。OpenClaw 的 apply_patch 是另一种设计——它面向的是"一次性多文件批量补丁"场景,适合大规模操作但不是逐步精细编辑的最优路径。

④ 三级渐进式权限:编码路径零摩擦

Claude Code(社区重写版,rust/crates/runtime/src/permissions.rs,第 4–9 行):

pub enum PermissionMode {    ReadOnly,           // 读文件、搜索 → 自由执行,零确认    WorkspaceWrite,     // 写文件、编辑 → 需要第二级权限    DangerFullAccess,   // bash 危险命令 → 需要最高级权限}

编码任务最常见的路径——"读代码 → 分析 → 改代码"——前两步在 ReadOnly 下无需任何确认。OpenClaw 的权限模型面向的是多用户消息安全,粒度更细(按工具类别、按用户身份),但编码路径上会多出审批摩擦。

⑤ system prompt 里的编码最佳实践

Claude Code(社区重写版,rust/crates/runtime/src/prompt.rs,第 468–481 行):

fn get_simple_doing_tasks_section() -> String {    // "Read relevant code before changing it and keep changes tightly scoped"    // "Do not add speculative abstractions, compatibility shims, or unrelated cleanup"    // "Do not create files unless they are required to complete the task"    // "Be careful not to introduce security vulnerabilities"}

这些指令直接硬编码在 system prompt 里,不占额外 token(属于固定底座),却确保每次编码都遵循最佳实践。OpenClaw 的 system prompt 把同等位置让给了消息路由规则和多渠道协议。

四、上下文管理的哲学差异

两类 Agent 对"上下文里什么最值钱"的判断完全相反:

编码 Agent 认为"当前代码最值钱"——底座尽可能小(省空间给代码内容),压缩选择零成本的本地规则摘要(compact.rs 第 113–197 行,纯 Rust 逻辑,不调 LLM),因为编码任务的历史对话价值衰减快,三步前读的文件可能已经不相关了。

消息 Agent 认为"对话记忆最值钱"——底座虽重但通过 Heartbeat 保温缓存来回收成本(heartbeat.ts,每 30 分钟保活),压缩选择 LLM 摘要(compaction.ts 第 3 行调用 generateSummary),因为消息场景的用户可能明天回来问"上周我们讨论的那个事"——历史语义必须保留。

五、选择参考:什么时候用哪个

场景
编码 Agent
消息 Agent
原因
改一个函数、修一个 bug
底座 5K vs 42K,单轮成本差 8 倍
连续重构多个文件
git diff 自带感知,权限无摩擦
跨天多人协作项目管家
Memory 系统 + 多会话 + 持久记忆
定时任务 + 消息提醒
cron + 多渠道 message 是内置能力
代码 + 浏览器 + 图片生成
browser / canvas / image_generate 全内置
简单问答、快问快答
底座越轻,简单任务性价比越高

一句话总结:OpenClaw 能编码,但每次编码都要为消息平台的全部能力买单;Claude Code 能且只能编码,但每一分 token 都花在刀刃上。 能做 ≠ 适合做——"用什么工具"和"做什么任务"匹配起来,才是真正省钱的方式。


结语

51 万行代码泄露之后,全网在扒隐藏功能、安全架构、愚人节彩蛋。

但翻完五个 Agent 的源码,最深的感受是——

Agent 的引擎只有三行伪代码。但围绕 Context 的管理代码,比引擎本身多出一个数量级。

五个工具,三大语言,五个团队,给出了同一批答案。七个机制之外,延伸出以下细节同样值得关注:

  • Token 估算都用 chars/4——TypeScript、Rust、Python,同一个魔法数字,不是巧合
  • 固定底座每次请求都在,对话还没开始就在计费
  • Provider 字段语义不统一,换渠道时工具显示的用量可能失准
  • 工具调用结果会累积,长任务的雪球效应是真实的
  • Prompt Caching 能大幅省钱,但得工具设计支持、前缀稳定才能命中
  • Thinking Token 合并在 output 里,是账单里最难追踪的消耗,但有旋钮可以调
  • 命令输出洪水无处不在——截断保上下文,卸载保信息,各有权衡
  • 指令文件加载时机各不同:Claude Code(社区重写版)启动时全量扫描固定底座;OpenCode 的底座随 Read 工具调用"生长";OpenClaw 在 Compaction 后重注入关键 section;Deep Agents 只放 skill metadata、完整内容按需读——五种设计,token 消耗特性迥异
  • 部分工具存在主对话之外的后台作业:例如 Codex CLI 存在独立的 memory 流水线,是与当前对话线程解耦的异步后台作业
  • 200K 分层计费:超过阈值后输入单价悄悄跳涨,Reasoning Token 按输出价格计费并藏在 output 账单里
  • Compaction 可配置:Claude Code(社区重写版)/ OpenCode / OpenClaw 均暴露了触发阈值配置;OpenCode 和 OpenClaw 还支持单独指定 Compaction 使用的模型,把摘要任务交给便宜的小模型是系统性降本手段;Deep Agents 未发现用户侧的 Compaction 阈值或关闭配置项
  • 编码 Agent 和消息 Agent 面对同一套约束,但优化方向相反:底座 5K vs 42K、10 个工具 vs 24+、零成本本地压缩 vs LLM 摘要——能做 ≠ 适合做,选对工具本身就是最大的省钱手段

这些不是某个工具的特有问题。这是 LLM-based Agent 的共同底层约束,理解它们,能让你在使用各类AI编程工具时做出更精准的决策。

从三行伪代码到七个机制,Claude Code(社区重写版)的 Rust 实现和 OpenClaw 的 TypeScript 实现从两种设计哲学印证了同一件事:Context 管理才是 token 消耗的真正战场——而选对工具类型,是进入这个战场之前最重要的一步。

理解这些,不是为了避开工具,而是用得更明白——知道钱花在哪里,才能在合适的时候做合适的选择。


可操作参考清单

以下是基于本文内容的参考方向,供结合实际场景判断使用。

选对工具类型(最优先)

  • 纯编码任务(改函数、修 bug、重构文件)优先用编码 Agent——底座成本比消息 Agent 低约 8 倍,工具集专为代码路径优化,git 状态自动感知、结构化 patch、渐进式权限都是编码专属设计
  • 需要跨天记忆、定时任务、多渠道消息、浏览器操作、图片生成时,消息 Agent 才是正确选择——这些能力编码 Agent 没有内置,勉强用反而多绕路

编码 Agent 类工具(OpenCode、Claude Code 等 AI 编程助手)

  • 接入了多少个 MCP server?每个 server 的工具定义都会加重底座——用不到的断开,有助于降低每次请求的起步成本
  • 如果工具提供了 cache 统计,查看 cache.read 占总输入 token 的比例——接近 0 时值得关注,频繁变动的配置文件可能是原因之一
  • 大任务拆成多个独立短对话,比一个超长对话更能控制雪球效应——每次重启对话,上下文从底座重新开始
  • 如果你在用 OpenCode 或 OpenClaw,可以把 Compaction(上下文压缩)单独配置为使用更便宜的小模型(如 Haiku 级别):OpenCode 在 agents.compaction.model 里指定,OpenClaw 在 agents.defaults.compaction.model 里填 "provider/model-id"——主对话继续用大模型,压缩任务交给小模型,几乎没有副作用

关于指令文件 / 项目配置(通用)

  • 如果你的工具支持项目级 AI 配置文件(如 .cursorrulesAGENTS.md、项目级系统提示),总字符量越大,靠后的配置越可能被截断或忽略——这是先到先得的预算机制,不是按重要性排序的。重要规则放前面,精简总长度,比多写规则更有效
  • 使用 OpenCode 时,如果项目目录层级较深且每层都有 AGENTS.md,底座会随 Agent 读取文件的深入而增量增重——考虑将规则集中到根目录一份,避免底座随对话"悄悄生长"
  • Thinking / Reasoning 等级配置中,adaptive(自适应)是固定映射到中等级别,不等于"按需思考"——简单任务可以手动调到 low 或 minimal,明确不需要思考时设为 off

通用(所有 Agent 工具)

  • 让 Agent 执行 grepgit logfind 等命令时,主动加 flag 限制输出规模:git log --oneline -20find . -maxdepth 2grep -m 50——大输出一旦进了上下文就出不去,后续每轮都要重读
  • 集中连续工作比频繁中断更省钱:Anthropic 的缓存 TTL 默认为 5 分钟(短缓存)或 1 小时(长缓存),空闲超过 TTL 后再回来,第一次请求需要重新写入缓存(写入成本比普通输入高 25%)——缓存收益要从第二轮开始才能抵回(注:这里说的是同一个对话内不要中途长时间挂起;上面"大任务拆成多个短对话"说的是跨任务之间主动拆分以控制雪球——两者针对不同维度,并不矛盾)
  • 对话上下文接近 200K token 时,是开新会话的重要信号——部分 Claude 模型在超过 200K 后输入单价会阶梯上涨,继续扛着对话的边际成本比重新开始更高
  • 切换 Provider(如从 Anthropic 直连换到 OpenRouter)后,工具内显示的用量数字可能因字段语义不同而有偏差——最终账单以 Provider 计费为准
  • 工具显示的上下文"还有空间"是估算值(chars/4),中文等多字节内容的实际 token 消耗可能明显高于工具显示值——偏差方向是低估,具体幅度因内容和模型而异

以上清单建议结合具体场景判断,不必全部执行——理解背后的机制比执行每一条更重要。


附录:本文参考的五个开源仓库

工具
GitHub 地址
说明
OpenCode
https://github.com/anomalyco/opencode
CLI 编码 Agent,TypeScript / Bun
OpenClaw
(龙虾)
https://github.com/openclaw/openclaw
消息平台 AI 代理,接入 WhatsApp / Telegram,TypeScript
Codex CLI
https://github.com/openai/codex
OpenAI 官方开源编码 Agent,Rust + TypeScript,Apache 2.0
Deep Agents
https://github.com/langchain-ai/deepagents
LangChain 官方 Python Agent 框架,MIT
Claude Code
(社区重写版)
https://github.com/instructkr/claw-code
Claude Code 架构的社区逆向重写(Rust + Python),非官方,2h 破 50K star


声明:本文来自公众号:游戏开发技术教程(GameDevLearning),转载请附上原文链接及本声明。

关注【游戏开发技术教程

游戏开发技术、技巧、教程和资源,答疑解惑,内推面试

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-05-13 12:13:22 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/617557.html
  2. 运行时间 : 0.194173s [ 吞吐率:5.15req/s ] 内存消耗:4,906.10kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=3fce9046778c73dfccf913b68adf8e2a
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000524s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000769s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000678s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.010681s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000951s ]
  6. SELECT * FROM `set` [ RunTime:0.002080s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000651s ]
  8. SELECT * FROM `article` WHERE `id` = 617557 LIMIT 1 [ RunTime:0.000676s ]
  9. UPDATE `article` SET `lasttime` = 1778645602 WHERE `id` = 617557 [ RunTime:0.017160s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.004468s ]
  11. SELECT * FROM `article` WHERE `id` < 617557 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.006612s ]
  12. SELECT * FROM `article` WHERE `id` > 617557 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.003149s ]
  13. SELECT * FROM `article` WHERE `id` < 617557 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.003760s ]
  14. SELECT * FROM `article` WHERE `id` < 617557 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.019641s ]
  15. SELECT * FROM `article` WHERE `id` < 617557 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.009326s ]
0.197272s