多轮工具调用区间,TaoToken 帮你对 PaperScout 做成本归因
多轮工具调用 Agent 的成本归因第一步是统一出口TaoTokenhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcost_attribution把 Key 和 Base URL 收在一处之后PaperScout 每跑一次 Search / Expand 循环花了多少 token、落在哪个模型上、单位召回率烧掉多少钱才能被逐条对账。如果你正准备复现相同工具调用次数下召回率这组结论建议先用同一个 Key 跑通链路去官网拿 KeyBase URL 统一填 https://taotoken.net/api。这篇文章不聊 PSPO 的算法推导只做一件成本分析工程师该做的事——把多轮检索里那段最不可控的账单拆成一张能复现、能对比、能追责的归因表。1. 为什么 PaperScout 的成本必须按工具调用区间统计把学术检索建模成 POMDP 之后Agent 的每一步动作不再是发一条 query而是在论文池上做一次决策。落到工程侧这个决策会展开成一次完整的模型往返把当前论文池、历史动作、参考文献摘要一起塞进上下文让模型输出下一个动作是什么、参数是什么再交给检索后端执行。这带来三个直接后果上下文是累积的。第一轮 Search 的 prompt 可能只有几百 token到第二十轮 Expand 时历史论文摘要、已探索标记、去重记录全都堆在 messages 里prompt 轻松破万。如果按单次请求平均 token × 请求次数做预算误差会非常夸张。工具调用次数不可预知。同一道题Agent 可能在第 6 轮就判断引用链饱和并切换分支也可能在第 30 轮还在原地 Expand。调用次数是策略学出来的不是配置写死的。动作类型影响单步成本。Search 要生成检索式、可能触发一次外部检索Expand 要挑论文、拉参考文献、做相关性判断。两者的 completion 长度分布完全不同混在一起算均值会掩盖掉真实开销。所以衡量一个多轮检索 Agent 是否划算最合理的横轴不是时间、也不是 token而是工具调用次数。论文里那张相同工具调用次数下取得更高召回率的曲线翻译成成本语言就是在同样的调用预算下谁的召回更高谁的单位召回成本更低。这就给成本分析定义了任务给定一条 recalltool_calls 曲线反推出每一档调用次数对应的累计费用。2. 先统一网关把 Key 与 Base URL 定死做成本归因最怕的不是贵而是口径不统一。实验组用 A 家的 Key、对照组用 B 家的 Key单价、缓存策略、限流阈值全不一样最后算出来的成本差异其实是供应商差异。工程上最省事的做法是所有 Agent 进程、所有客户端、所有实验分支走同一个 Base URL用同一类 Key只通过 Key 的标签区分实验组。TaoToken 控制台里创建的 Key 就是干这个的每个实验分支一个 KeyBase URL 全部指向https://taotoken.net/api最后账单可以直接按 Key 名聚合。官网入口见 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentkey_per_branch 创建与轮换在控制台完成。本文全程使用的两个常量Base URL : https://taotoken.net/api API Key : YOUR_API_KEY注意两点Base URL 是给工具配置用的不带 UTM 参数别把营销链接直接填进去Key 一律走环境变量或配置文件不要硬编码在仓库里。3. 三套客户端配置Claude Code、Codex、CC Switch 各写各的PaperScout 这类工程通常自己直连 API但做调优时你大概率会同时开 Claude Code 读代码、开 Codex 改脚本。这三者配置方式完全不同混用变量名是最常见的踩坑点。3.1 Claude Codesettings.json 里的 ANTHROPIC_*Claude Code 读~/.claude/settings.json的env段。所有ANTHROPIC_*变量只属于它不要把下面这组变量名复制到 Codex 里。{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: claude-sonnet-4-5, ANTHROPIC_SMALL_FAST_MODEL: claude-haiku-4-5 } }几个实操要点ANTHROPIC_BASE_URL填到根路径即可不要自己再拼/v1。ANTHROPIC_AUTH_TOKEN就是你在控制台创建的那串 Key。ANTHROPIC_MODEL与ANTHROPIC_SMALL_FAST_MODEL建议分开配主模型跑检索决策小模型跑摘要压缩、去重判断这类轻活。多轮 Agent 的成本大头往往不在决策本身而在每轮都要重做的上下文压缩。改完配置重新开终端避免旧进程还在用上一次的环境变量。完整对接说明与变量清单在 Claude Code 文档页见文末。3.2 Codexconfig.toml 里的自定义 providerCodex 走的是~/.codex/config.toml用 provider 段声明字段名和 Claude Code 完全无关。把 Anthropic 那套变量名塞进来只会静默失效。model gpt-5-codex model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat配套的环境变量export TAOTOKEN_API_KEYYOUR_API_KEYenv_key写的是环境变量名而不是 Key 本身这是最容易填错的一格。wire_api按网关实际支持的协议选先试chat如果供应商侧同时暴露了 Responses 接口且你的 Codex 版本要求走它再切过去切换前先用一条最小请求验证返回结构。3.3 CC Switch三件套一次配齐如果你在多个供应商之间来回切手工改配置文件迟早会出错。CC Switch 这类切换器把配置拆成三件套供应商条目名称 Base URLhttps://taotoken.net/api KeyYOUR_API_KEY。模型映射把主模型、快速模型、长上下文模型分别映射到具体模型 ID一张表管住所有客户端的模型选择。切换开关在当前生效供应商上按一下同时改写 Claude Code 与 Codex 两边的配置文件并保留上一份配置便于回滚。三件套的价值不在于省几次粘贴而在于实验可复现跑对比实验前先固定当前供应商条目名实验结束后 Key 与 Base URL 都能原样复现归因表里的每一行才有意义。3.4 自研 AgentPaperScout 这类工程环境变量优先PaperScout 是开源工程你大概率会改它的模型调用层。不论底层用哪家 SDK都建议改成从环境变量读取import os BASE_URL os.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api) API_KEY os.environ[TAOTOKEN_API_KEY]这样切换实验分支时只用改环境变量代码零改动也顺手解决了 Key 不进仓库的问题。4. 归因表的字段设计工具调用次数 × Key × Base URL可复现产出的核心是一张表。表设计得对不对决定了你能不能回答第 12 轮到底亏在哪。推荐字段如下字段含义为什么需要ts请求时间戳毫秒对齐并发窗口与限流事件session_id一次检索会话同一道题的多次请求归组turn_index第几轮决策定位成本突增的轮次actionSearch / Expand区分动作类型成本分布tool_call_cum本会话累计工具调用次数横轴直接对接召回率曲线key_labelKey 的实验标签多分支对比base_url实际请求的 Base URL防止某分支偷偷走了别的网关model实际生效的模型 ID模型映射是否被切换器改错prompt_tokens输入 token上下文膨胀的主要观察项completion_tokens输出 token动作生成开销cached_tokens命中缓存的输入 token决定单位成本能否压下来latency_ms端到端耗时与超时重试关联retry_count该轮重试次数失败成本经常被漏算两张关键视图按会话累计视图把tool_call_cum当横轴sum(cost)当纵轴得到单题的成本曲线。这张图和 recall 曲线并排放才能看出多花 10 次调用换来多少召回。按 Key 分组视图按key_label聚合得到每条实验分支的总成本与单位召回成本。这一步能立刻暴露对照组其实走了不同单价这类低级错误。5. 采集脚本把每一次工具调用的 usage 落成 CSV下面这段脚本可以直接套在 PaperScout 的模型调用层外面作为装饰器或包装函数使用。它做三件事透传请求、把 usage 落盘、维护tool_call_cum计数。# cost_ledger.py import csv import os import time from pathlib import Path from openai import OpenAI LEDGER Path(papertool_ledger.csv) HEADER [ ts, session_id, turn_index, action, tool_call_cum, key_label, base_url, model, prompt_tokens, completion_tokens, cached_tokens, latency_ms, retry_count, ] client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api), ) _cum {} def _ensure_ledger(): if not LEDGER.exists(): with LEDGER.open(w, newline, encodingutf-8) as f: csv.writer(f).writerow(HEADER) def call_model(session_id: str, turn_index: int, action: str, messages, toolsNone, modelgpt-4.1-mini): 一次完整的模型往返返回 (response, usage_row)。 _ensure_ledger() t0 time.time() kwargs {model: model, messages: messages} if tools: kwargs[tools] tools kwargs[tool_choice] auto resp client.chat.completions.create(**kwargs) latency int((time.time() - t0) * 1000) usage resp.usage calls len(resp.choices[0].message.tool_calls or []) _cum[session_id] _cum.get(session_id, 0) calls cached 0 details getattr(usage, prompt_tokens_details, None) if details is not None: cached getattr(details, cached_tokens, 0) or 0 row [ int(time.time() * 1000), session_id, turn_index, action, _cum[session_id], os.environ.get(KEY_LABEL, default), os.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api), resp.model, usage.prompt_tokens, usage.completion_tokens, cached, latency, 0, ] with LEDGER.open(a, newline, encodingutf-8) as f: csv.writer(f).writerow(row) return resp, row调用侧只需要把原来的直连替换成call_model(...)session_id用题目 IDaction传Search或Expand。聚合脚本# aggregate.py import csv from collections import defaultdict PRICE_IN 0.0 # 按你的 Key 实际单价填写元 / 千 token PRICE_OUT 0.0 buckets defaultdict(lambda: {calls: 0, cost: 0.0, sessions: set()}) with open(papertool_ledger.csv, encodingutf-8) as f: for r in csv.DictReader(f): cum int(r[tool_call_cum]) cost ( int(r[prompt_tokens]) / 1000 * PRICE_IN int(r[completion_tokens]) / 1000 * PRICE_OUT ) b buckets[cum // 5 * 5] # 每 5 次调用分一档 b[calls] 1 b[cost] cost b[sessions].add(r[session_id]) print(f{调用区间:10}{请求数:8}{会话数:8}{累计成本:12}) for k in sorted(buckets): b buckets[k] print(f{f{k}-{k4}:10}{b[calls]:8}{len(b[sessions]):8}{b[cost]:12.4f})跑完这一步你手里就有了工具调用次数区间 → 累计成本的对照表可以直接和召回率曲线拼在同一张图上。6. 相同调用次数下的对照实验排障清单复现相同工具调用次数、不同召回率时最容易出问题的不是模型本身而是配置和网络层。按下面顺序排查能省掉大量无效对比。401 / 403。九成是 Key 没读到。检查TAOTOKEN_API_KEY是否在当前 shell 生效Claude Code 看ANTHROPIC_AUTH_TOKENCodex 看env_key指向的环境变量名是否拼错。注意 Codex 的env_key填的是变量名不是 Key。404。多半是 Base URL 被写成了带路径的形式。统一用https://taotoken.net/api不要自己追加版本号。429。多轮 Agent 天然高并发尤其是 Expand 之后跟着一批相关性判断请求。给采集脚本加指数退避并把retry_count记进表里——重试产生的成本如果不算进去归因表会偏乐观。latency 突然翻倍但 token 没涨。通常是上下文里塞了过长的参考文献原文。在 prompt 侧做摘要压缩比换更贵的模型有效得多。缓存命中率异常低。多轮 Agent 的 prompt 是前缀稳定、尾部增长的结构天然适合缓存。如果你发现cached_tokens长期接近 0先检查是不是每轮都把 messages 重排了一遍。保持前缀不变是压低单位成本最直接的手段。两条分支成本差异过大但代码相同。去看归因表里的base_url和model两列。切换器改了配置但进程没重启是这类幽灵差异的常见来源。7. 把归因表接回召回率曲线论文报告的那组对比里最值得成本工程师记下来的不是具体数值而是那根横轴的含义在较宽的工具调用区间内经过策略优化的 4B 模型可以逼近未做同类训练的大模型。从归因表的角度看这句话等价于单位召回成本可以被训练策略压低而不是只能靠换更大的模型。具体怎么验证固定session_id的题目集合跑两套策略有 / 无策略优化。用采集脚本记录每轮的tool_call_cum与prompt_tokens。按 5 次调用一档分桶算出每档的累计成本与累计召回。画两条曲线横轴调用次数左纵轴召回率右纵轴累计成本。找交点——在哪个调用区间两套策略的召回拉开差距而成本差距还没同步放大。这个交点就是多轮检索 Agent 值不值得继续多想几步的工程答案。还有一点容易被忽略Expand 和 Search 的成本结构不同。Expand 的 prompt 更长要带上候选论文的完整信息Search 的 completion 更长要生成新检索式。如果你发现某一档调用区间的成本突然跳升先看那一档里 Expand 的占比——它往往意味着引用链开始原地打转这也是 Agent 该主动切换方向、而不是继续深挖的信号。8. 从环境变量到归因表一次跑通的最小动作把上面的东西串起来最小可执行路径只有四步第一步统一出口。去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentsetup_entry 拿到 Key把TAOTOKEN_BASE_URL固定为https://taotoken.net/api。第二步按客户端分别写配置。Claude Code 写settings.json的ANTHROPIC_*Codex 写config.toml的 provider 段 env_key两套配置别互相抄变量名。需要多分支对比时用 CC Switch 的三件套固定供应商、模型映射与切换开关。第三步套上采集包装。把call_model接到 PaperScout 的模型调用层action字段老老实实标 Search / Expandkey_label一个实验分支一个值。第四步聚合出表。跑aggregate.py得到调用次数区间与累计成本的对照表和召回率曲线并排看。做完这四步你得到的不是这个月花了多少钱而是第几次工具调用之后边际召回开始低于边际成本。对做 Agent 成本分析的人来说后者才是能拿去做决策的东西。需要先确认模型单价与可用模型清单可以从模型对话入口跑一条最小请求验证链路模型对话https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchat_verifyCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentplan_multiturn创建 Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentcreate_keyClaude Code 文档https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_code_doc建议顺序是先用模型对话验证 Key 与 Base URL 能通再按用量选 Coding Plan然后到控制台创建按实验分支命名的 Key最后照 Claude Code 文档把settings.json的env段补齐。四步走完你的第一张工具调用次数 × Key × Base URL归因表就可以开始跑了。

相关新闻

脑电上肢运动意图识别中的卷积神经网络与PyTorch实践

脑电上肢运动意图识别中的卷积神经网络与PyTorch实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 5:49:35 阅读更多 →
Node.js 24.14.1 ‘Krypton‘(LTS)安全发布全解析:8 个 CVE 修复、依赖更新与升级校验指南

Node.js 24.14.1 ‘Krypton‘(LTS)安全发布全解析:8 个 CVE 修复、依赖更新与升级校验指南

Node.js 24.14.1 Krypton(LTS)安全发布全解析:8 个 CVE 修复、依赖更新与升级校验指南 【免费下载链接】nodejs.org The Node.js Website 项目地址: https://gitcode.com/GitHub_Trending/no/nodejs.org 本篇文章基于 nodejs.org 官网…

2026/9/19 5:49:35 阅读更多 →
用 Workbrew 把 Homebrew 变成企业级包管理:Fleet 集成实战指南

用 Workbrew 把 Homebrew 变成企业级包管理:Fleet 集成实战指南

用 Workbrew 把 Homebrew 变成企业级包管理:Fleet 集成实战指南 【免费下载链接】fleet Open device management 项目地址: https://gitcode.com/GitHub_Trending/fl/fleet 企业中的 macOS 设备越来越多,开发者依赖 Homebrew 安装和升级软件&…

2026/9/19 5:49:35 阅读更多 →

最新新闻

Turborepo 二进制入口深度解析:从 `turbo` crate 的薄封装看 Rust 迁移架构

Turborepo 二进制入口深度解析:从 `turbo` crate 的薄封装看 Rust 迁移架构

Turborepo 二进制入口深度解析:从 turbo crate 的薄封装看 Rust 迁移架构 【免费下载链接】turbo Build system optimized for JavaScript and TypeScript, written in Rust 项目地址: https://gitcode.com/gh_mirrors/tu/turbo 本篇文章以仓库中 crates/tur…

2026/9/19 7:16:14 阅读更多 →
STM32CubeMX+FreeRTOS实战:从零搭建LED闪烁任务

STM32CubeMX+FreeRTOS实战:从零搭建LED闪烁任务

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 7:16:14 阅读更多 →
ESP32音频abort残留问题:解码器状态重置与DMA清空实战

ESP32音频abort残留问题:解码器状态重置与DMA清空实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 7:16:14 阅读更多 →
BrewUI 评测:给 Homebrew 一个图形界面,轻松管理 Mac 软件包

BrewUI 评测:给 Homebrew 一个图形界面,轻松管理 Mac 软件包

1. 项目概述:BrewUI 是什么,以及我为什么盯上它用 Mac 做开发的人基本都躲不开 Homebrew。从装 Node、Python 这种运行时,到开个 wget、tmux 之类的小工具,我每天都要跟它打交道。但说实话,Homebrew 这个包管理器非常强…

2026/9/19 7:16:14 阅读更多 →
Chromium历史版本离线安装包下载与部署全攻略

Chromium历史版本离线安装包下载与部署全攻略

1. 为什么需要 Chromium 历史版本离线安装包做前端自动化、浏览器兼容性测试或者 Electron 桌面应用开发的朋友,大概率都遇到过这样的场景:某个线上问题只在特定版本的 Chromium 内核上复现,新版本浏览器早就修掉了;或者公司内网环…

2026/9/19 7:16:14 阅读更多 →
Civitai Orchestrator 工作流查询统一化:从双端点走向类型感知的单一路由

Civitai Orchestrator 工作流查询统一化:从双端点走向类型感知的单一路由

Civitai Orchestrator 工作流查询统一化:从双端点走向类型感知的单一路由 【免费下载链接】civitai A repository of models, textual inversions, and more 项目地址: https://gitcode.com/GitHub_Trending/ci/civitai 导读 本文围绕 Civitai 主站&#xf…

2026/9/19 7:15:14 阅读更多 →

日新闻

BP神经网络时序预测:滑窗长度与多窗口平均策略

BP神经网络时序预测:滑窗长度与多窗口平均策略

简介:面向机器学习、深度学习与数据建模学习者的一份完整研究文献,聚焦BP神经网络在农业产量预测中的应用。文档以1980—2018年全国棉花产量为样本,系统讲解数据归一化处理、激活函数原理、多层神经网络结构搭建及训练流程,展示敏…

2026/9/19 0:00:30 阅读更多 →
Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

上个月调一个Deformable DETR模型,在单卡上要跑将近两天。第二天早上我下意识打开终端翻日志,发现loss从凌晨两点就开始往上爬,一路从0.8涨到1.35,整整六个小时没人发现。那六个小时的训练不仅白跑,还霸占着卡——等于…

2026/9/19 0:00:30 阅读更多 →
OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南 【免费下载链接】opencloud 🌤️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign. 项目地址: htt…

2026/9/19 0:00:30 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/19 3:59:36 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/19 3:53:08 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/19 4:02:43 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →