Claude Code 源码泄露的消息上周在技术圈炸开之后我第一时间把流出的核心模块过了一遍。长期做 Agent 开发的人看到这份代码都会有个共同感受这才是企业级智能体该有的样子。跟那些一个 while 循环加一堆工具函数就声称是 Agent 框架的开源项目相比它完全不在一个量级。这篇文章不聊事件本身的对错也不做新闻复盘只做一件事把这份源码里值得参考的企业级 Agent 工程实践一条条拆给你看。我整理出 11 个点覆盖 Agent 循环、工具设计、权限控制、上下文管理、可观测性、扩展机制六大层面。每个点我都会讲清楚为什么这么设计再给出落到自己项目里该怎么改。不管你是正在搭企业级 Agent 平台的架构师还是想把个人项目从 demo 推到生产环境的开发者这篇都值得读完。1. 这次泄露的代码是什么先看清 Claude Code 源码的含金量1.1 流出的不是完整仓库但核心运行时基本都在先给没吃瓜的朋友补个背景Claude Code 是 Anthropic 出的终端类编程 Agent 工具你装好后在命令行里下任务它会自己读写文件、跑命令、看测试结果反复迭代直到完成。这次流出的代码主要是这个工具的核心运行时也就是驱动整个 Agent 跑起来的那部分逻辑。具体能看到的有主循环实现、工具注册与调度器、权限判定模块、会话管理、多格式输出器以及一部分钩子hooks定义。需要说明的是这不等于完整的官方私有仓库。像 MCP 服务端的一些商业组件、内部模型路由策略并没有完整暴露。但对我们做 Agent 工程的人来说核心运行时的设计已经足够有参考价值。很多人问这东西值不值得逐行读我的答案非常明确值得但重点不是一行行抠语法而是读设计决策。这也是这篇文章的立脚点。1.2 为什么生产级 Agent 的源码尤其值得学市面上开源 Agent 框架其实不少但问题在于绝大多数是教学级项目代码漂亮、结构清晰真跑到生产环境就崩。Claude Code 是被大量真实用户每天用来改真实代码库的产品它的工程决策是为了处理真实世界的脏乱差做的。我在代码里印象最深的一点是工具调用的权限控制不是一个 if 搞定而是一整套规则引擎式的设计区分自动放行、逐次确认、直接禁用还能按目录和工具类型配置策略。这种设计背后是大量真实事故的沉淀。做 Agent 的人最缺的就是这种被生产环境毒打过的经验这份代码恰好补上了这一课。2. 先从源码看企业级 Agent 的四大骨架在拆 11 个实践之前我先把代码中体现的总体架构画个轮廓。Claude Code 的运行时大体分成四层内核循环层、工具层、权限安全层、上下文管理层。四层各司其职通过明确定义的数据结构和接口通信而不是像很多项目那样所有逻辑搅在一个文件里。2.1 内核循环层思考-行动-观察的总指挥内核循环层是 Agent 最核心的 while 循环把用户指令和当前上下文组装成请求发给大模型拿到响应后解析模型意图是继续说话还是调用工具如果要调工具就进入工具执行流程把结果追加回上下文再次发起请求如此反复直到任务完成。这层看起来人人都能写但 Claude Code 的处理有两个关键细节值得注意。第一循环是带状态的每一轮都清楚知道自己在等待用户确认正在执行工具还是等待模型响应而不是无脑轮询。第二每一轮的思考、行动、观察Thought-Action-Observation都被完整记录。这些记录既服务于会话恢复也服务于事后排查相当于给 Agent 装了一个黑匣子。2.2 工具层能力边界从 Schema 开始工具层管的是Agent 能对世界做什么。代码里内置了读写文件、编辑代码、运行 shell、搜索等工具每个工具都有完整的名称、描述、参数 JSON Schema 和副作用等级。工具注册用数据驱动所有调用先去 Schema 校验参数非法输入在进入真实环境之前就被拦截。这里有个很多项目会忽略的细节工具描述本身也是代码的一部分。模型靠描述来决定什么时候用哪个工具所以描述写得好不好直接决定 Agent 的智能上限。这就像你给一个新同事写交接文档写清楚了人家才办得对事。后面实践二我会专门展开。2.3 权限安全层能力不等于授权工具层定义了Agent 有能力做什么权限层定义Agent 被允许做什么。同一个 Bash 工具在自动放行模式下直接执行在默认模式下弹确认框在某些高危目录下直接拒绝。这个能力与授权分离的设计是所有严肃 Agent 系统的核心也是我最想让你抄走的一点。说白了能力是静态的授权是动态的。两者混在一起迟早出事。你项目的 Agent 能写文件不代表它可以随便写生产环境的配置文件这个边界必须由独立的权限层来守。2.4 上下文管理层决定模型记忆力的隐形功臣上下文管理层负责在每次请求前把系统提示词、项目记忆类似 CLAUDE.md 的规则沉淀、历史对话和工具结果裁剪成一份刚好够用的请求体。这里涉及 token 预算、消息裁剪、必要时做压缩总结。很多 Agent 项目做到一定规模后性能骤降用户以为模型坏了其实是上下文被塞爆。Claude Code 的思路是预算提前算、压缩自动做而不是等模型开始胡说八道再手工清理。做 Agent 平台的同学建议把 token 计数做成中间件每次请求前统一处理而不是在各个业务代码里零散维护。3. 从源码拆出的 11 个 Agent 工程实践这是全文的核心我按从内核到外围的顺序把这 11 个点逐个展开。每个实践都先讲源码里的做法再讲为什么最后讲怎么落到你的项目里。3.1 实践一Agent 循环做成显式状态机拒绝裸 while先看很多开源框架的典型写法while not done: response llm.chat(messages) if response.tool_call: result execute_tool(response.tool_call) messages.append(result) else: done True简洁是简洁但上线就出问题模型可能连续调用同一个失败工具几十次可能绕过护栏反复执行破坏性命令也可能在没获得用户确认的情况下就改了一堆文件。Claude Code 的循环是有显式状态的能区分等待用户确认和工具执行中并且对工具调用有次数上限和失败回退逻辑。落到你项目里建议用状态枚举来约束转移路径VALID_TRANSITIONS { INIT: {PLANNING, WAITING_USER}, PLANNING: {ACTING, DONE, FAILED}, ACTING: {OBSERVING, CANCELLED}, OBSERVING: {ACTING, PLANNING, DONE}, WAITING_USER: {ACTING, CANCELLED}, }循环体里只允许有限状态的合法跳转异常直接终止或回退而不是在混乱中继续。这个设计的价值在于Agent 的行为变得可审计、可预测这是生产环境的基础要求。状态机听起来多写了点代码但排查问题时你会感谢它。3.2 实践二工具注册用 Schema 驱动禁止 if-else 硬编码我在不少 Agent 项目里见过这种写法execute_tool 函数里一长串 if tool_name read_file 的分支。新增一个工具就要改核心代码参数校验散落在各个分支里模型一旦吐出一个畸形参数就直接穿透到真实环境。Claude Code 的做法是把工具定义序列化成数据。每个工具包含 name、description、input_schema、副作用等级调度器根据 name 找到实现先用 input_schema 校验参数通过才执行。简化示意长这样const tools: ToolDefinition[] [ { name: read_file, description: 读取指定路径的文件内容用于理解当前代码, inputSchema: { type: object, properties: { path: { type: string, description: 文件绝对路径 }, }, required: [path], }, permissionLevel: READ, }, ];这么做有三个直接好处。第一新增工具不需要动调度逻辑只用注册一份定义。第二参数校验前置模型幻觉生成的非法参数被拦在工具外面。第三每个工具的能力边界一目了然权限层可以直接根据 permissionLevel 做决策。这三个好处任何一个都值得你把代码改成 Schema 驱动。3.3 实践三权限模型默认拒绝危险操作逐次确认这是整个源码里我最推荐抄的设计。Claude Code 的权限模型不是要不要拦一下而是默认不信任工具能做什么是一回事被允许做什么是另一回事。权限判定走的是一个可配置的规则链支持三类结果放行、询问、拒绝。工具类型默认策略典型场景只读工具读文件、搜索自动放行代码理解、检索低风险写工具编辑文件自动放行或询问常规代码修改高风险工具shell、删除询问或拒绝执行命令、清理落到你的项目里最关键的一点是默认值必须是询问或拒绝而不是放行。演示时觉得弹确认框很烦但真实环境里一次误删除或误执行的代价远超那点确认成本。我自己的平台里还加了一层策略按目录配置白名单和黑名单开发目录自动放行生产目录一律拒绝这个思路就是从这里来的。3.4 实践四上下文预算显式管理压缩是常态不是应急大模型的上下文窗口虽然越开越大但真实 Agent 会话里塞进去的历史对话、工具结果、错误日志增长极快。Claude Code 的做法是显式管理 token 预算请求前计算上下文长度超过阈值就触发裁剪或压缩。裁剪是直接丢弃老的次要消息压缩是把前面的对话交给模型做摘要再放回上下文。这一点特别重要因为很多 Agent 项目前期跑得很好聊久了能力突然跳水。用户以为模型坏了其实是上下文被塞爆了。Claude Code 的设计思路是预算要提前算压缩要自动做而不是等问题出现再清理。我建议你把 token 计数做成一个中间件统一拦截所有请求做上下文整理包里带着预算、用了多少、还剩多少三个字段一目了然。3.5 实践五用 Hook 事件机制做扩展而不是 fork 源码Claude Code 的扩展性设计非常典型核心代码不开放给人乱改但定义了完整的生命周期事件比如用户提交 prompt 前、工具执行前、工具执行后、Agent 进入新轮次等。使用者通过配置回调或脚本响应这些事件实现策略注入。这个设计对企业来说是刚需。举个例子团队要求代码 Agent 不能未经评审就修改某些核心模块。如果一个个去改 Agent 源码升级一次就崩一次。用 Hook你在 PreToolUse 事件里写一段策略脚本检查工具类型和目标路径命中高危规则就返回拒绝这比 fork 源码做定制干净得多也经得起版本升级。3.6 实践六复杂任务交给 Subagent 分治不让一个 Agent 干到底一个 Agent 一把梭地处理复杂任务是很多项目的通病超长任务把上下文撑爆各种子任务目标互相干扰模型越做越糊涂。Claude Code 的思路是把任务拆给 subagent 专业子代理。每个 subagent 只负责一个明确子任务比如分析代码结构、跑测试、做代码审查各自的系统提示词聚焦上下文相对独立最后把结构化结果返回给主 Agent。用生活化的类比你不会让一个全科医生包办所有手术而是会让外科、麻醉、影像各司其职。Agent 也一样分工细化能显著提升准确率和可控性。做这类实现时关键在于每个 subagent 的输入输出协议要定义清楚返回值要是结构化摘要而不是大段对话记录否则上下文污染问题依旧存在。3.7 实践七流式输出是架构必需品不只是体验优化很多 Agent 项目用攒完整响应再展示的方式用户盯着光标转圈一等就是几十秒。Claude Code 把流式输出当成基础能力模型 token 实时打印工具执行状态实时更新你甚至能看到它正在读哪个文件、跑哪条命令。这个设计看起来是体验问题其实是架构问题。长任务的 Agent 天然耗时如果流程不流式化一是用户完全无法判断 Agent 是不是卡死了二是中间失败时没有任何可恢复的中间状态。落地建议从架构上把所有 Agent 事件模型输出、工具启动、工具完成、错误设计成事件流前端订阅事件流做渲染后端订阅事件流做调度和观测一套机制搞定多个需求。3.8 实践八会话持久化中断之后能精确恢复真实使用中Agent 跑一半进程被杀、网络断掉、电脑重启都是常态。Claude Code 会把整个会话的历史——消息、工具调用、结果、权限决策——完整持久化支持断点恢复。你重新打开后可以接着上次的上下文继续对话不用从头解释需求。这个实践对构建可靠系统的价值怎么说都不过分。会话持久化不仅是用户体验更是数据资产每个会话都是一份完整的执行记录。我自己的做法是为每个会话生成独立 ID所有事件按时间戳追加到会话存储里恢复时按序重放相当于给 Agent 装了存档系统。企业里做 Agent 平台这个功能必须一开始就设计进存储模型后期补非常痛苦。3.9 实践九输入输出用结构化契约人机边界才清晰Claude Code 的接口层有个很值得学的点它同时提供面向人的可读输出和面向机器的结构化输出比如 JSON 模式。不管哪种模式内部的工具调用请求和结果都走严格定义的结构化协议字段有 schema、版本、类型校验。这背后是一个很朴素的道理Agent 系统不是只有大模型它还要跟 CI 流水线、监控系统、其他服务协作。如果 Agent 输出全是自然语言散装文本对接方只能用正则硬抠必然又脆又乱。结构化契约让你的 Agent 可以被其他系统可靠地集成这是走向企业级的关键一步。建议定义一套统一的事件对象模型所有输出都从这上面渲染而不是各写各的。3.10 实践十全量日志落盘问题排查靠回放而不是猜Agent 系统最难排查的问题是它为什么这么做。模型调用是黑盒工具执行是分散的如果没有完整日志出了问题只能靠猜。Claude Code 把每一轮请求的 prompt、模型响应、工具输入输出、耗时、错误信息全部落盘格式是 JSONL方便按时间逐行回放。这个实践我强烈建议任何 Agent 项目从第一天就做。日志记录的不只是结果还有过程模型看到了什么上下文、选择了哪个工具、工具返回了什么、它基于这个结果做了下一步什么决策。有了这些调试 Agent 就像看回放录像一样哪里偏离预期一目了然。在企业里这份日志还能直接用来做评测集、回归测试和审计追溯价值远超排错本身。3.11 实践十一MCP 接入先做协议收敛和鉴权再谈扩展MCPModel Context Protocol现在基本是 Agent 生态的事实标准Claude Code 对 MCP 的支持也是这套代码里的亮点。但值得注意的设计是MCP 服务器的工具并不会直接暴露给模型随便调用。接入层会先把 MCP 工具映射成内部统一的工具 Schema做参数收敛再经过权限判定最后才进入调度器执行。这一步非常重要。直接把外部 MCP 工具一股脑塞给模型等于把五十个不受控的入口交给一个不可预测的调用方安全隐患非常大。正确做法是在 MCP 边界做四件事Schema 翻译、鉴权校验、速率限制、审计日志。外部工具再丰富也必须过你的安全闸门这个原则做 Agent 平台的团队越早建立越好。4. 复刻这套 Agent 架构时最容易踩的 5 个坑这节是我自己动手做过几个 Agent 平台之后总结的教训。源码可以抄坑也可以提前避下面几条几乎每个团队都会踩。4.1 坑一工具失败的反馈没有接回模型很多实现的错误处理是执行工具 → 失败 → 记录错误 → 结束。模型根本没有机会看到工具失败了、为什么失败、建议怎么换路这些信息于是只能反复用同一种错误方式重试白白浪费 token 和时间。正确做法是把工具执行结果包括错误栈、退出码、关键输出片段原样追加回上下文让模型基于真实反馈做下一步决策。这相当于你教一个新同事做错了不要闷头重试先看看报错信息再调整策略。4.2 坑二权限体系全自动上线必翻车演示阶段为了效果很多项目把权限全部设成自动放行。看着是敏捷了一到生产环境模型一个破坏性误操作就能让你后悔。权限默认值必须是询问或拒绝自动放行只留给明确验证过安全性的只读类工具。我见过最惨的案例Agent 在重构任务里误把生产配置目录当测试目录改写因为没有确认环节几千条配置直接改坏。全自动权限在演示时是爽点上线时就是事故点。4.3 坑三工具描述写太敷衍模型不知道该用哪个很多项目的工具定义就一句话执行命令。模型拿到这种描述根本不知道这个命令工具有没有危险操作、输出格式是什么、适用场景是什么。描述写得差Agent 就不会在正确时机选择正确工具这比代码写得差更隐蔽也更致命。写工具描述有个小技巧像教一个刚入职的开发一样写明工具的输入输出、副作用、适用场景、不适用场景甚至给一两个例子。模型是靠描述做决策的描述就是工具的说明书花在打磨描述上的时间回报率极高。4.4 坑四参数校验放执行后等于把炸弹交给模型不少项目图省事在工具实现内部才做参数检查结果就是模型的错误参数已经穿透到文件系统或 shell 里了这时候发现问题已经太晚。正确做法是在调度器里、工具执行前做严格的 Schema 校验非法输入直接拒绝不给它碰真实环境的机会。4.5 坑五不设计会话恢复任务一断就前功尽弃长任务执行中进程被杀是常态如果会话不能恢复用户要么重新解释一遍需求要么接受半途而废的结果。会话持久化看似麻烦其实是构建可靠 Agent 的底线。记住一点所有关键事件都要落盘恢复时要能还原出完整的上下文否则生产环境的可用性无从谈起。5. 抄代码容易抄决策难最后的个人体会把这份源码拆完我最大的感受是技术细节其实不难抄难的是背后那些决策逻辑。为什么权限默认拒绝为什么工具要 Schema 驱动为什么日志要全量落盘这些问题的答案不是某个大神的灵光一现而是生产环境一次一次事故换来的。5.1 看完源码我做的最重要的两个调整我自己搭 Agent 平台时踩过不少坑。看完这份代码后第一件事是把权限模型整个重写了从全量放行加特例改成默认拒绝加白名单第二件事是把上下文管理从前端页面里抽出来塞进了中间件层统一做 token 预算和压缩。改完之后线上问题的定位时间从小时级降到了分钟级这让我更确信做企业级 Agent别追求炫技先保证可控、可观测、可恢复。5.2 实操落地的优先级建议如果你也想从这份源码里学东西我的建议是别急着把 11 个实践全部抄一遍。先做日志落盘和会话持久化这两个是可靠性的地基再做权限默认拒绝这是安全底线然后才是 Schema 驱动工具和 subagent 分治这些能力增强项。每完成一项就上线验证用小步快跑的方式逐步逼近企业级。做内部效率工具权限默认询问就够了做对外 API 服务可能需要更细粒度的 policy 引擎。把决策逻辑想通代码怎么写都是对的。