1. 项目缘起为什么我们需要一个“简易版”的Coding Agent最近在折腾AI编程助手发现市面上的工具要么太重要么太贵要么就是API调用起来限制一堆。比如你想让AI帮你写个脚本处理点本地数据或者自动生成一些重复性的代码片段往往需要先开个网页复制粘贴再等它生成最后还得手动调整。这个过程本身就打断了编程的“心流”。于是我就琢磨能不能自己动手用最少的依赖搞一个能跑在本地命令行里的、能理解我简单指令并直接生成或修改代码的“小助手”这就是“简易版Coding Agent”的由来。它不是一个要替代IDE或者Copilot的庞然大物而是一个聚焦于特定场景的自动化脚本。核心目标就两个第一能用自然语言驱动我说“给当前目录下所有.py文件添加函数注释”它就能理解并执行第二能闭环执行从理解意图、规划步骤、编写代码到在安全沙箱内执行验证形成一个完整的“思考-行动”循环。这背后其实就是ReActReasoning and Acting模式的思想让大语言模型LLM不仅会“说”还会“做”。市面上LangChain、LangGraph这些框架当然能实现但它们的学习曲线和依赖复杂度对于只想快速实现一个小功能来说有点杀鸡用牛刀了。所以我们这次的目标是“从零实现”意味着我们会尽量用原生Python和直接的API调用把核心链路跑通让你彻底明白一个Coding Agent到底是怎么转起来的。2. 核心架构拆解一个Coding Agent的“五脏六腑”要造一个能跑起来的Agent我们不能只把它当成一个黑盒。你得清楚它内部有几个关键模块在协同工作。下面这张图描绘了它的核心工作流你可以把它想象成一个拥有“大脑”、“手”、“眼睛”和“安全区”的智能体。flowchart TD A[用户输入自然语言指令] -- B[“指令解析与任务规划模块brAgent‘大脑’”] B -- C{“能力判断与工具选择br思考”} C --|“需要写/读文件”| D[“代码文件操作工具br读写手”] C --|“需要执行代码/命令”| E[“安全沙箱执行工具br安全区”] C --|“需要分析代码结构”| F[“代码分析与检索工具br眼睛”] D -- G[“执行工具并观察结果”] E -- G F -- G G -- H{“结果评估与下一步决策br再思考”} H --|“任务未完成”| C H --|“任务完成或无法继续”| I[输出最终结果与总结]这个流程的核心是“思考-行动-观察”的循环。大脑LLM负责理解指令、规划步骤、选择工具手和眼睛各种工具负责执行具体操作安全区确保危险操作不会伤害你的真实系统而每一次行动的结果都会被“观察”并反馈给大脑供其做下一步决策。接下来我们就深入每个部分看看具体怎么实现。2.1 大脑指令解析与任务规划LLM Prompt Engineering这是Agent的智能核心我们依赖一个大语言模型LLM来担任。但直接扔一句“帮我写个爬虫”给LLM它可能给你一段代码但不会去执行更不会处理执行中的错误。所以我们需要用特定的提示词Prompt来“框定”它的行为模式让它按照ReAct的格式来输出。核心Prompt设计思路我们的Prompt需要明确告诉LLM身份与目标你是一个Python编程助手目标是将用户的自然语言请求转化为一系列可执行的操作。可用工具清晰地列出所有它可以调用的“工具”或“能力”包括工具名称、描述、输入参数和格式。例如read_file: 读取指定路径文件的内容。write_file: 将内容写入指定路径的文件。execute_python: 在安全环境中执行一段Python代码字符串。list_dir: 列出指定目录下的文件。输出格式约束强制要求LLM以严格的、机器可解析的格式如JSON或特定的标记文本进行输出包含thought思考、action行动指令、action_input行动输入等字段。思考链要求鼓励LLM进行逐步推理尤其是在复杂任务中要先分解任务再选择工具。一个简化的Prompt示例你是一个高效的Python编程助手。你可以通过以下工具与外界交互 工具列表 1. read_file: 读取文件内容。输入格式{path: 文件路径字符串} 2. write_file: 写入或创建文件。输入格式{path: 文件路径字符串, content: 文件内容字符串} 3. execute_python: 在安全沙箱中执行Python代码。输入格式{code: Python代码字符串} 4. list_dir: 列出目录内容。输入格式{path: 目录路径字符串} 请严格按照以下格式响应 Thought: 这里是你对当前任务和下一步的分析 Action: 要使用的工具名称必须是上述工具之一 Action Input: 工具的输入必须是一个合法的JSON对象 用户请求{user_input}通过这样的Prompt我们“塑造”了LLM的输出行为使其从一个自由的文本生成器变成了一个结构化的决策器。2.2 双手与双眼工具函数的实现工具是Agent能力的延伸。每个工具都是一个Python函数被设计成能够被LLM通过名称和参数调用。1. 文件读写工具 (read_file/write_file)这是最基础的工具。实现时要注意错误处理如文件不存在、权限不足和编码问题。import os import json def read_file(path: str) - str: 读取文件内容 try: with open(path, r, encodingutf-8) as f: return f.read() except FileNotFoundError: return f错误文件 {path} 不存在。 except Exception as e: return f读取文件时出错{str(e)} def write_file(path: str, content: str) - str: 写入文件内容 try: # 确保目录存在 os.makedirs(os.path.dirname(path), exist_okTrue) with open(path, w, encodingutf-8) as f: f.write(content) return f成功写入文件{path} except Exception as e: return f写入文件时出错{str(e)}2. 安全代码执行工具 (execute_python)这是最需要小心的部分。绝对不能让用户输入的或LLM生成的代码直接在你的主进程中运行那等同于“自杀”。我们必须使用沙箱。为什么用subprocess而不是exec直接使用Python的exec()函数风险极高它会在当前进程的全局和局部命名空间中执行代码可以轻易导入os模块并执行rm -rf /当然需要权限。subprocess可以将代码运行在一个独立的子进程中我们可以更好地控制其资源超时、内存和环境环境变量。如何实现一个简易沙箱将代码写入一个临时文件。使用subprocess.run()来执行python temp_file.py并捕获标准输出、标准错误和返回码。设置timeout参数防止无限循环。进阶可以使用docker run在一个干净的容器中执行隔离性最强但依赖Docker且启动较慢。import subprocess import tempfile import os def execute_python(code: str) - str: 在安全子进程中执行Python代码 # 创建一个临时文件 with tempfile.NamedTemporaryFile(modew, suffix.py, deleteFalse, encodingutf-8) as f: f.write(code) temp_path f.name try: # 使用subprocess运行设置超时例如10秒 result subprocess.run( [python, temp_path], capture_outputTrue, textTrue, timeout10, # 可以在这里设置环境变量如PYTHONPATH以限制模块导入 env{**os.environ, PYTHONPATH: } ) output [] if result.stdout: output.append(f标准输出:\n{result.stdout}) if result.stderr: output.append(f标准错误:\n{result.stderr}) output.append(f返回码: {result.returncode}) return \n---\n.join(output) except subprocess.TimeoutExpired: return 错误代码执行超时超过10秒。 except Exception as e: return f执行过程发生异常{str(e)} finally: # 清理临时文件 os.unlink(temp_path)注意这个沙箱仍然是“简易”的。它无法防止CPU/内存的耗尽除非用更复杂的resource模块或容器技术也无法防止一些针对Python解释器本身的攻击。对于完全不可信的代码最安全的方式是在一个一次性Docker容器或无服务器函数环境中运行。但对于个人辅助场景控制好超时和代码来源你自己或可信的LLM这个方案是实用的。3. 目录列表工具 (list_dir)这个工具让Agent能“看到”当前的工作环境是进行文件操作的基础。def list_dir(path: str .) - str: 列出目录下的文件和文件夹 try: items os.listdir(path) # 简单格式化一下可以区分文件和文件夹 formatted [] for item in items: full_path os.path.join(path, item) if os.path.isdir(full_path): formatted.append(f[目录] {item}/) else: formatted.append(f[文件] {item}) return \n.join(formatted) if formatted else 目录为空。 except FileNotFoundError: return f错误目录 {path} 不存在。 except Exception as e: return f列出目录时出错{str(e)}2.3 循环引擎ReAct循环的执行器这是将大脑LLM和工具函数连接起来的粘合剂。它的工作流程是一个严格的循环初始化将用户请求和系统Prompt组合发送给LLM获得第一个Thought和Action。解析与执行从LLM的响应中解析出Action和Action Input。根据Action找到对应的工具函数并将Action Input一个JSON字符串解析为字典参数调用该工具。观察获取工具的执行结果Observation。再思考将Thought、Action、Action Input和Observation全部作为历史上下文再次组合成新的Prompt发送给LLM让它基于之前的全部信息决定下一步是继续行动还是认为任务已完成输出最终答案。循环或终止重复步骤2-4直到LLM的输出中包含明确的完成信号如Action: FINISH或达到最大循环次数。关键实现细节上下文管理每次调用LLM都需要把之前所有的Thought, Action, Observation历史拼接起来这会让Token数量快速增长。对于简易版我们可以设置一个最大步数如10步来防止无限循环和成本过高。复杂版需要考虑更智能的上下文窗口压缩。输出解析LLM的输出可能不严格符合我们要求的JSON格式。我们需要一个健壮的解析器能处理一些微小的格式错误如多余的换行、尾随逗号。可以使用json.loads()配合简单的字符串预处理或者使用Pydantic模型进行验证。错误处理如果LLM返回了一个不存在的Action或者Action Input无法解析循环应该能捕获这个错误并将其作为Observation反馈给LLM让它“纠正”自己。import json import re class SimpleCodingAgent: def __init__(self, llm_client, tools, max_steps10): self.llm llm_client self.tools tools # 工具名到函数对象的映射 self.max_steps max_steps self.conversation_history [] # 保存历史交互 def run(self, user_query: str) - str: system_prompt self._build_system_prompt() full_prompt system_prompt f\n\n用户请求{user_query} for step in range(self.max_steps): # 1. 调用LLM获取响应 llm_response self.llm.generate(full_prompt) self.conversation_history.append(fAI: {llm_response}) # 2. 解析响应 thought, action, action_input self._parse_llm_response(llm_response) if not thought: return 无法解析LLM的响应。 print(f\n[步骤 {step1}]) print(f思考: {thought}) if action.lower() finish: # 从思考或响应中提取最终答案 final_answer self._extract_final_answer(llm_response) return final_answer print(f行动: {action}) print(f输入: {action_input}) # 3. 执行工具 if action not in self.tools: observation f错误未知工具 {action}。可用工具{list(self.tools.keys())} else: try: # 将action_input从JSON字符串转为字典 params json.loads(action_input) tool_func self.tools[action] observation tool_func(**params) except json.JSONDecodeError: observation f错误行动输入不是有效的JSON: {action_input} except TypeError as e: observation f错误工具参数不匹配: {str(e)} except Exception as e: observation f工具执行时发生意外错误: {str(e)} print(f观察: {observation[:200]}...) # 打印部分观察结果 # 4. 构建下一步的Prompt # 将本次交互Thought, Action, Action Input, Observation添加到历史中 step_record f\nThought: {thought}\nAction: {action}\nAction Input: {action_input}\nObservation: {observation} full_prompt step_record # 防止Prompt过长简易版可以只保留最近几步 # 这里为了简单我们继续累加。在实际中需要管理上下文长度。 return f达到最大步数限制 ({self.max_steps})任务未完成。 def _parse_llm_response(self, response: str): 一个简易的解析器使用正则表达式提取关键字段 thought_match re.search(rThought:\s*(.*?)(?\nAction:|$), response, re.DOTALL) action_match re.search(rAction:\s*(\w), response) action_input_match re.search(rAction Input:\s*(\{.*\}), response, re.DOTALL) thought thought_match.group(1).strip() if thought_match else action action_match.group(1).strip() if action_match else action_input action_input_match.group(1).strip() if action_input_match else {} return thought, action, action_input # ... _build_system_prompt 和 _extract_final_answer 方法省略3. 实战演练手把手组装并运行你的第一个Agent理论说了一大堆是时候动手了。我们假设你有一个能调用OpenAI GPT-3.5/4 API的客户端或者使用开源的本地模型通过Ollama、vLLM等框架提供类似API。这里以OpenAI API为例。3.1 环境准备与依赖安装首先创建一个干净的Python环境推荐使用venv或conda然后安装核心依赖。# 创建并激活虚拟环境 python -m venv agent_env source agent_env/bin/activate # Linux/Mac # agent_env\Scripts\activate # Windows # 安装依赖 pip install openai # LLM客户端 # 其他都是标准库json, os, subprocess, tempfile, re接下来你需要设置你的OpenAI API密钥。千万不要把密钥硬编码在代码里# 在Linux/Mac的终端中 export OPENAI_API_KEYyour-api-key-here # 在Windows的CMD中 set OPENAI_API_KEYyour-api-key-here # 在Windows的PowerShell中 $env:OPENAI_API_KEYyour-api-key-here3.2 组装完整代码我们将之前设计的各个模块组合成一个可运行的脚本simple_coding_agent.py。# simple_coding_agent.py import os import json import re import subprocess import tempfile from typing import Dict, Callable import openai # --- 工具函数实现 (与2.2节相同) --- def read_file(path: str) - str: # ... 实现同上 ... pass def write_file(path: str, content: str) - str: # ... 实现同上 ... pass def execute_python(code: str) - str: # ... 实现同上 ... pass def list_dir(path: str .) - str: # ... 实现同上 ... pass # --- LLM客户端封装 --- class OpenAIClient: def __init__(self, modelgpt-3.5-turbo): self.model model self.client openai.OpenAI() # 会自动读取环境变量 OPENAI_API_KEY def generate(self, prompt: str) - str: try: response self.client.chat.completions.create( modelself.model, messages[ {role: system, content: 你是一个严谨的Python编程助手必须严格按照指定格式输出。}, {role: user, content: prompt} ], temperature0.1, # 低温度输出更确定 max_tokens500 ) return response.choices[0].message.content except Exception as e: return f调用LLM API时出错{str(e)} # --- ReAct Agent 核心类 (与2.3节类似但更完整) --- class SimpleCodingAgent: def __init__(self, llm_client, max_steps8): self.llm llm_client self.max_steps max_steps # 注册工具 self.tools: Dict[str, Callable] { read_file: read_file, write_file: write_file, execute_python: execute_python, list_dir: list_dir, } self.system_prompt self._build_system_prompt() def _build_system_prompt(self) - str: tool_descriptions [] for name, func in self.tools.items(): # 这里可以更精细地描述工具这里用函数docstring的简单版 doc func.__doc__ or 无描述 tool_descriptions.append(f{name}: {doc}) prompt f你是一个高效的Python编程助手。你可以通过以下工具与外界交互 工具列表 {chr(10).join(tool_descriptions)} 请严格按照以下格式响应你的输出只能包含以下三个部分 Thought: 这里是你对当前任务和下一步的分析。请用中文思考。 Action: 要使用的工具名称必须是上述工具之一。如果任务完成请输出“FINISH”。 Action Input: 工具的输入必须是一个严格的、合法的JSON对象。如果Action是FINISH这里可以输出一个空JSON对象“{{}}”。 现在开始。记住除非用户要求否则不要在你的Thought或最终答案中解释你的内部工作流程。直接思考如何完成任务。 return prompt def _parse_llm_response(self, response: str): 解析LLM响应提取Thought, Action, Action Input # 使用更健壮的正则允许字段间有空行 thought_pattern rThought:\s*(.*?)(?\s*Action:\s*) action_pattern rAction:\s*(\w) # 匹配JSON对象可能跨多行 input_pattern rAction Input:\s*(\{.*?\}) thought action action_input {} thought_match re.search(thought_pattern, response, re.DOTALL) if thought_match: thought thought_match.group(1).strip() action_match re.search(action_pattern, response, re.DOTALL) if action_match: action action_match.group(1).strip() input_match re.search(input_pattern, response, re.DOTALL) if input_match: action_input input_match.group(1).strip() # 尝试验证JSON如果无效则置为空 try: json.loads(action_input) except json.JSONDecodeError: action_input {} return thought, action, action_input def run(self, user_query: str) - str: full_prompt self.system_prompt f\n\n用户请求{user_query} print(*50) print(f开始处理请求: {user_query}) print(*50) for step in range(self.max_steps): print(f\n--- 第 {step1} 步 ---) # 调用LLM llm_response self.llm.generate(full_prompt) # print(f[LLM原始响应]\n{llm_response}) # 调试时打开 # 解析 thought, action, action_input self._parse_llm_response(llm_response) print(f思考: {thought}) if action.upper() FINISH: # 尝试从Thought或响应末尾提取最终答案 final_answer thought if thought else 任务完成。 print(f\n✅ 任务完成) print(f最终结果: {final_answer}) return final_answer print(f行动: {action}) print(f输入: {action_input}) # 执行工具 observation if action not in self.tools: observation f错误未知工具 {action}。可用工具{list(self.tools.keys())} else: try: params json.loads(action_input) tool_func self.tools[action] observation tool_func(**params) except json.JSONDecodeError as e: observation f错误行动输入JSON解析失败: {e} except TypeError as e: observation f错误工具参数错误: {e} except Exception as e: observation f工具 {action} 执行异常: {str(e)} # 截断过长的观察结果以便显示 obs_display (observation[:300] ...) if len(observation) 300 else observation print(f观察: {obs_display}) # 构建下一步的Prompt step_record f\nThought: {thought}\nAction: {action}\nAction Input: {action_input}\nObservation: {observation} full_prompt step_record print(f\n⚠️ 达到最大步数限制 ({self.max_steps})任务终止。) return 任务未在限制步数内完成。 # --- 主程序 --- if __name__ __main__: # 初始化LLM客户端和Agent llm_client OpenAIClient(modelgpt-3.5-turbo) # 或 gpt-4 agent SimpleCodingAgent(llm_client, max_steps8) # 示例任务 # task 请列出当前目录下所有的Python文件。 # task 读取当前目录下的README.md文件如果存在的话的内容。 task 创建一个名为hello.py的文件内容为打印Hello, Agent!然后执行它。 result agent.run(task) print(\n *50) print(Agent运行结束。)3.3 运行与效果分析保存代码后在终端运行python simple_coding_agent.py你会看到类似以下的输出具体内容因LLM响应而异 开始处理请求: 创建一个名为hello.py的文件内容为打印Hello, Agent!然后执行它。 --- 第 1 步 --- 思考: 用户想要创建一个文件并执行它。我需要先创建文件然后执行它。第一步是使用write_file工具创建hello.py文件。 行动: write_file 输入: {path: hello.py, content: print(Hello, Agent!)} 观察: 成功写入文件hello.py --- 第 2 步 --- 思考: 文件已经创建成功。现在我需要执行这个Python文件。我应该使用execute_python工具来执行hello.py文件中的代码。我可以读取文件内容然后执行或者直接执行文件。最简单的方式是直接用execute_python工具执行文件中的代码。我先读取文件内容确认一下。 行动: read_file 输入: {path: hello.py} 观察: print(Hello, Agent!) --- 第 3 步 --- 思考: 文件内容确认无误。现在使用execute_python工具来执行这段代码。 行动: execute_python 输入: {code: print(Hello, Agent!)} 观察: 标准输出: Hello, Agent! --- 返回码: 0 --- 第 4 步 --- 思考: 代码执行成功输出了预期的结果。任务已经完成。 行动: FINISH 输入: {} ✅ 任务完成 最终结果: 代码执行成功输出了预期的结果。任务已经完成。看Agent成功地分解了任务先写文件再读文件确认这一步在思考中产生有时可以优化最后执行代码。它完成了从自然语言指令到实际文件操作和代码执行的完整闭环。4. 避坑指南与进阶思考从“能跑”到“好用”第一个能跑的Agent诞生了但距离“好用”还有十万八千里。下面是我在实现和迭代过程中踩过的坑以及一些进阶方向的思考。4.1 常见问题与调试技巧1. LLM不按格式输出这是初期最常见的问题。你的Prompt可能不够强硬或者模型“太有想法”。解决在系统Prompt中使用更严厉的措辞如“你必须严格按照以下格式响应你的输出只能包含以下三个部分...”。降低temperature参数如设为0.1可以减少随机性。在解析响应时编写更鲁棒的正则表达式或使用少量示例Few-shot在Prompt中展示正确格式。实战技巧在开发阶段把LLM的原始响应打印出来(print(f“[LLM原始响应]\n{llm_response}”))这是调试Prompt和解析器最直接的方法。2. 工具执行失败或结果不符合预期LLM可能生成错误的参数格式或者工具函数本身有Bug。解决在工具函数内部做好充分的错误捕获并返回清晰的错误信息如“错误文件不存在”而不是抛出异常导致整个Agent崩溃。这些错误信息会作为Observation反馈给LLM它有时能自我纠正。实战技巧为每个工具编写详细的文档字符串并在Prompt中清晰说明输入格式。例如write_file的输入是{path: string, content: string}明确标出键名和类型。3. 陷入无限循环或无效步骤Agent可能在一个简单问题上反复横跳比如不停地list_dir却不做实质操作。解决设置合理的max_steps如8-10步。在Prompt中鼓励其“在合理的最小步骤内完成任务”。更高级的做法是引入一个“批判”步骤让LLM评估当前进展是否有效或者实现一个“短期记忆”来避免重复操作。实战技巧观察Thought字段。如果思考内容开始重复或偏离主题说明LLM可能困惑了。这时可以尝试在用户请求中提供更具体的约束比如“请用不超过3个步骤完成”。4. 安全沙箱的局限性我们的execute_python工具虽然用了子进程和超时但并非绝对安全。重要警告它无法阻止import os; os.system(‘rm -rf /’)这样的命令如果子进程有权限。对于完全不可信的代码切勿使用此简易沙箱。进阶方案对于需要执行不可信代码的场景必须使用深度隔离技术。可以考虑Docker容器每次执行在一个全新的、网络和文件系统受限的容器中。这是生产级方案但启动有开销。PyPy Sandbox或gVisor更专业的沙箱技术但配置复杂。云函数/无服务器将代码提交到AWS Lambda、Google Cloud Functions等环境执行利用云服务商的隔离性。4.2 性能与成本优化1. 上下文长度与Token消耗ReAct模式会不断累积历史Thought, Action, Observation导致Prompt越来越长API调用成本增加还可能触及模型的最大上下文长度限制。优化策略摘要历史不保存完整的Observation尤其是长文件内容或输出而是让LLM或一个单独的摘要模型对之前的观察进行总结。滑动窗口只保留最近N步的完整交互更早的步骤被摘要或丢弃。更精炼的Prompt去除不必要的描述使用更简洁的工具说明。2. 工具设计的粒度工具不是越细越好也不是越粗越好。问题如果工具太细如create_file,append_to_file,delete_fileLLM需要更多步骤来组合容易出错。如果工具太粗如handle_file_operationLLM又难以准确生成复杂参数。经验工具的设计应与常见的用户意图“原子操作”对齐。对于文件read和write是两个最自然的基础操作。对于代码execute是一个基础操作。你可以根据你的常用场景添加复合工具比如create_and_run_script但这会降低系统的灵活性。4.3 扩展方向让你的Agent更强大一个基础的ReAct Agent已经成型你可以在此基础上像搭乐高一样添加新能力1. 增加更多工具网络请求添加一个http_request工具让Agent能获取网页内容或调用外部API。数据库操作添加query_database工具让Agent能查询或更新数据。Shell命令添加一个极度小心的run_shell工具仅限于白名单命令如ls,grep,find并做好严格的输入过滤和权限控制。代码分析集成ast模块添加analyze_python_ast工具让Agent能理解代码结构。2. 引入记忆与状态管理目前的Agent是“无状态”的每次交互都是独立的。你可以为它添加会话记忆记住同一会话中用户之前的要求实现多轮对话。长期记忆向量数据库将每次任务的成功经验、代码片段存入向量数据库。当遇到类似新任务时可以先检索相关记忆作为参考实现“学习”能力。3. 多Agent协作一个Agent能力有限可以设计多个各司其职的Agent如“架构师Agent”、“编码Agent”、“测试Agent”协同工作通过一个“协调员”来分配任务和整合结果。这其实就是LangGraph等框架擅长解决的编排问题。4. 集成更强大的代码模型除了通用的Chat模型如GPT可以尝试集成专门的代码模型如Codex、Claude、DeepSeek-Coder它们在代码生成、理解和补全上通常表现更好。你可以设计一个路由机制如果是纯聊天用通用模型如果涉及复杂代码自动切换到代码模型。实现一个简易的Coding Agent最大的收获不是代码本身而是彻底理解了AI Agent是如何将“思考”与“行动”结合起来的。它不是一个魔法黑盒而是一个由Prompt、工具函数、循环逻辑构成的、可预测可调试的系统。从这个简易版出发你再去学习LangChain的AgentExecutor、LangGraph的StateGraph就会明白它们无非是在这个基础骨架上增加了更强大的工具管理、更复杂的状态流转、更优雅的错误处理和更高效的内存管理。