편집자 노트

nnbw-liu/deepseek-ai-dsh-llm-local

OpenAI-compatible local model adapter for the harness LLM seam: direct fetch + SSE (framed by eventsource-parser ) against any server that speaks the OpenAI chat-completions dialect — Ollama (/v1), the llama.cpp server (/v1), Microsoft Foundry Local, LM Studio, vLLM, and OpenAI-compatible gateways, local or remote.

이것은 DeepSeek Harness(DSH) 플러그인입니다. 이 사이트는 GitHub README, 설치 정보, 유지보수 상태, 공개 보안 시그널을 모아 보여줍니다.

@deepseek-ai/dsh-llm-local

English | 中文

面向 Harness LLM 接缝的 OpenAI 兼容本地模型适配器:基于 fetch + SSE(由 eventsource-parser 分帧),对接任何讲 OpenAI chat-completions 方言的服务器——Ollama/v1)、llama.cpp server/v1)、微软 Foundry Local、LM Studio、vLLM,以及本地或远程的 OpenAI 兼容网关。请求不带任何 DeepSeek 专属字段,因此同一个适配器即可服务所有端点;支持推理的服务器若输出 reasoning_content,仍会以 Harness 的 reasoning 块流入会话。

本包内置 ollamallamacppfoundry-local 三个 Provider 路由预设,也支持你手工声明的任意路由。插件以 dormant(休眠)方式挂载:它会在 Models 页显示,但在 llm-local: 设置段(由 Web 的 Models 页或手工写入)提供 Provider 配置之前,不会真正服务任何请求。

关于本仓库 —— 这是 @deepseek-ai/dsh-llm-local 插件的独立源码快照,抽取自 DeepSeek Harness 单体仓库(packages/llm/llm-local)。它是面向 Harness 的 Cordis 插件,需在该单体仓库内构建与测试;package.json 依赖与 tsconfig.json 引用因此指向 Harness 工作区。上游主仓库为 https://github.com/deepseek-ai/deepseek-harness

安装与使用

dsh-llm-localDeepSeek Harness 的一个插件。它已接入 harness 的 base bundle,并以 dormant(休眠)方式挂载:ollamallamacppfoundry-local 路由会出现在 Models 页,但只有在 llm-local: 设置段提供 profile 后才会服务请求。

作为最终用户 —— 安装 harness,然后配置插件(无需单独安装本仓库):

npx @deepseek-ai/dsh web

打开 http://127.0.0.1:3080 的 Web 界面,进入 设置 → Models 编辑某个本地 provider 行;或在 $DSH_HOME/settings.yaml 写入 llm-local: 段(见配置)。

npx 拉取的是已发布的 harness 构建,因此该构建必须包含本包(及其 base bundle 条目)插件才会存在。在对应版本发布前,请改为从源码构建。

作为开发者 —— 在 harness 单体仓库内构建。本包使用 workspace:^ 依赖和单体仓库的 tsconfig.json 引用,因此无法独立构建:

git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
# place this repository's src/ and tests/ under packages/llm/llm-local/
pnpm install
pnpm run build
pnpm dsh web

然后像最终用户一样配置插件。

快速开始

  1. 重启 dsh 服务(Web GUI 进程)。插件在启动时加载;在插件存在之前启动的服务会静默忽略 llm-local: 设置——没有任何报错,重启前该段就是不生效。
  2. 配置 Provider:二选一——在 Web 界面操作(设置 → Models → 对应 Provider 行 → 编辑 → 填写 API 地址 → 获取可用模型 → 保存),或写入 $DSH_HOME/settings.yaml(见下文)。
  3. 新建会话后切换模型:打开模型选择器(/model),选择本地 Provider 与模型 ID。新会话的默认 Provider 仍是 deepseek-official,直到你主动切换。

settings.yaml 在哪里

设置文档是 harness home 目录下settings.yaml

  • 默认 home:~/.dsh——Windows 上是 C:\Users\<你的用户名>\.dsh,即文件为 C:\Users\<你的用户名>\.dsh\settings.yaml
  • 若设置了 DSH_HOME,则为 $DSH_HOME/settings.yaml
  • Web 设置页展示的路径、或组合 cordis.ymlsettings-file.config.path 指定的路径优先于以上两者。

该文件是热加载的:外部编辑约 100ms 内被感知,下一次模型请求即用新值——插件加载过一次之后,后续编辑无需重启

配置

插件注册了 llm-local 设置命名空间。providers 字典的键就是 Provider 路由:ollamallamacppfoundry-local 是内置预设(继承端点与显示名),其余键是手工声明的端点,必须填写 baseURL

最小可用示例(Ollama)

llm-local:
  providers:
    ollama:
      models:
        - id: qwen3:8b
          contextWindow: 32768

这样就够了:预设端点 http://127.0.0.1:11434/v1 被自动继承,无需任何 API 密钥,文件保存的瞬间路由即注册。请求时用 provider: ollamamodel: qwen3:8b

全字段示例

llm-local:
  providers:
    # Shipped preset: endpoint defaults to http://127.0.0.1:11434/v1.
    ollama:
      models:                        # optional; discovery can fill these
        - id: qwen3:8b
          contextWindow: 32768
      # defaultContextWindow: 128000   # fallback capacity for unlisted models
      # maxTokens: 32768               # default per-request output cap
      # usageInStream: true            # stream_options.include_usage
      # vision: false                  # image input for vision models
      # streamIdleTimeoutMs: 300000    # per-read idle budget
    # Shipped preset for the llama.cpp server.
    llamacpp:
      baseURL: http://127.0.0.1:8080/v1
      models:
        - id: qwen2.5-coder-14b-instruct-q4_K_M
          contextWindow: 32768
    # Shipped preset for Microsoft Foundry Local.
    foundry-local:
      baseURL: http://127.0.0.1:53415/v1   # confirm the port in `foundry local` output
      models: []
    # Hand-declared route: any OpenAI-compatible endpoint.
    my-gateway:
      displayName: My Gateway
      baseURL: http://127.0.0.1:1234/v1
      apiKeyEnv: MY_GATEWAY_KEY   # optional; local servers usually need none
      vision: true                # optional; image input for vision models
      usageInStream: true         # optional; stream_options.include_usage
      maxTokens: 32768            # optional default per-request output cap
      defaultContextWindow: 128000  # optional fallback context capacity
      streamIdleTimeoutMs: 300000   # optional per-read idle budget
      retryPolicy:                  # optional; normal defaults when omitted
        mode: normal
        maxRetries: 2
      models:
        - id: gpt-oss-120b
          contextWindow: 131072
          maxTokens: 32768

各字段说明:

  • baseURL — OpenAI 兼容根地址(会自动追加 /chat/completions/models)。预设默认值:Ollama http://127.0.0.1:11434/v1、llama.cpp http://127.0.0.1:8080/v1、Foundry Local http://127.0.0.1:53415/v1(具体端口以 foundry local 输出为准)。手工声明路由必填。
  • apiKeyEnv — 凭据引用,每次请求经 ctx.credentials、再退回到环境变量解析。省略即免认证——本地默认;Ollama、llama.cpp、Foundry Local 开箱即用无需密钥。一旦填写,解析不到就报 MISSING_CREDENTIAL
  • models — 提供给选择器与发现的建议目录;未列出的模型 id 也能直接请求。每项:id,可选 name/description/contextWindow/maxTokens/visionmodels: [] 表示不列出任何模型。
  • vision(profile 级或模型级)— 声明接受图片输入。图片块会经持久化附件服务序列化为 image_url 的 data-URL;纯文本模型收到图片会以 UNSUPPORTED_CONTENT 拒绝。
  • usageInStream — 默认 true(发送 stream_options.include_usage)。遇到不认该字段的旧版 llama.cpp 构建可关掉。
  • maxTokensdefaultContextWindowstreamIdleTimeoutMsretryPolicy — 语义与 DeepSeek 适配器一致。

在 Models 页配置

Web 的 Models 设置页已认识本适配器家族:每个 Provider 行(三个预设无论是否休眠都会列出)展开的编辑器包含 API 密钥(可选——留空即免认证访问本地端点)、API 地址(预设已预填)、以及带 获取可用模型 按钮的模型目录——该按钮会请求 GET {baseURL}/models,对预设路由即使未填 URL 也能直接询问。"添加提供方"下拉包含三个休眠预设。手工声明的路由仍需写 settings.yaml(本地路由没有协议下拉,因为所有本地端点讲同一种方言)。

动态配置(settings + credentials)

连接事实不在加载时冻结。resolveAdapterOptions 是唯一显式解析步骤,适配器每次操作通过 thunk 重新读取事实:baseURL、目录、usage 上报、vision、输出上限、空闲预算都会在下一个请求生效,而进行中的流保持其开始时的事实。

  • ctx.settings — 插件以同一 Config schema 注册 llm-local 命名空间,以组合条目为 base;用户设置文档中的 llm-local: 段可覆盖任意字段且无需重启。
  • ctx.credentials — 密钥每次流调用从同一个快照解析,与端点绑定。配置只携带 apiKeyEnv,从不携带字面密钥;未填写的路由直接免认证请求。

唯一在注册时捕获的事实是重试策略:某路由解析值变化时,插件会原地重注册整个路由集(同一适配器实例、同一同步区间)。路由集变化(增删路由)同样原地重注册。每次路由变化都会输出一行日志(llm-local: serving ollama (http://127.0.0.1:11434/v1), ...),休眠挂载时输出 llm-local: dormant; ...——这是排查"段写了没反应"时第一件要确认的事。

排查:settings.yaml 写了不生效

  1. 插件加入之后服务重启过吗? 文档中的 llm-local: 段在插件于启动时注册命名空间之前,会被静默保留但不生效。重启 dsh 服务,然后找 llm-local: 开头的日志行。
  2. 文件位置对吗? 该段必须是 $DSH_HOME/settings.yaml(默认 ~/.dsh/settings.yaml)的顶层键,不能嵌套在其他键下,也不能写进 cordis.yml
  3. YAML 有效且缩进正确吗? providers 是字典:Provider 键缩进在它下面,profile 字段缩进在 Provider 键下面,与示例一致。
  4. 路由注册了吗? Models 页上对应 Provider 行会从休眠的"添加"状态变成已配置行;服务日志打印 llm-local: serving <route> (<baseURL>)
  5. 会话真的在用这个 Provider 吗? 配置 Provider 只是让它可用;会话仍使用创建时的 Provider/模型。在新会话里打开模型选择器(/model)选择本地路由。
  6. 看服务日志里的错误。 schema 不合法的段会记 settings: keeping last good "llm-local" after invalid stored section 并附原因;路由解析失败会保留旧路由并记 llm-local: keeping the previously registered routes after a refused update

应用归属头

每个请求携带 dsh-llm attributionHeaders() 的共享归属头(强制 User-Agent 基线)。请求身份以 x-deepseek-harness-user-id(稳定匿名 id)随 wire 发送;带会话的请求还发送 x-deepseek-harness-session-id。不添加任何 Provider 专属头——本地端点不需要。

Wire 格式说明

  • 仅流式;默认发送 stream_options.include_usage(除非 usageInStream: false)。usage 可能挂在 finish 块上,也可能作为尾部仅 usage 块到达——翻译器把两者都推迟到 [DONE],因此 usage 永远先于 finish
  • 历史中的 assistant 消息回放 reasoning_content(OpenAI 方言没有 CoT 回传;本地服务器要么忽略要么拒绝)。收到的 reasoning_content 增量仍会变成 reasoning 块。
  • 缓存统计:cacheReadTokensprompt_tokens_details.cached_tokens(llama.cpp)或 prompt_cache_hit_tokens(DeepSeek 风格拼写);该值会从 inputTokens 中扣除以保持互斥口径。
  • 思考模式首块常带 reasoning_content: ""——已处理(不会误开 reasoning 块)。

错误

非 2xx 响应抛出带稳定码的 LlmErrorAUTH(401/403)、QUOTA(Provider 详情表明额度耗尽)、RATE_LIMIT(429)、CONTEXT_WINDOW_EXCEEDED(400 且详情表明超出上下文)、INVALID_REQUEST(其他 400)、SERVER(5xx),其余为 HTTP_<status>。可序列化的 failure 保留 HTTP 状态、有效的正数 Retry-After 延迟及 x-request-id(如有)。响应前的传输失败(DNS、拒连、TLS、代理)抛 TRANSPORT 并指名端点;调用方中止抛 ABORTED;协议违规抛 STREAM_CLOSED(缺 [DONE])或 MALFORMED_RESPONSE(JSON 损坏)。未知的 wire finish_reason 变成 finish {kind: 'error'} 块;以 stop 结束但未产出任何内容块的流变成 EMPTY_RESPONSE(默认策略会重试)。

已知限制与待办

  • 设置中的 models 列表整体替换组合列表——设置层按字段合并,数组算一个字段。
  • 未映射 tool_choice——不属于核心词汇表(与 DeepSeek、pi-ai 适配器一致)。
  • 请求使用原生 fetch,未走 @cordisjs/plugin-http——没有共享代理/拦截配置。
  • 无 reasoning effort 选择器——本地 OpenAI 兼容服务器没有统一的 reasoning_effort 方言;推理模型能流式输出 CoT,但 Harness 无法为它们选择思考档位。
  • 除非模型声明 vision,否则用户与工具结果内容会扁平化为纯文本;空工具输出以字面量 (no output) 过线。
REPOSITORY SIGNALS

보안 및 설치 증거

이 점수는 공개 저장소 메타데이터와 이 사이트에 등록된 설치 증거에만 기반하며, 코드 보안 감사와 다릅니다.

출처 추적 가능

공개 플러그인 카탈로그에서 왔으며, 공개 GitHub 저장소로 연결됩니다.

라이선스

저장소가 MIT 라이선스를 선언했습니다.

유지보수 활동

최근 180일 내 코드 업데이트가 있습니다.

설치 증거

재현 가능한 정확한 설치 메타데이터가 아직 등록되지 않았습니다. 저장소 설명에 따라 직접 확인하세요.

설치 라이프사이클 스크립트

검사한 패키지 메타데이터에 설치 라이프사이클 스크립트가 선언되지 않았습니다.