本文基于一个已完成的生产级项目,系统梳理业务系统与 OpenClaw 的集成方案。核心思路:一个用户一个 Agent,通过 REST API 打通业务数据,支持多端消息通道和主动 AI 问询。
一、架构全景
scss
┌─────────────────────────────────────────────────────────────────┐
│ 消息通道 (Channels) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ 飞书 │ │ 微信公众号 │ │ Web 前端 │ │ 更多渠道... │ │
│ │ (Feishu) │ │ (WeChat) │ │ (Nuxt 3) │ │ │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘ │
│ │ │ │ │ │
│ └──────────────┼──────────────┼───────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ OpenClaw Gateway (:18789) │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ Agent Binding & Routing │ │ │
│ │ │ channel + accountId → agentId 映射 │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ HTTP Endpoints │ │ │
│ │ │ POST /v1/responses (Responses API) │ │ │
│ │ │ POST /v1/chat/completions (Chat Completions) │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ Model Router │ │ │
│ │ │ 主模型 → fallback 链 → 自动切换 │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └──────────────────────┬──────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────┼──────────────────────────────────┐ │
│ │ Agent 隔离沙箱 (Per-User Workspace) │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ user_21 │ │ user_144 │ │ user_149 │ ...更多 │ │
│ │ │ ─────── │ │ ─────── │ │ ─────── │ │ │
│ │ │ SOUL.md │ │ SOUL.md │ │ SOUL.md │ │ │
│ │ │ AGENTS.md│ │ AGENTS.md│ │ AGENTS.md│ │ │
│ │ │ TOOLS.md │ │ TOOLS.md │ │ TOOLS.md │ │ │
│ │ │ skills/ │ │ skills/ │ │ skills/ │ │ │
│ │ │ Docker沙箱│ │ Docker沙箱│ │ Docker沙箱│ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
│ └───────┼─────────────┼─────────────┼─────────────────────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 业务 REST API 层 │ │
│ │ meeting-api │ task-api │ project-api │ report-api │ │
│ │ member-api │ document-api │ workspace-api │ ... │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 业务数据库 (Agent 不可直接访问) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
关键原则 :Agent 禁止直接访问数据库,所有业务数据必须通过 REST API 获取。这保证了权限控制、审计追踪和数据安全。
二、用户与 Agent 的关系模型
这是整个方案的核心设计决策:每个用户拥有独立的 Agent 实例。
2.1 为什么要一对一?
| 方案 | 优势 | 劣势 |
|---|---|---|
| 多用户共享 Agent | 资源开销小 | 会话隔离困难,上下文混乱,权限不可控 |
| 一用户一 Agent(本方案) | 天然隔离,独立上下文,独立沙箱 | 需要管理多个 Agent 实例 |
在一个多租户业务系统中,每个用户的数据可见性不同(项目 A 的用户不该看到项目 B 的数据),Agent 级别的隔离是最安全的方案。
2.2 Agent ID 命名与映射
typescript
// 每个用户对应一个唯一的 Agent ID
export function getUserAgentId(userId: number): string {
return `user_${userId}` // 例如: user_21, user_144
}
// 支持显式指定 agent,未指定时使用 user_xxx
export function resolveOpenClawAgentId(userId: number, agentId?: string): string {
return agentId?.trim() || getUserAgentId(userId)
}
命名规则 :user_{userId} --- 简单清晰,与业务系统用户 ID 直接对应。
2.3 多 Agent 实例示例
json
// openclaw.json 中的 agents.list(运行时自动创建,这里展示生成的快照)
{
"agents": {
"list": [
{ "id": "main" }, // 默认主 Agent
{ "id": "user_144" }, // 用户 144 的专属 Agent
{ "id": "user_21" }, // 用户 21 的专属 Agent
{ "id": "user_149" } // 用户 149 的专属 Agent
]
}
}
Agent 由代码懒创建------当用户首次发送消息时,自动检查是否存在对应 Agent,不存在则创建。
三、Session 会话管理
3.1 Session Key 设计
typescript
export function generateSessionKey(
userId: string | number,
sessionId: string,
agentId = 'main'
): string {
return `agent:${agentId}:user_${userId}:session_${sessionId}`
}
// 生成示例: "agent:user_21:user_21:session_a1b2c3d4"
Session Key 同时包含了 Agent 归属 、用户归属 和会话标识 ,作为 OpenAI Responses API 中 user 参数的值传入,实现会话级别的对话连续性。
3.2 请求上下文传递
每次请求注入的运行时上下文:
typescript
const requestBody = buildOpenClawResponsesRequestBody({
model: `openclaw/${agentId}`, // 指定目标 Agent
message, // 用户消息
sessionKey, // 会话标识
systemMessage, // 动态系统指令
metadata: { // 业务上下文
userId: String(userId),
apiHost, // 业务 API 地址
authToken, // 用户鉴权 Token
},
})
metadata 中的 authToken 是关键------它来自用户登录时的 JWT Token,有时效性。Agent 每次调用业务 API 都携带此 Token,既保证了安全性,也天然实现了用户级权限隔离。
四、Agent 自动创建机制
用户首次对话时,系统自动创建 Agent 并初始化 Workspace:
typescript
async function ensureOpenClawAgent(agentId: string): Promise<void> {
// 1. 幂等保护:同一 Agent 不会重复创建
if (agentCreationPromises.has(agentId)) {
return agentCreationPromises.get(agentId)!
}
// 2. 列出已有 Agent,新建才创建
const { stdout } = await execWithNodePath('openclaw agents list --json')
const agents = JSON.parse(stdout)
if (!agents.some((a: any) => a.id === agentId)) {
// 3. 拷贝 Skills 到 Workspace(每次都会执行)
await fs.cp(skillsSrc, skillsDst, { recursive: true, force: true })
// 4. 写入 Agent 行为文件
// SOUL.md --- 角色定位
// AGENTS.md --- 操作指令
// TOOLS.md --- 工具使用说明
// 5. 创建 Agent
await execWithNodePath(`openclaw agents add ${agentId} --workspace "${workspace}"`)
}
}
Agent 行为文件
SOUL.md --- 定义 Agent 的核心能力和行为边界:
markdown
你是用户的个人中文助手,专注于项目管理、任务、会议、报告、风险建议等查询和数据分析。
核心能力:
- 通过 REST API 查询任务、项目和会议数据
- 汇总待办事项并按优先级展示
- 提供数据分析和可视化建议
重要规则:
- 必须基于真实数据回答,不要编造数据
- 如果接口返回为空或报错,要明确说明
AGENTS.md --- 操作级指令:
markdown
当用户询问任务、报告、会议、数据等内容时,必须通过 REST API 获取真实数据。
数据访问原则:
- 启动时优先阅读运行时注入的 instructions 和 metadata
- 所有 API 接口信息已包含在 instructions 中
- 禁止直接访问数据库,所有数据必须通过 REST API 获取
TOOLS.md --- 工具使用约定:
markdown
所有业务数据查询均通过 REST API 完成。
优先使用 curl 调用接口,Header 中携带 Authorization: Bearer {token}
如 curl 不可用,使用 web_fetch 工具
token 从运行时 instructions 或 metadata 中获取
每次请求都重新同步 skills 到 workspace,确保 Agent 始终使用最新的业务 API 定义。
五、系统指令注入(核心机制)
每次请求都动态生成 System Message,注入业务上下文:
typescript
export function buildOpenClawSystemMessage({
apiHost, userId, projectId, authToken, doubaoApiKey,
}: BuildOpenClawSystemMessageOptions): string {
return `你是用户的个人助手,专注于项目管理、任务、会议、知识库检索等。
当前操作用户 ID: ${userId}
当前项目ID: ${projectId}
## 数据获取方式
使用 curl 或 web_fetch 工具调用 REST API,在请求头中携带 Authorization: Bearer {token}。
- 后端地址: ${apiHost}
- 鉴权方式: Authorization: Bearer ${authToken}
- 豆包图片生成 API Key: ${doubaoApiKey || '未配置'}
## 鉴权失效处理
如果接口返回 401 或提示 token 失效,说明 authToken 已过期。
此时不要反复重试,应明确告知用户"登录已过期,请提供用户名和密码重新登录",
然后调用 /api/user/login.do 获取新的 authToken。
## 可用 API 接口
- meeting-api:会议管理
- task-api:任务管理
- project-api:项目管理
- report-api:报告管理
- member-api:成员管理
- document-api:文档管理
- workspace-api:工作台
- proactive-interaction-api:主动问询
## 重要约束
缺少必要参数时必须向用户确认,禁止自行填补默认值。
创建/更新/删除等写操作,执行前向用户确认操作内容。
查不到数据时明确说明你查了什么、结果如何。`
}
为什么用 System Message 而不是 Skill?
| 方式 | 适合场景 |
|---|---|
| System Message | 运行时动态数据(userId, projectId, authToken 每次不同) |
| Skill 文件 | 静态 API 文档(接口地址、参数、示例不常变) |
两者配合:System Message 注入动态上下文,Skill 提供静态 API 知识。
六、Skills 体系 --- 业务 API 的知识层
6.1 业务 Skills 清单
每个业务模块对应一个 Skill 文件(SKILL.md),包含完整的 API 文档:
ruby
~/.openclaw/skills/
├── meeting-api/SKILL.md # 会议管理(30+ 接口)
├── task-api/SKILL.md # 任务管理(CRUD + 确认 + 导入)
├── project-api/SKILL.md # 项目管理
├── report-api/SKILL.md # 报告管理
├── member-api/SKILL.md # 成员管理
├── document-api/SKILL.md # 文档与知识库
├── workspace-api/SKILL.md # 工作台(待办/通知/建议)
├── proactive-interaction-api/SKILL.md # 主动问询
├── zhiqiu-creative/SKILL.md # 结果可视化
├── meeting-summary-indented-tree-html/ # 会议纪要树形 HTML
├── meeting-summary-mixed-html/ # 会议纪要混合 HTML
├── frontend-design/SKILL.md # 前端设计
└── ...(开发类 Skills: nuxt, vue, tailwind 等)
6.2 Skill 文件结构示例(task-api)
markdown
---
name: task-api
description: 任务管理 API --- 查询、创建、更新、删除任务,导入任务,确认任务等
---
# 任务管理 API
所有接口需在 Header 中携带 `Authorization: Bearer {token}`。
**apiHost** 和 **token** 从运行时 instructions 或 metadata 中获取。
## 1. 查询任务列表
```bash
curl -X GET "{apiHost}/api/project/issueList.do?projectIdList=123&pageNum=1&pageSize=20" \
-H "Authorization: Bearer {token}"
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectIdList | List | 是 | 项目ID列表 |
| statusIdList | List | 否 | 任务状态ID列表 |
| assignedToId | Integer | 否 | 指派人用户ID |
| pageNum | Integer | 否 | 页码,默认1 |
| pageSize | Integer | 否 | 每页条数 |
出参 :{ code: 200, data: { total, rows: IssueListRow[] } }
2. 创建任务
bash
curl -X POST "{apiHost}/api/project/issueCreate.do" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"projectId": 123, "subject": "完成前端开发", ...}'
csharp
**Skill 设计原则**:
- 每个接口包含完整的 cURL 示例------Agent 可以直接复制执行
- `{apiHost}` 和 `{token}` 是占位符,Agent 从运行时上下文替换
- 参数说明表格标注必填/可选和数据类型
- 出参格式让 Agent 知道如何解析响应
---
## 七、OpenClaw 配置详解
以下是 `~/.openclaw/openclaw.json` 的关键配置项说明。
### 7.1 模型路由配置
```jsonc
{
"agents": {
"defaults": {
"model": {
"primary": "deepseek/deepseek-chat", // 主模型
"fallbacks": [ // 自动降级链
"ollama/qwen2.5:7b", // 本地 Ollama(快速但能力弱)
"modelstudio/qwen3.5-plus", // 阿里百炼
"qwen/qwen3-max-2026-01-23", // 通义千问 Max
"qwen/qwen3-coder-next", // 千问 Coder
"qwen/qwen3-coder-plus", // 千问 Coder Plus
"qwen/MiniMax-M2.5", // MiniMax
"qwen/glm-5", // 智谱 GLM-5
"qwen/kimi-k2.5" // Moonshot Kimi
]
}
}
}
}
Fallback 机制:当主模型不可用时,Gateway 自动按顺序尝试下一个模型。优先使用本地 Ollama(零成本),再尝试云端 API。
7.2 多 Provider 配置
jsonc
{
"models": {
"mode": "merge", // 合并多个 provider 的模型列表
"providers": {
"deepseek": { // DeepSeek 官方 API
"baseUrl": "https://api.deepseek.com",
"api": "openai-completions",
"models": [{ "id": "deepseek-chat", "contextWindow": 131072, "maxTokens": 8192 }]
},
"qwen": { // 阿里云百炼(兼容 OpenAI API)
"baseUrl": "https://coding.dashscope.aliyuncs.com/v1",
"api": "openai-completions",
"models": [ // 8+ 模型,详见配置文件
{ "id": "qwen3.5-plus", "contextWindow": 1000000, "maxTokens": 65536 },
{ "id": "qwen3-max-2026-01-23", "contextWindow": 262144, "maxTokens": 65536 }
]
},
"ollama": { // 本地 Ollama 服务
"baseUrl": "http://<your-ollama-host>:11434",
"api": "ollama",
"models": [ // Gemma, Qwen, GLM 等本地模型
{ "id": "qwen2.5:7b", "contextWindow": 32768 },
{ "id": "qwen3.5:latest", "contextWindow": 262144 }
]
}
}
}
}
关键参数说明:
| 参数 | 说明 |
|---|---|
mode: "merge" |
合并所有 provider 的模型,统一调度 |
contextWindow |
上下文窗口大小(Token 数) |
maxTokens |
单次最大输出 Token 数 |
cost |
成本配置($/百万 Token),用于成本追踪 |
reasoning |
是否为推理模型(带思维链) |
input |
支持的输入类型:["text"] 或 ["text","image"] |
7.3 Gateway 配置
jsonc
{
"gateway": {
"mode": "local", // 本地模式(非远程/云端)
"port": 18789, // Gateway 监听端口
"bind": "loopback", // 仅本地回环(127.0.0.1)
"auth": {
"mode": "token", // Token 鉴权模式
"token": "your-gateway-token-here"
},
"http": {
"endpoints": {
"chatCompletions": { "enabled": true }, // 兼容 OpenAI Chat API
"responses": { "enabled": true } // OpenAI Responses API
}
},
"controlUi": {
"allowInsecureAuth": true // 允许 HTTP(非 HTTPS)鉴权
}
}
}
安全注意事项:
bind: "loopback"确保 Gateway 只监听本地,不暴露到公网- Token 鉴权防止未经授权的请求
- 生产环境建议使用反向代理(Nginx)+ HTTPS
7.4 沙箱配置
jsonc
{
"sandbox": {
"mode": "non-main", // 非 main agent 启用沙箱
"scope": "agent", // 每个 Agent 独立沙箱
"workspaceAccess": "rw", // 工作区可读写
"docker": {
"image": "openclaw-sandbox-common:bookworm-slim",
"network": "bridge" // 桥接网络(可访问业务 API)
}
}
}
non-main 策略下,user_xxx 这类用户 Agent 运行在 Docker 沙箱中,而 main Agent 不隔离。这保证了:
- 用户 Agent 的执行环境隔离,互不影响
- 沙箱内可安装依赖、执行脚本,不影响宿主机
workspaceAccess: "rw"让 Agent 可以读写自己的 workspace
7.5 消息通道绑定
jsonc
{
"bindings": [
{
"type": "route",
"agentId": "user_21",
"match": { "channel": "openclaw-weixin", "accountId": "user_21" }
},
{
"type": "route",
"agentId": "user_149",
"match": { "channel": "openclaw-weixin", "accountId": "user_149" }
}
]
}
路由规则 :channel + accountId → agentId。微信用户 user_21 的消息自动路由到 Agent user_21。
多通道配置:
jsonc
{
"channels": {
"feishu": {
"enabled": true,
"appId": "cli_xxxx",
"appSecret": "xxxx",
"connectionMode": "websocket", // 飞书使用 WebSocket 长连接
"dmPolicy": "allowlist", // 白名单模式
"allowFrom": ["ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]
},
"openclaw-weixin": {
"enabled": true,
"dynamicAccount": true, // 动态账号模式,自动按 user_xxx 分配
"accountPrefix": "user_"
}
}
}
微信通道的特殊设计 :dynamicAccount: true + accountPrefix: "user_" 意味着每新增一个微信用户,自动创建一个对应的账号和绑定。这与 user_{userId} 的 Agent 命名规则天然对应。
7.6 其他关键配置
jsonc
{
"compaction": { "mode": "safeguard" }, // 上下文压缩保护
"tools": {
"profile": "coding", // 工具配置文件(coding = 开发场景)
"web": { "search": { "provider": "tavily", "enabled": true } }, // 网络搜索
"exec": { "security": "full", "host": "auto" } // 命令执行安全策略
},
"session": { "dmScope": "per-account-channel-peer" }, // 会话隔离策略
"plugins": {
"entries": {
"memory-core": { "config": { "dreaming": { "enabled": true } } } // 长期记忆
}
}
}
八、Nuxt 3 服务端集成
8.1 运行时配置
typescript
// nuxt.config.ts
{
openclawGatewayUrl: process.env.OPENCLAW_GATEWAY_URL || 'ws://127.0.0.1:18789',
openclawGatewayToken: process.env.OPENCLAW_GATEWAY_TOKEN || '',
}
8.2 SSE 流式 API 端点
前端调用 POST /napi/ai/chat-stream,后端转发到 OpenClaw Gateway 并代理 SSE 流:
typescript
// server/routes/napi/ai/chat-stream.post.ts
export default defineEventHandler(async (event) => {
const { userId, sessionId, query, context, agentId } = await readBody(event)
// 1. 从请求头提取用户 JWT Token(有时效性,不持久化)
const authToken = getHeader(event, 'authorization')?.replace('Bearer ', '')
// 2. 生成 Session Key 和 Agent ID
const resolvedAgentId = resolveOpenClawAgentId(Number(userId), agentId)
const sessionKey = generateSessionKey(userId, sessionId, resolvedAgentId)
// 3. 设置 SSE 响应头
setHeader(event, 'Content-Type', 'text/event-stream')
// 4. 创建可读流,内部调用 OpenClaw
const stream = new ReadableStream({
async start(controller) {
await sendOpenClawMessage({
userId, projectId, sessionKey, message, agentId, authToken,
callbacks: {
onDelta: (data) => sendSSE({ content: data.content, ... }),
onCompleted: (data) => { sendSSE({ finishReason: ... }); closeStream() },
onError: (error) => { sendSSE({ content: error.message }); closeStream() },
},
})
},
})
return sendStream(event, stream)
})
流程:前端 SSE → Nuxt API Route → OpenClaw Gateway HTTP → Agent 处理 → 流式返回。
8.3 与 OpenClaw Gateway 通信
typescript
export async function sendOpenClawMessage(options) {
// 1. 确保 Agent 已创建(首次自动创建)
await ensureOpenClawAgent(agentId)
// 2. 构建请求体(Responses API 格式)
const requestBody = {
model: `openclaw/${agentId}`, // 模型名称 = openclaw/ + Agent ID
input: message, // 用户输入
instructions: systemMessage, // 动态系统指令
stream: true, // 启用流式输出
user: sessionKey, // 会话标识
metadata, // 业务上下文
}
// 3. POST 请求,携带 Gateway Token + Agent ID + Session Key
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${gatewayToken}`,
'x-openclaw-agent-id': agentId,
'x-openclaw-session-key': sessionKey,
},
body: JSON.stringify(requestBody),
signal: AbortSignal.timeout(10 * 60 * 1000), // 10 分钟超时
})
// 4. 读取 SSE 流并解析
const reader = response.body.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
// 解析 data: {...}\n\n 格式的 SSE 事件
// → 提取 content / reasoning_content / finishReason
}
}
关键 Header:
| Header | 说明 |
|---|---|
Authorization: Bearer {gatewayToken} |
Gateway 层鉴权 |
x-openclaw-agent-id |
指定目标 Agent |
x-openclaw-session-key |
会话标识,用于上下文连续性 |
8.4 SSE 流解析
模型返回的事件有多种格式,需要统一解析:
typescript
export function parseOpenClawStreamChunk(json: Record<string, any>) {
// OpenAI Responses API 格式:response.output_text.delta
if (json.type === 'response.output_text.delta') {
return { content: json.delta }
}
// 推理内容增量
if (json.type?.startsWith('response.reasoning') && json.type.endsWith('.delta')) {
return { reasoning_content: json.delta }
}
// 完成事件
if (json.type === 'response.completed') {
return { finishReason: json.response?.status === 'incomplete' ? 'length' : 'stop', done: true }
}
// 兼容 OpenAI Chat Completions 格式(其他 Provider)
const choice = json.choices?.[0]
if (choice?.delta?.content) return { content: choice.delta.content }
if (choice?.delta?.reasoning_content) return { reasoning_content: choice.delta.reasoning_content }
if (choice?.finish_reason) return { finishReason: choice.finish_reason, done: true }
return {}
}
兼容两种流式格式 :OpenAI Responses API(response.output_text.delta)和 Chat Completions API(choices[0].delta.content),因为不同 Provider 可能返回不同格式。
九、主动问询 --- Agent 主动触达用户
这是业务系统的特色功能:AI Agent 不只是被动应答,还能主动向用户发起问询。
9.1 触发时机
在 System Message 中约定了使用场景:
- AI 发现了需要用户关注的问题(任务逾期、数据异常)
- 用户要求 "主动跟我沟通"、"有问题通知我"
- AI 需要用户做出决定或提供更多信息
9.2 API 调用
bash
curl -X POST "{apiHost}/api/task/proactive/process/v2/requireInteraction" \
-H "Content-Type: application/json" \
-d '{
"taskName": "任务逾期提醒",
"from": "openclaw",
"userId": ${userId},
"projectId": ${projectId},
"interaction": {
"interactionType": "openclaw",
"interactionUserId": ${userId},
"messages": [{
"role": "assistant",
"content": "您有 3 个任务已逾期超过 3 天,需要确认是否延期或关闭..."
}]
}
}'
9.3 用户回复后的上下文拼接
当用户在业务系统前端回复了 Agent 的问询,服务端会自动拼接对话历史:
typescript
// chat-stream.post.ts 中的上下文拼接逻辑
if (context?.interactionType === 'openclaw' && Array.isArray(context?.messages)) {
const historyParts = context.messages.map(msg =>
`${msg.role === 'assistant' ? '你之前的留言' : '用户'}: ${msg.content}`
)
contextualMessage = `【对话上下文 - 主动问询】
${historyParts.join('\n')}
【用户的最新回复】
${query}
请结合上述对话历史理解上下文,回复用户的这条消息。
如果用户已经充分回复了你的问题,并且你也没有其他要追问的,
请在回复完本条消息后,调用主动问询的完成接口,将本次交互标记为已完成。`
}
这个设计解决了 Agent 的 "失忆"问题------不同 Session 之间 Agent 不记得之前的对话,通过拼接历史消息来恢复上下文。
十、完整请求链路
以一个 "查看我的待办任务" 为例:
css
1. 用户在 Web 前端输入 "帮我看看我有哪些待办任务"
↓
2. 前端 POST /napi/ai/chat-stream
Body: { userId: 21, sessionId: "abc", query: "帮我看看我有哪些待办任务",
context: { projectId: 123 } }
Headers: { Authorization: "Bearer <user_jwt>" }
↓
3. Nuxt API Route 提取 JWT token,生成 sessionKey
构建 System Message(注入 apiHost, userId, projectId, authToken)
↓
4. POST http://127.0.0.1:18789/v1/responses
Body: {
model: "openclaw/user_21",
input: "帮我看看我有哪些待办任务",
instructions: "<System Message>",
stream: true,
user: "agent:user_21:user_21:session_abc",
metadata: { userId: "21", apiHost: "https://api.xxx.com", authToken: "<jwt>" }
}
Headers: {
Authorization: "Bearer <gateway_token>",
x-openclaw-agent-id: "user_21",
x-openclaw-session-key: "agent:user_21:user_21:session_abc"
}
↓
5. OpenClaw Gateway 路由到 Agent user_21
注入 instructions 和 metadata 到 Agent 上下文
↓
6. Agent 识别意图:查询任务
自动加载 task-api skill
执行 curl 命令:
curl "https://api.xxx.com/api/project/issueList.do?projectIdList=123&assignedToId=21" \
-H "Authorization: Bearer <jwt>"
↓
7. 业务 API 返回用户 21 在项目 123 的任务列表
↓
8. Agent 分析数据,生成自然语言回复,流式返回
↓
9. Nuxt API Route 解析 SSE 流 → 转发给前端
↓
10. 前端实时渲染 AI 回复
十一、部署架构
scss
┌─────────────────────────────────────────────────────┐
│ 服务器 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Nuxt 3 │ │ OpenClaw │ │ Docker Engine │ │
│ │ (Node) │ │ Gateway │ │ ┌────────────┐ │ │
│ │ :3000 │ │ :18789 │ │ │ sandbox_21 │ │ │
│ └─────┬─────┘ └────┬─────┘ │ ├────────────┤ │ │
│ │ │ │ │ sandbox_144 │ │ │
│ └──────┬───────┘ │ ├────────────┤ │ │
│ │ │ │ sandbox_149 │ │ │
│ │ │ └────────────┘ │ │
│ │ └──────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────────────────┐ │
│ │ 业务 REST API │ │
│ └────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
│ │
▼ ▼
┌────────────┐ ┌──────────────────┐
│ Ollama │ │ 云端模型 API │
│ (本地 GPU) │ │ 阿里百炼/DeepSeek │
│ :11434 │ │ 通义千问/Kimi │
└────────────┘ └──────────────────┘
资源规划建议:
- OpenClaw Gateway 本身轻量,1-2 核即可
- 每个 Agent Sandbox 运行在 Docker 容器中,内存按 512MB-1GB 预估
- 本地 Ollama 服务建议独立部署在有 GPU 的机器上
- Nuxt 服务和 Gateway 可以部署在同一台机器上,通过 loopback 通信
十二、总结
核心设计决策
| 决策 | 选择 | 理由 |
|---|---|---|
| Agent 粒度 | 一用户一 Agent | 数据隔离、上下文独立、权限可控 |
| 数据访问 | 仅通过 REST API | 安全审计、权限复用、禁止直连 DB |
| 鉴权机制 | JWT Token 透传 | 用户级权限隔离、时效性保证 |
| 知识注入 | System Message + Skill | 动态上下文 + 静态 API 文档分工 |
| 多通道 | binding 路由映射 | channel+accountId → agentId 自动分发 |
| 模型策略 | 主模型 + Fallback 链 | 保证可用性,成本可控 |
| 会话管理 | 结构化 SessionKey | 同时编码 agent/user/session 信息 |
关键文件清单
| 文件 | 作用 |
|---|---|
~/.openclaw/openclaw.json |
OpenClaw 全局配置(模型、通道、沙箱) |
server/utils/openclaw.ts |
Nuxt 侧集成代码(消息发送、流解析、Agent 管理) |
server/routes/napi/ai/chat-stream.post.ts |
SSE 流式 API 端点 |
~/.openclaw/skills/*/SKILL.md |
业务 API Skill 定义 |
nuxt.config.ts |
Gateway URL / Token 环境变量 |
扩展方向
- 定时巡检:让 Agent 定时检查任务逾期、风险异常,触发主动问询
- 多 Agent 协作:复杂任务拆分给多个 Agent 并行处理
- Agent 能力进化 :基于用户反馈和使用数据,自动优化 Agent 行为(Skill 中已有
self-improving-agent的种子)中间省略的部分,都是这个方案中已经验证落地的模块。