Suna开源框架分析

github开源地址



https://github.com/kortix-ai/suna#

安装前准备

所有的前置安装都需要使用brew安装

安装brew

Ubuntu安装brew-优快云博客

安装supabase

brew install supabase/tap/supabase

安装redis

sudo apt-get install lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install redis

Redis will start automatically, and it should restart at boot time. If Redis doesn't start across reboots, you may need to manually enable it:

sudo systemctl enable redis-server
sudo systemctl start redis-server

安装daytona

Daytona

  • Set /usr/bin/supervisord -n -c /etc/supervisor/conf.d/supervisord.conf as the Entrypoint

登录supabase(注意要先切换到backend目录下执行)

因为后面的命令都是在相对路径下执行supabase db push会默认调用相对路径下的supabase/migrations下的sql脚本;

命令1:supabase login
默认密码Test1234

获取project id

Supabase

命令2: supabase link  project_id

填写对应的supabse信息
在对应的supabse的工程页面获取对应的URL和ANON信息

API Settings | Supabase

命令3:supabase db push

正常的效果是这样的:可以看到识别到需要执行的sql语句

下面的提示是不正常的,sql没有识别到;

解决办法:重新切到backend目录下,执行命令1,2,3;

执行成功:

supabase官网server端能看到对应的表创建成功;(没有创建,默认是空的,会提示建表)

注意:小心漏配

补充勾选basejump:

注意,需要点击右下的save按钮才能生效;

填写redis配置信息

配置正确,后端服务启动成功的提示:

前端

前端编译报错(windows)

ubuntu下无报错;

启动前后端

根据启动的信息,访问对应url:

输入需要处理的事情,弹出需要注册:

注册成功:

但是邮箱需要验证后才能使用;

注意这里的邮箱, 在本地调试时,实际验证的URL是LOCALHOST的url地址,并不是类似那种需要发给google邮箱,需要国外邮箱认证的情况;

 正常执行的界面:

(本地启动时,在第一个对话框界面耗时会有点长)

然后跳转到下面的界面,开始运行:

执行完成:

总共花了27步,执行过程还不算完美;

点击生成md文件,生效的效果,整体体验还是很不错的:

还能支持下载和导出、并打印;

右边的界面,可以回看每个步骤的详细执行界面的结果;

遇到的问题

问题1(close):Failed to create sandbox: Organization is suspended: Depleted credits(规则限制:不超过10个沙箱)

重新创建组织解决,正常daytona是可以面试创建10个沙箱的;

 沙箱超限,删除掉不用的即可;

2025-04-28 06:05:35,185 - ERROR - [api.py:384] - Failed to get/create sandbox for project 6abdcfc0-6db9-46e8-ac9c-e9fb73d006c9: Failed to create sandbox: Workspace quota exceeded. Maximum allowed: 10
INFO:     10.239.20.117:58485 - "POST /api/thread/ae279368-c379-49c9-be7a-f37af12a4038/agent/start HTTP/1.1" 500 Internal Server Error

问题2(close):模型 api-key非法

模型信息设置是在agent\api.py文件中:

还是一样的报错提示;

模型名称是从前端从传入:

前端代码修改模型的调用:

映射到后台的模型是下面的配置文件:

llm.py:关键的大模型调用函数make_llm_api_call;

调用大模型前的参数组装:

实际调用的是agent

修改agent的默认模型:gtp-4o,根据已有的模型选择;

基于openai封装的claude接口:

增加api_base和api_key的参数传递,确保增加的配置信息生效:

在utils/config.py中增加 自定义的 anthropic地址;

ANTHROPIC_API_BASE、ANTHROPIC_API_KEY(这个在.env中也有配置,但代码调用逻辑每处调用的来源好像不一样,先手动修改确保正确)

问题3(close):删除会话功能不生效(新版本已修复)

问题4(close):任务不往下执行(模型配置正确后解决)

LLM API请求报错:

ANTHROPIC_API_BASE不配置v1时,只配置前端的IP和端口时,会报错:

services2.llm.LLMRetryError: Failed to make API call after 1 attempts. Last error: litellm.APIConnectionError: AnthropicException - b'{\n  "error": {\n    "type": "forbidden",\n    "message": "Request not allowed"\n  }\n}'
2025-05-04 02:08:34,804 - ERROR - Error in run_thread: Failed to make API call after 1 attempts. Last error: litellm.APIConnectionError: AnthropicException - b'{\n  "error": {\n    "type": "forbidden",\n    "message": "Request not allowed"\n  }\n}'
Traceback (most recent call last):

以下是前后端各个配置模型的地方:

先增加报错的日志打印,看下入参:

根据入参分析:

使用的是原生调用anthropic的接口的方式,但是传入的api_key是openai封装的sk开头的;

以为是openai开头的问题,改成使用anthropic/claude-3-7-sonnet-latest 还是同样的报错:

下一步,通过源码确定调用模型和api_key的位置,目前初步看,模型是通过前端传入,与上面的model_name中的配置没有关系;(至少在当前这一步的报错还没有关系)

首先api_key的获取是在后端;

config.py默认会加载.env中配置的信息;

下一步确认读取api_key的逻辑顺序:

问题5:业务执行的死循环(模型配置正确后解决)

改成指定vpn代理的地址转发到原生的claude调用后,出现业务执行的死循环:

业务执行的死循环:

所以,之前跑通的是基于下面的配置跑通的;

下一步,还是回到解决claude的业务执行死循环的问题:

1、重新启动一个会话,也是会执行到上面的业务死循环,排除直接在旧会话中导致的问题;

2、前端改成gpt-4o后,并重启服务后,也是死循环;

解决办法:

关闭浏览器;重启前端服务后,从最开始界面进入,问题解决;

初步怀疑,是有缓存导致的问题;

回看能完整跑通时的配置:

config.py:

这里必须填写v1

但是注意:

anthropic的url地址,不加v1的,端口号3000后面不带v1;

还是会进入死循环:

一轮日志:

2025-05-04 09:13:02,236 - INFO - Starting thread execution for thread 3f063111-3be2-4551-8801-5da8f3d0ab51
2025-05-04 09:13:02,963 - INFO - Thread 3f063111-3be2-4551-8801-5da8f3d0ab51 token count: 242440/120000 (202.0%)
2025-05-04 09:13:02,964 - INFO - Automatic summarization disabled. Skipping token count check and summarization.
2025-05-04 09:13:05,412 - INFO - Streaming Config: XML=True, Native=False, Execute on stream=True, Strategy=parallel
2025-05-04 09:13:05,673 - INFO - Successfully added message to thread 3f063111-3be2-4551-8801-5da8f3d0ab51
2025-05-04 09:13:05,939 - INFO - Successfully added message to thread 3f063111-3be2-4551-8801-5da8f3d0ab51
2025-05-04 09:13:06,208 - INFO - Successfully added message to thread 3f063111-3be2-4551-8801-5da8f3d0ab51
2025-05-04 09:13:06,518 - INFO - Successfully added message to thread 3f063111-3be2-4551-8801-5da8f3d0ab51
2025-05-04 09:13:06,520 - INFO - Running in local development mode - billing checks are disabled

async def run_thread

Starting thread execution for thread

async def _run_once 打印下面两行日志:

2025-05-04 09:13:02,963 - INFO - Thread 3f063111-3be2-4551-8801-5da8f3d0ab51 token count: 242440/120000 (202.0%)
2025-05-04 09:13:02,964 - INFO - Automatic summarization disabled. Skipping token count check and summarization.

async def process_streaming_response 调1次

打印:Streaming Config:

async def add_message  会调4次

async def check_billing_status 打印:最后一行billing checks

从上面的分析看,从async def run_thread开始分析:

被run.py调用

run_agent,注意:这里也有一个写死的默认model_name

async def run_agent_background的内部方法:async def check_for_stop_signal()调用了run_agent

有两个地方会触发线程的启动:

@router.post("/thread/{thread_id}/agent/start")

@router.post("/agent/initiate"

重新观察前后端请求:

对应前端的两处请求发起点

被调用的地方:(待进一步细查)

被调用的地方:(待进一步细查)

差别是在agent的界面发起的命令:前台一样会触发向后端传递模型参数的接口调用;

关键修正点:模型名称填写正确;

重试5次后,每次都正常,未发现业务死循环;(每次都是重新打开浏览器,从下面的界面启动)

问题6(close):模型接口配置问题

2025-05-04 08:53:57,356 - ERROR - Error calculating final cost for stream: This model isn't mapped yet. model=anthropic.claude-3-7-sonnet-20250219-v1:0, custom_llm_provider=openai. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json.

使用了openai标准格式封装的claude接口,不兼容;

(最新版)解决办法:

直接使用claude原生的api_base,可以是公司内网的代理地址;

基于20250505更新的版本,前端代码不需要改动,后端代码改动:

1、llm.py中增加对api_base和api_key的传值;默认在llm的接口调用时,都没有传递这两个值,这两值是通过环境变量或者配置文件获取的;

2、修改config.py,制定模型名称和api_base(这个可以公司内网的代理地址)

3、backend\api.py中增加允许前端请求的url地址,保险起见本地调试时可以设置为*,生产发布时去掉;

suna的前端关键界面代码分析

右边的沙箱界面

suna工具调用可视化界面实现原理分析-优快云博客

supabase使用源码工程默认的调试方案:

npm install supabase

注意不要使用:npm install -g supabase,会报错,默认不允许进行全局安装;

切换到backend目录下,执行:node_modules/supabase/bin/supabase start

启动成功:

生产部署时,屏蔽标准模式的付费跳转问题;

正式正产部署后,会默认跳转到下面的付费页面;

找到下面的代码,并注释掉本地模式的判断,默认都返回true即可;

### SUNA 部署指南及问题解决方案 #### 1. SUNA 的部署步骤 在 VPS 上部署 SUNA AI 可以通过 Docker 和 Docker Compose 来实现。以下是具体的部署方法和注意事项[^1]: - 确保 VPS 已安装 Docker 和 Docker Compose。 - 克隆 SUNA 的官方仓库或下载对应的配置文件。 - 修改 `docker-compose.yml` 文件中的环境变量,例如端口、存储路径等。 - 使用以下命令启动服务: ```bash docker-compose up -d ``` - 检查容器是否正常运行: ```bash docker ps ``` 如果容器未能正常启动,可以通过查看日志来排查问题: ```bash docker-compose logs ``` #### 2. 常见问题及解决方案 ##### 问题 1: 容器无法启动 原因可能是镜像拉取失败或资源配置不足。解决方法包括: - 确认 Docker 镜像已成功拉取。 - 检查 VPS 的内存和 CPU 是否满足 SUNA 的最低要求[^1]。 ##### 问题 2: 沙盒访问问题 如果在本地化部署过程中遇到沙盒无法访问的问题,可以参考 Dayton 的解决方案[^2]: - 确认 Docker 环境:确保 SUNA 已正确部署在 Docker 中。 - 编写转发服务:开发一个简单的服务(如使用 Nginx 或 Python Flask)将请求转发至正确的容器接口。 - 修改沙盒的 domain:在数据库中找到相关表(如 `node` 表),将 domain 修改为转发服务的地址。 ##### 问题 3: 日志输出异常 当 SUNA 的日志显示错误时,可以通过以下方式定位问题: - 查看完整的日志输出: ```bash docker-compose logs suna_service_name ``` - 根据错误提示检查配置文件或网络连接。 #### 3. 性能优化建议 为了提高 SUNA 在 VPS 上的性能,可以采取以下措施: - 调整 Docker 的资源限制,分配更多内存或 CPU 给容器。 - 使用高性能的存储卷(如 SSD)来提升数据读写速度。 - 如果需要处理大量请求,可以考虑水平扩展 SUNA 的服务实例[^1]。 ### 示例代码:编写简单的转发服务 以下是一个基于 Python Flask 的简单转发服务示例,用于解决沙盒访问问题: ```python from flask import Flask, request, jsonify import requests app = Flask(__name__) @app.route('/forward', methods=['POST']) def forward_request(): data = request.json response = requests.post('http://suna_container_interface/endpoint', json=data) return jsonify(response.json()), response.status_code if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值