大模型驱动的编码智能体:Claude Code的诞生与工程实践
发布时间:2026/10/18 2:48:21 锦皓数字建站

我没有想到一篇不长的博文帖子能引出一段将近半年的持续重构。做这个项目的起因其实非常简单有一天我在整理代码的时候发现白天的大部分时间都花在了重复的样板代码、接口联调文档翻查、以及测试用例补写上。每次接到一个新需求都要从零开始搭结构、命名、填参数这个过程既不优雅也谈不上创造纯粹是体力活。当时团队内部也在讨论能不能把手头的一些编码环节交给大语言模型来做让模型看懂项目结构、理解需求描述、直接产出可落地的代码。于是就有了这个代号为 Claude Code 的内部项目——当时我们团队管这一类直接待在开发环境里、能看懂全工程代码、能自己动手改代码的编程助手统称为 Claude Code。今天想把这个工具的完整诞生过程写下来从需求动机、技术选型、架构设计到实际跑起来之后踩过的坑以及最终沉淀下来的工程经验希望能给同样在做 AI 辅助编码工具的同学一点参考。1. 缘起当代码量的瓶颈不再是键盘速度1.1 团队里面临的真实浪费场景先说一个数据。我们做过一次原始估算一位后端同学在完成一个中等规模的业务模块时真正在思考业务边界、设计接口、梳理状态流转上的时间大约只占四成剩下六成几乎都花在了翻译上——把心中已经想清楚的设计翻译成代码语法把需求文档里的字段描述翻译成数据库映射把接口联调时的异常场景翻译成套娃般的捕获逻辑。这部分时间砍掉的难度不大但收益很大因为它不需要更强的推理能力只需要模型足够熟悉当前工程的代码风格和既有约定。另一个浪费点是记忆成本。团队里任何一位开发都知道改一个老模块最花时间的不是改代码本身而是先花半天把老代码里那些隐性的约定读明白某个字段为什么叫这个名字、某个配置为什么写死在这里、某段历史逻辑能不能动。如果你让一个新人接手这个成本还要再翻倍。如果存在一个工具能直接把这个问题抛给它这个模块的入参为什么会兼容两种格式然后它基于全工程索引给出带代码引用的回答那省下来的时间就相当可观了。1.2 从代码补全到代码执行的需求跃迁一开始我们考虑过直接使用市面上已经成熟的代码补全工具还有各种基于规则的模板生成方案。但试用几天之后一个明显的感受是这类工具擅长局部补全——比如你写了一个函数签名它能补充函数体你写了一行注释它能补出对应实现。可一旦需求变成帮我新增一个用户注销接口要求兼容旧版 Session、有分布式锁防重、还要在返回结构里带上下线提醒时间它们就完全没有办法了。因为这个问题跨了多个文件、涉及既有服务的能力边界、还需要理解团队自己定义的路由和错误码规范。所以需求从补全升级到了执行我们希望这个工具不只给你一段建议代码而是能像一个结对编程的伙伴一样——先去工程里翻找相关实现弄清楚项目里的约定然后设计改动方案最后直接生成改动后的文件内容甚至把测试用例一并写出来。这也是Claude Code这个代号在团队里流传开来的原因它不再是提示一下、补一段的玩具而是真的站在工程语境里干活的工具。2. 技术底座为什么选大模型而不是规则引擎2.1 规则引擎和模板方案的根本局限动手之前团队内部有过一轮方案争论。一派主张做一个传统的代码生成引擎通过 AST 解析项目结构预定义大量的代码模板再配合配置文件里的参数拼装出目标代码。这个思路的好处是输出完全可控每一行代码都是你模板里写好的不会出现模型脑补出奇怪逻辑的情况。坏处也很明显每接入一个业务场景就要设计一套新的模板和参数协议而且模板只能解决你事前想得到的场景一旦需求描述的表达方式超出了模板设计者的预判整个引擎立刻就哑火了。我当时随手举了个例子帮我把所有使用了这个废弃方法的地方统一替换成新接口并保留原有日志级别。这个需求在规则引擎里几乎没法做因为你得先有一份全工程的调用关系数据还要能理解保留原有日志级别到底指的是什么。而这种事情在真实的迭代中太常见了它本质上是一个需要语义理解的动态任务而不是一个可以通过穷举模板来覆盖的静态任务。2.2 基座模型怎么选效果、成本与可控性的平衡定了必须用大模型这个大方向之后紧接着就是基座模型的选型。我们当时锁定的评测标准有三个代码理解能力、长文本窗口表现、以及单次任务成本。这里要特别说明一下长文本窗口为什么单独列出来——因为看懂整个工程和看懂一段代码是完全不同的难度。一个中等规模的仓库可能有几百个文件核心的业务链路从入口到落库可能要跨越十多个文件如果模型窗口不够大、对长内容的检索注意力不够好它就会像一个只看了一页文档就开始回答问题的实习生给出的答案注定是一知半解的。我们内部做了个对比测试让不同备选模型完成同样几个任务根据一段需求描述补齐接口实现、解释一个跨文件的状态机流转、把一段旧风格的异常处理改写成新风格的统一错误码。测试下来的结果差距非常明显一些模型在单文件场景下表现不错但一旦把多个相关文件的代码片段拼进上下文就开始出现记了前面忘了后面的问题。最终我们选择了一个在这几个任务上综合表现最稳的基座模型而且留了一个非常关键的接口抽象模型底座是要能随时更换的不能和上层业务逻辑耦合死。2.3 微调还是 Prompt 工程低成本的起步路线还有一段纠结是要不要对基座模型做微调。当时有同事提议干脆收集一批团队历史代码把模型微调成团队专属版这样生成风格天然贴合我们的仓库。深入评估之后我们放弃了——不是因为微调不好而是因为时机不对。微调需要稳定的数据流水线、评测集和回归机制这本身就是一个项目而当时最核心的矛盾是验证工具形态是否成立即一个能读取全工程、能动手改文件的智能体流程到底能不能真正帮开发省时间。这个验证用现成的基座模型加上精心设计的 Prompt 和工具调用流程就完全可以做。我们当时采用的路线是先靠上下文工程和检索手段把相关代码喂给模型用明确的提示词约定生成格式尽量不依赖微调来保证质量。3. 核心架构一个编码智能体的四大模块3.1 会话管理层多轮对话中的工程状态维护这个项目最终跑起来的架构被我拆成了四个大模块会话管理、工程检索、生成引擎、执行沙箱。第一个模块叫会话管理它解决的最核心问题是模型的记忆和工程状态如何保持一致。这里举个具体场景。用户说把订单模块的查询接口加上分页模型生成了修改后的文件。紧接着用户又说还是不要加在查询参数里了加在响应结构里吧。如果这是一个无状态的对话模型第二次回答时根本不知道第一次改了什么文件、改成了什么样它就必须重新去工程里找一遍相关文件再基于完整的当前状态重新生成。为了避免这种浪费会话管理层维护了一个虚拟工作区对话过程中模型修改过的文件、生成的中间结论、确认过的接口方案都会被记录在会话的上下文中。原生封装之后模型每一轮都能拿到当前工作区的快照而不用每次都从零开始探索工程。3.2 工程检索层先看懂代码再动手改代码第二个模块是工程检索层这也是我认为整个系统里最容易被低估的一块。一个编码智能体听起来很强大但前提是它真的看过你的代码。早期原型里我们尝试过把整个仓库的代码一股脑塞进上下文——效果非常差既浪费 Token又因为信息过载导致模型在不相干的代码里乱找依据。后来我们采用了两级检索策略。第一级是语义检索把仓库里的文件按代码块和函数级别做切分用向量化的方式建立索引当用户提出需求时先通过相似度检索找到最可能相关的文件列表。第二级是结构检索通过解析 AST抽象语法树建立函数调用关系、类继承关系、路由注册表等信息图谱当第一级检索定位到怀疑目标后再顺着调用链把上下游相关代码一并拉出来。举个例子用户要改订单导出功能语义检索会先把层层文件从仓库中捞出来结构检索再沿着Controller - Service - Mapper的调用链把这条链路上每一环的上下游代码都补齐到上下文里。这样模型看到的不只是一个孤立的文件而是这条业务链路的完整切片。3.3 生成引擎与工具调用协议让模型能真正操作工程第三块是生成引擎它不只是一个文本生成器而是一个遵循工具调用协议的逻辑核心。为了不生成出看起来合理但实际上没法落盘的代码我们定义了一套工具协议模型可以调用read_file读取某个文件、write_file写入某个文件、search_symbol搜索符号定义、run_command执行测试命令等等。每个工具调用都对应真实工程中的可执行操作模型需要像人类开发者一样先探查再动手而不是一上来就写一个完整文件。格式上我们早期试用过要求模型直接输出整套修正后的文件内容结果发现文件一长就各种问题——要么只输出改动片段、要么改动部位和用户要求对不上。后来改成模型输出结构化操作指令序列由后端的代码应用器负责真实落地比如让它先输出replace_block指令原代码块的哈希加上新代码块这个哈希由工程检索层实时计算如果原代码已经被改过、哈希不匹配这次替换就会失败并触发模型重新读取最新内容。这套机制极大地提升了改动的准确性也让每一次修改都可追踪、可回滚。3.4 执行沙箱生成之后的代码需要先证明自己最后一个模块是执行沙箱这可能是编码智能体和不过是个高级代码补全工具之间最本质的区别。模型生成代码之后不能直接认为完事了我们要求它主动调用执行沙箱来验证跑一遍相关的单元测试、检查语法是否正确、甚至启动服务打一个冒烟测试。沙箱本身是一套隔离出来的容器环境对资源使用做了严格限制网络访问默认关闭代码在里面跑跑挂了最多是容器重启不会影响开发者的本地环境。还有一个延伸设计是编译反馈闭环模型在沙箱中发现测试失败后可以把失败信息拿回来分析原因修正代码再跑一次直到测试通过或者达到最大重试次数。这一步在工作流程里很管用因为前面模型写错的代码很多都是因为变量名不一致、字段名大小写不对这类看一眼报错就能改对的问题让模型自己完成这个试错循环能省下大量人肉来回调试的时间。4. 上下文工程决定智能体智商上限的技术细节4.1 上下文窗口的分配策略与压缩算法如果直接用整段代码库填充上下文再让模型开始干活现在回头看会显得很愚蠢但在当时我们确实踩过这个坑。早期某次测试中我们把一个中等仓库的核心目录压缩进了 Prompt结果模型在一段无关的配置代码里发现了一个根本不存在的依赖关系又花了好几轮生成把整个系统往一个错误方向带。那次之后我们对上下文使用定了一条铁律上下文里只放当前任务必需的代码其他一切信息都要通过按需检索补齐。基于这条铁律我们实现了动态窗口管理。比如模型探查到某个函数涉及一个外部的配置类它会向上下文请求器发出需要 class 某配置类 的定义的请求上下文管理器先检查这段代码是否已经在窗口里如果没有则从索引里检索并替换掉当前窗口里最老且引用热度最低的内容。这个逐出策略很关键如果不做淘汰上下文会越滚越大既超窗口又拖慢响应。后来我们还对旧的内容做摘要化压缩——把一段已经讨论过、再也不会被改动的代码区域压缩成一行摘要文字保留在上下文里既保留记忆又不占空间。4.2 任务分解与中间验证防止模型在错误方向越走越远上下文工程不只是放什么代码的问题还包括如何把大任务拆成模型可掌控的小步骤。我们吃过一次比较大的亏让模型一次性地新增一个完整的报表统计模块结果它在没有验证中间模块的情况下直接写出了全部代码最后整体编译通过但业务统计口径全错了。问题出在模型没有把口径定义这一步拿出来和用户确认就闷头往下写。后来我们在生成流程里加入了中间验证关卡。针对涉及业务口径、数据流向、兼容性设计的大任务模型必须按顺序完成任务理解 - 提出关键问题 - 输出方案 - 等用户确认 - 按方案分步实现。而在按方案分步实现这一环每完成一个步骤都可以调用沙箱跑一次测试一旦测试不过就当场修正。整个过程还有一个反思机制模型完成一阶段后需要简单总结它做了什么、为什么这么做、还有哪些隐患这个总结会被拼进下一阶段的上下文中保证它在后续步骤里不会忘了前面做过的设计决策。4.3 结构化输出与格式约束让结果可解析、可执行最后再讲一个看起来很小但极其影响使用体验的细节模型输出格式的约束。最初版本里我们让模型以自然语言的方式描述我打算修改某文件把某函数改成……然后后端尝试从中解析出修改内容。这个方案在多轮对话中会频繁崩溃因为模型会在自然语言里夹带代码片段、甚至附带 Markdown 格式解析器一旦漏判整个操作就断掉了。最终我们全面改成了函数调用式协议模型的所有操作都通过结构化的 JSON 指令表达字段被严格约束成枚举值不合法的话模型会收到一条格式错误请重新输出的错误反馈并主动纠正。为了保证格式稳定我们还对模型做了几条强约束提示不允许在 JSON 指令中使用注释、不允许把代码块内容拼在指令外、每个指令最多包含多少个块替换操作。经过这轮改造后整个系统的解析成功率从最早的百分之七八十直接拉升到了稳定可靠的级别。现在回头看这个工作其实没有太多技术含量但它是让工具从实验室可用走向日常可用最关键的临门一脚。5. 实测中的翻车现场那些被模型自以为懂坑掉的时刻5.1 案例一模型幻觉出来的接口与不存在的依赖前面讲的都是设计但真正让这个系统变得可用的是它被真实项目毒打的过程。第一次大规模内测时我们挑了一位新同事负责的模块让它去改模型在理解完需求后生成了一段调用某加密组件的代码。问题在于这个组件在这个模块的依赖里根本不存在。人类开发者看到不存在的依赖会下意识去查一下有没有引错或者漏加模型在生成时却默认为它是存在的因为它大概在训练语料里见过类似组件。结果代码落到沙箱一跑直接编译失败。这件事促使我们做了一个针对性增强在生成引擎的工具链里加入一个check_dependency工具模型在引用任何外部符号之前必须通过这个工具确认它在工程配置或运行环境中真实存在。同时从 Prompt 层面反复强调不要编造依赖。不要编造这四个字听起来像一句废话但它是大模型应用里最值得反复强调的红线在代码生成场景里尤其致命。5.2 案例二上下文逐出导致修改方向漂移还有一个问题出在我们自己的上下文逐出策略上。当时测试一个横跨十多个文件的大改动上下文窗口被顶到接近上限早期的对话内容里那些用户明确说不要动历史兼容层这类信息被当成低热度内容逐出了。结果模型改到第六个文件的时候突然忘记了不要动历史兼容层这个约束直接对兼容层代码做了重构把整个测试打挂了。这次故障让我意识到上下文驱逐必须以关键约束优先保留无关代码优先逐出为原则。我们在上下文管理模块里维护了一条不可驱逐清单用户明确说过的否定性约束、模型自己生成的阶段性设计决策、以及尚未执行完的工具调用结果都属于高优先级内容任何时候都不得被逐出。而排在驱逐队列最前面的永远是那些模型已经用完、并被摘要化压缩过的旧代码片段。5.3 案例三沙箱误杀与重试风暴沙箱机制的初衷是好的但也给我们惹过麻烦。有一段时间每次模型在沙箱里跑测试都因为环境里缺少一个本地数据源而失败模型收到失败信息后开始疯狂地尝试修改代码试图让测试通过然而问题根本不在代码而在环境。这种重试风暴不仅浪费算力还可能把原本正确的代码改坏。我们后来在沙箱与生成引擎之间加了一个判别层沙箱返回失败信息时先做分类——如果失败是因为环境依赖缺失、资源配置错误等原因直接标记为环境异常终止代码重试并把问题反馈给用户如果失败是因为断言不通过、编译错误才允许模型进入修正循环。同时还设置了最大重试上限超出上限就立即停止强制要求模型输出当前进展、卡点原因、建议下一步把控制权交回给用户。这大概是整个项目中最像培养新人的一步允许犯错但不允许在同一条沟里反复摔。6. 成本与延迟的博弈让一个 AI 编码助手用得起6.1 Token 消耗审计哪些环节在偷偷烧钱项目进入内测阶段后一个很现实的问题浮出水面成本。大模型按 Token 计费编码场景又是一个天然的长度密集型场景——代码比自然语言长得多而让模型读懂上下文更是要反复喂代码。我们对一次中等难度任务做了 Token 审计结果相当惊人真正用于生成最终代码的 Token 只占 20% 左右剩下 80% 几乎都消耗在了上下文构建环节——检索回来的相关文件片段、多轮探测时的全量读取、以及沙箱失败后的重试都不得不重新读取文件中这些累加在一起才是成本大头。针对这个审计结果我们做了两项优化。第一项是相似代码增量复用当模型反复要求读取同一个文件时后端不再用传送全文而是只传送这个文件自上次读取以来发生变化的代码 diff。第二项是检索结果瘦身语义检索返回的相关片段按与任务关键词的重合度、在调用链中的位置做了排序裁剪绝不一股脑全部塞给模型。这两项叠加之后单次任务的平均 Token 消耗下降了差不多一半。6.2 分层路由小任务不劳驾大模型另一个省钱又提速的手段是模型分层路由。我们在生成引擎前挂了一个轻量级的意图分类器——这个分类器本身也是一个小模型但它的任务非常简单判断这个请求是轻量问答型比如解释一段代码、查一个符号定义还是复杂生成型比如新增接口、重构模块。轻量问答型请求被直接路由到一个小得多的模型处理只有复杂生成型任务才进入完整的大模型链路。这个分层带来的收益非常直观内测期间团队里发出的请求有接近一半是看懂这段代码级别的轻量任务它们用小模型处理后的响应速度和成本都理想得多而复杂生成任务虽然贵但价值也足够高这种把好钢用在刀刃上的路由让整个项目的单位成本降到了一个可以接受的水平。6.3 流式输出与可中断设计减少无效等待最后关乎体验的是等待时间。过去模型生成一个文件改动经常要等整个内容全部生成完毕才能看到结果如果是大文件等待时间可能长达一两分钟开发者的注意力早就散了。我们引入了流式输出——模型一边生成一边就以可读的增量形式发回界面用户能看到修改思路像打字一样逐行展开。更重要的是可中断设计当用户发现模型的修改方向不对时可以直接打断生成把纠正意见追加进上下文模型会带着新的要求重新生成而不是等整段错误代码生成完了再返工。这些优化做完之后整体反馈才真正从这东西好像挺有意思变成了这东西我现在每天要用。我自己的体感是一个工具的成功往往不是某一个炫酷功能决定的而是这些并不起眼、但每天都会触碰到的细节叠加出来的。7. 从内测到可用的最后一公里流程与体验的沉淀7.1 权限分级让 AI 有手但别乱动我们的沙箱和工具协议设计得再好也必须面对一个工程现实不同的用户对 AI 的信任度完全不同。有人希望 AI 放手去改遇到问题再回来有人则希望每一步都经过确认。后期我们对工具调用设计了三档权限模式只读模式模型只能读取和检索不能执行任何写操作、半自动模式模型可以改文件但是每次写操作会生成 diff由用户手动 approve、全自动模式模型在沙箱里自主完成改动并验证验证通过后再把改动同步到工作区。三分法上线之后内测参与者的接受度明显提升。有趣的是不少最初选全自动模式的资深开发者在遇到一两次模型改错方向后反而主动降到了半自动模式而新加入的同事则普遍从半自动开始熟练以后逐步放手。这说明工具本身没有标准答案关键是给使用者选择与模型配合距离的权利。7.2 审计日志与回滚AI 改代码也不能脱离可追溯代码是人类协作的产物AI 参与之后更不能丢了可追溯这条底线。我们从第一天起就给每一次工具调用做了完整审计日志调用了哪个工具、参数是什么、模型生成的结果是什么、最终是否应用、是否被用户手动回滚。贯穿内测全程这个日志系统在后来的问题定位中帮了大忙。有一次某个模块出现了一个诡异的状态丢失问题排查了常规流程都没找到原因最后回看审计日志才发现某次模型改动时把一段看似冗余的状态重置代码认为是可以移除的死代码给删掉了而那恰好是一个隐藏在上下文之外、被某个边缘分支依赖的状态恢复逻辑。如果没有审计日志和对应的代码 diff这种问题会拖很久。这给了我一个很深的心得AI 生成代码不是魔法它只是把写代码变成了一件可以追踪、可以复盘、可以回退的工程事件。7.3 人机协作的最终形态它改变了我们写代码的方式写到这里项目已经不再是一个单纯的编码玩具它实实在在地改变了团队的协作方式。过去评审代码时我们主要关注逻辑对不对现在评审时还要多一个问题这个方案是不是 AI 在当前上下文限制下给出的最优解还是人类凭借领域知识可以走得更远日常开发里的变化更微妙。以前新同学接到任务第一反应是先搜代码、看博客、问老同事现在很多人的第一反应是先把这个任务的背景和约束描述给编码助手让它产出一版方案和代码然后自己再在这个底子上做审查、调整和优化。这让我想起当年引入测试驱动开发和代码评审时的争论——每一种新工程实践都会让大家先恐慌然后慢慢形成新的舒适区。Claude Code 这类工具也一样它不会消灭程序员但它确实正在一点一点地把程序员的日常推向更高层的定义、判断与审查。最后分享一个小经验很多人以为做这类 AI 编码工具最关键的是模型多强、窗口多大但真正跑完整个诞生过程后我会说模型选型的权重可能只占三成剩下的七成在架构的工程韧性、上下文的精细运营、以及人与工具之间交互分寸的把握上。这个项目从最初一个能不能让 AI 帮忙改代码的脑洞变成现在团队每天离不开的基础设施也正好验证了这一点。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。