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.
Files changed (54) hide show
  1. package/package.json +29 -0
  2. package/packs/default/faq.yaml +8 -0
  3. package/packs/default/intents.yaml +19 -0
  4. package/packs/default/pack.yaml +12 -0
  5. package/packs/default/policies.yaml +1 -0
  6. package/packs/default/scenarios.yaml +1 -0
  7. package/packs/default/synonyms.yaml +1 -0
  8. package/packs/default/templates.yaml +16 -0
  9. package/packs/default/tools.yaml +1 -0
  10. package/readme.md +1219 -0
  11. package/src/auth.ts +24 -0
  12. package/src/better-sqlite3.d.ts +17 -0
  13. package/src/config.ts +63 -0
  14. package/src/core/matcher.ts +214 -0
  15. package/src/core/normalizer.test.ts +37 -0
  16. package/src/core/normalizer.ts +183 -0
  17. package/src/core/pack-loader.ts +97 -0
  18. package/src/core/reply-engine.test.ts +76 -0
  19. package/src/core/reply-engine.ts +256 -0
  20. package/src/core/request-adapter.ts +65 -0
  21. package/src/core/session-store.ts +48 -0
  22. package/src/core/stream-renderer.ts +237 -0
  23. package/src/core/tool-engine.ts +60 -0
  24. package/src/debug-log.ts +211 -0
  25. package/src/index.ts +23 -0
  26. package/src/openai.ts +79 -0
  27. package/src/response-api.ts +107 -0
  28. package/src/routes/admin.ts +32 -0
  29. package/src/routes/chat-completions.ts +173 -0
  30. package/src/routes/health.ts +7 -0
  31. package/src/routes/models.ts +21 -0
  32. package/src/routes/request-validation.ts +33 -0
  33. package/src/routes/responses.ts +182 -0
  34. package/src/routes/tasks.ts +138 -0
  35. package/src/runtime-stats.ts +80 -0
  36. package/src/server.test.ts +776 -0
  37. package/src/server.ts +108 -0
  38. package/src/tasks/chat-integration.ts +70 -0
  39. package/src/tasks/service.ts +320 -0
  40. package/src/tasks/store.test.ts +183 -0
  41. package/src/tasks/store.ts +602 -0
  42. package/src/tasks/time-parser.test.ts +94 -0
  43. package/src/tasks/time-parser.ts +610 -0
  44. package/src/tasks/timezone.ts +171 -0
  45. package/src/tasks/types.ts +128 -0
  46. package/src/types.ts +202 -0
  47. package/src/weather/chat-integration.ts +56 -0
  48. package/src/weather/location-catalog.ts +166 -0
  49. package/src/weather/open-meteo-provider.ts +221 -0
  50. package/src/weather/parser.test.ts +23 -0
  51. package/src/weather/parser.ts +102 -0
  52. package/src/weather/service.test.ts +54 -0
  53. package/src/weather/service.ts +188 -0
  54. 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
+