Skip to main content

Integrating DeepSeek Harness with the Turing Platform

DeepSeek Harness (command name dsh) is DeepSeek's open-source agent harness: models, tools, skills, sessions, sandboxes, loops, scheduling, and the UI are all mounted as plugins and can be swapped one by one. It ships two entry points -- a Web UI and a headless CLI -- and accepts any OpenAI-compatible endpoint as a model source, so it can talk to the Turing Platform directly.

Use deepseek-v4-flash-0731

On Turing this model goes direct to DeepSeek's own API and therefore to DeepSeek's own KV cache, so hits stay contiguous across a long session -- 8 calls with a fixed prefix held a steady 99.0% hit rate on every call after the cold start. At ¥0.1, a cache hit costs 1/30 of the input rate, and cache is exactly where agent spend concentrates. See Recommended models.

Developer preview

dsh is a 0.1.0-rc.x developer preview and upstream states breaking changes are expected. Every command, config field, and error string below was verified against dsh v0.1.0-rc.8 + Node v22.22.2 + the Turing live environment (2026-08-20). Re-check them against upstream docs after an upgrade.

Prerequisites

  • A Turing Platform API key (how to get one)

  • macOS / Linux / WSL2

  • Node must expose zstd from node:zlib (dsh compresses session records with zstd). That API landed in Node v23.8.0 and was backported to 22.x LTS: v22.22.2 works, while v23.6.0 fails on startup:

    SyntaxError: The requested module 'node:zlib' does not provide an export named 'createZstdDecompress'
  • The first install pulls 60+ @deepseek-ai/dsh-* plugin packages. On a slow or China-based network, point the registry at a mirror first:

    npm config set registry https://registry.npmmirror.com
pnpm installs much faster

On the same machine, npm i @deepseek-ai/dsh spent more than ten minutes in dependency resolution without writing anything to disk, while pnpm add @deepseek-ai/dsh finished in 68 seconds (503 packages). npx goes through npm, so a slow first run is expected.

Two ways to wire it up

ApproachConfigurationAvailable modelsWhen to use
Custom provider (recommended)One YAML block or one UI formAll models on TuringYou need to pin a specific model, or switch between routes
Override the built-in deepseek routeTwo environment variablesDeepSeek model IDs onlyYou only use DeepSeek and want the fastest path

The two can coexist.

1. Start dsh

npx @deepseek-ai/dsh@latest web

The Web UI listens on http://127.0.0.1:3080 by default and opens a browser. dsh uses the directory it was launched from as its default filesystem location, so cd into your project first.

Flags accepted by the web entry point (dsh web --help):

FlagEffect
--no-openServe without opening a browser
--port <port>Change the listen port; pass 0 to let the OS pick one
--host <host>Change the bind host
--trusted-host <authority...>Add an authority the /api browser-trust fence accepts; repeatable

2. Add the Turing provider in the UI

Open Settings → Models → Add a custom provider and fill in:

FieldValueNotes
Provider IDturingLowercase, starts with a letter, and permanent -- session records, model defaults, and credential references all index on it
Display nameTuringDisplay only
Base URLhttps://live-turing.cn.llm.tcljd.com/api/v1Turing's China-region endpoint, see Get an API Key
API protocolopenai-completionsMaps to v1/chat/completions
API keyYour Turing API keyOnly a redacted descriptor is read back; the secret lands in ~/.dsh/.credentials.yaml

The model route becomes usable immediately, without restarting the server.

Turing supports model auto-discovery

Turing implements the OpenAI-compatible GET /v1/models (160+ model IDs in practice), so the UI can fetch the list instead of you typing IDs. Models missing from the list can still be entered by hand -- the model list is authoritative for IDs.

3. Or edit the config file directly

Configuration lives in $DSH_HOME/settings.yaml (DSH_HOME defaults to ~/.dsh). Top-level keys are plugin IDs, and model routes belong to llm-pi-ai:

llm-pi-ai:
providers:
turing:
displayName: Turing
api: openai-completions
baseURL: https://live-turing.cn.llm.tcljd.com/api/v1
apiKeyEnv: TURING_API_KEY
models:
- id: deepseek-v4-flash-0731
- id: aliyun/deepseek-v4-flash-0731

Then put the key in that environment variable:

echo 'export TURING_API_KEY="your-api-key"' >> ~/.zshrc # bash users: ~/.bashrc
source ~/.zshrc
Never put a literal key in settings.yaml

Upstream recommends referencing an environment variable through apiKeyEnv, or saving the key in the UI (which writes it to ~/.dsh/.credentials.yaml, write-only). settings.yaml should only ever hold the reference.

Each entry's id is the model name sent to Turing, identical to the API model ID in the model list. Hand-entered models default to text-only; declare input: [text, image] explicitly to send images.

On Turing, deepseek-v4-flash-0731 answers on all three protocols (v1/chat/completions, v1/responses, and v1/messages all returned 200), so api may also be openai-responses or anthropic-messages. Use openai-completions unless you need otherwise.

4. Pick a default model and run your first task

  1. Select a model under Settings → Models -- it becomes the default for new sessions (existing sessions keep the model recorded in their log)
  2. Click Choose workspace and add a project directory -- the session composer stays disabled until a workspace is selected
  3. Try a task, for example "read this repository and summarize its structure"

Approach 2: override the built-in deepseek route

dsh ships a deepseek-official route that reads just two environment variables. Point them at Turing:

export DEEPSEEK_BASE_URL=https://live-turing.cn.llm.tcljd.com/api/v1
export DEEPSEEK_API_KEY=your-turing-api-key
npx @deepseek-ai/dsh@latest web

No config file needed. The trade-off is that the model name must be a DeepSeek ID that Turing serves -- dsh's factory default is deepseek-v4-flash, which Turing does provide, so the environment variables alone are enough to get a run through (verified with a headless task). To pin a dated release such as deepseek-v4-flash-0731, change the default model as shown in the next section, or pick it in the UI.

headless: one-shot tasks

dsh --profile headless "read src/ and list the modules it exports"

The headless profile creates one persisted session, prints the final answer, and exits -- useful for scripts and CI. It defaults to the deepseek-official route, so either set the environment variables from approach 2, or move the default model onto your turing provider by editing the profile's patch layer at $DSH_HOME/profiles/headless/cordis.patch.yml (generated on first launch; its content is a YAML array):

- id: agent-default-model
config:
provider: turing
model: deepseek-v4-flash-0731

Run dsh --profile headless --dump-config afterwards to confirm the patch applied -- it prints the composed plugin tree.

Other launcher flags:

FlagEffect
dsh --profile <name>Boot the profile under $DSH_HOME/profiles/<name>; dsh web is an alias of --profile web
dsh plugin --profile <name> <pnpm args>Manage a profile's plugins by forwarding to pnpm in that directory
--patch <path>Apply an extra config overlay; repeatable
--dump-config / --dump-default-configPrint the composed plugin tree (with / without the user layer) and exit

For agent workloads, start with deepseek-v4-flash-0731: direct to DeepSeek's own API, ¥3 input / ¥9 output / ¥0.1 on a cache hit, a 1M context window, with tool calling and thinking both supported.

The same model snapshot is available on Turing through two routes. Input and output rates are identical; they differ on the cache-hit rate and on which hours count as off-peak:

Model IDUpstreamCache-hit rateOff-peak hours (UTC+8)
deepseek-v4-flash-0731DeepSeek official, direct¥0.1Peak is only 09:00-12:00 and 14:00-18:00; every other hour is off-peak
aliyun/deepseek-v4-flash-0731Aliyun Model Studio¥0.322:00 to 08:00 the next day

Beyond the cheaper hit rate, the official route also holds its hits more steadily across a long session (see below). Cache-heavy traffic, or traffic concentrated in the off-peak daytime hours, is cheaper there; late-night batches cost the same either way. Full rates, context limits, and protocol support live in the model list → Deepseek; for how billing is applied see time-of-day pricing.

Measured cache hits

An agent resends the system prompt, the tool definitions, and the whole history on every turn, so the common prefix is enormous and the cache-hit rate is the real bill: ¥0.1 is 1/30 of the ¥3 input rate.

Measured against live with a byte-identical ~6.6k-token fixed prefix, single-threaded, 8 calls 4s apart, on deepseek-v4-flash-0731:

Callprompt_tokenscached_tokensHit rate
#1659200% (cold)
#2 – #86592652899.0%

After the cold start every call held 99.0% -- no regressions, no sawtooth. The official direct route is served by DeepSeek's own cache, so the common prefix of a long session accumulates contiguously. On the Model Studio route to the same snapshot, hits showed up later in the same test and never covered the whole prefix, which is why cache-sensitive agent workloads should stay on the official route.

The 64 uncached tokens are not measurement noise: cached counts came back block-aligned (always a multiple of 64), so a tail that does not fill a block is never cached.

Getting the hit rate up

DeepSeek's context cache is on by default and needs no request parameter, but it requires a complete prefix match -- upstream states it plainly: having sent A + B, a later A + C does not hit. So your hit rate is a function of how stable your request prefix is:

  1. Stable content first: system prompt, tool definitions, project conventions such as AGENTS.md, long reference documents -- all at the head of the conversation and byte-identical every turn.
  2. Volatile content last: timestamps, random IDs, the current branch name, per-turn retrieval results belong at the tail. A current timestamp inside the prefix invalidates the cache on every single turn.
  3. Append to the history, never rewrite it: do not trim, reorder, or edit earlier messages. Agent context compaction rewrites the history prefix, so the first call after a compaction behaves like a cold start -- that is expected.
  4. Keep one session serial: firing the same prefix concurrently spreads it across backend instances and hits arrive noticeably later.
  5. Do not expect hits on short sessions: a prefix below the vendor's minimum is not cached at all (see prompt caching), and the first call is always a cold 0%.
  6. The cache is best-effort: upstream guarantees no hit rate, and an unused cache is cleared within hours to days -- coming back after a long idle period and paying for a cold start is expected, so never build a cost model that assumes a hit.

Bill against usage.prompt_tokens_details.cached_tokens in the response (DeepSeek's own prompt_cache_hit_tokens) rather than an estimate. Upstream reference: DeepSeek KV Cache.

Two things that bite
  • Context window: dsh assumes 262144 tokens for hand-entered models, while deepseek-v4-flash-0731 accepts 1M input on Turing, and it does not scale that assumption up -- long sessions trigger compaction earlier than they need to.
  • Thinking model: the DeepSeek V4 family thinks by default, and reasoning consumes the output budget first. Set the output cap too low (max_tokens: 16 in testing) and you get thinking with no answer.

Troubleshooting

Error / symptomWhat to do
dsh: MISSING_CREDENTIAL: llm-pi-ai: no credential for provider route "turing"The provider has no key: save one under Settings → Models, or make sure the variable named by apiKeyEnv is visible in the shell that launches dsh
Startup fails with does not provide an export named 'createZstdDecompress'Node is too old -- switch to a build with zstd support (see Prerequisites)
HTTP 401 with API key not existThe key does not belong to this environment (a live key will not work against the test gateway), or it has been revoked
Model not exist. / Unknown LLM providerThat model ID is not enabled in the current environment; use an ID that the model list shows as live
You want to rename a Provider IDCreate a new one and delete the old one; existing sessions stay pointed at the old ID

Reference

Back

← Back to AI Coding Tools Overview