让 Agent 自己写代码:Code Interpreter 的原理与安全沙箱
让 Agent 自己写代码:Code Interpreter 的原理与安全沙箱
关键词:大语言模型、代码解释器、安全沙箱、代码执行、LLM编程、自主Agent、代码生成验证
摘要:当我们看到ChatGPT-4、Claude 3 Opus这类大语言模型(LLM)能像资深程序员一样,从一句“帮我画一张带统计置信区间的北京近10年降水量柱状图”直接写出Python代码,然后运行代码、解释结果、甚至根据反馈修改代码时,是不是觉得很神奇?这背后的核心功臣就是Code Interpreter(代码解释器)——它给只会“说人话”的LLM装了一双“会干活的手”。但Code Interpreter可不是随便装的,一旦代码运行失控,可能会窃取用户隐私、破坏系统资源,甚至威胁整个云平台的安全!这时候**安全沙箱(Security Sandbox)**就像一个“带锁的独立实验室”,把代码牢牢关在里面,出了问题也不会殃及外面。本文我们会像搭积木、玩游戏一样,从一个“帮小朋友数巧克力豆”的小需求切入,一步一步拆解Code Interpreter的核心原理、与LLM的协作流程,再深入探索安全沙箱的技术选型、核心机制,最后给大家展示一个可运行的极简版Code Interpreter+沙箱项目,再聊聊这个领域的未来发展。全文没有晦涩难懂的黑话,每个技术点都有生活中的类比,还有完整的Python代码和直观的Mermaid流程图,保证你看完就能懂,甚至能动手搭个小玩具!
背景介绍
目的和范围
目的
- 用大白话讲透技术:打破大众对Code Interpreter和安全沙箱的“黑盒认知”,让哪怕是刚学Python的小白,或者是对AI感兴趣的产品经理、运营,都能明白它们是怎么工作的。
- 梳理核心逻辑:从需求触发、代码生成、安全校验、代码执行到结果反馈,把整个LLM+Code Interpreter的协作链条理得明明白白,像看流水账一样清楚。
- 提供实践参考:写一个可运行的、基于Docker的极简版Code Interpreter+沙箱,让大家能亲手试试,感受技术的魅力;同时给出最佳实践Tips,防止在实际项目中踩坑。
- 引发思考:探讨Code Interpreter和安全沙箱的未来发展方向,以及可能带来的机遇和挑战。
范围
- 核心聚焦:主要讲面向大语言模型的通用型代码解释器,比如ChatGPT的Code Interpreter、Claude的Code Editor(带运行功能)、Open Source的LangChain Code Interpreter Tool、LlamaIndex的Code Execution,而不是像Python官方解释器那样面向人类程序员的“纯解释器”。
- 安全侧重:重点讲云原生环境下的安全沙箱,因为现在绝大多数LLM服务都部署在云端;也会简单提一下本地环境的轻量级沙箱方案,比如pyenv、venv的安全增强版。
- 技术选型:代码实现会用Python(因为Python是LLM代码生成的首选语言),沙箱会用Docker(最主流的云原生容器化沙箱方案)和nsjail(Google开源的轻量级Linux沙箱,也很常用)做对比和示例。
- 不深入展开的部分:不会讲LLM本身的代码生成原理(比如Transformer、注意力机制),不会讲太底层的Linux内核安全机制(比如seccomp-bpf的具体字节码规则),不会讲商业级Code Interpreter的所有细节(因为很多是闭源的)。
预期读者
- AI初学者/爱好者:对大语言模型、自主Agent感兴趣,想了解它们怎么“自己动手干活”。
- 初级/中级Python程序员:想写一个自己的Code Interpreter工具,或者想知道怎么安全地执行第三方/AI生成的代码。
- AI产品经理/运营:想了解LLM+Code Interpreter的能力边界、安全风险,以便更好地设计和运营产品。
- 云原生/安全工程师:想了解面向LLM的安全沙箱技术选型和最佳实践。
文档结构概述
本文的结构就像“玩游戏通关”一样,一共有10个关卡:
- 背景介绍:现在这一关,告诉你我们为什么要玩这个游戏,玩的是什么,谁适合玩。
- 核心概念与联系:像认识游戏角色一样,认识Code Interpreter、安全沙箱、LLM这些核心角色,还要搞清楚它们之间的关系——就像孙悟空、唐僧、紧箍咒的关系一样!
- 核心算法原理 & 具体操作步骤:像看游戏攻略一样,知道LLM和Code Interpreter是怎么一步一步协作完成任务的,包括代码生成的“过滤修正算法”、结果反馈的“语义解析算法”。
- 数学模型和公式:虽然这个游戏不用算数学题,但一些简单的数学模型能帮我们更好地理解安全沙箱的“资源限制”和LLM代码生成的“置信度评估”——就像游戏里的“体力条”“装备评分”一样!
- 项目实战:可运行的极简版Code Interpreter+沙箱:终于到了“动手玩游戏”的环节!我们会用Python、Docker、FastAPI写一个小工具:你输入一句自然语言需求,它会调用本地的LLM(比如用Ollama跑Llama 3 8B)生成Python代码,然后把代码放到Docker容器里运行,最后把结果返回给你。
- 实际应用场景:看看这个“游戏工具”在现实生活中有什么用——比如数据分析、自动化办公、教育辅助、科学研究等等。
- 工具和资源推荐:给你推荐一些“外挂”和“攻略书”,帮你更好地玩这个游戏——比如开源的Code Interpreter工具、安全沙箱工具、LLM工具,还有一些学习资料。
- 未来发展趋势与挑战:看看这个游戏未来会怎么更新——比如Code Interpreter会支持更多语言、更多硬件、更复杂的任务,安全沙箱会更轻量、更安全、更智能,同时也会面临哪些“新Boss”——比如更复杂的安全威胁、更高的性能要求、更严格的监管要求。
- 总结:学到了什么?:像游戏通关后的“回顾总结”一样,再用大白话回顾一下核心概念和它们之间的关系。
- 思考题:动动小脑筋:像游戏通关后的“隐藏任务”一样,给你留几个思考题,鼓励你进一步探索。
- 附录:常见问题与解答:像游戏里的“FAQ手册”一样,解答一些你可能会遇到的问题。
- 扩展阅读 & 参考资料:像游戏里的“隐藏关卡入口”一样,给你推荐一些更深入的学习资料。
术语表
核心术语定义
- 大语言模型(LLM, Large Language Model):一个会“说人话”“理解人话”的超级AI助手,它读了互联网上几乎所有的公开文本,能根据你的输入生成各种各样的内容——比如文章、代码、诗歌、翻译等等。类比:一个读了全世界所有课本、小说、报纸的“超级学霸”。
- 代码解释器(面向LLM的,本文默认是这种):一个给“超级学霸”LLM装的“会干活的手”,它能让LLM生成的代码真正运行起来,然后把运行结果(比如数据、图表、错误信息)返回给LLM,LLM再根据结果继续修改代码或者解释给你听。类比:超级学霸旁边的“实验员助手”——学霸说“把这些试剂混合起来,加热到100度”,助手就去做,然后把结果(比如颜色变化、温度曲线)告诉学霸。
- 安全沙箱(面向代码执行的,本文默认是这种):一个给“实验员助手”装的“带锁的独立实验室”,实验员只能在实验室里做实验,不能随便拿实验室外面的东西(比如你的银行卡密码、系统文件),也不能把实验室里的危险东西(比如病毒、恶意代码)带出去,更不能破坏实验室外面的东西(比如你的电脑、云平台的服务器)。类比:小朋友玩橡皮泥的“专用桌垫”——小朋友只能在桌垫上玩橡皮泥,不能把橡皮泥蹭到衣服上、沙发上,桌垫脏了可以直接洗,不会影响别的东西。
- 自主Agent:一个能“自己设定目标、自己规划步骤、自己执行任务、自己反馈结果、自己调整策略”的AI系统,它通常由LLM(大脑)、Code Interpreter(手)、感知模块(眼睛、耳朵)、记忆模块(笔记本)组成。类比:一个能自己做饭的“超级机器人”——你说“我想吃番茄炒蛋”,它就自己去买菜、洗菜、切菜、炒菜、装盘,要是盐放多了,它还会自己加点水或者糖调整。
- 代码生成验证:在运行LLM生成的代码之前,先检查一下代码有没有问题——比如有没有恶意代码(比如窃取文件、删除文件)、有没有语法错误、有没有逻辑错误、有没有超过资源限制(比如内存、CPU、时间)。类比:小朋友做实验之前,老师先检查一下实验步骤对不对、有没有用到危险的试剂、有没有超过实验时间。
相关概念解释
- 纯代码解释器:比如Python官方解释器、Node.js解释器,它们是面向人类程序员的,只负责把代码翻译成机器语言或者中间语言并运行,不会和LLM交互,也没有安全保护(除非你自己加)。类比:一个只会按按钮的“机器操作工”——你按什么按钮,它就做什么,不管按的是对是错,会不会出事。
- 容器化(Containerization):一种把应用程序及其所有依赖(比如库、配置文件)打包成一个“轻量级、可移植、独立运行”的容器的技术,容器之间是隔离的,每个容器都有自己的文件系统、网络、进程空间。类比:一个“独立的小公寓”——每个公寓都有自己的厨房、卫生间、卧室,公寓之间是隔离的,你不能随便进别人的公寓,也不能随便用别人的东西。
- Docker:目前最主流的容器化平台,它能让你很容易地创建、运行、管理容器。类比:一个“公寓管理公司”——它负责建公寓、租公寓、管理公寓的水电煤气。
- seccomp-bpf:Linux内核提供的一种安全机制,它能限制进程可以调用的系统调用(System Call)——比如进程不能调用“删除文件”“打开网络连接”“读取系统密码文件”的系统调用。类比:公寓里的“门禁系统”——你只能进自己的公寓,只能用自己公寓里的东西,不能随便打开公寓的大门、不能随便用走廊里的公共设施。
- cgroups(Control Groups):Linux内核提供的一种资源限制机制,它能限制进程可以使用的资源——比如CPU使用率、内存大小、磁盘IO、网络带宽、运行时间。类比:公寓里的“水电煤气表”——每个公寓的水电煤气都是限量的,超过了就会停掉。
缩略词列表
- LLM:Large Language Model,大语言模型
- AI:Artificial Intelligence,人工智能
- API:Application Programming Interface,应用程序编程接口
- Docker:没有全称,就是一个品牌名
- seccomp:secure computing mode,安全计算模式
- bpf:Berkeley Packet Filter,伯克利包过滤器
- cgroups:Control Groups,控制组
- Ollama:没有全称,就是一个开源的LLM本地部署平台
- FastAPI:没有全称,就是一个开源的Python Web框架
- LangChain:没有全称,就是一个开源的LLM应用开发框架
核心概念与联系
故事引入
小朋友们(包括大朋友小朋友们),你们有没有过这样的经历:
妈妈给了你10颗巧克力豆,让你分给3个小伙伴,每个小伙伴要分一样多,剩下的留给自己。你数了又数,算到头疼——10除以3等于3,还剩1颗?不对,等一下,3乘以3是9,10减9是1,对的!但要是妈妈给了你1000颗巧克力豆,分给37个小伙伴呢?你肯定更头疼了!
这时候,你可以请你的“超级学霸”AI助手帮忙——你输入一句“帮我算一下1000颗巧克力豆分给37个小伙伴,每个小伙伴分多少,剩下多少”,AI助手马上就能告诉你答案:“每个小伙伴分27颗,剩下1颗。”
但你要是说“帮我画一张带统计置信区间的北京近10年降水量柱状图,数据要用中国气象局的公开数据”,AI助手只会“说人话”——它能告诉你“你可以用Python的requests库爬取中国气象局的公开数据,用pandas库处理数据,用matplotlib库画柱状图,用scipy库算置信区间”,但它不会自己去爬数据、处理数据、画图!
这时候,你需要给AI助手装一个“实验员助手”——也就是Code Interpreter!你输入那句需求之后,Code Interpreter会让AI助手生成Python代码,然后把代码放到一个“带锁的独立实验室”——也就是安全沙箱里运行,最后把生成的柱状图和置信区间的结果返回给你!
是不是很神奇?接下来,我们就来认识一下这三个核心角色:“超级学霸”LLM、“实验员助手”Code Interpreter、“带锁的独立实验室”安全沙箱,还要搞清楚它们之间的关系!
核心概念解释(像给小学生讲故事一样)
核心概念一:大语言模型(LLM)——读了全世界所有书的“超级学霸”
想象一下,有一个小朋友,他从出生开始,每天24小时不睡觉,读了互联网上几乎所有的公开文本——比如课本、小说、报纸、杂志、博客、代码库、论文等等,一直读到10岁!这时候,这个小朋友就变成了一个“超级学霸”!
这个“超级学霸”有什么本领呢?
- 理解人话:你说什么他都能听懂——比如你说“帮我算数学题”“帮我写作文”“帮我写代码”“帮我翻译英文”。
- 说人话:他能说各种各样的人话——比如中文、英文、法文、德文、日文等等,还能说专业的话——比如程序员的话、医生的话、律师的话、科学家的话。
- 生成内容:他能根据你的输入生成各种各样的内容——比如数学题的答案、作文、代码、翻译、诗歌、故事、剧本等等。
但这个“超级学霸”也有一个致命的缺点:他只会“纸上谈兵”,不会“自己动手干活”!比如他能告诉你怎么做番茄炒蛋,但他不会自己去买菜、洗菜、切菜、炒菜;他能告诉你怎么画柱状图,但他不会自己去爬数据、处理数据、画图;他能告诉你怎么修电脑,但他不会自己去拆电脑、换零件!
核心概念二:面向LLM的代码解释器(Code Interpreter)——超级学霸旁边的“万能实验员助手”
为了让“超级学霸”LLM能“自己动手干活”,我们给他请了一个“万能实验员助手”——也就是Code Interpreter!
这个“万能实验员助手”有什么本领呢?
- 听学霸的话:LLM说“生成一段Python代码来画北京近10年降水量的柱状图”,助手就会让LLM生成代码;LLM说“修改一下代码,把柱状图的颜色改成蓝色”,助手就会让LLM修改代码。
- 检查代码的安全性和正确性:在运行代码之前,助手会先检查一下代码有没有问题——比如有没有恶意代码(比如窃取你的银行卡密码、删除你的文件)、有没有语法错误、有没有逻辑错误、有没有超过资源限制(比如内存、CPU、时间)。
- 运行代码:如果代码没问题,助手就会把代码放到一个“带锁的独立实验室”——也就是安全沙箱里运行。
- 收集运行结果:代码运行完之后,助手会收集所有的运行结果——比如数据、图表、错误信息、警告信息、打印信息。
- 把结果反馈给学霸:助手会把收集到的运行结果反馈给LLM,LLM再根据结果继续修改代码、解释结果给你听,或者完成其他任务。
核心概念三:面向代码执行的安全沙箱(Security Sandbox)——万能实验员助手的“带锁的独立实验室”
要是“万能实验员助手”随便在你的电脑上或者云平台的服务器上运行代码,那可就太危险了!比如LLM生成的代码可能是恶意代码——比如窃取你的银行卡密码、删除你的重要文件、安装病毒、攻击其他服务器!
为了防止这种情况发生,我们给“万能实验员助手”建了一个“带锁的独立实验室”——也就是安全沙箱!
这个“带锁的独立实验室”有什么特点呢?
- 完全隔离:实验室和外面的世界是完全隔离的——实验室里的实验员不能随便拿实验室外面的东西(比如你的银行卡密码、系统文件),也不能把实验室里的危险东西(比如病毒、恶意代码)带出去,更不能破坏实验室外面的东西(比如你的电脑、云平台的服务器)。
- 资源限制:实验室里的资源是有限的——比如只有1个CPU核心、1GB内存、1GB磁盘空间、10分钟的运行时间、1MB/s的网络带宽,实验员不能随便用更多的资源,防止实验室“爆炸”或者影响其他实验室。
- 权限限制:实验室里的实验员只有“做实验”的权限——比如只能读自己实验室里的文件、只能写自己实验室里的临时文件、只能调用一些“安全”的系统调用(比如计算数学题、画图、处理数据),不能调用“危险”的系统调用(比如删除文件、打开网络连接到陌生的服务器、读取系统密码文件)。
- 用完即毁:实验做完之后,实验室会被立即销毁——里面的所有东西(比如临时文件、生成的图表、运行的进程)都会被彻底删除,不会留下任何痕迹,防止恶意代码“潜伏”在实验室里。
核心概念之间的关系(用小学生能理解的比喻)
整体关系:孙悟空(LLM)、唐僧(用户)、猪八戒(Code Interpreter)、紧箍咒+五指山(安全沙箱)
我们可以把整体关系类比成《西游记》里的师徒四人(加上紧箍咒和五指山):
- 唐僧(用户):是整个团队的“领导者”,他有一个“目标”——比如“去西天取经”“算数学题”“画柱状图”,他会把这个“目标”告诉孙悟空。
- 孙悟空(LLM):是整个团队的“大脑”,他有“七十二变”的本领——比如能听懂人话、能说人话、能生成各种各样的内容,但他也有一个“缺点”——有时候会“调皮捣蛋”(比如生成恶意代码),这时候就需要紧箍咒和五指山来约束他。
- 猪八戒(Code Interpreter):是整个团队的“执行者”,他会听孙悟空的话——比如让孙悟空生成代码、修改代码,检查代码的安全性和正确性,把代码放到五指山里运行,收集运行结果,把结果反馈给孙悟空。
- 紧箍咒(代码生成验证):是约束孙悟空的“第一道防线”,它会在孙悟空“调皮捣蛋”之前(也就是生成恶意代码之后、运行代码之前),念紧箍咒——也就是检查代码有没有问题,如果有问题,就让孙悟空修改,直到没问题为止。
- 五指山(安全沙箱):是约束孙悟空的“第二道防线”,就算紧箍咒没起作用(也就是漏过了恶意代码),孙悟空也只能在五指山里“闹腾”——也就是只能在安全沙箱里运行恶意代码,不能跑到外面的世界去“搞破坏”,实验做完之后,五指山会被立即销毁,孙悟空也会被“放出来”(但已经没机会“搞破坏”了)。
概念一和概念二的关系:超级学霸(LLM)和万能实验员助手(Code Interpreter)——指挥者和执行者
我们可以把LLM和Code Interpreter的关系类比成“指挥者和执行者”的关系:
- 指挥者(LLM):负责“动脑子”——比如理解用户的需求、规划完成需求的步骤、生成完成步骤的代码、根据运行结果修改代码或者解释结果。
- 执行者(Code Interpreter):负责“动手干活”——比如听指挥者的话、检查代码的安全性和正确性、运行代码、收集运行结果、把结果反馈给指挥者。
指挥者和执行者是“互相依赖”的——没有指挥者,执行者不知道该做什么;没有执行者,指挥者只会“纸上谈兵”,不会“自己动手干活”。
概念二和概念三的关系:万能实验员助手(Code Interpreter)和带锁的独立实验室(安全沙箱)——使用者和保护者
我们可以把Code Interpreter和安全沙箱的关系类比成“使用者和保护者”的关系:
- 使用者(Code Interpreter):负责“使用”安全沙箱——比如把代码放到安全沙箱里、告诉安全沙箱需要多少资源、需要哪些权限。
- 保护者(安全沙箱):负责“保护”外面的世界和里面的实验——比如隔离实验室和外面的世界、限制实验室的资源、限制实验员的权限、用完即毁实验室。
使用者和保护者也是“互相依赖”的——没有保护者,使用者不敢随便运行代码;没有使用者,保护者就没有存在的意义。
概念一和概念三的关系:超级学霸(LLM)和带锁的独立实验室(安全沙箱)——被约束者和约束者
我们可以把LLM和安全沙箱的关系类比成“被约束者和约束者”的关系:
- 被约束者(LLM):有时候会“调皮捣蛋”——比如生成恶意代码,这时候就需要约束者来约束他。
- 约束者(安全沙箱):就算被约束者“调皮捣蛋”,也只能在约束者的“控制范围”内“闹腾”,不能跑到外面的世界去“搞破坏”。
核心概念原理和架构的文本示意图(专业定义)
现在,我们用专业的语言画一张核心概念原理和架构的文本示意图:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 用户(User) │
│ 输入:自然语言需求(Natural Language Query) │
│ 输出:自然语言解释(Natural Language Explanation)+ 执行结果(Execution Result)│
└────────────────────────┬────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 大语言模型(LLM) │
│ 核心模块: │
│ 1. 需求理解模块(Query Understanding):把自然语言需求翻译成LLM能理解的格式 │
│ 2. 任务规划模块(Task Planning):把需求分解成多个可执行的子任务 │
│ 3. 代码生成模块(Code Generation):根据子任务生成代码(比如Python代码) │
│ 4. 代码修正模块(Code Correction):根据运行结果修改代码 │
│ 5. 结果解释模块(Result Explanation):把执行结果翻译成自然语言解释 │
└────────────────────────┬────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 代码解释器(Code Interpreter) │
│ 核心模块: │
│ 1. 代码接收模块(Code Reception):接收LLM生成的代码 │
│ 2. 代码生成验证模块(Code Generation Validation): │
│ a. 语法检查(Syntax Check):检查代码有没有语法错误 │
│ b. 恶意代码检测(Malicious Code Detection):检查代码有没有恶意代码 │
│ c. 逻辑检查(Logic Check):检查代码有没有逻辑错误(可选) │
│ d. 资源预估(Resource Estimation):预估代码需要的资源(可选) │
│ 3. 沙箱配置模块(Sandbox Configuration):告诉安全沙箱需要多少资源、需要哪些权限│
│ 4. 代码提交模块(Code Submission):把代码提交到安全沙箱 │
│ 5. 结果收集模块(Result Collection):收集安全沙箱返回的执行结果 │
│ 6. 结果预处理模块(Result Preprocessing):预处理执行结果(比如过滤无关信息) │
└────────────────────────┬────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 安全沙箱(Security Sandbox) │
│ 核心隔离/限制机制: │
│ 1. 命名空间隔离(Namespace Isolation):隔离进程空间、文件系统、网络、用户等 │
│ 2. 控制组资源限制(cgroups Resource Limitation):限制CPU、内存、磁盘IO、网络带宽、运行时间等│
│ 3. 系统调用过滤(seccomp-bpf System Call Filtering):限制进程可以调用的系统调用│
│ 4. 文件系统权限限制(Filesystem Permission Limitation):限制进程可以读/写/执行的文件│
│ 5. 网络权限限制(Network Permission Limitation):限制进程可以访问的网络地址、端口等│
│ 6. 用完即毁(Ephemeral):实验做完之后立即销毁沙箱 │
└────────────────────────┬────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 执行环境(Execution Environment)—— 比如Python环境、Node.js环境等 │
│ 功能:运行代码 │
└────────────────────────┬────────────────────────────────────────────────────┘
│
▲
│ 执行结果(Execution Result)—— 比如数据、图表、错误信息、警告信息、打印信息
└────────────────────────┴────────────────────────────────────────────────────┘
Mermaid 流程图 (Mermaid 流程节点中不要有括号逗号等特殊字符)
现在,我们用Mermaid画一张核心概念协作的流程图:
核心算法原理 & 具体操作步骤
算法原理概述
在上一节的流程图中,我们可以看到LLM+Code Interpreter的协作链条中有两个核心算法:
- 代码生成验证算法:在Code Interpreter的代码生成验证模块中,用来检查LLM生成的代码有没有问题——比如语法错误、恶意代码、逻辑错误、资源预估(可选)。
- 结果反馈迭代算法:在整个协作链条中,用来根据执行结果不断修正代码,直到结果满足需求为止。
接下来,我们就用Python代码来详细阐述这两个核心算法的原理和具体操作步骤!
核心算法一:代码生成验证算法
问题背景
LLM生成的代码可能存在以下问题:
- 语法错误:比如少了一个冒号、少了一个括号、变量名拼写错误等等,这些错误会导致代码无法运行。
- 恶意代码:比如窃取用户的银行卡密码、删除用户的重要文件、安装病毒、攻击其他服务器等等,这些错误会导致严重的安全问题。
- 逻辑错误:比如代码的逻辑不对,导致运行结果错误——比如把10除以3算成了4,这些错误会导致结果不符合需求。
- 资源超限:比如代码需要的内存太大、CPU使用率太高、运行时间太长、磁盘IO太大等等,这些错误会导致系统资源耗尽,影响其他用户。
所以,我们需要一个代码生成验证算法,在运行代码之前,先检查一下代码有没有这些问题!
算法原理
代码生成验证算法是一个多阶段的验证算法,它会依次检查代码的语法错误、恶意代码、逻辑错误(可选)、资源预估(可选),只有所有阶段都通过了,才会允许代码运行!
算法的具体原理如下:
- 阶段一:语法检查:用目标语言的官方解释器或者第三方库来检查代码有没有语法错误——比如用Python的
ast模块(抽象语法树模块)来检查Python代码有没有语法错误。 - 阶段二:恶意代码检测:用静态分析(Static Analysis)或者动态分析(Dynamic Analysis,不过动态分析一般放在安全沙箱里做,因为动态分析需要运行代码)来检查代码有没有恶意代码——比如用Python的
bandit库(专门用来检测Python恶意代码的静态分析工具)来检查Python代码有没有恶意代码。 - 阶段三:逻辑检查(可选):用形式化验证(Formal Verification)或者测试用例生成(Test Case Generation)来检查代码有没有逻辑错误——比如用Python的
hypothesis库(专门用来生成测试用例的库)来生成测试用例,然后检查代码的运行结果是否符合预期。 - 阶段四:资源预估(可选):用静态分析或者机器学习(Machine Learning)来预估代码需要的资源——比如用Python的
pycparser库(专门用来解析C代码的库)或者ast模块来解析Python代码,然后预估代码需要的内存、CPU使用率、运行时间等。
具体操作步骤(用Python代码详细阐述)
现在,我们用Python代码来详细阐述代码生成验证算法的具体操作步骤!
我们会用到以下Python库:
ast:Python官方的抽象语法树模块,用来检查Python代码的语法错误。bandit:Python第三方的静态恶意代码检测库,用来检查Python代码的恶意代码。subprocess:Python官方的子进程模块,用来调用bandit命令行工具。typing:Python官方的类型提示模块,用来给代码添加类型提示,让代码更易读。
首先,我们需要安装bandit库:
pip install bandit
然后,我们来写代码生成验证算法的Python实现:
import ast
import subprocess
from typing import Tuple, Optional
class CodeGenerationValidator:
"""
代码生成验证类,用来检查LLM生成的Python代码有没有问题
"""
def __init__(self):
"""
初始化代码生成验证类
"""
pass
def validate_syntax(self, code: str) -> Tuple[bool, Optional[str]]:
"""
阶段一:语法检查
:param code: LLM生成的Python代码
:return: 一个元组,第一个元素是布尔值,表示语法检查是否通过;第二个元素是字符串,表示错误信息(如果语法检查失败的话)
"""
try:
# 用ast.parse()方法解析代码,如果代码有语法错误,会抛出SyntaxError异常
ast.parse(code)
# 如果没有抛出异常,说明语法检查通过
return True, None
except SyntaxError as e:
# 如果抛出SyntaxError异常,说明语法检查失败,返回错误信息
error_msg = f"语法错误:{e.msg},在第{e.lineno}行,第{e.col_offset}列"
return False, error_msg
def validate_malicious_code(self, code: str) -> Tuple[bool, Optional[str]]:
"""
阶段二:恶意代码检测
:param code: LLM生成的Python代码
:return: 一个元组,第一个元素是布尔值,表示恶意代码检测是否通过;第二个元素是字符串,表示错误信息(如果恶意代码检测失败的话)
"""
try:
# 把代码写入一个临时文件,因为bandit命令行工具需要读取文件
with open("temp_code.py", "w", encoding="utf-8") as f:
f.write(code)
# 调用bandit命令行工具来检测恶意代码
# bandit的参数说明:
# -r:递归检测(不过我们这里只有一个文件,所以不用)
# -f:输出格式(我们这里用json格式,方便解析)
# -o:输出文件(我们这里不用输出文件,直接输出到标准输出)
# -q:安静模式(只输出错误信息,不输出警告信息)
# temp_code.py:要检测的文件
result = subprocess.run(
["bandit", "-f", "json", "-q", "temp_code.py"],
capture_output=True,
text=True,
encoding="utf-8"
)
# 检查bandit的返回值,如果返回值是0,说明没有检测到恶意代码;如果返回值是1,说明检测到了恶意代码
if result.returncode == 0:
# 删除临时文件
subprocess.run(["rm", "temp_code.py"], capture_output=True)
# 恶意代码检测通过
return True, None
else:
# 删除临时文件
subprocess.run(["rm", "temp_code.py"], capture_output=True)
# 恶意代码检测失败,返回错误信息
error_msg = f"检测到恶意代码:{result.stdout}"
return False, error_msg
except Exception as e:
# 删除临时文件(如果存在的话)
try:
subprocess.run(["rm", "temp_code.py"], capture_output=True)
except:
pass
# 抛出异常
error_msg = f"恶意代码检测出错:{str(e)}"
return False, error_msg
def validate_all(self, code: str) -> Tuple[bool, Optional[str]]:
"""
多阶段验证:依次检查语法错误、恶意代码
:param code: LLM生成的Python代码
:return: 一个元组,第一个元素是布尔值,表示所有阶段的验证是否通过;第二个元素是字符串,表示错误信息(如果有阶段验证失败的话)
"""
# 阶段一:语法检查
syntax_valid, syntax_error_msg = self.validate_syntax(code)
if not syntax_valid:
return False, syntax_error_msg
# 阶段二:恶意代码检测
malicious_valid, malicious_error_msg = self.validate_malicious_code(code)
if not malicious_valid:
return False, malicious_error_msg
# 所有阶段的验证都通过
return True, None
# 测试代码生成验证算法
if __name__ == "__main__":
# 初始化代码生成验证类
validator = CodeGenerationValidator()
# 测试用例1:语法正确、没有恶意代码的Python代码
test_code_1 = """
import math
def calculate_chocolate(n: int, m: int) -> Tuple[int, int]:
each = n // m
left = n % m
return each, left
if __name__ == "__main__":
n = 1000
m = 37
each, left = calculate_chocolate(n, m)
print(f"每个小伙伴分{each}颗,剩下{left}颗")
"""
print("测试用例1:语法正确、没有恶意代码的Python代码")
valid, error_msg = validator.validate_all(test_code_1)
if valid:
print("验证通过!")
else:
print(f"验证失败:{error_msg}")
print()
# 测试用例2:语法错误的Python代码(少了一个冒号)
test_code_2 = """
import math
def calculate_chocolate(n: int, m: int) -> Tuple[int, int]
each = n // m
left = n % m
return each, left
if __name__ == "__main__":
n = 1000
m = 37
each, left = calculate_chocolate(n, m)
print(f"每个小伙伴分{each}颗,剩下{left}颗")
"""
print("测试用例2:语法错误的Python代码(少了一个冒号)")
valid, error_msg = validator.validate_all(test_code_2)
if valid:
print("验证通过!")
else:
print(f"验证失败:{error_msg}")
print()
# 测试用例3:有恶意代码的Python代码(尝试删除系统密码文件)
test_code_3 = """
import os
# 尝试删除Linux系统的密码文件
os.remove("/etc/passwd")
"""
print("测试用例3:有恶意代码的Python代码(尝试删除系统密码文件)")
valid, error_msg = validator.validate_all(test_code_3)
if valid:
print("验证通过!")
else:
print(f"验证失败:{error_msg}")
print()
代码解读与分析
我们来解读一下上面的代码:
- CodeGenerationValidator类:这是一个代码生成验证类,用来检查LLM生成的Python代码有没有问题。
- validate_syntax方法:这是阶段一的语法检查方法,它用Python官方的
ast.parse()方法解析代码,如果代码有语法错误,会抛出SyntaxError异常,我们捕获这个异常并返回错误信息;如果没有抛出异常,说明语法检查通过。 - validate_malicious_code方法:这是阶段二的恶意代码检测方法,它把代码写入一个临时文件,然后调用
bandit命令行工具来检测恶意代码,bandit会返回一个json格式的结果,如果返回值是0,说明没有检测到恶意代码;如果返回值是1,说明检测到了恶意代码,我们返回错误信息;最后,我们删除临时文件。 - validate_all方法:这是多阶段验证方法,它依次调用
validate_syntax方法和validate_malicious_code方法,只有所有阶段都通过了,才会返回True;否则,返回False和对应的错误信息。 - 测试代码:我们写了三个测试用例,分别测试语法正确、没有恶意代码的Python代码,语法错误的Python代码,有恶意代码的Python代码,我们运行这些测试用例,看看代码生成验证算法是否能正常工作。
核心算法二:结果反馈迭代算法
问题背景
LLM第一次生成的代码可能无法运行,或者运行结果不符合需求——比如语法错误、恶意代码、逻辑错误、资源超限等等。所以,我们需要一个结果反馈迭代算法,用来根据执行结果不断修正代码,直到结果满足需求为止!
算法原理
结果反馈迭代算法是一个迭代式的算法,它会不断重复以下步骤,直到结果满足需求或者达到最大迭代次数为止:
- 步骤一:生成代码:LLM根据用户的需求或者上一次的执行结果生成代码。
- 步骤二:验证代码:用代码生成验证算法验证代码有没有问题。
- 步骤三:运行代码:如果代码验证通过,把代码放到安全沙箱里运行。
- 步骤四:判断结果:LLM根据执行结果判断结果是否满足需求。
- 步骤五:结束或迭代:如果结果满足需求或者达到最大迭代次数,结束算法;否则,回到步骤一,LLM根据执行结果修正代码。
算法的具体原理可以用以下伪代码表示:
def result_feedback_iteration(
user_query: str,
llm: LLM,
code_validator: CodeGenerationValidator,
sandbox: SecuritySandbox,
max_iterations: int = 5
) -> Tuple[str, Any]:
"""
结果反馈迭代算法
:param user_query: 用户的自然语言需求
:param llm: 大语言模型对象
:param code_validator: 代码生成验证对象
:param sandbox: 安全沙箱对象
:param max_iterations: 最大迭代次数
:return: 一个元组,第一个元素是自然语言解释;第二个元素是执行结果
"""
# 初始化迭代次数
iteration = 0
# 初始化上一次的执行结果
last_execution_result = None
# 初始化上一次的错误信息
last_error_msg = None
while iteration < max_iterations:
# 迭代次数加1
iteration += 1
print(f"第{iteration}次迭代...")
# 步骤一:生成代码
code = llm.generate_code(user_query, last_execution_result, last_error_msg)
print(f"生成的代码:\n{code}")
# 步骤二:验证代码
valid, error_msg = code_validator.validate_all(code)
if not valid:
print(f"代码验证失败:{error_msg}")
last_error_msg = error_msg
last_execution_result = None
continue
# 步骤三:运行代码
print("代码验证通过,开始运行代码...")
execution_result, error_msg = sandbox.run_code(code)
if error_msg is not None:
print(f"代码运行失败:{error_msg}")
last_error_msg = error_msg
last_execution_result = None
continue
# 步骤四:判断结果
print(f"代码运行成功,执行结果:\n{execution_result}")
is_satisfied = llm.judge_result(user_query, execution_result)
if is_satisfied:
print("结果满足需求!")
# 步骤五:生成自然语言解释
explanation = llm.explain_result(user_query, execution_result)
return explanation, execution_result
else:
print("结果不满足需求,继续迭代...")
last_execution_result = execution_result
last_error_msg = None
# 达到最大迭代次数
print(f"达到最大迭代次数{max_iterations},无法满足需求!")
return "无法满足需求,请重新输入需求!", None
具体操作步骤(用Python代码详细阐述,模拟LLM和安全沙箱)
现在,我们用Python代码来详细阐述结果反馈迭代算法的具体操作步骤!
因为我们现在还没有实现安全沙箱和连接到真实的LLM(比如OpenAI的GPT-4、Anthropic的Claude 3 Opus、Ollama的Llama 3 8B),所以我们会模拟LLM和安全沙箱的功能!
我们会用到以下Python库:
- `typing
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)