当前位置: 首页 > news >正文

MCP工具吃Token太猛?3个实测方案砍掉70%消耗

用Claude Code或Cursor在大项目里干活最头疼的不是模型不够聪明是上下文窗口不够用。你让它查一个认证模块怎么实现的它把相关的20个文件全读进来。grep一遍、读一遍、分析一遍Token哗哗地烧。还没开始写代码呢上下文就快满了。问题出在哪MCP工具的返回设计。我最近在自己的项目里做了一轮MCP工具的Token优化效果很直观同样的任务Token消耗从平均4.2万降到了1.1万。方法不复杂就三个方向。问题到底多严重先说数据。我用Claude Code跑了一个中等规模的Node.js项目大约380个文件总共12万行代码记录了10次常见操作的Token消耗。常见操作的Token消耗对比查找某个函数的定义和用法平均消耗3.8万Token理解一个模块的整体逻辑平均消耗5.2万Token修改一个跨3个文件的功能平均消耗6.7万Token这些数字是什么概念Claude的上下文窗口是200K Token。光是理解一个模块就吃掉了窗口的25%。连续做3个任务上下文基本就满了。根因很简单默认的文件读取MCP工具是全文返回模式。你问它auth.js里有什么它把整个文件内容原封不动地塞进上下文。380行的文件就是380行不管你需要的是第52行的那个函数签名还是整份代码。方案一摘要优先按需展开最直接的改法MCP工具不要默认返回全文返回结构化摘要。我写了一个叫code-summary的MCP工具用AST解析代码文件返回的不是源代码是这样的结构{file:src/auth/middleware.js,exports:[authMiddleware,validateToken,refreshSession],functions:[{name:authMiddleware,params:[req,res,next],lines:[15,48],calls:[validateToken,getUserFromCache],description:Express中间件校验请求头中的Bearer Token},{name:validateToken,params:[token],lines:[50,82],calls:[jwt.verify,checkTokenBlacklist],description:校验JWT Token有效性检查黑名单}],imports:[jsonwebtoken,./cache,../config],loc:127}一个127行的文件全文返回大约消耗800个Token。摘要返回只消耗120个Token左右——少了85%。关键点在按需展开。智能体看完摘要后知道validateToken函数在第50到82行需要看细节时再调用一次read-lines工具只读这33行。实现代码不长核心是AST解析那部分// mcp-server/tools/code-summary.jsconstparserrequire(babel/parser);consttraverserequire(babel/traverse).default;functionsummarizeFile(filePath,source){constastparser.parse(source,{sourceType:module,plugins:[typescript,jsx]});constfunctions[];constimports[];constexports[];traverse(ast,{FunctionDeclaration(path){functions.push({name:path.node.id.name,params:path.node.params.map(pp.name||...),lines:[path.node.loc.start.line,path.node.loc.end.line],description:extractLeadingComment(path)});},ImportDeclaration(path){imports.push(path.node.source.value);},ExportNamedDeclaration(path){if(path.node.declaration?.id){exports.push(path.node.declaration.id.name);}}});return{file:filePath,functions,imports,exports,loc:source.split(\n).length};}Python项目也一样用ast模块做解析就行。注意一个坑纯AST解析拿不到函数的实际用途。我的做法是读函数上方的注释作为description。如果没注释就取函数体的前3行作参考。别试图让LLM来生成description那样每个文件又多一次API调用得不偿失。方案二给每次MCP调用设Token上限第二个方案更粗暴但很有效给MCP工具的返回值设一个Token硬上限。在MCP server的响应层加一个中间件超过指定长度就自动截断并在末尾附上提示// mcp-server/middleware/token-limit.jsconst{encode}require(gpt-tokenizer);functionwithTokenLimit(handler,maxTokens2000){returnasync(params){constresultawaithandler(params);constcontenttypeofresultstring?result:JSON.stringify(result);consttokensencode(content);if(tokens.lengthmaxTokens){returnresult;}// 按Token数截断不是按字符数consttruncatedtokens.slice(0,maxTokens);consttruncatedTexttruncated.map(tt).join();return{content:truncatedText,truncated:true,totalTokens:tokens.length,returnedTokens:maxTokens,hint:内容已截断(${maxTokens}/${tokens.length}tokens)。用read-lines工具指定行号范围获取完整内容。};};}我给不同类型的工具设了不同的上限constTOOL_TOKEN_LIMITS{read-file:2000,// 文件读取最多2000 Tokensearch-code:3000,// 代码搜索最多3000 Tokenlist-directory:500,// 目录列表最多500 Tokengit-diff:4000,// Git差异最多4000 Tokenread-lines:1500// 行范围读取最多1500 Token};踩坑提醒Token上限不能设太低。我一开始把read-file设成了800 Token结果智能体经常需要连续调用3-4次read-lines才能凑齐需要的信息来回调用反而比一次读完消耗更多。2000是我测出来比较平衡的数值。还有一个细节截断的时候别在代码块中间切断。我加了个处理——如果截断点在代码块内就往前退到代码块开始之前functionfindSafeBreakpoint(text,position){constcodeBlockPattern/[\s\S]*?/g;letmatch;while((matchcodeBlockPattern.exec(text))!null){if(match.indexpositionmatch.indexmatch[0].lengthposition){returnmatch.index;// 退到代码块开始前}}returnposition;}方案三语义搜索替代全文grep第三个方案投入最大效果也最好。传统的代码搜索MCP工具底层就是grep或ripgrep。你搜authentication它把所有包含这个词的文件和匹配行全部返回。在大项目里随便一搜就是几十个匹配Token消耗轻松过万。语义搜索的思路不同先给代码库建向量索引搜索时返回语义最相关的Top-K结果。我的方案用的是本地的Embedding模型nomic-embed-text通过Ollama跑。不依赖外部API没有额外费用。索引构建的流程# 安装依赖npminstallanthropic-ai/sdkvectordb# 在项目根目录运行索引脚本nodebuild-index.js--dir./src--extensions.js,.ts,.py索引脚本的核心逻辑是把每个函数拆成独立的chunk而不是按固定字符数切分// build-index.jsasyncfunctionbuildIndex(projectDir){constfilesglob.sync(${projectDir}/**/*.{js,ts},{ignore:**/node_modules/**});constchunks[];for(constfileoffiles){constsourcefs.readFileSync(file,utf-8);constfunctionsextractFunctions(source);// 用AST提取for(constfnoffunctions){chunks.push({id:${file}:${fn.name},text:fn.body,metadata:{file,name:fn.name,startLine:fn.startLine,endLine:fn.endLine}});}}// 批量生成embeddingconstembeddingsawaitgenerateEmbeddings(chunks.map(cc.text));// 写入本地向量数据库awaitdb.insert(chunks.map((c,i)({...c,vector:embeddings[i]})));console.log(索引完成:${chunks.length}个函数块, 来自${files.length}个文件);}搜索时返回Top 5相关函数就够了// mcp-server/tools/semantic-search.jsasyncfunctionsemanticSearch(query,topK5){constqueryEmbeddingawaitembed(query);constresultsawaitdb.search(queryEmbedding,topK);returnresults.map(r({file:r.metadata.file,function:r.metadata.name,lines:${r.metadata.startLine}-${r.metadata.endLine},relevance:r.score.toFixed(3),preview:r.text.slice(0,200)...}));}实测数据对比搜索用户登录后的Token刷新逻辑 - grep模式返回34个匹配消耗约8600 Token - 语义搜索返回5个函数消耗约1200 Token准确率方面语义搜索前5条命中目标函数的概率在我的项目里达到了92%。grep模式虽然不会遗漏但34条里只有3-4条是真正需要的噪声太多。索引构建一次需要2-3分钟380个文件之后增量更新在秒级。我在项目的pre-commithook里加了自动增量索引改了哪个文件就重建那个文件的chunk。三个方案组合的效果回到开头的数据。三个方案全部上线后同样10次操作的Token消耗查找函数定义和用法3.8万 → 0.9万减少76%理解模块整体逻辑5.2万 → 1.4万减少73%修改跨文件功能6.7万 → 2.1万减少69%平均下来Token消耗减少了约72%。上下文窗口的压力小了很多同一个对话里能连续做更多事。还有个附带好处智能体的回答质量也上去了。以前全文塞进上下文模型需要从一堆无关代码里找有用信息。现在只给相关片段模型的注意力更集中回答更准确。部署清单如果你想在自己的项目里试试按这个顺序来先上方案二Token上限中间件——改动最小5分钟搞定立刻生效再上方案一摘要优先——需要写AST解析逻辑大约半天工作量最后考虑方案三语义搜索——依赖Ollama和向量数据库初次部署需要1-2天方案二单独就能砍掉40%左右的Token消耗。三个方案叠加能到70%以上。代码我放在GitHub上了MCP server的完整实现包括上面提到的所有工具。有具体配置问题可以评论区聊。
http://www.zskr.cn/news/1388366.html

相关文章:

  • 为AI智能体设计的浏览器:从渲染引擎到语义引擎的范式转变
  • DeepSeek模型训练数据溯源指南:如何在48小时内完成IP权属链路审计?
  • Unity翻书效果实现:从Shader顶点位移到多页联动的完整方案
  • 不给现金,只给超3亿美元Token!Sam Altman开始“拿算力换股份”:向169家YC公司发200万美元Token,但要拿股权来换
  • AndLua加密APK逆向分析:从字节码提取到Java逻辑还原
  • IDA Pro花指令清除三法:字节匹配、CFG裁剪与语义替换
  • 基于大语言模型的GitHub PR描述自动生成工具设计与实践
  • 2026年舟山市本地上门黄金回收门店指南 彩金+铂金+金条+白银回收门店联系方式推荐 - 大熊猫898989
  • 2026年朔州市正规上门黄金白银回收品牌门店名录 K金+铂金+金条+银条回收门店联系方式推荐+指南 - 盛世金银回收
  • Unity Android构建报错SDK Tools version 0.0的根因与实战修复
  • 告别重复点击:用PyAutoGUI+psutil打造Windows游戏自动化守护进程(附完整源码)
  • ESP32-S3双功能实战:一个USB口同时实现U盘和虚拟串口,完整配置流程分享
  • A2UI框架:构建可解释、确定性交互的知识图谱智能体系统
  • 2026年四平市正规上门黄金白银回收品牌门店名录 K金+铂金+金条+银条回收门店联系方式推荐+指南 - 盛世金银回收
  • 用Xilinx Artix-7 FPGA驱动TDC-GPX2:一个完整的状态机SPI控制模块实现
  • Java集合全解析:体系架构+分类详解+底层原理+使用场景
  • IPSec的封装——TK
  • 全域无死角监测,无感技术筑牢矿山安全防线——黎阳之光重塑矿山安防新格局
  • PX4无人机Offboard模式实战:从Gazebo仿真到真机飞行避坑全记录
  • ASP.NET Core与Angular全栈开发自动化:代码生成器与AI代理协同工作流
  • 第四次小组会议纪要
  • 一文搞懂防孤岛和反孤岛的区别
  • 为AI工具调用添加数字签名收据:实现可审计与可信操作追踪
  • Unity Draw Call性能优化实战:从原理到真机调优
  • DeepSeek系统设计辅助:3步实现LLM集成效率提升47%(附可落地的Checklist)
  • 为Claude Desktop集成USDC钱包实现付费API自动化调用
  • 安卓7+ HTTPS抓包失效原因与4种实战解决方案
  • DS1302高精度RTC模块:嵌入式系统时间基准的硬件与软件实践
  • 荣耀出征 挂机练级与日常活动玩法心得 最新下载
  • 国内外5款用户行为分析工具盘点:国内企业为什么更应优先看 GrowingIO?