news 2026/5/28 11:10:01

从托管平台到自建VPS:AI技能迁移实战与成本优化指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从托管平台到自建VPS:AI技能迁移实战与成本优化指南

1. 项目概述:从Manus AI到OpenClaw VPS的技能迁移实战

最近在折腾一个挺有意思的事儿:把我之前在Manus AI平台上训练和部署的6个核心技能,完整地迁移到了自己搭建的OpenClaw VPS上。这事儿听起来可能有点技术宅,但背后的动机其实很实际——成本、控制权和数据隐私。Manus AI作为一个托管平台,上手快,初期部署确实方便,但随着技能使用频率增加,按调用次数计费的模式开始让我感到肉疼。更重要的是,一些涉及特定业务逻辑和数据处理流程的技能,我希望能把代码和数据都攥在自己手里,方便后续深度定制和集成。OpenClaw VPS提供了一个干净、可控的Linux环境,正好能满足这个需求。这次迁移涉及到的6个技能,功能各异,有处理文档的,有调用外部API的,也有基于规则进行内容生成的,算是一次对AI技能全生命周期管理(从开发、测试到生产部署)的完整实践。如果你也在用类似的AI技能平台,并且开始考虑自建环境来获得更大的灵活性和更低的长期成本,那么我踩过的这些坑和总结出来的这套流程,或许能给你省下不少时间。

2. 迁移前的整体规划与环境准备

2.1 技能清单分析与依赖梳理

动手之前,第一件事不是急着敲命令,而是坐下来好好盘点。我把Manus AI控制台里这6个技能全部拉出来,列了一个详细的清单表格。这个表格不仅仅是记录名字,更重要的是分析每个技能的“技术成分”。

技能名称核心功能描述主要依赖库/框架外部API依赖配置文件/密钥数据存储方式
技能A: 文档摘要器接收长文本,输出关键点摘要openai,langchain,python-docxOpenAI APIopenai.api_key临时文件处理,无持久化
技能B: 天气查询助手根据城市名返回天气信息requests,json某第三方天气APIweather_api_key,city_mapping.json
技能C: 数据格式转换器将CSV转换为特定JSON格式pandas,numpy转换规则rules.yaml读取用户上传的CSV文件
技能D: 内容合规检查检查文本是否包含特定关键词re(正则表达式)关键词列表blocked_words.txt
技能E: 图像描述生成分析图片URL,生成文字描述openai,PIL,requestsOpenAI API (GPT-4V)openai.api_key临时下载图片
技能F: 定时报告生成器按模板生成日报/周报jinja2,datetime,openpyxl报告模板template.html, 数据源data.xlsx读取本地数据文件

通过这个表格,迁移的复杂性一目了然。技能A和E依赖OpenAI API,这意味着迁移后需要妥善管理API密钥。技能C和F依赖本地数据文件和模板,这些静态资源需要一并打包。技能B虽然有外部API,但逻辑简单。技能D则是纯本地逻辑。梳理清楚后,我决定采用“分步迁移、统一封装”的策略:先迁移最简单的、无外部依赖的技能(如D),验证基础环境;再处理有数据文件的(C、F);最后攻克有外部API调用和复杂依赖的(A、B、E)。

2.2 OpenClaw VPS环境初始化

我选择的OpenClaw VPS是最基础的Ubuntu 22.04 LTS版本。系统初始化是稳定性的基石,我做了以下几件事:

  1. 系统更新与基础工具安装:第一件事永远是sudo apt update && sudo apt upgrade -y。然后安装后续开发必备的工具包:sudo apt install -y python3-pip python3-venv git curl wget vim。这里特别注意,Manus AI的运行环境可能是特定的Python版本,为了最大限度兼容,我选择使用venv为每个技能或技能组创建独立的虚拟环境,避免依赖冲突。

  2. 安全加固与防火墙设置:既然是自建服务,安全不能马虎。我配置了UFW防火墙,默认拒绝所有入站,只开放SSH(22端口)和后续技能服务需要用的端口(例如HTTP服务的80/443)。sudo ufw allow 22/tcpsudo ufw enable。同时,禁用root的SSH密码登录,改用密钥认证,这是基本操作。

  3. 项目目录结构规划:在用户目录下,我建立了清晰的项目结构,这为后续管理和维护提供了便利。

    ~/ai_skills/ ├── skills/ # 存放所有技能代码 │ ├── skill_a_summarizer/ │ ├── skill_b_weather/ │ └── ... ├── environments/ # 存放各技能的虚拟环境(可按需创建) ├── data/ # 公共数据目录(如需要共享的数据文件) ├── logs/ # 统一日志目录 └── scripts/ # 部署、启动、监控脚本

    这个结构将代码、环境、数据、日志分离,符合应用部署的最佳实践。

注意:在VPS上,务必第一时间修改默认SSH端口并设置强密码或密钥,并考虑安装fail2ban这类工具来防止暴力破解。安全是自建服务的第一道门槛,马虎不得。

3. 技能代码与依赖的迁移实操

3.1 从Manus AI导出技能代码

Manus AI平台通常提供代码导出功能,但导出的内容完整度因平台而异。我的做法是“双保险”:

  • 官方导出:在Manus AI的技能编辑界面,找到“导出”或“下载代码”功能。这通常会得到一个ZIP包,里面包含了技能的主逻辑文件(如main.py,skill.py)、requirements.txt依赖列表,有时还包括平台特定的配置文件(如manifest.yaml)。
  • 手动备份:对于关键技能,我还会直接在平台的在线编辑器中,将核心代码文件完整地复制粘贴到本地。特别是那些包含了重要业务逻辑和自定义函数的文件,确保万无一失。

导出的代码通常不能直接运行,因为它包含了大量Manus AI平台的运行时封装和触发器定义(比如@app.on_event等)。我们的核心任务就是剥离这些平台特定的部分,提取出纯净的业务逻辑函数。

3.2 依赖管理与虚拟环境配置

requirements.txt是迁移的生命线。但直接从Manus AI导出的依赖列表可能包含平台自身的SDK(如manus-ai-sdk),这些在自建环境里是不需要的,需要剔除。

以技能A(文档摘要器)为例,其原始的requirements.txt可能长这样:

manus-ai-sdk==1.2.3 openai==1.3.0 langchain==0.0.340 python-docx==0.8.11 tiktoken

我们需要将其精简为只包含第三方库的版本:

openai==1.3.0 langchain==0.0.340 python-docx==0.8.11 tiktoken

然后,在VPS上为这个技能创建独立的虚拟环境并安装依赖:

cd ~/ai_skills/skills/skill_a_summarizer python3 -m venv venv source venv/bin/activate pip install --upgrade pip pip install -r requirements.txt

实操心得:不同技能对库的版本可能有细微要求。比如技能C用的pandas是1.5.3,而技能F可能兼容2.0以上。为每个技能创建独立虚拟环境(venv)是避免“依赖地狱”最有效的方法。虽然会占用一些磁盘空间,但保证了绝对的隔离性。对于依赖类似的技能(如A和E都用了openai),可以考虑共享一个环境,但前提是经过充分测试。

3.3 业务逻辑的剥离与重构

这是迁移中最核心、最需要耐心的一步。Manus AI上的技能通常是一个完整的、响应平台事件的函数。我们需要把它改造成一个可以独立运行或通过标准接口(如HTTP API)调用的模块。

原始代码片段(Manus AI风格)示例:

from manus_ai import Skill, Event app = Skill() @app.on_event("skill.invoke") async def handle_summarize(event: Event): # 从event中获取用户输入 text = event.data.get("text") # 调用OpenAI API进行摘要 summary = await call_openai_summarize(text) # 按照平台格式返回 return {"result": summary}

重构后的独立模块(summarizer.py):

import openai import os class DocumentSummarizer: def __init__(self, api_key=None): self.client = openai.OpenAI(api_key=api_key or os.getenv("OPENAI_API_KEY")) # 可以在这里初始化其他组件,如LangChain的链 def summarize(self, text, model="gpt-3.5-turbo", max_tokens=150): """核心摘要函数""" try: response = self.client.chat.completions.create( model=model, messages=[{"role": "user", "content": f"请总结以下文本:\n{text}"}], max_tokens=max_tokens ) return response.choices[0].message.content.strip() except Exception as e: return f"摘要生成失败:{str(e)}" # 提供简单的命令行测试接口 if __name__ == "__main__": import sys if len(sys.argv) > 1: summarizer = DocumentSummarizer() result = summarizer.summarize(sys.argv[1]) print(result) else: print("请提供要摘要的文本作为参数。")

重构的关键在于:

  1. 移除平台依赖:去掉所有manus_aiEvent等导入和装饰器。
  2. 明确输入输出:将业务逻辑封装成标准的类或函数,输入参数(如text)和返回值(如摘要字符串)清晰明确。
  3. 外部化配置:API密钥等敏感信息不再硬编码,而是通过环境变量(os.getenv)或配置文件读取。
  4. 增加可测试性:添加if __name__ == "__main__":块,方便直接运行脚本进行功能测试。

对于技能B(天气查询),需要将城市映射文件city_mapping.json和API密钥一起迁移。对于技能C和F,需要将数据文件(rules.yaml,template.html,data.xlsx)放置在代码目录中合适的位置,并修改代码中的文件路径为相对路径。

4. 服务化封装与API暴露

4.1 选择轻量级Web框架:FastAPI

代码能在命令行跑通只是第一步,要让这些技能能被远程调用,就需要将它们封装成服务。我选择了FastAPI,原因如下:

  • 异步支持好:我的部分技能(如调用OpenAI API)涉及网络I/O,异步能提升并发性能。
  • 开发速度快:自动生成交互式API文档(Swagger UI),调试方便。
  • 性能优异:基于Starlette和Pydantic,速度很快。
  • 类型提示:利用Python类型提示,代码更健壮,编辑器支持好。

为每个技能单独创建一个FastAPI应用可能有点重,我采用了“单应用多路由”的模式,将所有技能集成在一个服务里,便于统一管理。

4.2 构建统一的技能网关服务

我在~/ai_skills/目录下创建了一个主应用文件skill_gateway.py

from fastapi import FastAPI, HTTPException from pydantic import BaseModel import sys import os # 将技能目录加入Python路径 sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'skills')) # 导入重构后的技能类 from skill_a_summarizer.summarizer import DocumentSummarizer from skill_b_weather.weather import WeatherFetcher # ... 导入其他技能 app = FastAPI(title="AI Skills Gateway", description="迁移自Manus AI的技能集合") # 定义统一的请求/响应模型 class SkillRequest(BaseModel): skill_name: str input_data: dict # 灵活的参数容器 class SkillResponse(BaseModel): success: bool result: any error: str = None # 技能路由注册 @app.post("/invoke", response_model=SkillResponse) async def invoke_skill(request: SkillRequest): skill_handlers = { "document_summarizer": lambda data: DocumentSummarizer().summarize(data.get("text", "")), "weather_query": lambda data: WeatherFetcher().get_weather(data.get("city", "")), # ... 注册其他技能 } handler = skill_handlers.get(request.skill_name) if not handler: raise HTTPException(status_code=404, detail=f"Skill '{request.skill_name}' not found.") try: result = handler(request.input_data) return SkillResponse(success=True, result=result) except Exception as e: return SkillResponse(success=False, result=None, error=str(e)) @app.get("/skills") async def list_skills(): """列出所有可用的技能""" return {"skills": ["document_summarizer", "weather_query", "data_converter", "content_filter", "image_describer", "report_generator"]} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

这个网关的设计思路是提供一个统一的/invoke接口,通过skill_name参数来分发请求到具体的技能处理函数。输入参数通过input_data这个字典传递,保持了灵活性。

4.3 使用Gunicorn与Nginx进行生产部署

直接用python skill_gateway.py运行开发服务器不适合生产环境。我们需要一个更稳定、高性能的WSGI/ASGI服务器。

  1. 安装Gunicorn(配合Uvicorn Worker处理异步):在项目虚拟环境里安装:pip install gunicorn uvicorn[standard]

  2. 创建Gunicorn配置文件(gunicorn_conf.py):

    bind = "127.0.0.1:8000" # 本地监听,由Nginx反向代理 workers = 2 # 根据VPS的CPU核心数调整,通常为 (2 * CPU核心数) + 1 worker_class = "uvicorn.workers.UvicornWorker" # 使用Uvicorn worker处理ASGI应用 timeout = 120 # 对于处理长文本或复杂任务的技能,需要延长超时时间 accesslog = "/home/ubuntu/ai_skills/logs/gunicorn_access.log" errorlog = "/home/ubuntu/ai_skills/logs/gunicorn_error.log"
  3. 使用Systemd管理服务:创建系统服务文件/etc/systemd/system/ai-skills.service,实现开机自启和便捷管理。

    [Unit] Description=AI Skills Gateway Service After=network.target [Service] User=ubuntu Group=ubuntu WorkingDirectory=/home/ubuntu/ai_skills Environment="PATH=/home/ubuntu/ai_skills/venv/bin" Environment="OPENAI_API_KEY=your_key_here" # 在此处或通过EnvironmentFile设置环境变量 ExecStart=/home/ubuntu/ai_skills/venv/bin/gunicorn -c gunicorn_conf.py skill_gateway:app Restart=always RestartSec=3 [Install] WantedBy=multi-user.target

    然后启用服务:sudo systemctl daemon-reload,sudo systemctl enable ai-skills,sudo systemctl start ai-skills

  4. 配置Nginx反向代理:让服务可以通过域名和HTTPS访问,并处理静态文件、负载均衡等。

    server { listen 80; server_name your-domain.com; # 替换为你的域名 location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 可以添加静态文件服务、限流等配置 }

    配置好后,sudo nginx -t测试配置,sudo systemctl reload nginx重载。

重要提示:务必在Systemd服务文件或通过.env文件管理OPENAI_API_KEY等敏感信息,绝对不要硬编码在代码中或提交到版本控制系统。可以使用python-dotenv库来方便地加载环境变量。

5. 配置管理、监控与日志

5.1 集中化的配置管理

迁移后,配置散落在代码、环境变量、系统服务文件中,难以维护。我引入了.env文件和环境变量管理。

  1. 在项目根目录创建.env文件(并加入.gitignore):
    OPENAI_API_KEY=sk-你的真实key WEATHER_API_KEY=你的天气api key SKILL_GATEWAY_HOST=0.0.0.0 SKILL_GATEWAY_PORT=8000 LOG_LEVEL=INFO
  2. 修改skill_gateway.py,使用python-dotenv加载配置:
    from dotenv import load_dotenv load_dotenv() # 加载 .env 文件中的环境变量 openai_api_key = os.getenv("OPENAI_API_KEY")
  3. 修改Systemd服务文件,通过EnvironmentFile指令加载.env文件(注意权限安全,确保.env文件仅对服务用户可读)。

5.2 完善的日志记录

日志是排查问题的眼睛。我为服务配置了结构化日志。

  1. 在技能代码中使用Python标准库logging
    import logging logger = logging.getLogger(__name__) def summarize(self, text): logger.info(f"开始处理摘要请求,文本长度:{len(text)}") try: # ... 业务逻辑 logger.info("摘要生成成功") return result except openai.RateLimitError: logger.error("OpenAI API速率限制触发") raise except Exception as e: logger.exception(f"摘要处理过程中发生未预期错误:{e}") raise
  2. 在Gunicorn配置中指定了访问日志和错误日志路径。同时,可以配置日志轮转(logrotate),防止日志文件无限增大。

5.3 基础监控与健康检查

虽然VPS资源监控可以依赖云平台的控制台,但应用层面的健康检查必不可少。

  1. 在FastAPI中添加健康检查端点
    @app.get("/health") async def health_check(): """健康检查端点,可用于负载均衡器或监控系统""" # 这里可以添加更复杂的健康检查逻辑,如数据库连接、外部API连通性测试 return {"status": "healthy", "timestamp": datetime.datetime.utcnow().isoformat()}
  2. 使用简单的Cronjob进行心跳监控:可以写一个脚本,定期调用/health端点,如果失败则发送告警(如通过邮件、Telegram Bot等)。
  3. 监控关键指标:对于有外部API调用的技能(如A、B、E),需要关注API调用失败率、响应时间。可以在代码中记录这些指标,并输出到日志或推送到简单的监控面板(如用Grafana+Prometheus,但初期用日志分析也够用)。

6. 迁移后的验证、测试与优化

6.1 功能回归测试

迁移完成不是终点,确保所有技能行为与在Manus AI上一致才是关键。我设计了一个简单的测试套件。

  1. 单元测试:为每个技能的核心函数编写单元测试。例如,对于摘要器,测试空文本、超长文本、特殊字符文本的处理。
    # test_summarizer.py def test_summarizer_empty_text(): summarizer = DocumentSummarizer() result = summarizer.summarize("") assert "失败" in result or result == "" # 根据你的错误处理逻辑断言 def test_summarizer_normal_text(): summarizer = DocumentSummarizer() test_text = "这是一段用于测试的文本。" # 这里可以mock OpenAI API的返回,避免真实调用和计费 # 假设mock返回固定的摘要 result = summarizer.summarize(test_text) assert isinstance(result, str) and len(result) > 0
  2. 集成测试:通过HTTP客户端(如requests库)直接测试部署好的API网关。模拟真实的调用请求,验证整个链路(网络->网关->技能->响应)是否通畅。
    import requests resp = requests.post("http://localhost:8000/invoke", json={"skill_name": "document_summarizer", "input_data": {"text": "长文本内容..."}}) print(resp.status_code, resp.json())
  3. 对比测试:将同样的输入,分别发送给Manus AI上的原技能和自建VPS上的新服务,对比输出结果是否在可接受的误差范围内(对于AI生成类技能,结果不可能完全一致,但语义应相近)。

6.2 性能与压力测试

自建服务的性能表现如何?我用locust做了一个简单的压力测试。

  1. 安装Locustpip install locust
  2. 编写Locust测试脚本(locustfile.py):
    from locust import HttpUser, task, between class SkillUser(HttpUser): wait_time = between(1, 3) # 模拟用户思考时间 @task def invoke_summarizer(self): self.client.post("/invoke", json={ "skill_name": "document_summarizer", "input_data": {"text": "这是一段测试文本。" * 50} # 生成一段长文本 })
  3. 运行测试locust -f locustfile.py --host=http://localhost:8000,然后通过Web界面(默认http://localhost:8089)设置并发用户数,观察响应时间、失败率等指标。

通过测试,我发现当并发请求数较高时,直接调用OpenAI API的技能(A、E)响应时间会显著增加,并且容易触发OpenAI的速率限制。这引出了下一个优化点。

6.3 成本与性能优化策略

迁移到VPS后,成本从Manus AI的按调用付费,转变为VPS的固定月租+OpenAI API的实际使用费。优化方向很明确:在保证体验的前提下,减少不必要的API调用,提升响应速度。

  1. 缓存策略:对于技能B(天气查询),天气数据变化不频繁,可以引入缓存。使用redis或简单的内存缓存(如cachetools库),将城市-天气结果缓存10-30分钟,能极大减少对第三方API的调用。
    from cachetools import TTLCache weather_cache = TTLCache(maxsize=100, ttl=1800) # 缓存100个城市,30分钟过期 def get_weather(city): if city in weather_cache: return weather_cache[city] # ... 调用真实API weather_cache[city] = result return result
  2. 请求合并与批处理:对于技能C(数据转换),如果预期会有大量小文件转换请求,可以考虑设计一个支持批量处理的接口,减少频繁的进程启动和上下文切换开销。
  3. 异步处理与队列:对于技能F(报告生成),如果生成报告耗时较长(超过HTTP请求的合理等待时间),可以考虑引入任务队列(如Celery+Redis)。API接口只负责接收请求并提交任务到队列,立即返回一个任务ID。客户端随后通过另一个端点轮询任务结果。这提升了接口的响应速度,避免了HTTP超时。
  4. 监控API用量:密切关注OpenAI API的使用情况,设置用量告警。可以考虑使用更便宜的模型(如gpt-3.5-turbo替代gpt-4)或调整请求参数(如减少max_tokens)来降低成本。

7. 常见问题与故障排查实录

迁移和运维过程中,我遇到了不少问题,这里记录下最典型的几个及其解决方法。

7.1 依赖安装失败或版本冲突

问题:在VPS上pip install -r requirements.txt时,某个包(比如langchain的某个特定版本)安装失败,提示找不到合适的分发版本或与现有包冲突。排查

  1. 首先检查Python版本是否匹配。Manus AI可能用了Python 3.9,而你的VPS是3.10或3.11。有些包对Python版本有要求。
  2. 使用pip list查看当前环境中已安装的包及其版本。
  3. 尝试单独安装失败的包,并查看详细的错误信息:pip install package_name==x.x.x -v解决
  • 指定版本范围:在requirements.txt中,将严格的==改为兼容的>=,并指定一个上限,如langchain>=0.0.340,<0.1.0。但需注意,这可能导致行为不一致。
  • 使用替代包或升级:有时需要升级或降级其他相关依赖。可以尝试先安装基础依赖,再安装有冲突的包。
  • 终极方案:如果依赖环境极其复杂,可以考虑使用Docker容器来封装整个技能及其运行环境,实现绝对的隔离。这是我为技能A和E最终采用的方案,虽然增加了复杂性,但部署一致性极佳。

7.2 服务启动后无法访问或超时

问题systemctl start ai-skills显示成功,但访问http://<vps-ip>:8000/health端点时连接超时或拒绝连接。排查

  1. 检查服务状态sudo systemctl status ai-skills,查看是否是active (running)状态。如果失败,查看journalctl -u ai-skills -f或我们配置的errorlog获取具体错误信息。
  2. 检查端口监听sudo netstat -tlnp | grep :8000,看是否有进程在监听8000端口。如果Gunicorn绑定的是127.0.0.1,那么从外部是无法直接访问的,必须通过Nginx反向代理。
  3. 检查防火墙sudo ufw status,确认是否允许了Nginx的80/443端口,以及是否允许了本地回环通信。
  4. 检查Nginx配置sudo nginx -t测试配置语法。sudo systemctl status nginx查看Nginx状态。查看Nginx错误日志/var/log/nginx/error.log解决
  • 确保Gunicorn服务正常运行。
  • 确保Nginx配置中的proxy_pass地址(http://127.0.0.1:8000)与Gunicorn监听的地址端口一致。
  • 如果是云服务器,还需要检查安全组(Security Group)或防火墙规则,是否开放了80/443端口入站。

7.3 技能调用返回错误或结果异常

问题:API调用返回500内部服务器错误,或者返回的结果与在Manus AI上不一致。排查

  1. 查看应用日志:这是最直接的途径。tail -f ~/ai_skills/logs/gunicorn_error.log,找到对应的错误堆栈信息。常见错误有:导入错误(路径问题)、KeyError(输入数据格式不对)、API认证失败(环境变量未加载)、超时等。
  2. 对比输入数据:仔细检查发送到自建API的请求体,是否与之前调用Manus AI时完全一致。特别注意JSON的格式、字段名、编码等。
  3. 环境变量问题:确认API密钥等环境变量是否正确设置。可以在Python代码中临时打印os.getenv('OPENAI_API_KEY')的前几位进行验证(切勿打印完整密钥到日志)。
  4. 文件路径问题:对于技能C和F,代码中读取的rules.yamltemplate.html等文件路径是否正确。在VPS上,建议使用绝对路径或基于__file__构造的相对路径。
    import os config_path = os.path.join(os.path.dirname(__file__), 'config', 'rules.yaml')

解决:根据日志错误信息对症下药。如果是路径问题,修正路径。如果是依赖问题,检查虚拟环境。如果是逻辑错误,回退到代码重构步骤进行调试。

7.4 OpenAI API调用频率限制(Rate Limit)错误

问题:技能A或E在短时间内被多次调用时,返回429 Too Many RequestsRateLimitError排查:查看错误日志,确认错误信息来自OpenAI API。解决

  1. 客户端限流:在技能网关层面实现简单的限流。例如,使用slowapiasyncio的信号量(Semaphore)来控制并发向OpenAI发起的请求数。
    import asyncio openai_semaphore = asyncio.Semaphore(5) # 限制最多5个并发OpenAI请求 async def call_openai_with_limit(prompt): async with openai_semaphore: return await client.chat.completions.create(...)
  2. 指数退避重试:在调用OpenAI的代码中添加重试逻辑,在遇到速率限制错误时等待一段时间再重试。
    from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type import openai @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10), retry=retry_if_exception_type(openai.RateLimitError) ) def call_openai_with_retry(text): # ... 调用代码
  3. 调整使用策略:评估是否真的需要如此高的调用频率,是否可以合并请求,或者使用缓存来避免重复处理相同或相似的请求。

整个迁移过程,从前期梳理到后期调优,花了差不多一周的碎片时间。最大的感受是,自建服务给了你最大的控制权和灵活性,但也把运维的担子完全交给了你自己。从环境配置、服务部署、监控告警到故障排查,每一个环节都需要亲力亲为。对于个人或小团队来说,在技能数量不多、复杂度不高的情况下,使用Manus AI这类平台依然是快速启动和验证想法的最佳选择。但当你的技能成为业务核心,且调用量增长到一定程度时,迁移到自建VPS所带来的成本节约和技术自主性,就会变得非常值得。这次迁移的6个技能,现在运行稳定,月度成本比在平台上降低了约60%,更重要的是,代码和数据都在自己手里,后续想怎么集成、怎么改造,都畅通无阻了。如果你也走到了需要考虑这一步的时候,希望这份详细的记录能帮你少走些弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 11:09:57

CSDN博客下载器:3种模式打造你的专属离线技术图书馆

CSDN博客下载器&#xff1a;3种模式打造你的专属离线技术图书馆 【免费下载链接】CSDNBlogDownloader 项目地址: https://gitcode.com/gh_mirrors/cs/CSDNBlogDownloader 在技术学习的道路上&#xff0c;你是否曾经为这些场景感到困扰&#xff1f;精心收藏的CSDN技术文…

作者头像 李华
网站建设 2026/5/28 11:01:00

D3KeyHelper终极配置指南:5个核心模块彻底解析暗黑3自动化助手

D3KeyHelper终极配置指南&#xff1a;5个核心模块彻底解析暗黑3自动化助手 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面&#xff0c;可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper D3KeyHelper是一款专为暗黑…

作者头像 李华
网站建设 2026/5/28 10:58:02

3分钟解决Windows DLL缺失问题:Visual C++ Redistributable AIO完整指南

3分钟解决Windows DLL缺失问题&#xff1a;Visual C Redistributable AIO完整指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过新安装的游戏…

作者头像 李华
网站建设 2026/5/28 10:56:11

AsymFLUX.2-klein-9B许可证详解:非商业使用的注意事项

AsymFLUX.2-klein-9B许可证详解&#xff1a;非商业使用的注意事项 【免费下载链接】AsymFLUX.2-klein-9B 项目地址: https://ai.gitcode.com/hf_mirrors/Lakonik/AsymFLUX.2-klein-9B AsymFLUX.2-klein-9B是一个基于FLUX.2-klein-base-9B模型微调的非对称流模型&#x…

作者头像 李华