news 2026/10/11 22:39:08

【全域智能营销实战】3、OpenClaw 架构源码深度解析:Gateway、Agent、Skill、Memory 四大模块完全拆解与 TaoToken 统一接入实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【全域智能营销实战】3、OpenClaw 架构源码深度解析:Gateway、Agent、Skill、Memory 四大模块完全拆解与 TaoToken 统一接入实践

1. 为什么要在 OpenClaw 里做统一模型接入

OpenClaw 是一个把大模型推理和本地系统操作结合起来的 Agent 运行时框架,核心由 Gateway、Agent、Skill、Memory 四大模块组成。Gateway 负责消息调度和路由,Agent 负责决策推理,Skill 封装具体能力,Memory 管理上下文持久化。这套架构跑起来之后,真正决定体验上限的其实是模型通道——Agent 每一轮 Lobster Loop 都要调 LLM,Skill 执行结果要回灌上下文,Memory 检索出来的片段也要塞进 Prompt,这些环节全部依赖一个稳定、低延迟、可切换的模型入口。

我试过在 OpenClaw 里直接写死某一家厂商的 API Key,结果换模型要改源码、加渠道要重新打包、多 Agent 共用一套配置时 Key 到处散落。后来把模型通道统一收敛到 TaoToken,Gateway 只认一个 Base URL 和一个 Key,Agent 初始化时通过环境变量注入,Skill 和 Memory 的 embedding 也走同一条通道,整个链路清爽很多。

这篇会按源码结构把四个模块拆开讲,重点落在可复制的配置上:Gateway 的路由配置、Agent 的初始化参数、Skill 的注册模板、Memory 的持久化设置,每一步都给验证动作。适合已经在跑 OpenClaw、想把它接进自己业务链路的开发者,也适合刚开始读这套源码、想先跑通再深入的人。下面所有配置都基于 OpenClaw 的openclaw.json和~/.openclaw/workspace/目录结构,路径和字段名跟源码保持一致。

2. TaoToken 前置准备与 OpenClaw 模型通道配置

在动 Gateway 和 Agent 之前,先把模型通道准备好。TaoToken 提供统一的 API 入口,OpenClaw 的providers/目录下每个 Provider 本质上就是一个 baseURL + apiKey + model 的组合,所以接入方式很直接。

先拿 Key。打开 https://taotoken.net/api-keys ,登录后创建一个 API Key,复制出来。这个 Key 后面会同时给 Agent 推理、Skill 内部调用、Memory embedding 三处使用,所以建议单独建一个项目 Key,方便按项目做额度隔离。

Base URL 用https://taotoken.net/api,注意不要带任何查询参数。OpenClaw 的 Provider 配置里 baseURL 会被拼成{baseURL}/v1/chat/completions这种形式,多一个斜杠或少一个斜杠都会导致 404,这个坑后面排障章节会细说。

模型 ID 方面,Agent 主推理建议用带工具调用能力的模型,比如claude-sonnet-4-20250514或gpt-4o,具体可用列表在 https://taotoken.net/doc 里能查到。Memory 的 embedding 单独配一个 embedding 模型,比如text-embedding-3-small,1536 维,跟 OpenClaw 默认的chunks_vec表结构对得上。

配置写进openclaw.json的providers段:

{ "providers": { "taotoken": { "type": "openai-compatible", "baseURL": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}", "models": { "default": "claude-sonnet-4-20250514", "fast": "gpt-4o-mini", "embedding": "text-embedding-3-small" } } }, "defaultProvider": "taotoken" }

Key 不要硬编码进 JSON,用环境变量注入。在启动脚本或.env里写:

export TAOTOKEN_API_KEY="sk-你的实际Key"

OpenClaw 的src/runtime.ts在初始化时会读取${VAR}形式的占位符并做环境变量替换,所以这样写是安全的。如果你用 Docker 跑,在docker-compose.yml的environment段里加一行TAOTOKEN_API_KEY=${TAOTOKEN_API_KEY},宿主机.env里放真实值。

验证通道是否通,不用等整个 OpenClaw 起来,先单独打一个请求:

curl -s 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"}], "max_tokens": 16 }'

返回里能看到choices[0].message.content就说明 Key 和 Base URL 都对。这一步过了再往下配 Gateway,能省掉很多「到底是通道问题还是框架问题」的排查时间。

3. Gateway 路由配置与 Agent 初始化参数可复制模板

Gateway 是 OpenClaw 的中枢,源码在src/gateway/目录下,server.ts管 WebSocket 和 HTTP 服务,boot.ts管启动引导。它默认监听ws://127.0.0.1:18789和http://127.0.0.1:18793,所有渠道消息、Agent 会话、工具调用都从这里过。

Gateway 本身不直接调模型,它把消息归一化成MsgContext之后路由给 Agent 实例。所以 Gateway 的配置重点是路由规则和鉴权,模型通道在 Agent 层注入。

openclaw.json里 Gateway 段这样写:

{ "gateway": { "host": "127.0.0.1", "wsPort": 18789, "httpPort": 18793, "auth": { "mode": "token", "token": "${GATEWAY_TOKEN}" }, "routing": { "defaultAgent": "marketing-agent", "rules": [ { "match": { "channel_id": "feishu" }, "agent": "marketing-agent" }, { "match": { "channel_id": "telegram", "content_prefix": "/code" }, "agent": "coding-agent" } ] }, "rateLimit": { "enabled": true, "tokensPerMinute": 120 } } }

routing.rules是三级路由里的第二层,按channel_id和内容前缀把消息分发给不同 Agent。defaultAgent兜底。rateLimit用令牌桶,防止某个渠道刷爆。

Agent 初始化参数在agents段。OpenClaw 的 Agent Runtime 在src/agents/下,Lobster Loop 的循环逻辑在这里,Planner 的强规则校验也在这里。初始化时最关键的是把 provider 和 model 指对:

{ "agents": { "marketing-agent": { "provider": "taotoken", "model": "claude-sonnet-4-20250514", "systemPromptFile": "~/.openclaw/workspace/SOUL.md", "maxToolRounds": 12, "contextWindow": 128000, "planner": { "enabled": true, "blockedTools": ["exec", "write"], "requireConfirm": ["browser"] }, "skills": { "allowlist": ["weather", "github", "notion", "feishu-doc"] }, "memory": { "agentId": "marketing-agent", "sqlitePath": "~/.openclaw/memory/marketing-agent.sqlite", "embeddingProvider": "taotoken", "embeddingModel": "text-embedding-3-small" } } } }

几个参数值得展开。maxToolRounds对应 Lobster Loop 的最大轮数终止条件,复杂任务调十几次工具很常见,设 12 是保守值,你可以按业务调。planner.blockedTools是安全防线,把exec和write拦掉,防止 LLM 幻觉直接改本地文件。skills.allowlist是 per-agent 的 Skill 白名单,只有列出来的 Skill 会被注入这个 Agent 的 System Prompt。

memory.agentId决定 SQLite 文件名,每个 Agent 一个独立库,互不干扰。embeddingProvider指向 taotoken,复用同一个 Key。

Gateway 和 Agent 都配好之后,启动服务:

cd openclaw npm run build node dist/entry.js --config ./openclaw.json

启动日志里会依次打印:加载配置、初始化日志、扫描 skills 目录、初始化 provider、启动 WebSocket 18789、启动 HTTP 18793、注册 Channel 适配器、初始化记忆系统。看到Gateway ready就说明四模块的骨架都起来了。

4. Skill 注册模板与 Memory 持久化设置

Skill 解决的是「Agent 应该怎么做」,每个 Skill 是一个含SKILL.md的目录,放在skills/下。SKILL.md分两部分:YAML Frontmatter 给 OpenClaw 读元数据,Markdown Body 给 Agent 读行为指令。

一个可复制的最小 Skill 模板,比如做营销文案生成的:

--- name: marketing-copy description: 根据产品信息生成营销文案,支持多平台风格适配。 metadata: openclaw: requires: bins: [] env: [] --- # Marketing Copy Skill 当用户要求生成营销文案时,按以下流程执行: 1. 先确认产品名称、目标平台、核心卖点三个要素,缺哪个问哪个。 2. 根据平台选择风格:小红书偏口语化带 emoji 分段,公众号偏正式带小标题,Twitter 偏短句带钩子。 3. 生成 3 个版本,每个版本标注适用场景。 4. 输出格式固定为:标题 / 正文 / 标签建议。 调用 `read` 工具读取产品资料文件,不要凭空编造卖点。

Frontmatter 里的metadata.openclaw.requires是门控条件,bins列依赖的二进制,env列需要的环境变量,不满足条件的 Skill 会被过滤掉,不会注入 Prompt。这个机制在多环境部署时很有用。

Skill 的加载优先级是:内置skills/目录 → 用户本地覆盖 → per-agent allowlist。同名 Skill 本地覆盖内置。加载链路就三步:扫描目录、解析 SKILL.md 提取 name+description+body、格式化成 XML 片段拼进 System Prompt。

Memory 的持久化设置分两块:工作区文件结构和 SQLite 索引。工作区在~/.openclaw/workspace/:

~/.openclaw/workspace/ ├── MEMORY.md # 长期记忆:偏好、决策、持久事实 ├── memory/ │ ├── 2026-03-05.md # 今日日志(短期记忆) │ └── 2026-03-04.md # 昨日日志 ├── sessions/ # 会话存档(近端记忆) ├── USER.md # 用户身份 └── SOUL.md # Agent 人格设定

新会话启动时,OpenClaw 自动加载「今天+昨天」的日志作为短期记忆,MEMORY.md作为长期记忆常驻,sessions/里的历史会话按需检索。

SQLite 索引在~/.openclaw/memory/{agentId}.sqlite,核心表结构:

CREATE TABLE files ( id INTEGER PRIMARY KEY, path TEXT UNIQUE, mtime INTEGER, size INTEGER, hash TEXT ); CREATE TABLE chunks ( id INTEGER PRIMARY KEY, file_id INTEGER, start_line INTEGER, end_line INTEGER, text TEXT, hash TEXT UNIQUE, embedding TEXT ); CREATE VIRTUAL TABLE chunks_fts USING fts5(text, content=chunks); CREATE VIRTUAL TABLE chunks_vec USING vec0(embedding float[1536]);

files表用mtime和hash做增量索引,只重新索引变更的文件。chunks表存分块内容和向量,hash做跨文件去重。chunks_fts是 BM25 全文检索,chunks_vec是向量检索,两路并行后合并加权排序。

embedding 走 TaoToken 的话,chunks_vec的维度要跟模型对上,text-embedding-3-small是 1536 维,跟上面建表语句一致。如果换text-embedding-3-large的 3072 维,建表语句里的float[1536]要改,否则插入会报维度不匹配。

Memory 的检索配置在openclaw.json的memory段:

{ "memory": { "retrieval": { "topK": 8, "bm25Weight": 0.4, "vectorWeight": 0.6, "minScore": 0.3 }, "indexing": { "chunkSize": 512, "chunkOverlap": 64, "watch": true } } }

bm25Weight和vectorWeight控制两路检索结果的合并权重,关键词查询多的场景把 bm25 调高,语义查询多的把 vector 调高。watch: true开启文件监听,工作区文件一改就触发增量索引。

5. 四模块协同验证与常见报错排查

配置写完,启动服务,按 Gateway → Agent → Skill → Memory 的顺序逐个验证。

Gateway 转发日志。启动后看控制台,正常会打印:

[gateway] WebSocket server listening on ws://127.0.0.1:18789 [gateway] HTTP server listening on http://127.0.0.1:18793 [gateway] routing rules loaded: 2 [gateway] channel adapters registered: feishu, telegram

发一条测试消息,日志里应该出现[gateway] MsgContext normalized和[gateway] routed to agent=marketing-agent。如果只看到 normalized 没有 routed,说明routing.rules的 match 条件没命中,检查channel_id拼写。

Agent 任务响应。Gateway 路由过去之后,Agent 的 Lobster Loop 开始跑,日志里会看到[agent] Think→[agent] Act→[agent] Observe的循环。如果卡在 Think 不动,多半是模型通道问题,回到第 2 节的 curl 验证。

Skill 调用链路。Agent 决定调 Skill 时,日志里出现[skill] loading marketing-copy和[skill] injected into system prompt。如果 Skill 没被加载,检查skills.allowlist里有没有列,以及SKILL.md的 frontmatter 格式对不对。

Memory 读写结果。Agent 每轮结束会把关键信息写进当日日志,日志里出现[memory] appended to 2026-03-05.md。检索时出现[memory] bm25 hits=3 vector hits=5 merged=6。如果 vector hits=0,检查 embedding 模型和维度。

下面是我踩过的几个真实报错,对照排查。

401 Unauthorized。日志里[provider] request failed status=401。原因通常是 Key 没注入成功,${TAOTOKEN_API_KEY}没被替换。检查启动环境里有没有export,Docker 里检查environment段。还有一种情况是 Key 复制时带了空格,用echo $TAOTOKEN_API_KEY | wc -c看长度对不对。

local proxy failed / ECONNREFUSED。日志里[provider] local proxy failed。这是 baseURL 写错,比如写成了https://taotoken.net/api/带尾斜杠,或者写成了https://taotoken.net少了/api。正确值是https://taotoken.net/api,不带尾斜杠。

reading choices 报错。日志里Cannot read properties of undefined (reading 'choices')。这是响应体结构跟预期不符,通常是模型 ID 写错,返回了错误对象而不是正常响应。用 curl 单独打一次确认模型 ID 在 https://taotoken.net/doc 的列表里。

OAuth / token expired。日志里[provider] oauth token expired。OpenClaw 某些 Provider 走 OAuth 流程,taotoken 走的是 API Key 模式,如果出现这个报错说明type字段写错了,应该是openai-compatible而不是oauth。

Skill 没生效。Agent 回复里完全没提 Skill 的流程。检查SKILL.md的 frontmatter 有没有---包裹,YAML 缩进对不对。OpenClaw 解析失败时会静默跳过,日志里不会有明显报错,可以在启动时加--verbose看扫描结果。

Memory 检索为空。[memory] bm25 hits=0 vector hits=0。检查~/.openclaw/workspace/memory/下有没有当日日志文件,以及 SQLite 文件有没有生成。如果 SQLite 生成了但 chunks 表为空,说明索引没跑,手动触发一次node dist/cli.js memory reindex --agent marketing-agent。

Gateway 端口占用。EADDRINUSE: address already in use 127.0.0.1:18789。上次进程没退干净,lsof -i :18789找到 PID 杀掉,或者改wsPort换端口。

Agent 循环不终止。日志里 Lobster Loop 一直转,超过maxToolRounds才停。这是 Planner 没拦住,检查planner.enabled是不是 true,以及blockedTools有没有覆盖到出问题的工具。

上下文超限。日志里context length exceeded, compressing。这是 Memory 的动态上下文管理在压缩,正常行为。如果频繁触发,把memory.retrieval.topK调小,或者把chunkSize调大减少碎片。

6. 把四模块接进你的业务链路

跑通之后,下一步是把 OpenClaw 接进实际业务。Gateway 的 HTTP 接口http://127.0.0.1:18793可以直接被外部系统调用,用POST /v1/message发消息,body 里带channel_id和content,Gateway 会按路由规则分发给对应 Agent。这样你的 CRM、工单系统、营销后台都能通过一个 HTTP 接口触发 Agent。

多 Agent 场景下,每个 Agent 在agents段独立配置 provider、model、skills、memory,共用同一个 TaoToken Key。额度按项目 Key 隔离,在 https://taotoken.net/console 里能看到每个 Key 的调用量和费用。长期跑编码类 Agent 的话,Coding Plan 的额度模型比按量计费更划算,具体在 https://taotoken.net/coding-plan 看。

Skill 的扩展是这套架构里最灵活的部分。你不需要改 Gateway 或 Agent 的源码,只要在skills/下新建目录、写SKILL.md、加进allowlist,重启服务就生效。我建议把业务相关的 Skill 单独放一个目录,用metadata.openclaw.requires.env做环境门控,测试环境和生产环境用不同的 Skill 集合。

Memory 的调优是个持续过程。初期topK设小一点,8 左右,观察 Agent 回复质量。如果发现 Agent 经常「忘记」之前说过的偏好,把MEMORY.md手动补几条关键事实,长期记忆是常驻的,不参与检索排序,优先级最高。日志文件按天滚动,历史日志靠 BM25 + 向量检索捞,所以写日志时尽量把关键决策写清楚,检索命中率会高很多。

最后提一个容易忽略的点:Gateway 的auth.token和 TaoToken 的 API Key 是两套东西。前者是 OpenClaw 内部 WebSocket/HTTP 的鉴权,后者是模型通道的鉴权。两个都要设,但用途不同,别混在一起。Gateway token 用openssl rand -hex 32生成一个随机值就行,不需要跟 TaoToken 有任何关联。

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

Android自定义上下滚动控件:从测量到回弹的完整实现

简介:Android自定义上下滚动控件项目资源,面向需要实现类似密码盘数字滚动效果的开发者,适用于自定义输入界面、动态数据展示等场景,可作为自定义View学习与改造的参考。资源从基础类创建、onDraw绘制、触摸事件处理、ValueAnimat…

作者头像 李华
网站建设 2026/10/11 22:38:41

SQL Server中索引查找退化为索引扫描的原因与排查指南

简介:SQL Server 执行计划中,索引查找(Index Seek)为何会退化为索引扫描(Index Scan)?这份文档以排查思路为主线,面向 SQL Server 开发与运维人员,梳理了导致该问题的 10…

作者头像 李华
网站建设 2026/10/11 22:37:47

手写数字识别毕设工程化:从MNIST到真实场景的完整落地实践

简介:本资源是一套面向本科毕业设计、课程设计及期末大作业的高分Python手写数字识别完整项目,适用于人工智能入门学习者与计算机相关专业学生,解决从模型构建、训练到部署演示的全流程实践需求。压缩包共28个文件,约29.22MB&…

作者头像 李华
网站建设 2026/10/11 22:36:05

P1348公交网建设:最小生成树Prim与Kruskal算法深度解析

1. 题目拆解:公交网建设到底在考什么P1348这道题,乍一看是城市公交网建设,好像是个规划问题,但剥开外壳就是一道非常典型的**最小生成树(MST)**问题。这类题目在信息学奥赛里属于"模板题中的变式"…

作者头像 李华
网站建设 2026/10/11 22:34:09

Java 接 YOLO ONNX:跨语言视频目标检测落地实践

简介:本资源面向需要在 Java 项目中落地视频目标检测的开发者,提供一套 Java 调用 Python YOLO ONNX 模型的完整方案,支持 YOLOv5、YOLOv7、YOLOv8 等主流模型,并覆盖 RTSP/RTMP 视频流处理场景。整体架构由 Java 端负责视频流获取…

作者头像 李华