1. 为什么要在 AWS 上自建类 Manus 的 Agent 服务
Manus 这类通用 AI Agent 最让人上头的地方,是它能自己拆任务、自己调工具、自己检查结果,一个复杂需求丢进去,它能在几十步里把活干完。但真到自己动手做,问题马上来了:模型调用散落在各个文件里,今天用 OpenAI 的 Key,明天换 Claude 的 Key,后天又要接 DeepSeek,密钥管理一团乱;任务跑到第 15 步上下文超了,Agent 开始"失忆",前面做过什么全忘了;再加上 AWS 上一堆服务要串起来,ECS、Lambda、S3、SQS,光是让链路跑通就得折腾好几天。
这篇就解决两件事。第一,用 TaoToken 的统一 Key 和 API 通道,把多模型调用收敛成一个入口,Agent 服务端不用再关心底层是哪家模型,换模型只改一个配置。第二,落地 Planning-with-Files 机制,用"任务计划 + 进展笔记 + 交付成果"三个文件当 Agent 的外部记忆,让长周期任务不再丢状态。适合已经在 AWS 上有基础、想搭一套能上生产的 Agent 服务的后端和平台同学,也适合想先跑通链路再逐步优化的个人开发者。
我试过把模型调用和任务状态分开管理之后,整个 Agent 服务的可维护性提升非常明显,下面把可复制的配置和验证步骤完整给出来。
2. TaoToken 前置:统一 Key 与 API 通道准备
TaoToken 在这里扮演的角色是"模型能力的统一网关"。你的 Agent 服务端只需要认一个 base_url 和一个 Key,具体请求打到哪个模型,由配置决定。这样做的好处很直接:Agent 的规划模块、执行模块、总结模块可以分别指定不同模型,但代码里只有一套调用逻辑。
先拿到访问凭证。打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册后进入控制台,在 API Keys 页面创建一个 Key。建议按环境拆 Key,比如 dev 一个、prod 一个,方便后续在 AWS Secrets Manager 里做隔离。
创建 Key 的入口在控制台里:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
API 的基础地址是 https://taotoken.net/api ,注意这个地址不带任何查询参数,直接作为 OpenAI 兼容客户端的 base_url 使用即可。如果你用的是 Anthropic 风格的 SDK,走的是另一套路径,文档里有说明。
注意:Key 只创建一次就保存好,页面刷新后不再完整显示。生产环境不要把它写进代码或镜像,统一放 Secrets Manager。
模型能力可以先在对话页验证通不通:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
如果你后面要做长期编码类 Agent,或者需要跑 Coding Plan 这种持续任务,可以单独看下套餐页:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
接入细节和参数说明在文档里:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
3. 可复制配置:settings.json 与 config.toml 骨架
Agent 服务端我习惯用 Python,配置分两层:一层是应用级 settings.json,管模型路由和任务参数;一层是工具级 config.toml,管 Planning-with-Files 的文件路径和沙箱行为。下面两份骨架可以直接抄。
3.1 settings.json:模型路由与任务参数
{ "taotoken": { "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "timeout_seconds": 120, "max_retries": 3 }, "model_routing": { "planner": { "model": "claude-sonnet-4-20250514", "temperature": 0.2, "max_tokens": 4096 }, "executor": { "model": "gpt-4o", "temperature": 0.1, "max_tokens": 8192 }, "summarizer": { "model": "deepseek-chat", "temperature": 0.3, "max_tokens": 2048 } }, "agent": { "max_steps": 40, "step_timeout_seconds": 300, "context_window_tokens": 128000, "planning_with_files": { "enabled": true, "workspace_root": "/app/workspace", "plan_file": "task_plan.md", "notes_file": "notes.md", "deliverables_dir": "deliverables" } }, "aws": { "region": "us-east-1", "s3_bucket": "ai-agent-workspace", "sqs_queue_url": "https://sqs.us-east-1.amazonaws.com/123456789012/agent-tasks" } }这里的关键点是 model_routing 把三个角色拆开了。planner 用推理强的模型做任务分解,executor 用工具调用稳的模型做执行,summarizer 用便宜的模型做收尾总结。三个角色都走同一个 base_url,换模型只改 model 字段。
3.2 config.toml:Planning-with-Files 与沙箱配置
[workspace] root = "/app/workspace" plan_file = "task_plan.md" notes_file = "notes.md" deliverables_dir = "deliverables" max_file_size_mb = 10 [planning] auto_checkpoint = true checkpoint_every_steps = 5 replan_on_failure = true max_replan_attempts = 2 [sandbox] enabled = true runtime = "python:3.11-slim" cpu_limit = "1.0" memory_limit = "1024m" network_disabled = true timeout_seconds = 120 readonly_rootfs = true [storage] backend = "s3" bucket = "ai-agent-workspace" prefix = "tasks" sync_interval_seconds = 30 [logging] level = "INFO" cloudwatch_group = "/ecs/ai-agent"sandbox 段是生产环境必须开的。network_disabled = true 让代码执行环境断网,readonly_rootfs = true 防止容器内文件被篡改,这两个开关能挡掉大部分意外。
3.3 在 AWS Secrets Manager 里存 Key
aws secretsmanager create-secret \ --name ai-agent/taotoken-key \ --secret-string '{"TAOTOKEN_API_KEY":"sk-你的实际Key"}'然后在 ECS 任务定义里引用:
{ "name": "TAOTOKEN_API_KEY", "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:ai-agent/taotoken-key:TAOTOKEN_API_KEY::" }这样容器启动时环境变量自动注入,代码里用 os.environ 读就行,镜像里永远不出现明文 Key。
4. CC Switch / Cline 接入与端到端验证
配置写好了,先别急着上 ECS,本地用 CC Switch 或 Cline 把链路验证通,能省掉大量在云上排查的时间。
4.1 CC Switch 接入步骤
CC Switch 用来管理多套模型配置,切换环境很方便。新建一个配置,字段这样填:
{ "name": "taotoken-prod", "base_url": "https://taotoken.net/api", "api_key": "sk-你的实际Key", "default_model": "claude-sonnet-4-20250514", "models": [ "claude-sonnet-4-20250514", "gpt-4o", "deepseek-chat" ] }保存后切到这套配置,发一条测试消息,能正常返回就说明 Key 和通道没问题。
4.2 Cline 接入步骤
Cline 在 VS Code 里配置更直接。打开设置,API Provider 选 OpenAI Compatible,Base URL 填 https://taotoken.net/api ,API Key 填你的 Key,Model ID 填 claude-sonnet-4-20250514。保存后新建一个对话,让它读一个本地文件并总结,能跑通就说明工具调用链路正常。
4.3 服务端验证脚本
本地验证通过后,写一个最小脚本验证 Agent 服务端的调用逻辑:
import os import json from openai import OpenAI client = OpenAI( base_url="https://taotoken.net/api", api_key=os.environ["TAOTOKEN_API_KEY"], ) def plan_task(description: str) -> str: resp = client.chat.completions.create( model="claude-sonnet-4-20250514", temperature=0.2, messages=[ {"role": "system", "content": "你是任务规划器,把用户需求拆成可执行步骤,输出 JSON。"}, {"role": "user", "content": description}, ], ) return resp.choices[0].message.content if __name__ == "__main__": result = plan_task("分析一份 CSV 销售数据,输出月度趋势报告") print(result)跑起来看到结构化的步骤 JSON,说明规划模块通了。接着把 executor 和 summarizer 也各发一次请求,三个角色都通,模型路由层就算验证完成。
4.4 Planning-with-Files 落盘验证
在服务端加一段初始化逻辑,确认三个文件能正确创建:
from pathlib import Path import json def init_task_workspace(task_id: str, description: str) -> dict: root = Path("/app/workspace") / task_id root.mkdir(parents=True, exist_ok=True) (root / "deliverables").mkdir(exist_ok=True) plan = { "task_id": task_id, "description": description, "status": "planning", "steps": [], "current_step": 0, } (root / "task_plan.md").write_text( "# Task Plan\n\n```json\n" + json.dumps(plan, ensure_ascii=False, indent=2) + "\n```\n", encoding="utf-8", ) (root / "notes.md").write_text("# Notes\n\n", encoding="utf-8") return {"workspace": str(root), "plan": str(root / "task_plan.md")}执行后检查 /app/workspace 下是否出现任务目录和两个 md 文件,deliverables 目录是否为空目录。这一步过了,说明文件工作流的基础设施就绪。
5. 本篇常见错排查
5.1 401 或 403:Key 没注入或环境变量名对不上
最常见的是 ECS 任务定义里 valueFrom 的 ARN 写错,或者环境变量名和代码里读的不一致。先在容器里执行 env | grep TAOTOKEN 确认变量存在,再确认代码里 os.environ 的键名完全一致。Secrets Manager 的 ARN 末尾要带 :TAOTOKEN_API_KEY:: 这种 JSON key 后缀,漏了会拿到整个 JSON 字符串而不是值。
5.2 模型名报错:路由配置里的 model 字段写错
TaoToken 的模型名要和平台支持的名称一致,写错会返回 model not found。排查方法是把 settings.json 里的 model 字段单独拿出来,用 curl 直接打一次:
curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"claude-sonnet-4-20250514","messages":[{"role":"user","content":"ping"}]}'能返回就说明模型名对,报错就换一个平台支持的名称。
5.3 任务跑到中途上下文超限
这是 Planning-with-Files 要解决的核心问题。如果还是超,检查两点:一是 checkpoint_every_steps 是不是设太大,建议 5 步一次;二是 notes.md 是不是只追加不压缩,长任务里笔记会膨胀,需要定期让 summarizer 把旧笔记压缩成摘要再写回。可以在 planning 段加一个 notes_max_tokens 限制,超过就触发压缩。
5.4 沙箱里代码执行超时
timeout_seconds 默认 120,数据分析类任务经常不够。调大到 300 的同时,确认 memory_limit 也同步调大,否则会 OOM 而不是超时。另外 network_disabled = true 时,任何需要联网的代码都会失败,如果任务确实要调外部 API,得单独开一个受控的出网策略,不要直接关掉这个开关。
5.5 S3 同步失败:IAM 权限不足
任务文件写本地没问题,但同步到 S3 报 AccessDenied,基本是任务角色的 IAM 策略没给 s3:PutObject 和 s3:ListBucket。检查任务定义里的 taskRoleArn 对应的策略,Resource 要同时包含 arn:aws:s3:::ai-agent-workspace/* 和 arn:aws:s3:::ai-agent-workspace 两条,少一条都会失败。
6. 把链路跑通之后
整套东西跑通之后,你会发现 Agent 服务的复杂度其实不在模型调用,而在状态管理和错误恢复。TaoToken 把模型这一层收敛掉之后,你可以把精力放在 Planning-with-Files 的检查点设计和沙箱的隔离策略上。建议先把 checkpoint 和 replan 这两个机制调稳,再考虑接更多工具。模型对话页可以用来快速验证新模型的表现,接入文档里有完整的参数说明,长期跑编码类任务的话 Coding Plan 会更划算。