还在自己开发代码执行沙箱吗?试试langchain 官方的这个沙箱吧
在大模型agent 开发过程中,经常会遇到需要代码执行的操作,以往我们会单独创建一个沙箱,对外暴露一个web 端口,接受用户的代码,将执行结果返回给调用端,这种方式是一种比较安全的方式,但是需要开发沙箱服务,且还要返回符合大模型规范的内容。
langchain 团队近期开源了一个沙箱服务,专门用于执行python 代码,且这个项目和langchain 生态相结合,可以很方便的开发出代码执行工具。
项目地址 https://github.com/langchain-ai/langchain-sandbox
让我们来看一下它的使用吧。
环境安装
lanchain-sandbox 是基于 Deno开发的,Deno 是一个开源的 JavaScript、TypeScript 和 WebAssembly 运行时,具有安全的默认设置和出色的开发者体验。它基于 V8、Rust 和 Tokio 构建。
安装 deno
好几种方式,参考官方文档 https://docs.deno.com/runtime/getting_started/installation/
这里我使用 npm 方式
安装 langchain-sandbox
| pip install langchain-sandbox
|
使用
下面由浅入深演示 langchain-sandbox 的使用
hello world
langchain_sandbox 主要提供了两个类
- PyodideSandbox 异步类
- SyncPyodideSandbox 同步类
以下主要以 PyodideSandbox 异步类为例,同步类和异步类方法一样。
| from langchain_sandbox import PyodideSandbox
import asyncio
sandbox = PyodideSandbox(
allow_net=True,
)
code = """\
print("hello world")
"""
if __name__ == "__main__":
result = asyncio.run(sandbox.execute(code))
print(result)
|
上面的代码演示了使用 PyodideSandbox 对象执行最简单的hello world 程序。
| sandbox = PyodideSandbox(
allow_net=True,
)
|
这里使用 allow_net 表示允许沙箱访问网络,当要执行的代码需要额外的第三方依赖时,允许其进行安装。
执行结果
| CodeExecutionResult(result=None, stdout='hello world', stderr=None, status='success', execution_time=6.9243810176849365, session_metadata={'created': '2025-06-01T16:07:05.517Z', 'lastModified': '2025-06-01T16:07:05.610Z', 'packages': []}, session_bytes=None)
|
python 中的print 打印的内容放到了 stdout 中,
执行一个函数
| from langchain_sandbox import PyodideSandbox
import asyncio
sandbox = PyodideSandbox(
allow_net=True,
)
code = """\
def hello():
print("hello world")
return True
hello()
"""
if __name__ == "__main__":
result = asyncio.run(sandbox.execute(code))
print(result)
|
这里的hello 函数使用 return 返回了 True
结果
| CodeExecutionResult(result=True, stdout='hello world', stderr=None, status='success', execution_time=6.3663108348846436, session_metadata={'created': '2025-06-01T16:04:49.652Z', 'lastModified': '2025-06-01T16:04:49.716Z', 'packages': []}, session_bytes=None)
|
这时 CodeExecutionResult 中的 result 接收到了函数return 的值。
安装第三方依赖
尝试安装一个第三方包 requests, 再使用这个包访问一个url
| from langchain_sandbox import PyodideSandbox
import asyncio
sandbox = PyodideSandbox(
allow_net=True,
)
code = """\
import requests
def test():
return requests.get("https://www.baidu.com").text
test()
"""
if __name__ == "__main__":
result = asyncio.run(sandbox.execute(code))
print(result)
|
结果
| CodeExecutionResult(result='<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type ...(省略了)', stdout=None, stderr=None, status='success', execution_time=9.710697889328003, session_metadata={'created': '2025-06-01T16:11:07.760Z', 'lastModified': '2025-06-01T16:11:11.483Z', 'packages': ['requests']}, session_bytes=None)
|
result 字符串太长了,上面省略了,上面的输出也在 packages 中展示了安装了 requests 库。
限制网络访问
有时为了安全,会限制可以访问的url
| sandbox = PyodideSandbox(
allow_net=["www.baidu.com"],
)
code = """\
import requests
def test():
return requests.get("https://www.taobao.com").text
test()
"""
|
上面限制了只能访问www.baidu.com, 所以当代码中有访问taobao的请求,则会被拒绝。如果 allow_net 设置为 False(默认就是 False), 则拒绝所有网络请求。
与langchain 生态结合
langchain-sandbox 主要也是配合langchain 生态中的代码执行功能的,在agent 智能体开发过程中,有大量的涉及到代码执行的功能。
| from langchain_sandbox import PyodideSandboxTool
import asyncio
tool = PyodideSandboxTool()
if __name__ == "__main__":
result = asyncio.run(tool.ainvoke("print('Hello, world!')"))
print(result)
|
上面打印输出为 Hello, world!
, 没有什么额外的信息,这样也方便后续的内容处理。
上面的代码都是我们手工写好的代码,下面这个例子创建了一个 react agent, 用户可以通过自然语言和大模型交互,大模型返回了需要执行的代码,然后在代码沙箱中执行:
| from langgraph.prebuilt import create_react_agent
from langchain_sandbox import PyodideSandboxTool
import asyncio
async def main():
tool = PyodideSandboxTool(
allow_net=True
)
agent = create_react_agent(
"openai:qwen-plus",
tools=[tool],
)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "what's 5 + 7?"}]},
)
print(result)
if __name__ == "__main__":
asyncio.run(main())
|
结果
| {'messages': [
HumanMessage(content="what's 5 + 7?", additional_kwargs={}, response_metadata={}, id='8de733fe-8e9f-4f5d-a137-7a7cab17acb8'),
AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_b395fc7701dd48c590f78e', 'function': {'arguments': '{"code":"print(5 + 7)"}', 'name': 'python_code_sandbox'}, 'type': 'function', 'index': 0}], 'refusal': None}, ...),
ToolMessage(content='12', name='python_code_sandbox', id='70ae26a8-1eb2-4a78-8379-dd29982e4fa3', tool_call_id='call_b395fc7701dd48c590f78e'),
AIMessage(content='The answer to 5 + 7 is 12.', ...})
|
对结果做了一点简化,第一次AIMessage 返回了要执行的python 代码 print(5 + 7)
,然后 ToolMessage 为PyodideSandboxTool 执行的结果 12 。
如何保障安全性?
执行代码是一个非常危险的操作,如果控制不好权限,可能会被执行了 rm -rf /
这样的代码就完蛋了,来看一下PyodideSandbox 是如何保障运行安全的代码的
| class BasePyodideSandbox:
def __init__(
self,
*,
stateful: bool = False,
allow_env: list[str] | bool = False,
allow_read: list[str] | bool = False,
allow_write: list[str] | bool = False,
allow_net: list[str] | bool = False,
allow_run: list[str] | bool = False,
allow_ffi: list[str] | bool = False,
node_modules_dir: str = "auto",
skip_deno_check: bool = False,
) -> None:
|
有5个参数用于控制代码的执行
- allow_env: 允许获取哪些环境变量,默认是不允许读取环境变量,这种是最安全的,也可以传入一个字符串列表如
["PATH", "PYTHONPATH"]
- allow_read: 控制可以读哪些文件有读取的权限,默认不能读取任何文件
- allow_write: 控制可以写哪些文件,默认不能写任何文件
- allow_net: 控制是否可以访问网络,默认不能访问任何网络
- allow_run: 控制可以运行哪些命令,如 git ,rm 等,默认也是不能执行任何命令
如果上面这5个参数都是默认的False, 那么是最安全的,基本上只能运行一些计算相关的代码了,不过对于一些大模型应用来讲,应该已经够用了。我们可以动态的配置这几个参数来管理代码的安全性。
总结
本文介绍了如何使用langchain 团队开发的 langchain-sandbox 来构建一个可以执行python 代码的沙箱,并且最后创建了一个相对复杂的react 智能体,让大模型来生成代码并执行。这个项目为 langchain 生态提供了一个强大的代码执行环境。