openclaw-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +29 -0
- package/packs/default/faq.yaml +8 -0
- package/packs/default/intents.yaml +19 -0
- package/packs/default/pack.yaml +12 -0
- package/packs/default/policies.yaml +1 -0
- package/packs/default/scenarios.yaml +1 -0
- package/packs/default/synonyms.yaml +1 -0
- package/packs/default/templates.yaml +16 -0
- package/packs/default/tools.yaml +1 -0
- package/readme.md +1219 -0
- package/src/auth.ts +24 -0
- package/src/better-sqlite3.d.ts +17 -0
- package/src/config.ts +63 -0
- package/src/core/matcher.ts +214 -0
- package/src/core/normalizer.test.ts +37 -0
- package/src/core/normalizer.ts +183 -0
- package/src/core/pack-loader.ts +97 -0
- package/src/core/reply-engine.test.ts +76 -0
- package/src/core/reply-engine.ts +256 -0
- package/src/core/request-adapter.ts +65 -0
- package/src/core/session-store.ts +48 -0
- package/src/core/stream-renderer.ts +237 -0
- package/src/core/tool-engine.ts +60 -0
- package/src/debug-log.ts +211 -0
- package/src/index.ts +23 -0
- package/src/openai.ts +79 -0
- package/src/response-api.ts +107 -0
- package/src/routes/admin.ts +32 -0
- package/src/routes/chat-completions.ts +173 -0
- package/src/routes/health.ts +7 -0
- package/src/routes/models.ts +21 -0
- package/src/routes/request-validation.ts +33 -0
- package/src/routes/responses.ts +182 -0
- package/src/routes/tasks.ts +138 -0
- package/src/runtime-stats.ts +80 -0
- package/src/server.test.ts +776 -0
- package/src/server.ts +108 -0
- package/src/tasks/chat-integration.ts +70 -0
- package/src/tasks/service.ts +320 -0
- package/src/tasks/store.test.ts +183 -0
- package/src/tasks/store.ts +602 -0
- package/src/tasks/time-parser.test.ts +94 -0
- package/src/tasks/time-parser.ts +610 -0
- package/src/tasks/timezone.ts +171 -0
- package/src/tasks/types.ts +128 -0
- package/src/types.ts +202 -0
- package/src/weather/chat-integration.ts +56 -0
- package/src/weather/location-catalog.ts +166 -0
- package/src/weather/open-meteo-provider.ts +221 -0
- package/src/weather/parser.test.ts +23 -0
- package/src/weather/parser.ts +102 -0
- package/src/weather/service.test.ts +54 -0
- package/src/weather/service.ts +188 -0
- package/src/weather/types.ts +56 -0
package/readme.md
ADDED
|
@@ -0,0 +1,1219 @@
|
|
|
1
|
+
# openclaw-server 设计方案
|
|
2
|
+
|
|
3
|
+
## 1. 项目定位
|
|
4
|
+
|
|
5
|
+
`openclaw-server` 不是一个真正的大模型服务,而是一个“拟态 AI 服务”。
|
|
6
|
+
|
|
7
|
+
它的目标是:
|
|
8
|
+
|
|
9
|
+
- 使用 TypeScript 开发一个独立后台服务
|
|
10
|
+
- 以 OpenAI 兼容接口的形式给 OpenClaw 提供模型能力
|
|
11
|
+
- 不调用任何真实 AI API
|
|
12
|
+
- 通过预制回复、规则匹配、场景状态机、模板渲染、受控工具调用,尽量做出“像 AI 一样能对话”的效果
|
|
13
|
+
|
|
14
|
+
它的本质不是“通用智能”,而是“可控的、场景化的、可运营的智能拟态层”。
|
|
15
|
+
|
|
16
|
+
## 2. 设计目标与硬约束
|
|
17
|
+
|
|
18
|
+
### 2.0 硬约束
|
|
19
|
+
|
|
20
|
+
- 不改动任何 OpenClaw 源代码
|
|
21
|
+
- 不修改 `src/` 下的 provider、gateway、protocol、agent 逻辑
|
|
22
|
+
- 不新增 OpenClaw 内置 provider,不注册新的 OpenClaw 原生 API,不 fork OpenClaw 协议
|
|
23
|
+
- 不修改 `pnpm-workspace.yaml`、根 `package.json`、构建链路来“迁就” `openclaw-server`
|
|
24
|
+
- OpenClaw 侧只允许做部署和配置变更,例如 `openclaw.json`、环境变量、启动脚本
|
|
25
|
+
- `openclaw-server` 必须兼容 OpenClaw 已有的 provider 调用方式,而不是反过来要求 OpenClaw 适配它
|
|
26
|
+
|
|
27
|
+
### 2.1 目标
|
|
28
|
+
|
|
29
|
+
- 让 OpenClaw 可以把 `openclaw-server` 当成一个自定义模型提供商使用
|
|
30
|
+
- 支持多轮对话
|
|
31
|
+
- 支持流式输出
|
|
32
|
+
- 支持预制知识包和场景包
|
|
33
|
+
- 支持有限的工具调用能力
|
|
34
|
+
- 支持运营人员持续扩充“像 AI 一样”的回复库
|
|
35
|
+
- 通过服务端逻辑和知识包迭代升级能力,不依赖 OpenClaw 代码变更
|
|
36
|
+
|
|
37
|
+
### 2.2 非目标
|
|
38
|
+
|
|
39
|
+
- 不追求开放域推理能力
|
|
40
|
+
- 不追求代码生成、复杂规划、数学推理等真实大模型能力
|
|
41
|
+
- 不保证对任意陌生问题都有高质量回答
|
|
42
|
+
- 不做“假装自己是通用 AGI”的产品定位
|
|
43
|
+
|
|
44
|
+
## 3. 设计依据
|
|
45
|
+
|
|
46
|
+
本方案基于当前仓库中 OpenClaw 已有的 provider 接入方式设计,核心依据如下:
|
|
47
|
+
|
|
48
|
+
- `docs/gateway/local-models.md`
|
|
49
|
+
说明 OpenClaw 已支持接入 OpenAI 兼容的本地或自定义服务
|
|
50
|
+
- `docs/providers/litellm.md`
|
|
51
|
+
说明 OpenClaw 可以通过统一兼容协议接入代理网关
|
|
52
|
+
- `src/commands/onboard-auth.config-shared.ts`
|
|
53
|
+
说明自定义 provider 可以通过 `models.providers` 合并进入模型配置
|
|
54
|
+
- `src/agents/model-auth.ts`
|
|
55
|
+
说明 OpenClaw 会从 `models.providers.<provider>` 解析 `baseUrl`、`apiKey`
|
|
56
|
+
- `src/agents/model-compat.ts`
|
|
57
|
+
说明非 OpenAI 官方 `openai-completions` 端点会被视为兼容端点,`developer` role 不应作为强依赖
|
|
58
|
+
- `src/agents/custom-api-registry.ts`
|
|
59
|
+
说明技术上可以注册原生自定义 API,但这需要 OpenClaw 侧配合,不符合“零源码改动”约束
|
|
60
|
+
|
|
61
|
+
因此,在“不改动任何 OpenClaw 代码”的前提下,`openclaw-server` 的接入方式必须是:
|
|
62
|
+
|
|
63
|
+
- 完全适配 OpenClaw 已存在的自定义 provider 机制
|
|
64
|
+
- 通过 `models.providers.openclaw-server` 接入 OpenClaw
|
|
65
|
+
- 以 OpenAI 兼容 HTTP 接口为边界,不要求 OpenClaw 增加新协议
|
|
66
|
+
- 所有新增能力都在 `openclaw-server` 内部完成
|
|
67
|
+
|
|
68
|
+
## 4. 推荐总体方案
|
|
69
|
+
|
|
70
|
+
### 4.1 推荐接入模式
|
|
71
|
+
|
|
72
|
+
推荐 `openclaw-server` 第一阶段提供以下接口:
|
|
73
|
+
|
|
74
|
+
- `GET /healthz`
|
|
75
|
+
- `GET /v1/models`
|
|
76
|
+
- `POST /v1/chat/completions`
|
|
77
|
+
|
|
78
|
+
按需可补充以下接口,但它们不是 OpenClaw 零改动接入的前提:
|
|
79
|
+
|
|
80
|
+
- `POST /v1/responses`
|
|
81
|
+
- `POST /admin/packs/reload`
|
|
82
|
+
- `GET /admin/stats`
|
|
83
|
+
|
|
84
|
+
### 4.2 推荐协议
|
|
85
|
+
|
|
86
|
+
第一阶段优先实现 `openai-completions`,原因:
|
|
87
|
+
|
|
88
|
+
- OpenClaw 已支持用自定义 `baseUrl` 对接 OpenAI 兼容端点
|
|
89
|
+
- 不需要修改 OpenClaw 源码
|
|
90
|
+
- 实现复杂度最低
|
|
91
|
+
- 支持流式输出
|
|
92
|
+
- 便于后续接入其他客户端
|
|
93
|
+
|
|
94
|
+
### 4.3 推荐产品边界
|
|
95
|
+
|
|
96
|
+
`openclaw-server` 不应一开始就尝试覆盖“任何问题”。
|
|
97
|
+
|
|
98
|
+
推荐从闭域场景开始:
|
|
99
|
+
|
|
100
|
+
- 问候和闲聊
|
|
101
|
+
- OpenClaw 产品问答
|
|
102
|
+
- 常见配置指导
|
|
103
|
+
- 常见错误排查
|
|
104
|
+
- 常见命令解释
|
|
105
|
+
- 固定业务流程问答
|
|
106
|
+
- 限定任务的脚本式交互
|
|
107
|
+
|
|
108
|
+
也就是说,先做“高覆盖的封闭场景助手”,而不是“低质量的通用助手”。
|
|
109
|
+
|
|
110
|
+
## 5. 总体架构
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
OpenClaw
|
|
114
|
+
-> models.providers.openclaw-server
|
|
115
|
+
-> POST /v1/chat/completions
|
|
116
|
+
|
|
117
|
+
openclaw-server
|
|
118
|
+
-> API Compatibility Layer
|
|
119
|
+
-> Request Normalizer
|
|
120
|
+
-> Session Store
|
|
121
|
+
-> Intent Router
|
|
122
|
+
-> Scenario State Machine
|
|
123
|
+
-> Retrieval and Template Engine
|
|
124
|
+
-> Tool Decision Layer
|
|
125
|
+
-> Stream Renderer
|
|
126
|
+
-> Observability and Admin
|
|
127
|
+
|
|
128
|
+
Knowledge Packs
|
|
129
|
+
-> intents
|
|
130
|
+
-> scenarios
|
|
131
|
+
-> templates
|
|
132
|
+
-> faq
|
|
133
|
+
-> tools
|
|
134
|
+
-> policies
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 5.1 核心思想
|
|
138
|
+
|
|
139
|
+
服务端不“生成”答案,而是“选择、组合、渲染、串联”答案。
|
|
140
|
+
|
|
141
|
+
整体流程分为 7 层:
|
|
142
|
+
|
|
143
|
+
1. 协议兼容层
|
|
144
|
+
2. 请求归一化层
|
|
145
|
+
3. 会话状态层
|
|
146
|
+
4. 意图识别层
|
|
147
|
+
5. 场景编排层
|
|
148
|
+
6. 文本渲染层
|
|
149
|
+
7. 输出与观测层
|
|
150
|
+
|
|
151
|
+
## 6. 核心模块设计
|
|
152
|
+
|
|
153
|
+
### 6.1 API Compatibility Layer
|
|
154
|
+
|
|
155
|
+
职责:
|
|
156
|
+
|
|
157
|
+
- 接收 OpenAI 兼容请求
|
|
158
|
+
- 校验请求结构
|
|
159
|
+
- 转换成内部统一格式
|
|
160
|
+
- 输出 OpenAI 兼容响应
|
|
161
|
+
- 支持 SSE 流式返回
|
|
162
|
+
|
|
163
|
+
建议支持的请求字段:
|
|
164
|
+
|
|
165
|
+
- `model`
|
|
166
|
+
- `messages`
|
|
167
|
+
- `stream`
|
|
168
|
+
- `temperature`
|
|
169
|
+
- `user`
|
|
170
|
+
- `max_tokens`
|
|
171
|
+
- `tools`
|
|
172
|
+
- `tool_choice`
|
|
173
|
+
|
|
174
|
+
建议第一阶段忽略或固定处理的字段:
|
|
175
|
+
|
|
176
|
+
- `temperature`
|
|
177
|
+
- `top_p`
|
|
178
|
+
- `presence_penalty`
|
|
179
|
+
- `frequency_penalty`
|
|
180
|
+
- `logprobs`
|
|
181
|
+
|
|
182
|
+
原因:
|
|
183
|
+
|
|
184
|
+
- 这是拟态服务,不是真实采样模型
|
|
185
|
+
- 这些参数不应影响核心业务逻辑
|
|
186
|
+
|
|
187
|
+
### 6.2 Request Normalizer
|
|
188
|
+
|
|
189
|
+
职责:
|
|
190
|
+
|
|
191
|
+
- 提取系统提示、历史对话、当前用户问题
|
|
192
|
+
- 识别语言
|
|
193
|
+
- 归一化标点、空白、数字、时间表达
|
|
194
|
+
- 提取关键词、命令词、实体词
|
|
195
|
+
- 生成查询指纹
|
|
196
|
+
|
|
197
|
+
输出统一结构:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
type NormalizedTurn = {
|
|
201
|
+
requestId: string;
|
|
202
|
+
sessionId: string;
|
|
203
|
+
model: string;
|
|
204
|
+
locale: "zh-CN" | "en-US" | "mixed";
|
|
205
|
+
systemPrompt: string[];
|
|
206
|
+
history: Array<{ role: "user" | "assistant" | "tool"; text: string }>;
|
|
207
|
+
userText: string;
|
|
208
|
+
tools: ClientToolDef[];
|
|
209
|
+
toolChoice?: "auto" | "none" | "required" | { name: string };
|
|
210
|
+
features: {
|
|
211
|
+
keywords: string[];
|
|
212
|
+
commands: string[];
|
|
213
|
+
entities: string[];
|
|
214
|
+
isQuestion: boolean;
|
|
215
|
+
isGreeting: boolean;
|
|
216
|
+
isHelpRequest: boolean;
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 6.3 Session Store
|
|
222
|
+
|
|
223
|
+
职责:
|
|
224
|
+
|
|
225
|
+
- 维护每个会话的上下文状态
|
|
226
|
+
- 保存最近若干轮对话
|
|
227
|
+
- 保存当前场景节点
|
|
228
|
+
- 保存已提取的槽位数据
|
|
229
|
+
- 保存命中的知识包版本
|
|
230
|
+
|
|
231
|
+
建议第一阶段使用:
|
|
232
|
+
|
|
233
|
+
- 内存缓存保存热会话
|
|
234
|
+
- JSONL 持久化会话日志
|
|
235
|
+
|
|
236
|
+
第二阶段可升级:
|
|
237
|
+
|
|
238
|
+
- SQLite 持久化
|
|
239
|
+
- 支持多实例共享会话
|
|
240
|
+
|
|
241
|
+
会话结构建议:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
type SessionState = {
|
|
245
|
+
sessionId: string;
|
|
246
|
+
locale: string;
|
|
247
|
+
activeScenarioId?: string;
|
|
248
|
+
activeNodeId?: string;
|
|
249
|
+
slots: Record<string, string>;
|
|
250
|
+
lastIntent?: string;
|
|
251
|
+
lastReplyId?: string;
|
|
252
|
+
turnCount: number;
|
|
253
|
+
recentHistory: Array<{ role: string; text: string; ts: number }>;
|
|
254
|
+
debug: {
|
|
255
|
+
lastMatchedPack?: string;
|
|
256
|
+
lastMatchedIntent?: string;
|
|
257
|
+
lastScore?: number;
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 6.4 Intent Router
|
|
263
|
+
|
|
264
|
+
职责:
|
|
265
|
+
|
|
266
|
+
- 将用户输入映射到某个意图
|
|
267
|
+
- 给出候选意图和置信分
|
|
268
|
+
- 决定进入 FAQ、闲聊、流程型场景还是工具调用型场景
|
|
269
|
+
|
|
270
|
+
推荐采用混合匹配:
|
|
271
|
+
|
|
272
|
+
- 精确短语匹配
|
|
273
|
+
- 关键词匹配
|
|
274
|
+
- 正则匹配
|
|
275
|
+
- 词组倒排索引
|
|
276
|
+
- 简单相似度评分
|
|
277
|
+
- 历史场景加权
|
|
278
|
+
|
|
279
|
+
建议打分公式:
|
|
280
|
+
|
|
281
|
+
```text
|
|
282
|
+
score =
|
|
283
|
+
0.35 * exact_or_regex_match
|
|
284
|
+
+ 0.25 * keyword_overlap
|
|
285
|
+
+ 0.20 * scenario_context_match
|
|
286
|
+
+ 0.10 * slot_match
|
|
287
|
+
+ 0.10 * locale_match
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
意图路由结果:
|
|
291
|
+
|
|
292
|
+
- `faq`
|
|
293
|
+
- `smalltalk`
|
|
294
|
+
- `workflow`
|
|
295
|
+
- `tool_call`
|
|
296
|
+
- `fallback`
|
|
297
|
+
|
|
298
|
+
### 6.5 Scenario State Machine
|
|
299
|
+
|
|
300
|
+
职责:
|
|
301
|
+
|
|
302
|
+
- 管理多轮固定流程
|
|
303
|
+
- 处理“先问 A,再问 B,再给结果”的会话
|
|
304
|
+
- 把看起来像 AI 的多轮交互拆成可控流程
|
|
305
|
+
|
|
306
|
+
典型场景:
|
|
307
|
+
|
|
308
|
+
- 首次欢迎
|
|
309
|
+
- 配置引导
|
|
310
|
+
- 故障排查
|
|
311
|
+
- 收集参数
|
|
312
|
+
- 推荐下一步命令
|
|
313
|
+
- 引导用户执行某个 OpenClaw 工具或命令
|
|
314
|
+
|
|
315
|
+
状态机的核心价值:
|
|
316
|
+
|
|
317
|
+
- 避免每一轮都重新“猜”上下文
|
|
318
|
+
- 能稳定输出高一致性结果
|
|
319
|
+
- 更适合运营配置和回放排查
|
|
320
|
+
|
|
321
|
+
### 6.6 Retrieval and Template Engine
|
|
322
|
+
|
|
323
|
+
职责:
|
|
324
|
+
|
|
325
|
+
- 从知识包中检索候选答案
|
|
326
|
+
- 按场景和槽位渲染模板
|
|
327
|
+
- 根据用户语气和语言输出不同版本
|
|
328
|
+
|
|
329
|
+
推荐回答来源优先级:
|
|
330
|
+
|
|
331
|
+
1. 当前场景节点模板
|
|
332
|
+
2. FAQ 精确匹配
|
|
333
|
+
3. FAQ 模糊匹配
|
|
334
|
+
4. 小闲聊模板
|
|
335
|
+
5. 兜底模板
|
|
336
|
+
|
|
337
|
+
模板引擎建议支持:
|
|
338
|
+
|
|
339
|
+
- 变量插值
|
|
340
|
+
- 条件片段
|
|
341
|
+
- 随机同义变体
|
|
342
|
+
- 语言分支
|
|
343
|
+
- 回复后动作
|
|
344
|
+
|
|
345
|
+
模板示例:
|
|
346
|
+
|
|
347
|
+
```yaml
|
|
348
|
+
id: troubleshooting.gateway_down.reply
|
|
349
|
+
locale: zh-CN
|
|
350
|
+
variants:
|
|
351
|
+
- "看起来网关当前没有正常运行。你可以先执行 `openclaw gateway run`,然后再检查一次状态。"
|
|
352
|
+
- "当前更像是网关未启动的问题。先运行 `openclaw gateway run`,再确认端口和日志。"
|
|
353
|
+
postActions:
|
|
354
|
+
- suggest_intent: gateway_health_check
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### 6.7 Tool Decision Layer
|
|
358
|
+
|
|
359
|
+
职责:
|
|
360
|
+
|
|
361
|
+
- 当 OpenClaw 传入 `tools` 时,决定是否返回工具调用
|
|
362
|
+
- 限制只有预定义场景允许触发工具
|
|
363
|
+
- 保证工具参数来自明确规则,不来自自由生成
|
|
364
|
+
|
|
365
|
+
这是拟态服务里最重要的安全点之一。
|
|
366
|
+
|
|
367
|
+
原则:
|
|
368
|
+
|
|
369
|
+
- 工具调用必须是白名单
|
|
370
|
+
- 参数必须经过 schema 校验
|
|
371
|
+
- 不允许“自由拼接”未知工具名
|
|
372
|
+
- 不允许根据模糊意图直接执行高风险工具
|
|
373
|
+
|
|
374
|
+
推荐策略:
|
|
375
|
+
|
|
376
|
+
- 第一阶段默认只返回文本,不主动调用工具
|
|
377
|
+
- 第二阶段仅开放少量安全工具
|
|
378
|
+
- 高风险工具永远要求明确命中场景和参数
|
|
379
|
+
|
|
380
|
+
### 6.8 Stream Renderer
|
|
381
|
+
|
|
382
|
+
职责:
|
|
383
|
+
|
|
384
|
+
- 把最终文本拆成流式 chunk 输出
|
|
385
|
+
- 模拟真实 AI 的逐步回复体验
|
|
386
|
+
- 控制首包延迟和 chunk 大小
|
|
387
|
+
|
|
388
|
+
建议实现:
|
|
389
|
+
|
|
390
|
+
- 首包延迟 100ms 到 300ms
|
|
391
|
+
- 每个 chunk 8 到 32 字符
|
|
392
|
+
- 标点优先切片
|
|
393
|
+
- 对工具调用场景可直接一次性返回结构化结果
|
|
394
|
+
|
|
395
|
+
### 6.9 Observability and Admin
|
|
396
|
+
|
|
397
|
+
职责:
|
|
398
|
+
|
|
399
|
+
- 记录命中率、兜底率、场景转移、工具调用数
|
|
400
|
+
- 输出结构化日志
|
|
401
|
+
- 支持热加载知识包
|
|
402
|
+
- 支持对低命中问题做运营回补
|
|
403
|
+
|
|
404
|
+
建议指标:
|
|
405
|
+
|
|
406
|
+
- `requests_total`
|
|
407
|
+
- `intent_match_rate`
|
|
408
|
+
- `fallback_rate`
|
|
409
|
+
- `scenario_continue_rate`
|
|
410
|
+
- `tool_call_rate`
|
|
411
|
+
- `unknown_query_topn`
|
|
412
|
+
|
|
413
|
+
## 7. 知识包设计
|
|
414
|
+
|
|
415
|
+
“预制大量 AI 返回”的关键不在代码,而在知识包体系。
|
|
416
|
+
|
|
417
|
+
建议把知识包拆成以下文件:
|
|
418
|
+
|
|
419
|
+
```text
|
|
420
|
+
openclaw-server/
|
|
421
|
+
packs/
|
|
422
|
+
default/
|
|
423
|
+
pack.json
|
|
424
|
+
intents.yaml
|
|
425
|
+
scenarios.yaml
|
|
426
|
+
templates.yaml
|
|
427
|
+
faq.yaml
|
|
428
|
+
tools.yaml
|
|
429
|
+
policies.yaml
|
|
430
|
+
synonyms.yaml
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 7.1 intents.yaml
|
|
434
|
+
|
|
435
|
+
职责:
|
|
436
|
+
|
|
437
|
+
- 定义意图名
|
|
438
|
+
- 提供关键词、正则、例句、优先级
|
|
439
|
+
|
|
440
|
+
示例:
|
|
441
|
+
|
|
442
|
+
```yaml
|
|
443
|
+
- id: greeting
|
|
444
|
+
locale: zh-CN
|
|
445
|
+
priority: 100
|
|
446
|
+
keywords: ["你好", "在吗", "嗨", "hello", "hi"]
|
|
447
|
+
examples: ["你好", "你在吗", "hi"]
|
|
448
|
+
|
|
449
|
+
- id: gateway_status_help
|
|
450
|
+
locale: zh-CN
|
|
451
|
+
priority: 90
|
|
452
|
+
keywords: ["网关", "gateway", "状态", "启动失败", "日志"]
|
|
453
|
+
regex:
|
|
454
|
+
- "(gateway|网关).*(状态|启动|失败|日志)"
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### 7.2 faq.yaml
|
|
458
|
+
|
|
459
|
+
职责:
|
|
460
|
+
|
|
461
|
+
- 承载高频问答
|
|
462
|
+
- 适合单轮、稳定、标准答案
|
|
463
|
+
|
|
464
|
+
示例:
|
|
465
|
+
|
|
466
|
+
```yaml
|
|
467
|
+
- id: faq.install.local
|
|
468
|
+
intents: ["install_help"]
|
|
469
|
+
questionPatterns:
|
|
470
|
+
- "怎么安装"
|
|
471
|
+
- "如何部署"
|
|
472
|
+
answerTemplate: install.guide.basic
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### 7.3 scenarios.yaml
|
|
476
|
+
|
|
477
|
+
职责:
|
|
478
|
+
|
|
479
|
+
- 定义多轮状态机
|
|
480
|
+
- 适合引导式交互
|
|
481
|
+
|
|
482
|
+
示例:
|
|
483
|
+
|
|
484
|
+
```yaml
|
|
485
|
+
- id: setup.gateway
|
|
486
|
+
entryIntents: ["setup_gateway"]
|
|
487
|
+
nodes:
|
|
488
|
+
- id: ask_platform
|
|
489
|
+
replyTemplate: setup.gateway.ask_platform
|
|
490
|
+
transitions:
|
|
491
|
+
- whenIntent: setup_platform_linux
|
|
492
|
+
to: linux_steps
|
|
493
|
+
- whenIntent: setup_platform_windows
|
|
494
|
+
to: windows_steps
|
|
495
|
+
|
|
496
|
+
- id: linux_steps
|
|
497
|
+
replyTemplate: setup.gateway.linux_steps
|
|
498
|
+
end: true
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### 7.4 templates.yaml
|
|
502
|
+
|
|
503
|
+
职责:
|
|
504
|
+
|
|
505
|
+
- 管理所有回复模板
|
|
506
|
+
- 分语言、分语气、分场景
|
|
507
|
+
|
|
508
|
+
### 7.5 tools.yaml
|
|
509
|
+
|
|
510
|
+
职责:
|
|
511
|
+
|
|
512
|
+
- 定义允许调用的工具
|
|
513
|
+
- 绑定对应场景
|
|
514
|
+
- 约束参数来源
|
|
515
|
+
|
|
516
|
+
示例:
|
|
517
|
+
|
|
518
|
+
```yaml
|
|
519
|
+
- id: get_gateway_health
|
|
520
|
+
toolName: gateway.health
|
|
521
|
+
allowedIntents: ["gateway_status_help"]
|
|
522
|
+
argMap:
|
|
523
|
+
target: "$session.defaultTarget"
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### 7.6 policies.yaml
|
|
527
|
+
|
|
528
|
+
职责:
|
|
529
|
+
|
|
530
|
+
- 约束不可回答的问题
|
|
531
|
+
- 约束敏感操作
|
|
532
|
+
- 约束不确定回答
|
|
533
|
+
|
|
534
|
+
示例策略:
|
|
535
|
+
|
|
536
|
+
- 未命中高置信意图时,不编造事实
|
|
537
|
+
- 涉及删除、重置、密钥泄露的操作时,只给出确认指引,不直接触发工具
|
|
538
|
+
- 对未知问题使用明确兜底模板
|
|
539
|
+
|
|
540
|
+
## 8. 响应生成策略
|
|
541
|
+
|
|
542
|
+
### 8.1 文本响应模式
|
|
543
|
+
|
|
544
|
+
适用于:
|
|
545
|
+
|
|
546
|
+
- 闲聊
|
|
547
|
+
- FAQ
|
|
548
|
+
- 配置说明
|
|
549
|
+
- 错误排查建议
|
|
550
|
+
|
|
551
|
+
生成方式:
|
|
552
|
+
|
|
553
|
+
- 先检索最相关模板
|
|
554
|
+
- 再插入槽位和上下文
|
|
555
|
+
- 最后做风格微调
|
|
556
|
+
|
|
557
|
+
### 8.2 工具调用模式
|
|
558
|
+
|
|
559
|
+
适用于:
|
|
560
|
+
|
|
561
|
+
- 请求明确
|
|
562
|
+
- 工具可安全执行
|
|
563
|
+
- 参数可由规则确定
|
|
564
|
+
|
|
565
|
+
返回形式:
|
|
566
|
+
|
|
567
|
+
- OpenAI 兼容 `tool_calls`
|
|
568
|
+
|
|
569
|
+
### 8.3 兜底模式
|
|
570
|
+
|
|
571
|
+
适用于:
|
|
572
|
+
|
|
573
|
+
- 无法识别意图
|
|
574
|
+
- 命中分过低
|
|
575
|
+
- 不确定该回答什么
|
|
576
|
+
|
|
577
|
+
推荐兜底原则:
|
|
578
|
+
|
|
579
|
+
- 明确说明能力边界
|
|
580
|
+
- 引导用户换一种问法
|
|
581
|
+
- 给出 2 到 4 个可选问题方向
|
|
582
|
+
|
|
583
|
+
示例:
|
|
584
|
+
|
|
585
|
+
> 我现在更适合回答 OpenClaw 的配置、网关、通道、常见故障和固定流程问题。
|
|
586
|
+
> 你可以继续问我:
|
|
587
|
+
>
|
|
588
|
+
> 1. 如何配置网关
|
|
589
|
+
> 2. 如何查看日志
|
|
590
|
+
> 3. 某个命令怎么用
|
|
591
|
+
> 4. 某个报错怎么排查
|
|
592
|
+
|
|
593
|
+
## 9. 请求处理流程
|
|
594
|
+
|
|
595
|
+
```text
|
|
596
|
+
1. OpenClaw 发送 /v1/chat/completions 请求
|
|
597
|
+
2. openclaw-server 校验 token 和请求 schema
|
|
598
|
+
3. Request Normalizer 提取 userText、history、tools
|
|
599
|
+
4. Session Store 读取会话状态
|
|
600
|
+
5. Intent Router 计算候选意图
|
|
601
|
+
6. Scenario Engine 判断是否在已有流程中
|
|
602
|
+
7. Retrieval Engine 选出模板或 FAQ
|
|
603
|
+
8. Tool Layer 决定返回文本还是 tool_call
|
|
604
|
+
9. Stream Renderer 生成兼容响应
|
|
605
|
+
10. Logger 记录匹配结果和兜底情况
|
|
606
|
+
11. Session Store 更新状态
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
## 10. 对 OpenClaw 的接入方案
|
|
610
|
+
|
|
611
|
+
### 10.0 接入边界
|
|
612
|
+
|
|
613
|
+
允许的事情:
|
|
614
|
+
|
|
615
|
+
- 启动 `openclaw-server`
|
|
616
|
+
- 在 OpenClaw 配置中增加一个自定义 provider
|
|
617
|
+
- 通过环境变量或配置写入 `baseUrl`、`apiKey`、默认模型
|
|
618
|
+
|
|
619
|
+
不允许的事情:
|
|
620
|
+
|
|
621
|
+
- 修改 OpenClaw 的 `src/` 代码
|
|
622
|
+
- 向 OpenClaw 增加新的内置 provider 代码
|
|
623
|
+
- 让 OpenClaw 为 `openclaw-server` 新增私有协议
|
|
624
|
+
- 修改 OpenClaw 的构建、workspace、依赖结构来容纳 `openclaw-server`
|
|
625
|
+
|
|
626
|
+
### 10.1 推荐配置
|
|
627
|
+
|
|
628
|
+
建议在 OpenClaw 中把 `openclaw-server` 当成一个自定义 provider:
|
|
629
|
+
|
|
630
|
+
```json5
|
|
631
|
+
{
|
|
632
|
+
agents: {
|
|
633
|
+
defaults: {
|
|
634
|
+
model: { primary: "openclaw-server/default-assistant" },
|
|
635
|
+
models: {
|
|
636
|
+
"openclaw-server/default-assistant": { alias: "OpenClaw Server" },
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
models: {
|
|
641
|
+
mode: "merge",
|
|
642
|
+
providers: {
|
|
643
|
+
"openclaw-server": {
|
|
644
|
+
baseUrl: "http://127.0.0.1:4318/v1",
|
|
645
|
+
apiKey: "${OPENCLAW_SERVER_API_KEY}",
|
|
646
|
+
api: "openai-completions",
|
|
647
|
+
models: [
|
|
648
|
+
{
|
|
649
|
+
id: "default-assistant",
|
|
650
|
+
name: "OpenClaw Server Default Assistant",
|
|
651
|
+
reasoning: false,
|
|
652
|
+
input: ["text"],
|
|
653
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
654
|
+
contextWindow: 32000,
|
|
655
|
+
maxTokens: 2048,
|
|
656
|
+
},
|
|
657
|
+
],
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### 10.2 为什么用 `openai-completions`
|
|
665
|
+
|
|
666
|
+
原因:
|
|
667
|
+
|
|
668
|
+
- 与 OpenClaw 当前自定义 provider 接入方式最吻合
|
|
669
|
+
- 不改动 OpenClaw 源码,仅使用现有配置能力
|
|
670
|
+
- 可以直接复用 OpenClaw 现有模型选择逻辑
|
|
671
|
+
|
|
672
|
+
### 10.3 兼容注意事项
|
|
673
|
+
|
|
674
|
+
根据 `src/agents/model-compat.ts`,对非官方 OpenAI 端点:
|
|
675
|
+
|
|
676
|
+
- 不应依赖 `developer` role
|
|
677
|
+
- 应重点处理 `system` 和 `user` 消息
|
|
678
|
+
|
|
679
|
+
因此 `openclaw-server` 内部应将:
|
|
680
|
+
|
|
681
|
+
- `system`
|
|
682
|
+
- `developer`
|
|
683
|
+
|
|
684
|
+
统一作为“额外系统上下文”处理。
|
|
685
|
+
|
|
686
|
+
### 10.4 `openclaw-server` 必须兼容的最小行为
|
|
687
|
+
|
|
688
|
+
- 支持 `Authorization: Bearer <token>`
|
|
689
|
+
- 支持 `POST /v1/chat/completions`
|
|
690
|
+
- 支持 `stream=false` 和 `stream=true`
|
|
691
|
+
- 能处理 `system`、`developer`、`user`、`assistant` 历史消息
|
|
692
|
+
- 对 `developer` role 不做强依赖,内部统一折叠到系统上下文
|
|
693
|
+
- 能接受 `tools` 和 `tool_choice`,即使第一阶段只选择性支持
|
|
694
|
+
- 支持 `GET /v1/models`,方便 OpenClaw 或运维侧探活
|
|
695
|
+
- 即使没有真实 token 统计,也应返回兼容的 `usage` 字段,必要时可填 0
|
|
696
|
+
|
|
697
|
+
## 11. API 设计
|
|
698
|
+
|
|
699
|
+
### 11.1 `GET /healthz`
|
|
700
|
+
|
|
701
|
+
返回:
|
|
702
|
+
|
|
703
|
+
```json
|
|
704
|
+
{ "ok": true, "version": "0.1.0" }
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### 11.2 `GET /v1/models`
|
|
708
|
+
|
|
709
|
+
返回:
|
|
710
|
+
|
|
711
|
+
```json
|
|
712
|
+
{
|
|
713
|
+
"object": "list",
|
|
714
|
+
"data": [
|
|
715
|
+
{
|
|
716
|
+
"id": "default-assistant",
|
|
717
|
+
"object": "model",
|
|
718
|
+
"owned_by": "openclaw-server"
|
|
719
|
+
}
|
|
720
|
+
]
|
|
721
|
+
}
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### 11.3 `POST /v1/chat/completions`
|
|
725
|
+
|
|
726
|
+
支持:
|
|
727
|
+
|
|
728
|
+
- 非流式文本回复
|
|
729
|
+
- 流式 SSE 回复
|
|
730
|
+
- 可选工具调用
|
|
731
|
+
|
|
732
|
+
文本响应示例:
|
|
733
|
+
|
|
734
|
+
```json
|
|
735
|
+
{
|
|
736
|
+
"id": "chatcmpl_123",
|
|
737
|
+
"object": "chat.completion",
|
|
738
|
+
"created": 1760000000,
|
|
739
|
+
"model": "default-assistant",
|
|
740
|
+
"choices": [
|
|
741
|
+
{
|
|
742
|
+
"index": 0,
|
|
743
|
+
"message": {
|
|
744
|
+
"role": "assistant",
|
|
745
|
+
"content": "当前更像是网关没有启动。你可以先执行 `openclaw gateway run`。"
|
|
746
|
+
},
|
|
747
|
+
"finish_reason": "stop"
|
|
748
|
+
}
|
|
749
|
+
],
|
|
750
|
+
"usage": {
|
|
751
|
+
"prompt_tokens": 0,
|
|
752
|
+
"completion_tokens": 0,
|
|
753
|
+
"total_tokens": 0
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
工具调用响应示例:
|
|
759
|
+
|
|
760
|
+
```json
|
|
761
|
+
{
|
|
762
|
+
"id": "chatcmpl_124",
|
|
763
|
+
"object": "chat.completion",
|
|
764
|
+
"created": 1760000001,
|
|
765
|
+
"model": "default-assistant",
|
|
766
|
+
"choices": [
|
|
767
|
+
{
|
|
768
|
+
"index": 0,
|
|
769
|
+
"message": {
|
|
770
|
+
"role": "assistant",
|
|
771
|
+
"content": null,
|
|
772
|
+
"tool_calls": [
|
|
773
|
+
{
|
|
774
|
+
"id": "call_1",
|
|
775
|
+
"type": "function",
|
|
776
|
+
"function": {
|
|
777
|
+
"name": "gateway.health",
|
|
778
|
+
"arguments": "{\"target\":\"local\"}"
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
]
|
|
782
|
+
},
|
|
783
|
+
"finish_reason": "tool_calls"
|
|
784
|
+
}
|
|
785
|
+
]
|
|
786
|
+
}
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
## 12. 推荐代码结构
|
|
790
|
+
|
|
791
|
+
在“零源码改动 OpenClaw”的约束下,这里只有一个合理选择:保持 `openclaw-server` 独立。
|
|
792
|
+
|
|
793
|
+
- 不应把实现迁到 `packages/openclaw-server`
|
|
794
|
+
- 不应修改 `pnpm-workspace.yaml`
|
|
795
|
+
- 不应让 `openclaw-server` 绑定 OpenClaw 仓库内部的构建链路
|
|
796
|
+
|
|
797
|
+
即使当前暂时放在同一个仓库目录下,也应把它视为独立服务,自带自己的 `package.json`、`tsconfig.json`、启动脚本和发布流程。
|
|
798
|
+
|
|
799
|
+
建议结构如下:
|
|
800
|
+
|
|
801
|
+
```text
|
|
802
|
+
openclaw-server/
|
|
803
|
+
readme.md
|
|
804
|
+
package.json
|
|
805
|
+
tsconfig.json
|
|
806
|
+
src/
|
|
807
|
+
index.ts
|
|
808
|
+
server.ts
|
|
809
|
+
config.ts
|
|
810
|
+
routes/
|
|
811
|
+
health.ts
|
|
812
|
+
models.ts
|
|
813
|
+
chat-completions.ts
|
|
814
|
+
admin.ts
|
|
815
|
+
core/
|
|
816
|
+
request-normalizer.ts
|
|
817
|
+
session-store.ts
|
|
818
|
+
intent-router.ts
|
|
819
|
+
scenario-engine.ts
|
|
820
|
+
retrieval-engine.ts
|
|
821
|
+
template-engine.ts
|
|
822
|
+
tool-engine.ts
|
|
823
|
+
stream-renderer.ts
|
|
824
|
+
response-builder.ts
|
|
825
|
+
packs/
|
|
826
|
+
loader.ts
|
|
827
|
+
validator.ts
|
|
828
|
+
compiler.ts
|
|
829
|
+
schemas/
|
|
830
|
+
openai.ts
|
|
831
|
+
pack.ts
|
|
832
|
+
infra/
|
|
833
|
+
logger.ts
|
|
834
|
+
metrics.ts
|
|
835
|
+
jsonl-store.ts
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
## 13. 技术选型建议
|
|
839
|
+
|
|
840
|
+
### 13.1 语言与运行时
|
|
841
|
+
|
|
842
|
+
- TypeScript
|
|
843
|
+
- Node 22+
|
|
844
|
+
- ESM
|
|
845
|
+
|
|
846
|
+
### 13.2 HTTP 层
|
|
847
|
+
|
|
848
|
+
推荐:
|
|
849
|
+
|
|
850
|
+
- `express`
|
|
851
|
+
- `zod`
|
|
852
|
+
|
|
853
|
+
原因:
|
|
854
|
+
|
|
855
|
+
- 仓库根依赖里已存在 `express`
|
|
856
|
+
- 实现 OpenAI 兼容接口足够简单
|
|
857
|
+
- 可快速支持 SSE
|
|
858
|
+
|
|
859
|
+
### 13.3 存储
|
|
860
|
+
|
|
861
|
+
第一阶段:
|
|
862
|
+
|
|
863
|
+
- JSON
|
|
864
|
+
- YAML
|
|
865
|
+
- JSONL
|
|
866
|
+
- 内存 LRU
|
|
867
|
+
|
|
868
|
+
第二阶段:
|
|
869
|
+
|
|
870
|
+
- SQLite
|
|
871
|
+
|
|
872
|
+
### 13.4 观测
|
|
873
|
+
|
|
874
|
+
- 结构化日志
|
|
875
|
+
- Prometheus 风格 metrics
|
|
876
|
+
- 命中调试信息写入日志
|
|
877
|
+
|
|
878
|
+
## 14. 实施阶段
|
|
879
|
+
|
|
880
|
+
### Phase 0: 文档和样例包
|
|
881
|
+
|
|
882
|
+
产出:
|
|
883
|
+
|
|
884
|
+
- README 设计文档
|
|
885
|
+
- 基础 pack schema
|
|
886
|
+
- 一套中文默认知识包
|
|
887
|
+
|
|
888
|
+
### Phase 1: 可运行 MVP
|
|
889
|
+
|
|
890
|
+
范围:
|
|
891
|
+
|
|
892
|
+
- `GET /healthz`
|
|
893
|
+
- `GET /v1/models`
|
|
894
|
+
- `POST /v1/chat/completions`
|
|
895
|
+
- 非流式文本回复
|
|
896
|
+
- 流式文本回复
|
|
897
|
+
- FAQ 和闲聊
|
|
898
|
+
- 基础会话状态
|
|
899
|
+
- 兜底模板
|
|
900
|
+
|
|
901
|
+
验收标准:
|
|
902
|
+
|
|
903
|
+
- OpenClaw 在零源码改动前提下,能通过现有 provider 配置直接调用它
|
|
904
|
+
- 可稳定回答 50 到 100 个高频问题
|
|
905
|
+
- 兜底率可观测
|
|
906
|
+
|
|
907
|
+
### Phase 2: 场景化引导
|
|
908
|
+
|
|
909
|
+
范围:
|
|
910
|
+
|
|
911
|
+
- 状态机场景
|
|
912
|
+
- 槽位提取
|
|
913
|
+
- 多轮引导
|
|
914
|
+
- pack 热加载
|
|
915
|
+
|
|
916
|
+
验收标准:
|
|
917
|
+
|
|
918
|
+
- 至少 5 个可复用多轮流程
|
|
919
|
+
- 多轮一致性明显提升
|
|
920
|
+
|
|
921
|
+
### Phase 3: 受控工具调用
|
|
922
|
+
|
|
923
|
+
范围:
|
|
924
|
+
|
|
925
|
+
- 支持 OpenAI 兼容 `tools`
|
|
926
|
+
- 白名单工具映射
|
|
927
|
+
- 参数模板化
|
|
928
|
+
|
|
929
|
+
验收标准:
|
|
930
|
+
|
|
931
|
+
- 只在明确场景下触发工具
|
|
932
|
+
- 无未知工具名
|
|
933
|
+
- 无未校验参数
|
|
934
|
+
|
|
935
|
+
### Phase 4: 运营系统
|
|
936
|
+
|
|
937
|
+
范围:
|
|
938
|
+
|
|
939
|
+
- 未命中问题分析
|
|
940
|
+
- pack 版本管理
|
|
941
|
+
- 问题聚类和人工补录
|
|
942
|
+
|
|
943
|
+
验收标准:
|
|
944
|
+
|
|
945
|
+
- 可以根据日志持续扩充拟态能力
|
|
946
|
+
- 新增知识包无需改核心代码
|
|
947
|
+
|
|
948
|
+
## 15. 测试方案
|
|
949
|
+
|
|
950
|
+
### 15.1 单元测试
|
|
951
|
+
|
|
952
|
+
覆盖:
|
|
953
|
+
|
|
954
|
+
- 意图匹配
|
|
955
|
+
- 场景转移
|
|
956
|
+
- 模板渲染
|
|
957
|
+
- 工具参数生成
|
|
958
|
+
- 请求 schema 校验
|
|
959
|
+
|
|
960
|
+
### 15.2 集成测试
|
|
961
|
+
|
|
962
|
+
覆盖:
|
|
963
|
+
|
|
964
|
+
- `/v1/chat/completions` 非流式
|
|
965
|
+
- `/v1/chat/completions` 流式
|
|
966
|
+
- OpenClaw provider 接入
|
|
967
|
+
- 会话连续多轮
|
|
968
|
+
|
|
969
|
+
### 15.3 回归测试
|
|
970
|
+
|
|
971
|
+
建立固定用例集:
|
|
972
|
+
|
|
973
|
+
- 闲聊 20 条
|
|
974
|
+
- FAQ 50 条
|
|
975
|
+
- 故障排查 30 条
|
|
976
|
+
- 工具调用 20 条
|
|
977
|
+
- 兜底 20 条
|
|
978
|
+
|
|
979
|
+
每次 pack 更新都跑一遍。
|
|
980
|
+
|
|
981
|
+
## 16. 风险与限制
|
|
982
|
+
|
|
983
|
+
### 16.1 最大风险
|
|
984
|
+
|
|
985
|
+
如果知识包覆盖不够,用户会很快发现这不是真 AI。
|
|
986
|
+
|
|
987
|
+
所以项目成败主要取决于:
|
|
988
|
+
|
|
989
|
+
- 场景收敛是否清晰
|
|
990
|
+
- 预制内容是否充足
|
|
991
|
+
- 兜底设计是否体面
|
|
992
|
+
- 多轮状态机是否自然
|
|
993
|
+
|
|
994
|
+
### 16.2 核心限制
|
|
995
|
+
|
|
996
|
+
- 无法覆盖开放域复杂推理
|
|
997
|
+
- 容易在陌生问题上重复兜底
|
|
998
|
+
- 需要持续运营维护知识包
|
|
999
|
+
- 不能把“模板拼装”误认为“模型理解”
|
|
1000
|
+
|
|
1001
|
+
### 16.3 风险控制建议
|
|
1002
|
+
|
|
1003
|
+
- 只对封闭域宣称能力
|
|
1004
|
+
- 对未知问题明确说不知道
|
|
1005
|
+
- 工具调用必须白名单
|
|
1006
|
+
- 对高风险动作始终要求二次确认
|
|
1007
|
+
|
|
1008
|
+
## 17. 最终结论
|
|
1009
|
+
|
|
1010
|
+
`openclaw-server` 最合理的定位,不是“造一个假的大模型”,而是“造一个 OpenAI 兼容、场景化、可运营、可扩充的智能应答引擎”。
|
|
1011
|
+
|
|
1012
|
+
推荐路线是:
|
|
1013
|
+
|
|
1014
|
+
1. 用 TypeScript 实现独立服务
|
|
1015
|
+
2. 先提供 OpenAI Chat Completions 兼容接口
|
|
1016
|
+
3. 通过 `models.providers.openclaw-server` 接入 OpenClaw
|
|
1017
|
+
4. 以知识包、状态机、模板、白名单工具调用为核心能力
|
|
1018
|
+
5. 先把封闭场景做到像 AI,再逐步扩展
|
|
1019
|
+
|
|
1020
|
+
如果后续进入编码阶段,建议先做 Phase 1 MVP;后续扩展也应继续保持“OpenClaw 零源码改动、由 openclaw-server 单向适配”的边界。
|
|
1021
|
+
|
|
1022
|
+
## 18. 当前实现状态
|
|
1023
|
+
|
|
1024
|
+
当前 `openclaw-server` 已实现以下能力:
|
|
1025
|
+
|
|
1026
|
+
- 独立 TypeScript 服务,不依赖 OpenClaw 构建链路
|
|
1027
|
+
- `GET /healthz`
|
|
1028
|
+
- `GET /v1/models`
|
|
1029
|
+
- `POST /v1/chat/completions`
|
|
1030
|
+
- `POST /v1/responses`
|
|
1031
|
+
- `POST /v1/tasks/chat`
|
|
1032
|
+
- `GET /v1/tasks`
|
|
1033
|
+
- `GET /v1/tasks/reminders/pending`
|
|
1034
|
+
- `GET /v1/tasks/stats`
|
|
1035
|
+
- `GET /admin/stats`
|
|
1036
|
+
- `POST /admin/packs/reload`
|
|
1037
|
+
- Bearer Token 鉴权
|
|
1038
|
+
- 非流式文本回复
|
|
1039
|
+
- SSE 流式回复
|
|
1040
|
+
- OpenAI Responses API 兼容子集(文本、SSE、受控 tool call)
|
|
1041
|
+
- 基于 SQLite 的任务提醒机器人(自然语言建任务、提醒、完成/延后/取消、统计)
|
|
1042
|
+
- 基于知识包的意图匹配和 FAQ 检索
|
|
1043
|
+
- 简单多轮场景继续
|
|
1044
|
+
- 受控工具调用骨架和 `tool_choice` 前置校验
|
|
1045
|
+
|
|
1046
|
+
当前目录结构:
|
|
1047
|
+
|
|
1048
|
+
```text
|
|
1049
|
+
openclaw-server/
|
|
1050
|
+
package.json
|
|
1051
|
+
tsconfig.json
|
|
1052
|
+
vitest.config.ts
|
|
1053
|
+
src/
|
|
1054
|
+
packs/default/
|
|
1055
|
+
readme.md
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
## 19. 本地运行
|
|
1059
|
+
|
|
1060
|
+
### 19.1 启动服务
|
|
1061
|
+
|
|
1062
|
+
在仓库根目录执行:
|
|
1063
|
+
|
|
1064
|
+
```bash
|
|
1065
|
+
cd openclaw-server
|
|
1066
|
+
pnpm exec tsx src/index.ts
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
也可以先设置环境变量:
|
|
1070
|
+
|
|
1071
|
+
```bash
|
|
1072
|
+
export OPENCLAW_SERVER_PORT=4318
|
|
1073
|
+
export OPENCLAW_SERVER_API_KEY=openclaw-server-dev
|
|
1074
|
+
pnpm exec tsx src/index.ts
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
Windows PowerShell 示例:
|
|
1078
|
+
|
|
1079
|
+
```powershell
|
|
1080
|
+
$env:OPENCLAW_SERVER_PORT = "4318"
|
|
1081
|
+
$env:OPENCLAW_SERVER_API_KEY = "openclaw-server-dev"
|
|
1082
|
+
pnpm exec tsx src/index.ts
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
### 19.2 直接验证接口
|
|
1086
|
+
|
|
1087
|
+
健康检查:
|
|
1088
|
+
|
|
1089
|
+
```bash
|
|
1090
|
+
curl http://127.0.0.1:4318/healthz
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
查看模型:
|
|
1094
|
+
|
|
1095
|
+
```bash
|
|
1096
|
+
curl http://127.0.0.1:4318/v1/models \
|
|
1097
|
+
-H 'Authorization: Bearer openclaw-server-dev'
|
|
1098
|
+
```
|
|
1099
|
+
|
|
1100
|
+
聊天请求:
|
|
1101
|
+
|
|
1102
|
+
```bash
|
|
1103
|
+
curl http://127.0.0.1:4318/v1/chat/completions \
|
|
1104
|
+
-H 'Authorization: Bearer openclaw-server-dev' \
|
|
1105
|
+
-H 'Content-Type: application/json' \
|
|
1106
|
+
-d '{
|
|
1107
|
+
"model": "default-assistant",
|
|
1108
|
+
"messages": [{"role": "user", "content": "你好"}]
|
|
1109
|
+
}'
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
Responses 请求:
|
|
1113
|
+
|
|
1114
|
+
```bash
|
|
1115
|
+
curl http://127.0.0.1:4318/v1/responses \
|
|
1116
|
+
-H 'Authorization: Bearer openclaw-server-dev' \
|
|
1117
|
+
-H 'Content-Type: application/json' \
|
|
1118
|
+
-d '{
|
|
1119
|
+
"model": "default-assistant",
|
|
1120
|
+
"input": "gateway status",
|
|
1121
|
+
"tools": [
|
|
1122
|
+
{
|
|
1123
|
+
"type": "function",
|
|
1124
|
+
"function": { "name": "gateway.health" }
|
|
1125
|
+
}
|
|
1126
|
+
],
|
|
1127
|
+
"tool_choice": "required"
|
|
1128
|
+
}'
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
任务机器人请求:
|
|
1132
|
+
|
|
1133
|
+
```bash
|
|
1134
|
+
curl http://127.0.0.1:4318/v1/tasks/chat \
|
|
1135
|
+
-H 'Authorization: Bearer openclaw-server-dev' \
|
|
1136
|
+
-H 'Content-Type: application/json' \
|
|
1137
|
+
-d '{
|
|
1138
|
+
"user": "demo-user",
|
|
1139
|
+
"text": "明天下午3点开会",
|
|
1140
|
+
"now": "2026-03-12T09:00:00+08:00"
|
|
1141
|
+
}'
|
|
1142
|
+
```
|
|
1143
|
+
|
|
1144
|
+
查询待提醒任务:
|
|
1145
|
+
|
|
1146
|
+
```bash
|
|
1147
|
+
curl 'http://127.0.0.1:4318/v1/tasks/reminders/pending?user=demo-user&now=2026-03-13T14%3A45%3A00%2B08%3A00' \
|
|
1148
|
+
-H 'Authorization: Bearer openclaw-server-dev'
|
|
1149
|
+
```
|
|
1150
|
+
|
|
1151
|
+
查看统计:
|
|
1152
|
+
|
|
1153
|
+
```bash
|
|
1154
|
+
curl http://127.0.0.1:4318/admin/stats \
|
|
1155
|
+
-H 'Authorization: Bearer openclaw-server-dev'
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
重载知识包:
|
|
1159
|
+
|
|
1160
|
+
```bash
|
|
1161
|
+
curl -X POST http://127.0.0.1:4318/admin/packs/reload \
|
|
1162
|
+
-H 'Authorization: Bearer openclaw-server-dev'
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
## 20. OpenClaw 零改动接入示例
|
|
1166
|
+
|
|
1167
|
+
OpenClaw 侧只需要改配置,不需要改源码:
|
|
1168
|
+
|
|
1169
|
+
```json5
|
|
1170
|
+
{
|
|
1171
|
+
agents: {
|
|
1172
|
+
defaults: {
|
|
1173
|
+
model: { primary: "openclaw-server/default-assistant" },
|
|
1174
|
+
models: {
|
|
1175
|
+
"openclaw-server/default-assistant": { alias: "OpenClaw Server" },
|
|
1176
|
+
},
|
|
1177
|
+
},
|
|
1178
|
+
},
|
|
1179
|
+
models: {
|
|
1180
|
+
mode: "merge",
|
|
1181
|
+
providers: {
|
|
1182
|
+
"openclaw-server": {
|
|
1183
|
+
baseUrl: "http://127.0.0.1:4318/v1",
|
|
1184
|
+
apiKey: "${OPENCLAW_SERVER_API_KEY}",
|
|
1185
|
+
api: "openai-completions",
|
|
1186
|
+
models: [
|
|
1187
|
+
{
|
|
1188
|
+
id: "default-assistant",
|
|
1189
|
+
name: "OpenClaw Server Default Assistant",
|
|
1190
|
+
reasoning: false,
|
|
1191
|
+
input: ["text"],
|
|
1192
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1193
|
+
contextWindow: 32000,
|
|
1194
|
+
maxTokens: 2048,
|
|
1195
|
+
},
|
|
1196
|
+
],
|
|
1197
|
+
},
|
|
1198
|
+
},
|
|
1199
|
+
},
|
|
1200
|
+
}
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
## 21. 当前已验证项
|
|
1204
|
+
|
|
1205
|
+
本地已验证:
|
|
1206
|
+
|
|
1207
|
+
- `openclaw-server` 单元测试通过
|
|
1208
|
+
- 服务真实启动成功
|
|
1209
|
+
- `/healthz` 可访问
|
|
1210
|
+
- `/v1/chat/completions` 可返回回复
|
|
1211
|
+
- `/v1/responses` 可返回文本和受控工具调用
|
|
1212
|
+
- `/v1/tasks/chat` 可完成自然语言任务创建与提醒确认
|
|
1213
|
+
- `/v1/tasks/reminders/pending` 可返回到点提醒
|
|
1214
|
+
- `/v1/tasks/stats` 可返回任务统计
|
|
1215
|
+
- `/admin/stats` 可返回运行时统计
|
|
1216
|
+
- `/admin/packs/reload` 可触发知识包重载
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
|