解密prompt系列61. 手搓代码沙箱与FastAPI-MCP实战

news/2025/10/9 8:09:49/文章来源:https://www.cnblogs.com/gogoSandy/p/19130377

最近Vibe Code在各种技术社区刷屏,不过说实话,在日常工作中,我更多是用LLM来生成文档、批量修改代码或者排查问题。毕竟业务需求嘛,很少有能一次性描述清楚的(懂的都懂哈哈~)。但在看了最新的SWE-Bench Pro评测后,我决定尝试一下端到端的AI编程体验。

前两章我们讨论了JupyterAgent,当时用的是E2B的代码沙箱。这次我决定自己动手,用字节的TRAE从头构建一个Python代码沙箱,并加入MCP支持。完整代码已经开源在simple_sandbox,Star is Welcomed!

个人体感TRAE在国内Coding IDE里算Very Good,比开源的Cline,Kilo等在Token使用上效率更高,但和cursor还有距离。如何最大化Token使用效率和效果是个系统工程问题~

Vibe Coding实战:从零构建代码沙箱

本来想完整分享整个Vibe Coding过程的,结果TRAE升级把历史对话记录清空了(哭)。那就跟大家分享一下我的操作思路和最终成果吧!

我在使用AI IDE时通常有两种策略:

  • 模型主导:让模型先做整体规划,我人工调整后让模型执行,依赖模型的测试文件和执行报错进行迭代优化
  • 人工主导:我自己拆解任务,让模型逐步实现,每一步都进行人工校验

如何选择这两种模式完全取决于我对于整个项目是否有很强的先验思考,哈哈就是我知道怎么做的我带着模型做,我不知道的模型带着我做。

这次的任务因为有E2B的SDK可以参考,我选择了人工主导的方式,将任务拆解成几个明确的步骤:

  1. 沙箱核心功能:沙箱创建、环境初始化、代码执行
  2. 功能完善:结构化输出、预装环境、工作目录隔离、中文字体支持
  3. 扩展功能:文件上传、文件获取、超时关闭
  4. 服务化:搭建FastAPI服务接口
  5. 客户端Demo:创建请求示例
  6. 文档撰写:完善的README

最终模型实现的沙箱核心类如下,完整代码请移步Github,在整个编码过程中,我只在功能设计层面做了调整,没有发现任何编码错误:


# 沙箱类
class Sandbox:def __init__(self, sandbox_id: str, work_dir: str, venv_dir: str):self.sandbox_id = sandbox_idself.work_dir = work_dirself.venv_dir = venv_dir# 配置KernelManager使用虚拟环境中的Python解释器self.kernel_manager = KernelManager(kernel_name='python3',kernel_spec_manager=self._create_custom_kernel_spec_manager())# 设置环境变量env = os.environ.copy()env['VIRTUAL_ENV'] = venv_dir# 设置内核使用虚拟环境中的Pythonself.kernel_manager.start_kernel(cwd=work_dir,env=env,)self.kernel_client = self.kernel_manager.client()self.kernel_client.start_channels()self.kernel_client.wait_for_ready()self.last_execute_id = 0# 复制字体文件到沙箱工作目录font_source_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'SimHei.ttf')font_dest_path = os.path.join(work_dir, 'SimHei.ttf')if os.path.exists(font_source_path):try:shutil.copy2(font_source_path, font_dest_path)print(f"字体文件已复制到: {font_dest_path}")except Exception as e:print(f"复制字体文件失败: {e}")else:print(f"未找到字体文件: {font_source_path}")# 安装基本包self._install_basic_packages()# 执行字体注册代码self.execute_code(font_code)def _create_custom_kernel_spec_manager(self):# 创建自定义的内核规范管理器,确保使用正确的Python环境from jupyter_client.kernelspec import KernelSpecManagerksm = KernelSpecManager()return ksmdef _install_basic_packages(self):# 在虚拟环境中安装基本包# 如果是从镜像复制的环境,可能已经包含了基本包,这里可以跳过或仅检查try:# 直接使用Linux路径设置pip_path = os.path.join(self.venv_dir, 'bin', 'pip')python_exe = os.path.join(self.venv_dir, 'bin', 'python')# 检查ipykernel是否已安装check_result = subprocess.run([python_exe, '-c', 'import ipykernel'],capture_output=True,text=True)# 如果ipykernel未安装,则安装if check_result.returncode != 0:print("ipykernel未安装,开始安装...")subprocess.check_call([pip_path, 'install', 'ipykernel'])except Exception as e:print(f"安装基础包失败: {e}")def execute_code(self, code: str) -> Dict:# 生成执行IDself.last_execute_id += 1# 执行代码msg_id = self.kernel_client.execute(code)stdout = []stderr = []error = Noneresults = []# 收集执行结果while True:try:msg = self.kernel_client.get_iopub_msg(timeout=3600)msg_type = msg['header']['msg_type']if msg['parent_header'].get('msg_id') != msg_id:continue elif msg_type == 'stream':content = msg['content']if content['name'] == 'stdout':stdout.append(content['text'])elif content['name'] == 'stderr':stderr.append(content['text'])elif msg_type == 'error':content = msg['content']# 合并error字段,包含ename、evalue和tracebackerror = {'name':ansi_escape.sub('',  content['ename']),'value': ansi_escape.sub('',content['evalue']),'traceback': [ansi_escape.sub('', i) for i in content['traceback']]}elif msg_type == 'execute_result':# 处理执行结果,按照{type,data}格式存储data = msg['content']['data']for data_type, data_value in data.items():results.append({"type": data_type, "data": data_value})elif msg_type == 'display_data':# 处理显示数据,按照{type,data}格式存储data = msg['content']['data']for data_type, data_value in data.items():results.append({"type": data_type, "data": data_value})elif msg_type == 'execute_reply':breakelif msg_type == 'status':if msg['content']['execution_state'] == 'idle':breakexcept Exception:breakreturn {'stdout': [ansi_escape.sub('', i) for i in stdout],'stderr': [ansi_escape.sub('', i) for i in stderr],'error': error,'results': results}def upload_file(self, file: UploadFile, file_path: Optional[str] = None) -> str:# 确定文件保存路径:默认为工作目录最简化codeif file_path:save_path = os.path.join(self.work_dir, file_path)else:save_path = os.path.join(self.work_dir, file.filename)# 确保目标目录存在os.makedirs(os.path.dirname(save_path), exist_ok=True)# 保存文件with open(save_path, "wb") as f:shutil.copyfileobj(file.file, f)return save_pathdef get_files(self) -> List[Dict[str, str]]:files = []for root, _, filenames in os.walk(self.work_dir):for filename in filenames:file_path = os.path.join(root, filename)relative_path = os.path.relpath(file_path, self.work_dir)files.append({'path': relative_path,'size': os.path.getsize(file_path)})return filesdef get_file_path(self, file_path: str) -> str:full_path = os.path.abspath(os.path.join(self.work_dir, file_path))# 安全检查,确保文件在工作目录内if not full_path.startswith(os.path.abspath(self.work_dir)):raise HTTPException(status_code=403, detail="File access denied")return full_pathdef shutdown(self):try:self.kernel_client.stop_channels()self.kernel_manager.shutdown_kernel()# 清理工作目录shutil.rmtree(self.work_dir, ignore_errors=True)# 清理虚拟环境目录shutil.rmtree(self.venv_dir, ignore_errors=True)except Exception:passdef install_package(self, package_name: str) -> Dict:"""在沙箱的虚拟环境中安装Python包"""try:# 获取虚拟环境中的pip路径(Linux环境)pip_path = os.path.join(self.venv_dir, 'bin', 'pip')# 执行pip安装命令result = subprocess.run([pip_path, 'install', package_name],capture_output=True,text=True,timeout=60  # 设置超时时间)# 检查安装是否成功if result.returncode == 0:return {'success': True,'stdout': result.stdout,'stderr': result.stderr,'message': f"成功安装包: {package_name}"}else:return {'success': False,'stdout': result.stdout,'stderr': result.stderr,'message': f"安装包失败: {package_name}"}except Exception as e:return {'success': False,'stdout': '','stderr': str(e),'message': f"安装过程出错: {str(e)}"}

用FastAPI-MCP打造标准化MCP服务

沙箱服务跑通后,我决定将其打包成标准的MCP服务。这时候就轮到FastAPI-MCP出场了!就像我们在解密prompt系列58. MCP - 工具演变 & MCP基础中提到的MCP本身并不是工具,它只是Adapter,而FastAPI-MCP库完美体现了这一特性——它可以将现有的FastAPI工具直接转换成标准MCP服务。

但这里遇到了一个常见问题:大模型对新的library支持不够好。解决方案是使用上下文管理模块,将API接口文档加入上下文。这种方法特别适用于:

  • 这两年的新Library:MCP etc.
  • 大版本更新的Lirabry: 例如ES 7.XX -> Elastic Search 8.XX

image

这样我们就可以引用对应的API文档让TRAE帮我们进一步把服务借助FastAPI-MCP包装成MCP服务,并使用FastMCP给出请求Demo。而FastAPI-MCP的使用也非常简单,只需要添加三行代码就可以完成MCP服务的适配

from fastapi_mcp import FastApiMCP
# 创建并挂载MCP服务器 - 移到所有端点定义之后
mcp = FastApiMCP(app)
mcp.mount_http()

接下来,我把FastMCP的接口文档加入上下文,让模型生成MCP Client来验证服务。但运行时发现MCP服务可以请求成功,list_tool却显示为空。通过观察输入输出来定位问题,TRAE成功找到了问题所在并进行了修复。

image

重要提示:使用FastMCP-API时需要先添加端点再挂载MCP!

不过下一个问题难住了TRAE:调用后发现FastMCP-API默认使用端点名称+函数名称作为工具名称,导致list_tool显示的工具名很奇怪。我想优化工具命名,但TRAE没有在接口文档中找到对应内容。

image

其实解决方案很简单,只需要添加operation_id参数就能提供工具别名:

# Explicit operation_id (tool will be named "get_user_info")
@app.get("/users/{user_id}", operation_id="get_user_info")
async def read_user(user_id: int):return {"user_id": user_id}

image

结合上下文和明确的任务拆解,LLM在Coding任务上确实是当前AI能发挥最大价值的领域可能没有之一。笔者已经很明显的感觉在工作中能否最大程度发挥工具的能力已经能很显著地拉开大家工作效率的差距。哈哈这里肯定有人吐槽当牛马你要这么高的效率干什么,但咱就说省出来的时间咱鼓捣点新鲜好玩的不香么?下次咱结合开源的Cline或Kilo一边看上下文的工程设计,一边看下模型自主对复杂任务的拆解效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/932293.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 高可用构建方案详解

MySQL 高可用构建方案详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &…

企业网站建设应该注意什么事项问题雁塔区网站建设

曾经做过单片机和以下20种PLC的Modbus RTU串口通信,现将这20种PLC输入、输出和寄存器元件与Modbus编号地址对应表分享出来。三菱FX3G-40MR/ES-A、西门子S7-200 CPU226 AC/DC/RLY、欧姆龙CP1H-X40DR-A、松下AFPX-C40R、台达DVP-12SA2、信捷XC5-48、永宏FBs-40MC、产电…

VMware ESXi 9.0.1.0 macOS Unlocker OEM BIOS 2.7 标准版和厂商定制版

VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS 2.7 标准版和厂商定制版VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS 2.7 标准版和厂商定制版 ESXi 9.0 标准版,Dell (戴尔)、HPE (慧与)、Lenovo (联想)、…

使用sqlite-loadable-rs开发一个简单sqlite uuid 扩展

使用sqlite-loadable-rs开发一个简单sqlite uuid 扩展默认sqlite 缺少uuid 函数, sqlite-loadable-rs 是一个基于rust包装的框架,可以用来快速开发sqlite 扩展,以下是一个简单测试 项目准备cargo.toml注意当前editio…

C语言数据结构笔记3:Union联合体+结构体取8位Bool量 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

多机器人协同首现基础模型技术突破

某机构研发出首个多机器人协同基础模型DeepFleet,通过Transformer架构处理机器人导航数据,能预测交通模式并提升10%运营效率。该技术利用数十亿小时真实数据训练,包含四种不同架构模型的对比实验。多机器人协同首现…

文登做网站的公司wordpress建英文博客

HTML placeholder 属性实例 1带有 placeholder 文本的两个输入字段:尝试一下 placeholder 文本也可以指定颜色。实例 2带有 placeholder 文本设置颜色:尝试一下 浏览器支持Internet Explorer 10、Firefox、Opera、Chrome 和 Safari 支持 placeholder 属性…

做查询系统网站如何写网站文案

OpenSSL(Open Secure Sockets Layer)是一个开源的软件库,提供了SSL和TLS协议的实现,用于加密通信。它广泛用于安全连接,例如在网站上通过HTTPS协议进行安全的数据传输. 但是从openssl申请道德证书是不安全的。对于网站…

PHP 图像处理实战 GD/Imagick 从入门到精通,构建高性能图像服务

PHP 图像处理实战 GD/Imagick 从入门到精通,构建高性能图像服务 网页上经常能看到模糊的用户头像、被拉伸变形的卡片图片,还有动辄几 MB 大小的 JPEG 文件。其实这些问题完全可以避免,关键在于建立合适的图像处理流…

上海百度整站优化服务wordpress获取指定图片大小

1. 作用 匹配文档中的某些元素为其应用样式。根据不同需求把不同的标签选出来。 2. 分类 分类 基础选择器 包含 标签选择器、ID选择器、类选择器、通用选择器等 复合选择器 包含 后代选择器、子代选择器、伪类选择器等 1 标签选择器 介绍 又称为元素选择器,根…

湘潭营销网站建设物理机安装虚拟机做网站好处

说明 vue路由切换时&#xff0c;当前页面左侧和右侧容器分别从两侧滑出&#xff0c;新页面左右分别从两侧滑入 效果展示 路由切换-滑入滑出效果 难点和踩坑 现路由和新路由始终存在一个页面根容器&#xff0c;通过<transition>组件&#xff0c;效果只能对页面根容器有效…

完全免费的网站源码做app网站的软件

咳咳&#xff0c;请各位小伙伴们注意啦&#xff01;我们要聊的主题可是相当高大上——小动物呼吸机&#xff01; 我们得先了解一下什么是小动物呼吸机。这可不是一般的机器哦&#xff0c;它是一种实验设备&#xff0c;主要用于各种各样的科学研究实验中。比如&#xff0c;在基…

注销主体和注销网站互联网广告精准营销

因项目原因&#xff0c;公司需要在钉钉里面开发小程序。之前用uniapp开发过app&#xff0c;H5&#xff0c;小程序。还真没尝试过钉钉小程序&#xff0c;今天就简单的记录下uniapp运行钉钉小程序中的过程。 在项目目录新建package.json文件&#xff0c;在文件中添加如下代码&am…

农业服务网站建设方案互联网制作公司

时态篇开篇导言&#xff1a;英语的时态是一种动词形式&#xff0c;不同的时态表示动作行为的不同时间与发生方式。粤语同样也有时态&#xff0c;这种时态是通过动词与对应的前后缀以及时间词共同表示。 &#xff08;一&#xff09;普通时态说明&#xff1a;普通时态一般指经常发…

网站开发外包 验收国内设计的企业网站

简介&#xff1a; 由汽车之家实时计算平台负责人邸星星在 4 月 17 日上海站 Meetup 分享的&#xff0c;基于 Flink Iceberg 的湖仓一体架构实践。 内容简要&#xff1a; 一、数据仓库架构升级的背景 二、基于 Iceberg 的湖仓一体架构实践 三、总结与收益 四、后续规划 一、数据…

江苏省城乡建设局网站兰州网站设计制作

QT学习笔记&#xff08;一&#xff09;&#xff1a;VS2013 QT 5.8 运行、编译问题解决 jom: E:\C\4.QT\HelloWord\Makefile.Debug [debug\moc_predefs.h] Error 1 ‘cl’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 jom: E:\C\4.QT\HelloWord\Makefile…

淘宝api 做网站关注公众号平台

在介绍开发板之前&#xff0c;让我们先来区分一下核心板和开发板的区别。核心板是一种集成度高、功能完整的计算模块&#xff0c;搭载系统&#xff0c;简化了外围接口&#xff0c;体积尺寸相对较小&#xff0c;主要适用于嵌入式系统。而开发板由核心板底板组成&#xff0c;提供…

17网站一起做网店质量怎么样秦皇岛网站制作电话

二维教组A[12][18]采用列优先的存储方法&#xff0c;若每个元素各占3个存储单元&#xff0c;且第1个元素的地址为150&#xff0c;则元素A[9][7]的地址为 ( ) A&#xff0e;429 B&#xff0e;432 C&#xff0e;435 D&#xff0e;438 [分析] 本题考查数组元素存储地址的计算。…

手机端网站界面如何做唐山做网站

本节课程将学习以下内容&#xff1a;函数的复写(override)使用super调用父类的成员函数函数的复写(override)复写(override)&#xff0c;也被称为覆盖或者重写。在你对父类的成员方法不满意的时候&#xff0c;你可以在子类中复写这个方法&#xff0c;来写出符合自己要求的方法。…

凡科可以做视频网站吗wordpress完美重置

一.服务器端获取Session对象依赖于客户端携带的Cookie中的JSESSIONID数据。如果用户把浏览器的隐私级别调到最高&#xff0c;这时浏览器是不会接受Cookie、这样导致永远在服务器端都拿不到的JSESSIONID信息。这样就导致服务器端的Session使用不了。Java针对Cookie禁用&#xff…