Skip to content

2.4 LLM 层:适配器与流式调用

本章概览:ctx.llm 是 DSH 与模型世界之间的"普通话"——provider 中立的词汇表、适配器注册表、单一流式调用 API,以及配套的 token 计量与重试策略。

定位:provider 中立的语言

dsh-llm 定义"agent loop、会话日志与每个插件都讲的规范语言"。它做两件事:

  1. 适配器注册表:provider 路由(如 deepseek)→ 适配器实例;
  2. 单一流式调用 APIctx.llm.stream(options): AsyncIterable<StreamChunk>,可经 llm/stream waterfall 拦截。

出处:packages/llm/llm/README.mddeepseek-harness-src/packages/llm/llm/README.md

适配器注册与替换

ts
ctx.llm.registerAdapter(['deepseek'], adapter)   // 返回 AdapterRegistrationHandle
handle.replace(['deepseek', 'pi-ai'])            // 原子替换路由集
  • 注册全有或全无,随调用 fiber dispose;
  • replace() 先整体校验候选路由集再动任何东西——与另一适配器冲突时当前路由保持注册与服务;
  • 适配器是 LlmAdapter 子类,可覆盖 providerRetryPolicy()providerInfo()、异步 listModels()resolveModel()(精确身份/容量/输出默认/推理努力)。

流式协议:单一终态

ctx.llm.stream() 把来自适配器抛错 / finish {kind:'error'|'aborted'} / 迭代器构造失败 / 迭代失败全部规范化为流协议的唯一终态finish { kind: 'error' | 'aborted', failure }。消费者用 BlockAssembler 把 token 级 delta 组装成块/消息。

IMPORTANT

契约双端遵守defensive-patterns):LlmAdapter.stream() 实现可以抛错或发终态,但 LlmRuntime.stream() 只以终态 finish 暴露模型请求失败;中间件、嵌套调用、适配器清理、下游消费者的缺陷保持抛出——消费者无需猜测异常来自提供方、包裹器、chunk 日志还是自己的组装。

调用生命周期:prepareCall

ctx.llm.prepareCall(config, signal) 在一次精确模型查找中解析配置 + 脱离的上下文元数据 + "哪些字段由适配器默认提供"标记,并捕获当前适配器注册与不可变重试策略,返回一次性 PreparedLlmCall——防止 HMR 把一个适配器的能力结果与另一个适配器的请求组合。复用该句柄或改其字段即 INVALID_PREPARED_CALL

重试策略

  • 注册时捕获 provider 拥有的重试策略(ctx.llm.providerRetryPolicy(provider) 返回,带正常默认解析);
  • 已发出 chunk 后的重试没有持久尝试边界——所以官方 shipped 的重试策略走 agent/request-error 事件而非 llm/stream 包裹器(packages/llm/llm-retry2.2 轮次流程 的恢复瀑布)。

token 计量:token-meter

ctx.tokenMeterllm/token-meter)拥有隔离的每会话回放折叠(replay folds),压力消费者共享不可变、带修订号的测量值。它是压缩(compaction)压力触发的基础(见 3.9)。

出处:docs/capability-seams.mdctx.tokenMeter 行)

模型发现与可配置 provider

  • ctx.llm.registerModelDiscovery(settingsNs, discover):提供方声明"能询问端点广告哪些模型"(配置期工作,凭据只用于这一次询问、不存储);
  • ctx.llm.registerConfigurableProviders(entries):声明适配器可通过配置激活的 provider 路由(注册或休眠),配置界面据此显示;
  • ctx.llm.listProviders() / listModels()发现面,不是路由白名单:消费者不得因模型未列出而拒绝请求;
  • llm/adapters-updated 事件在每次拓扑提交点(注册/注销/目录增删)后发出,消费方重读而非轮询。

精确模型元数据

resolveModelInfo() 向拥有精确 provider/model 路由的适配器询问一次:contextdefaultMaxTokens(适配器配置的每请求输出上限,仅请求省略 maxTokens 时物化)、reasoning(不透明适配器自有标识符)。resolveCallConfig() 校验显式 effort 并物化适配器默认(不 clamp)。

适配器全家

适配器说明
llm-deepseekDeepSeek provider(生产默认)
llm-pi-aiPi AI provider
llm-replay测试支持:确定性回放

出处:packages/llm/llm-deepseek/README.mdpackages/test-support/llm-replay/README.md

小结

LLM 层用"注册表 + 单一流式 API + 契约化终态"把模型世界封装成可替换、可拦截、可计量的能力缝。添加新 provider = 写一个 LlmAdapter 并注册(教程见 4.2 添加一个 LLM 适配器)。

参考资料

本文档为学习用途的原创讲解,基于 MIT 许可的开源项目 deepseek-ai/deepseek-harness 编写;所有引用均注明出处。