从零构建 ClaudeCode 风格的 AI 编程助手:Code Agent 完整架构解析
前言随着 Claude Code、Cursor、Devin 等 AI 编程工具的兴起“AI Agent 编程工作台” 成为最热门的 AI 应用方向之一。这篇文章将完整拆解Code Agent项目 —— 从架构设计、核心模块实现到前后端联调带你看清一个真正可用的 LLM Agent 系统是怎么做出来的。项目地址github.com/myh-1302/code_agent技术栈Python · Flask · Socket.IO · React 18 · TypeScript ·deepseek api一、为什么要自己造轮子市面上已有很多 AI 编程工具为什么还要自己做原因很简单只有自己造过才真正懂得其中的难点。通过构建 Code Agent我深刻理解了以下问题的工程解法LLM 流式输出如何在前端实时渲染Tool Use工具调用的完整生命周期如何管理多 Agent 协作时状态同步如何保证一致性长对话下上下文 Token 超限怎么处理如何在 Agent 修改文件时保障安全回滚二、整体架构设计┌─────────────────────────────────────────────────┐ │ Frontend (React 18 TS) │ │ 文件树 │ 对话流 工具卡片 │ 任务看板/Todo │ └──────────────────────┬──────────────────────────┘ │ WebSocket (Socket.IO) ┌──────────────────────▼──────────────────────────┐ │ api_server.py (Flask SocketIO) │ │ RESTful API 实时事件推送 │ └──────────────────────┬──────────────────────────┘ │ ┌──────────────────────▼──────────────────────────┐ │ Agent Core │ │ loop.py (主循环) │ subagent.py (子 Agent) │ └──────────────────────┬──────────────────────────┘ │ ┌──────────────────────▼──────────────────────────┐ │ Components (功能组件) │ │ memory · safety · todo · task · team · compactor│ └──────────────────────┬──────────────────────────┘ │ ┌──────────────────────▼──────────────────────────┐ │ Tools (工具层) │ │ 10 工具记忆/快照/任务/Todo/团队/Skill... │ └─────────────────────────────────────────────────┘四层清晰分离表现层 → 通信层 → Agent 核心 → 工具层每层职责单一易于独立测试和扩展。三、核心模块详解3.1 Agent 主循环core/loop.py这是整个系统最核心的部分。Agent 循环的本质是一个推理 → 行动 → 观察 → 推理的反复迭代过程# 伪代码示意 Agent 主循环asyncdefagent_loop(messages,tools,callbacks):whileTrue:# 1. 调用 Claude API 获取推理结果流式responseawaitcall_claude_api(messages,tools,streamTrue)# 2. 触发事件回调前端实时更新awaitcallbacks.on_chunk(response.delta)# 3. 如果是工具调用执行工具ifresponse.stop_reasontool_use:tool_resultawaitexecute_tool(response.tool_use)awaitcallbacks.on_tool_result(tool_result)messages.append(tool_result)continue# 带上工具结果继续推理# 4. 推理完成退出循环ifresponse.stop_reasonend_turn:break关键设计点事件回调钩子callbacks每个关键节点chunk/tool_start/tool_result都触发回调解耦 Agent 逻辑与 UI 推送流式中断通过标志位 asyncio.CancelledError 优雅处理用户中途终止3.2 实时通信层Flask-SocketIO前端与后端之间用 Socket.IO 实现双向实时通信这是整个用户体验的关键。事件协议设计# 服务端推送事件格式{type:chunk,# run_start / chunk / tool_start / tool_result / run_end / errordata:{content:...,# 文字内容chunk 时tool_name:...,# 工具名tool_start 时input:{...},# 工具输入output:{...},# 工具输出elapsed_ms:1234# 耗时}}为什么用 SocketIO 而不是 SSEServer-Sent EventsSSE只支持单向推送而我们还需要客户端发送中断信号interruptSocketIO 的双向通信天然支持这个场景。3.3 工具调用体系tools/工具层采用注册模式每个工具继承BaseTool并自动注册# tools/base.pyclassBaseTool:name:strdescription:strinput_schema:dictasyncdefexecute(self,**kwargs)-dict:raiseNotImplementedError# 工具注册表TOOL_REGISTRY:dict[str,BaseTool]{}defregister_tool(tool:BaseTool):TOOL_REGISTRY[tool.name]tool目前实现的 10 工具工具功能memory长期记忆读写safety文件快照创建/恢复task_board任务状态管理todoTodo 列表同步team子 Agent 协作background后台任务执行compress上下文压缩skillSkill 加载执行worktree工作目录管理3.4 上下文压缩components/compactor.pyClaude 的 context window 是有限的长对话必然面临 Token 超限问题。解决思路# 简化的压缩策略defcompact_messages(messages,token_budget):# 1. 统计当前 Token 数current_tokenscount_tokens(messages)ifcurrent_tokenstoken_budget:returnmessages# 2. 保留系统消息 最近 N 轮对话# 3. 对中间历史调用 Claude 生成摘要summarysummarize_history(messages[1:-N])# 4. 用摘要替换中间历史return[system_msg,summary_msg]messages[-N:]关键挑战压缩时要保留工具调用的配对关系tool_use 和 tool_result 必须成对出现否则 API 会报错。3.5 安全快照系统components/safety_manager.pyAgent 会修改文件万一改错了怎么办这是实际使用中非常真实的痛点。解决方案在 Agent 执行写文件操作前先创建文件快照。classSafetyManager:defcreate_checkpoint(self,files:list[str],tag:str):创建文件快照checkpoint{id:uuid4(),tag:tag,timestamp:datetime.now(),files:{f:read_file(f)forfinfiles}}self.checkpoints.append(checkpoint)defrestore(self,checkpoint_id:str):恢复到指定快照checkpointself.get_checkpoint(checkpoint_id)forpath,contentincheckpoint[files].items():write_file(path,content)3.6 多 Agent 协作core/subagent.py components/team_manager.py对于复杂任务单个 Agent 往往力不从心。Code Agent 支持多 Agent 协作主 Agent负责任务拆解与调度子 Agent各自执行具体子任务如分析需求 / 写代码 / 写测试团队管理器维护各 Agent 状态前端实时展示主 Agent ├── 子 Agent A需求分析 ├── 子 Agent B代码生成 └── 子 Agent C测试验证四、前端架构React 18 TypeScript前端采用三栏布局┌──────────┬────────────────────┬──────────────┐ │ 文件树 │ 对话 工具卡片 │ 任务看板/Todo│ │ (左侧栏) │ (主区域·流式) │ (右侧栏) │ └──────────┴────────────────────┴──────────────┘自定义 Hooks 管理 SocketIO 状态// hooks/useSocketIO.tsfunctionuseSocketIO(){const[messages,setMessages]useStateMessage[]([]);const[agentState,setAgentState]useStateAgentState(idle);useEffect((){constsocketio(http://localhost:5000);socket.on(agent_event,(event:AgentEvent){switch(event.type){casechunk:// 流式追加文字appendChunk(event.data.content);break;casetool_start:// 新增工具调用卡片addToolCard(event.data);break;casetool_result:// 更新工具卡片结果updateToolCard(event.data);break;caserun_end:setAgentState(idle);break;}});return()socket.disconnect();},[]);return{messages,agentState,sendMessage,interrupt};}工具调用卡片是前端最有特色的设计每次工具调用都以折叠卡片展示工具名、输入参数、输出结果、耗时让用户清晰看到 Agent “在做什么”。五、API 接口设计提供完整的 RESTful API方便第三方集成GET /api/status # Agent 状态 POST /api/chat # 发送消息 POST /api/chat/interrupt # 中断执行 GET /api/history # 对话历史 GET /api/tasks # 任务列表 GET /api/todos # Todo 列表 GET /api/team # 多 Agent 状态 GET /api/memory/stats # 记忆统计 POST /api/memory/search # 记忆搜索 GET /api/safety/checkpoints # 快照列表 POST /api/safety/checkpoint # 创建快照 POST /api/safety/restore # 恢复快照 GET /api/files/tree # 文件树 GET /api/files/content # 文件内容六、一键启动# 克隆项目gitclone https://github.com/myh-1302/code_agent.gitcdcode_agent# 配置 API KeyechoANTHROPIC_AUTH_TOKENsk-ant-your-key.envechoMODEL_IDclaude-sonnet-4-20250514.env# 安装依赖pipinstall-rrequirements.txtcdfrontendnpminstallcd..# 启动./start.sh# 访问 http://localhost:5173七、踩坑与经验总结坑 1工具调用配对问题Claude API 要求tool_use和tool_result必须成对出现在 messages 中进行上下文压缩时一定要注意保持配对完整性否则会得到400 Bad Request。坑 2流式中断的状态恢复用户点击中断后Agent 循环被打断此时 messages 列表可能处于不完整状态有tool_use但没有tool_result。需要在中断处理中补全消息队列才能让下一次对话正常进行。坑 3SocketIO 事件顺序保证在高并发推送时SocketIO 事件可能乱序。解决方案是给每个事件加sequence_id前端收到后排序再渲染。坑 4React 状态更新与 SocketIO 事件的竞态React 的useState是异步更新的在 SocketIO 回调中直接读取 state 可能拿到旧值。使用useRef存储需要即时读取的状态useState只用于触发重渲染。八、后续优化方向Agent 循环稳定性— 长对话下工具调用超时重试、流式中断后的状态一致性恢复上下文压缩策略— 按 token 预算智能裁剪历史保留关键决策节点而非简单截断前端渲染性能— 长消息列表虚拟滚动、工具卡片懒加载、SocketIO 事件节流错误恢复增强— 分级降级策略重试→回退→提示用户减少对话中断文件编辑 Diff 预览— Agent 修改文件前展示 diff支持逐块接受/拒绝记忆检索优化— 向量化存储 语义搜索长生命周期项目中精准召回上下文多工作目录并行— 侧栏多项目标签页Agent 跨项目引用代码测试自愈— Agent 发现测试失败后自动分析根因并提议修复总结构建 Code Agent 让我真正理解了 LLM Agent 系统的复杂性它不只是调用API 这么简单而是需要在实时通信、状态管理、工具编排、安全保障、上下文控制等多个维度同时做好工程设计。如果你也在学习 AI Agent 开发强烈建议自己动手做一个完整项目比看再多教程都有收获。项目开源地址github.com/myh-1302/code_agent欢迎 Star、提 Issue 和 PR