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

第十二篇:MessageBuilder 深度解析 —— Claude Code 如何构建对话消息

第十二篇:MessageBuilder 深度解析 —— Claude Code 如何构建对话消息

📚系列文章 第12篇/共100篇· 2026年7月 · ⏱️ 阅读时间约 13 分钟
源码位置:src/services/anthropic/MessageBuilder.ts


一、引言:为什么需要 MessageBuilder?

上一篇我们拆解了AnthropicClient.ts,它负责"连接" Anthropic API。但在这之前还有一个关键问题:

API 需要的不是零散的字符串,而是结构化的消息对象。这些消息从哪来?如何把用户的文本、系统提示、历史对话、工具调用结果、甚至图片,拼装成符合 Anthropic 规范的messages数组?

答案就是MessageBuilder.ts

它是 Claude Code 对话流水线的第一道加工车间

  • 🧱 把多源输入(用户输入、系统提示、工具结果、图片)统一成标准Message结构
  • 🖼️ 处理多模态:把图片转成base64或 URL 引用的imagecontent block
  • 📐 管理对话上下文:裁剪过长历史、压缩旧消息、控制 token 预算
  • 🔗 串联工具调用:把tool_use/tool_result配对成合法对话轮次

可以说,没有 MessageBuilder,AnthropicClient 拿到的就是一堆无法发送的数据


二、MessageBuilder 架构概览

┌─────────────────────────────────────────────────────────────┐ │ MessageBuilder │ ├─────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ Text Builder │ │ Image Builder│ │ System Builder │ │ │ │ (纯文本块) │ │ (多模态) │ │ (系统提示) │ │ │ └──────────────┘ └──────────────┘ └──────────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ History Mgr │ │ Token Budget │ │ Tool Round Mgr │ │ │ │ (历史裁剪) │ │ (预算控制) │ │ (工具轮次配对) │ │ │ └──────────────┘ └──────────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ AnthropicClient.sendMessage(messages)

数据流:

用户输入 + 系统提示 + 工具结果 + 图片 │ ▼ MessageBuilder.build() │ ├── 文本 → { type: 'text', text } ├── 图片 → { type: 'image', source } ├── 工具 → { type: 'tool_use' / 'tool_result' } ▼ 标准 Message[] ──► AnthropicClient ──► /v1/messages

三、核心类型定义

3.1 Anthropic 消息协议

MessageBuilder 的产物必须严格符合 Anthropic Messages API 的 schema:

interfaceMessage{role:'user'|'assistant';content:ContentBlock[];// 注意:content 是数组,不是字符串}typeContentBlock=|{type:'text';text:string}|{type:'image';source:ImageSource}|{type:'tool_use';id:string;name:string;input:unknown}|{type:'tool_result';tool_use_id:string;content:ContentBlock[]};interfaceImageSource{type:'base64';media_type:'image/jpeg'|'image/png'|'image/gif'|'image/webp';data:string;// base64 编码的图片数据}

关键认知:Anthropic 的content是一个块数组,而不是单个字符串。这正是多模态和工具调用的基础。MessageBuilder 的核心职责,就是正确地生成这个数组。

3.2 Builder 配置

interfaceMessageBuilderConfig{maxTokens:number;// 总 token 预算(如 200000)systemPrompt:string;// 系统提示reserveTokens:number;// 为回复预留的 token 数imageCompression?:boolean;// 是否压缩大图truncateStrategy:'head'|'tail'|'smart';// 裁剪策略}

四、文本与系统提示构建

4.1 构建系统提示

系统提示(system prompt)在 Anthropic API 中是顶层参数,不是 messages 的一部分:

buildSystem():string{constblocks:string[]=[];// 1. 基础身份提示blocks.push(this.config.systemPrompt);// 2. 注入当前环境信息(OS、shell、cwd、日期)blocks.push(this.buildEnvironmentContext());// 3. 注入工具定义摘要blocks.push(this.buildToolCatalog());returnblocks.join('\n\n');}privatebuildEnvironmentContext():string{constenv=this.envCollector.collect();return[`<environment>`,`OS:${env.os}`,`Shell:${env.shell}`,`CWD:${env.cwd}`,`Date:${env.isoDate}`,`</environment>`].join('\n');}

设计要点:系统提示是动态拼装的,会实时注入环境上下文,让模型"知道自己在哪台机器上工作"。

4.2 构建用户文本消息

addUserText(text:string):this{this.pendingUserBlocks.push({type:'text',text});returnthis;// 支持链式调用}// 用法builder.addUserText('帮我重构这个函数').addUserText('注意保留测试用例').build();

五、多模态:图片处理

这是 MessageBuilder 最精彩的部分——把图片塞进对话。

5.1 从文件路径读取并编码

asyncaddUserImage(filePath:string):Promise<this>{constbuffer=awaitfs.readFile(filePath);constmediaType=this.detectMediaType(filePath);// 大图压缩(可选)constdata=this.config.imageCompression?awaitthis.compressImage(buffer):buffer;constbase64=data.toString('base64');this.pendingUserBlocks.push({type:'image',source:{type:'base64',media_type:mediaType,data:base64}});returnthis;}

5.2 从 URL 引用图片

Claude 也支持直接传 URL(无需 base64):

addUserImageUrl(url:string):this{this.pendingUserBlocks.push({type:'image',source:{type:'url',url:url}});returnthis;}

5.3 多模态消息示例

constmessage=awaitbuilder.addUserText('这张截图里有什么错误?').addUserImage('./error-screenshot.png').build();// 生成的 content 块:// [// { type: 'text', text: '这张截图里有什么错误?' },// { type: 'image', source: { type: 'base64', media_type: 'image/png', data: 'iVBOR...' } }// ]

💡 实战价值:这就是为什么 Claude Code 能"看"截图、读取设计稿、分析图表。MessageBuilder 把图片转成模型可消费的块,是多模态能力的根基。


六、工具调用轮次管理

工具调用在 Anthropic 协议里是一对配对块,必须严格交替:

assistant: { type: 'tool_use', id: 't1', name: 'Read', input: {...} } user: { type: 'tool_result', tool_use_id: 't1', content: [...] }

6.1 配对管理

addToolUse(block:ToolUseBlock):this{// tool_use 必须来自 assistant 消息if(this.lastRole!=='assistant'){this.flush();// 先结束当前轮次}this.pendingAssistantBlocks.push(block);this.lastRole='assistant';returnthis;}addToolResult(toolUseId:string,content:ContentBlock[]):this{// tool_result 必须来自 user 消息this.pendingUserBlocks.push({type:'tool_result',tool_use_id:toolUseId,content});this.lastRole='user';returnthis;}

6.2 关键约束校验

validateToolPairs():void{// 每个 tool_use 必须有对应的 tool_resultconstuseIds=this.collectToolUseIds();constresultIds=this.collectToolResultIds();for(constidofuseIds){if(!resultIds.has(id)){thrownewMessageBuildError(`工具调用${id}缺少对应的 tool_result`);}}}

⚠️ 血的教训:Anthropic API 对工具配对极其严格。如果tool_use没有配对的tool_result,或反之,API 会直接返回 400。MessageBuilder 的校验逻辑正是为了拦截这类错误。


七、上下文与 Token 预算管理

这是 MessageBuilder 最复杂、也最能体现工程功力的部分。

7.1 Token 估算

privateestimateTokens(blocks:ContentBlock[]):number{lettotal=0;for(constblockofblocks){switch(block.type){case'text':total+=this.tokenizer.count(block.text);break;case'image':// 图片按像素估算 token(约 每 512x512 ≈ 85 token)total+=this.estimateImageTokens(block.source);break;case'tool_use':case'tool_result':total+=this.tokenizer.count(JSON.stringify(block.input??block.content));break;}}returntotal;}

7.2 智能裁剪

当历史超出预算时,按策略裁剪:

privatefitToBudget(messages:Message[]):Message[]{constbudget=this.config.maxTokens-this.config.reserveTokens;letused=this.estimateMessagesTokens(messages);if(used<=budget)returnmessages;// 从最旧的消息开始裁剪(保留最近对话)constresult=[...messages];while(used>budget&&result.length>1){constremoved=result.shift()!;// 移除最旧的一条used-=this.estimateMessagesTokens([removed]);}// 在开头插入截断标记result.unshift(this.buildTruncationNotice());returnresult;}

7.3 三种裁剪策略对比

策略行为适用场景
head丢弃最旧消息长对话,最近内容最重要
tail丢弃最新消息罕见,保留早期上下文
smart保留首尾,压缩中间需要全局上下文的复杂任务

💡 设计哲学:Claude Code 默认用head策略——因为编程对话中,最近的指令和上下文通常最关键。但smart策略会在处理超大文件/跨文件重构时启用,避免丢失早期的重要约束。


八、完整构建流程

build():BuiltMessages{// 1. 收尾当前 pending 的块this.flush();// 2. 组装 messages 数组constmessages=this.assembleMessages();// 3. 校验工具配对this.validateToolPairs();// 4. Token 预算裁剪constfitted=this.fitToBudget(messages);// 5. 构建系统提示constsystem=this.buildSystem();return{messages:fitted,system};}// 最终交给 AnthropicClientconst{messages,system}=builder.build();constresponse=awaitclient.sendMessage(messages,{system});

完整 ASCII 时序:

用户/工具 ──► MessageBuilder │ ├─ addUserText() ─┐ ├─ addUserImage() ├─ 累积 pending 块 ├─ addToolUse() │ ├─ addToolResult() ─┘ │ ▼ build() ├─ flush() 收尾轮次 ├─ assemble() 组装 messages ├─ validateToolPairs() 校验 ├─ fitToBudget() token 裁剪 └─ buildSystem() 系统提示 │ ▼ { messages, system } ──► AnthropicClient

九、使用示例

9.1 最简用法

constbuilder=newMessageBuilder({maxTokens:200000,systemPrompt:'你是一个编程助手',reserveTokens:4096,truncateStrategy:'head'});const{messages,system}=builder.addUserText('用 TypeScript 写一个快速排序').build();client.sendMessage(messages,{system});

9.2 多模态 + 工具混合

const{messages,system}=awaitbuilder.addUserText('这个 UI 有问题,看图').addUserImage('./ui-bug.png')// 多模态.addToolUse({// 工具调用type:'tool_use',id:'t1',name:'Read',input:{file_path:'./App.tsx'}})// (tool_result 会在下一轮由工具执行结果填入).build();

9.3 长对话自动裁剪

// 假设已经累积了 300 轮对话,远超 200k token 预算const{messages}=builder.addUserText('继续').build();// 内部自动裁剪最旧的消息,保留最近上下文

十、源码亮点总结

特性实现方式价值
多模态块content块数组 +imagesource支持图片输入
动态系统提示实时注入环境/工具上下文模型"身临其境"
工具配对校验validateToolPairs()避免 400 错误
Token 预算fitToBudget()智能裁剪永不超窗口
链式 APIaddX().addY().build()调用优雅
策略可配head/tail/smart灵活适配场景

十一、下一篇预告

第13篇我们将深入流式编排(StreamProcessor / query.ts),看看 Claude Code 如何把消息推送到 API、处理流式响应中的tool_use增量块、并实时渲染终端 UI。敬请期待!


📚Claude Code 源码解析系列

  1. 源码泄露事件深度解析
  2. 开发环境搭建指南
  3. CLI入口与命令系统
  4. AI对话引擎全解析
  5. 工具系统深度解析
  6. CLI命令行解析核心
  7. Handler处理器链
  8. QueryEngine查询引擎
  9. query.ts API对话层
  10. callModel.ts API调用层
  11. AnthropicClient API客户端
  12. MessageBuilder 消息构建器← 本文
  13. StreamProcessor 流式编排(待续)

💡如果这篇文章对你有帮助,欢迎点赞、收藏、关注!

有问题欢迎在评论区讨论!

#ClaudeCode #源码分析 #MessageBuilder #多模态 #TypeScript #AI编程

http://www.cnnetsun.cn/news/3192512.html

相关文章:

  • 5个提升英雄联盟游戏体验的智能功能:League Akari实战指南
  • yuzu模拟器终极指南:5分钟在PC上畅玩任天堂Switch游戏的完整教程
  • AMP by Example入门教程:如何在5分钟内创建你的第一个AMP页面
  • React-redux-toastr 源码深度剖析:从reducer到组件的完整实现原理
  • GeoQ用户权限管理:构建多层次地理数据访问控制体系
  • 免费开源风扇控制软件:FanControl终极静音散热指南
  • macOS平台下SourceEditor的应用实践:桌面端代码编辑新体验
  • stm 1.3.6 中文文本处理实战:从分词到主题建模的5步避坑指南
  • Rusty File Dialog高级特性:自定义按钮、隐藏文件与目录创建权限的完整指南
  • Next.js-tailwindcss-blog-template深度解析:揭秘现代博客架构设计
  • 安装到使用:FileRise文件管理器Docker部署全攻略
  • 提升React项目代码质量:tslint-react与ESLint的对比分析
  • 基于SSM+分布式开发的健康管理系统设计与实现
  • 基于SpringBoot人格障碍诊断系统设计与实现
  • 30 Days of SwiftUI:从SwiftUI新手到专家的终极学习路线图
  • Person Search项目安装配置:从零开始搭建CVPR 2017获奖框架
  • Audacity终极指南:免费专业音频编辑软件从入门到精通
  • Mac Mouse Fix终极指南:让普通鼠标在macOS上超越苹果触控板的5个秘诀
  • 如何用embyToLocalPlayer解决媒体服务器与本地播放器的割裂问题:完整实践指南
  • 如何快速上手M3u8Downloader_H:5分钟学会下载加密M3U8视频
  • Nintendo Switch大气层系统完整指南:解锁游戏设备的终极潜力
  • 【Java毕业设计】基于 SpringBoot 的区域乡村振兴助农服务平台的设计与实现 基于前后端分离的北部湾农户产销帮扶系统(源码+文档+远程调试,全bao定制等)
  • 高效实战:深度解析Transformer模型的TensorFlow实现与部署
  • Ubuntu 22.04 安装 NVIDIA 驱动 550.90.07:图形界面与 TTY 模式 2 种方案实测
  • 探索gh_mirrors/presentations170/presentations中的乐观主义:编程心态与成长指南
  • Android应用安全检测实战:使用Ruam Mij深度剖析可疑应用行为
  • Planning-with-Files三大文件详解:task_plan.md、findings.md、progress.md的使用技巧
  • Blender贝塞尔曲线终极指南:如何用Flexi Bézier工具集提升3D建模效率
  • Mix 2.0动画系统详解:从隐式动画到关键帧的完整教程
  • Tasker Permissions:Android自动化权限授予终极指南