OpenClaw @openclaw/ai 最小消费者示例:一个隔离 LLM 运行时、内置 Provider 与流式补全

📅 发布时间:2026/9/10 8:34:10
OpenClaw @openclaw/ai 最小消费者示例:一个隔离 LLM 运行时、内置 Provider 与流式补全
OpenClaw openclaw/ai 最小消费者示例一个隔离 LLM 运行时、内置 Provider 与流式补全【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw本文基于 OpenClaw 仓库中 examples/ai-chat 的官方最小示例讲解如何仅使用已发布的openclaw/ai包不依赖任何 OpenClaw 应用代码创建隔离的 LLM 运行时、注册 8 个内置 API Provider并以纯 Node.js ESM 脚本流式消费一次模型补全。读完后你将掌握该包的公开入口createLlmRuntime、registerBuiltInApiProviders、模型对象各字段的含义、三种 ProviderAnthropic / OpenAI / Ollama的实际运行命令以及底层延迟注册与事件流机制的源码实现。示例定位为什么这个示例有价值openclaw/ai是 OpenClaw 对外发布的可复用模型适配包提供 Provider 中立的契约、Provider 适配器与流式原语。包文档packages/ai/README.md明确了它的能力边界支持隔离的运行时实例导入该包不会在包级别全局注册任何 ProviderProvider 中立的契约、校验、诊断与事件流可从包根及openclaw/ai/event-stream、openclaw/ai/transports、openclaw/ai/validation等子路径导入Provider 凭据、模型目录、重试与故障转移属于应用层关注点OpenClaw 应用在这个包之上提供这些策略主机策略自定义 fetch 防护、密钥脱敏、strict-tool 默认值、诊断日志可通过configureAiTransportHost注入默认值是不活跃的inertopenclaw/ai/internal/*系列子路径仅供 OpenClaw 应用自身使用无 semver 保证外部不应依赖。examples/ai-chat 就是这个包最小外部消费者的活体证明它只依赖openclaw/ai的公开面不引入任何 OpenClaw 应用代码。package.jsonexamples/ai-chat/package.json声明为私有 ESM 包{ name: openclaw/example-ai-chat, version: 0.0.0-private, private: true, description: Minimal external-consumer example for openclaw/ai, type: module, scripts: { start: node index.mjs }, dependencies: { openclaw/ai: workspace:* } }这里有一个关键的运行前提在仓库内部openclaw/ai的 workspace 链接解析到该包的已构建dist产物——也就是 npm 消费者实际安装的同一份产物。因此必须先执行pnpm build否则示例无法解析到包内容。完整示例代码解析index.mjs整个示例只有约 80 行examples/ai-chat/index.mjs结构分四段模型表、参数解析、运行时创建、流式消费。1. 模型声明表三个 Provider 的完整配置const MODELS { anthropic: { id: claude-sonnet-4-6, name: Claude Sonnet 4.6, api: anthropic-messages, provider: anthropic, baseUrl: https://api.anthropic.com, reasoning: true, input: [text], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 200_000, maxTokens: 8192, }, openai: { id: gpt-5.6-sol, name: GPT-5.6 Sol, api: openai-responses, provider: openai, baseUrl: https://api.openai.com/v1, reasoning: true, input: [text], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1_050_000, maxTokens: 128_000, }, // Local Ollama server; no API key required. ollama: { id: process.env.OLLAMA_MODEL || llama3.2:latest, name: Ollama, api: openai-completions, provider: ollama, baseUrl: http://localhost:11434/v1, reasoning: false, input: [text], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32_000, maxTokens: 4096, }, };模型对象的每个字段对应openclaw/ai的模型契约字段作用示例中的取值要点id/name模型标识与展示名Ollama 的id由OLLAMA_MODEL环境变量覆盖默认llama3.2:latestapi决定走哪个内置传输transport三个取值分别对应anthropic-messages、openai-responses、openai-completions三种注册好的协议适配器providerProvider 标识anthropic/openai/ollamabaseUrlAPI 端点Ollama 指向本机http://localhost:11434/v1OpenAI 兼容端点reasoning是否具备推理extended thinking / reasoning tokens能力Anthropic、OpenAI 为trueOllama 为falseinput支持的输入模态均为[text]cost每百万 token 的计价参数本地 Ollama 全为 0contextWindow上下文窗口大小Ollama 32KOpenAI 1.05MmaxTokens单次最大输出 token 数Ollama 4096OpenAI 128K注意一个设计细节Ollama 通过api: openai-completions复用 OpenAI 兼容传输——本地模型服务器只要暴露 OpenAI 兼容的/v1接口就无需单独适配。2. 命令行参数解析const args process.argv.slice(2); const providerFlag args.indexOf(--provider); const provider providerFlag -1 ? anthropic : args[providerFlag 1]; const prompt args.filter((_, i) i ! providerFlag i ! providerFlag 1).join( ) || Reply with one short sentence: what is openclaw/ai?; const model MODELS[provider]; if (!model) { console.error(Unknown provider ${provider}. Use one of: ${Object.keys(MODELS).join(, )}); process.exit(1); }--provider缺省时默认anthropic提示词 除--provider及其取值外的所有剩余参数拼接保留空格分隔再整体作为单条 user 消息无提示词时使用内置默认提示未识别的 provider 直接打印可用列表并以退出码 1 终止。3. 运行时创建与 Provider 注册整个包最核心的两步const runtime createLlmRuntime(); registerBuiltInApiProviders(runtime.registry);对照 packages/ai/src/stream.ts 的实现createLlmRuntime会创建一个隔离的运行时export function createLlmRuntime(registry: ApiRegistry createApiRegistry()) { function resolveApiProvider(api: Api) { const provider registry.getApiProvider(api); if (!provider) { throw new Error(No API provider registered for api: ${api}); } return provider; } // ... return { registry, stream, complete, streamSimple, completeSimple }; }从源码结构看运行时暴露了 5 个成员registryProvider 注册表ApiRegistry模型请求按model.api在此解析出对应的stream/streamSimple函数未注册则抛No API provider registered for api: ...stream(model, context, options?)走完整Context契约的流式调用返回AssistantMessageEventStreamContractcomplete(...)stream(...).result()的便捷封装等待流结束返回最终AssistantMessagestreamSimple(model, context, options?)走简化的SimpleStreamOptions如{ messages }示例使用的正是这一档completeSimple(...)streamSimple(...).result()的便捷封装。registerBuiltInApiProviders实现见 packages/ai/src/providers/register-builtins.ts。它一次性注册8 个内置传输与 README 描述一一对应api 标识对应协议说明anthropic-messagesAnthropic Messages示例 anthropic 配置所用openai-completionsOpenAI Chat Completions 兼容Ollama 走此传输openai-responsesOpenAI Responses API示例 openai 配置所用azure-openai-responsesAzure OpenAI—openai-chatgpt-responsesChatGPT (Codex) Responses—mistral-conversationsMistral Conversations—google-generative-aiGoogle—google-vertexVertex—注册采用惰性加载createLazyRegistration为每个 api 注册一个包装函数调用时才动态import()对应 Provider 模块如import(./anthropic.js)且加载结果被缓存streamsPromise ?? importModule().then(select)。因此Provider SDK 模块在首次使用时才加载——注册本身是零成本的示例进程只加载了实际请求命中的那个适配器。同时createLazyStream保证调用方同步拿到一个流对象底层模块加载完成后通过forwardStream把事件逐条转发进这个外层流加载失败时则推送一条error事件并以零用量结果收尾projectProviderError会统一错误投影。4. 流式消费stdout 与 stderr 的分流const stream runtime.streamSimple( model, { messages: [{ role: user, content: prompt, timestamp: Date.now() }] }, // Ollama ignores credentials but the OpenAI-compatible transport requires one. provider ollama ? { apiKey: ollama } : undefined, ); for await (const event of stream) { if (event.type text_delta) { process.stdout.write(event.delta); } } const result await stream.result(); process.stdout.write(\n); if (result.stopReason error || result.stopReason aborted) { console.error(error: ${result.errorMessage ?? result.stopReason}); process.exit(1); } const { input, output } result.usage; console.error([${model.id}] stop${result.stopReason} tokens in${input} out${output});三个值得注意的点输出分流文本增量text_delta事件逐块写到 stdout停止原因与 token 用量走 stderr。这使得模型输出可以被管道消费而诊断信息不污染管道内容Ollama 的占位 keyOllama 本身不需要凭据但 OpenAI 兼容传输要求存在apiKey所以传入字面量ollama占位结果收尾stream.result()在流结束后返回最终AssistantMessage包含stopReason、errorMessage错误投影时与usageinput/outputtoken 数及cost明细。stopReason为error或aborted时以退出码 1 终止。运行方式完整命令清单POSIX ShellOllama 一条在 PowerShell 中同样可用ANTHROPIC_API_KEYexample-anthropic-key-not-real node index.mjs Say hello OPENAI_API_KEYexample-openai-key-not-real node index.mjs --provider openai Say hello # keyless, against a local Ollama server (OLLAMA_MODEL overrides the model id) node index.mjs --provider ollama Say helloPowerShell$env:ANTHROPIC_API_KEY example-anthropic-key-not-real node index.mjs Say hello $env:OPENAI_API_KEY example-openai-key-not-real node index.mjs --provider openai Say hello # Clear the session-scoped keys. $env:ANTHROPIC_API_KEY $null $env:OPENAI_API_KEY $null两种写法的差异与限制需要注意POSIX 中KEY... node index.mjs的形式环境变量只作用于单条命令执行完即消失PowerShell 的$env:赋值在会话内持续存在直到手动清空置$null或关闭 shell——README 特意提示了这一点避免密钥残留Ollama 分支完全无 key但要求本机有一个运行中的 Ollama 服务器http://localhost:11434可用OLLAMA_MODEL环境变量覆盖默认的llama3.2:latest模型 id。运行前请确认已执行pnpm buildworkspace 链接指向构建产物并将占位 key 替换为真实 API key。面向库使用者的四条要点README 末尾给出的四条 library consumer notes逐条对应到源码事实createLlmRuntime()给你隔离注册表导入包本身不产生任何全局注册每个createLlmRuntime()实例拥有独立的ApiRegistrypackages/ai/src/stream.ts 中默认参数createApiRegistry()即为每实例新建。registerBuiltInApiProviders(runtime.registry)一次性获得 8 个内置传输Anthropic、OpenAI Completions/Responses、Azure OpenAI、ChatGPT Responses、Google、Vertex、MistralProvider SDK 模块在首次使用时惰性加载见上文createLazyRegistration分析。主机策略可注入自定义 fetch、密钥脱敏、strict-tool 默认值、诊断日志通过configureAiTransportHost注入默认实现是 inert 的——也就是说开箱即用时不会拦截或改写任何请求行为。完整 TypeScript 类型随包发布类型声明位于dist/*.d.mts见 packages/ai/package.json 的exports字段根及 7 个公共子路径均带types条件示例刻意使用纯 ESM 以便在裸node环境下直接运行无需 TS 工具链。延伸阅读包文档packages/ai/README.md运行时实现packages/ai/src/stream.ts内置 Provider 注册与惰性加载packages/ai/src/providers/register-builtins.ts示例源码examples/ai-chat/index.mjs这个示例展示了openclaw/ai作为独立库的最小接入形态隔离运行时 内置注册 一次流式补全。如果你的应用需要多 Provider 故障转移、凭据管理或模型目录则应在该包之上自行实现这些应用层策略——这正是openclaw/ai刻意不内置的边界。【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考