news 2026/9/18 12:34:04

从 DSH 的 --default-only 看默认组合,TaoToken 补凭据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 DSH 的 --default-only 看默认组合,TaoToken 补凭据

1. 从--default-only的 llm 行缺凭据说起:先拿到 /tmp/base.yml

如果你第一次跑 DSH,很可能会遇到这种场景:Web profile 能启动,但一到模型对话就提示凭据缺失;或者你执行pnpm dsh --profile web --dump-config --default-only,看到llm行里只有 provider、model、超时之类的默认值,却没有baseUrlapiKey。这不是 DSH 配置坏了,而是你正在看的是bundle 层默认组合。默认组合负责给出可运行的骨架,不负责携带你的个人密钥。

这时正确的动作不是去改 bundle,也不是把整棵配置树重写,而是去 TaoToken 官网创建 API Key,再用用户补丁层补进llm行。TaoToken 的入口在这里:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=dsh_default_only_intro 。拿到 Key 后,DSH 的 Base URL 固定用https://taotoken.net/api,不要在后面附加多余路径,也不要在 Base URL 上挂 UTM。

本篇只做 DSH 强化训练里的练习 1:只看 bundle 层,产出/tmp/base.yml,再叠加用户补丁做对比。你需要建立三个直觉:

  1. --default-only输出的是 bundle 默认组合,不含 profile 补丁、家目录补丁和命令行--patch
  2. llm行属于“设置凭据”分组,默认只给结构,凭据应在用户层补。
  3. 补丁是整行替换,不是深合并。想保住原来的字段,就要重述整行。

先准备实验目录并导出两份配置:

mkdir -p /tmp/dsh-lab cd /path/to/your/dsh/workspace # 只看 bundle 层,不包含用户补丁 pnpm dsh --profile web --dump-config --default-only > /tmp/base.yml # 完整组合,包含 profile 补丁、家目录补丁等用户层 pnpm dsh --profile web --dump-config > /tmp/full.yml # 对比两份,观察多出来的行来自哪一层 diff -u /tmp/base.yml /tmp/full.yml | tee /tmp/base-vs-full.diff

如果diff输出很多,不要慌。DSH 的配置树本质上是“行的组合”,每一行代表一个插件或服务。你要先抓住七行:llmsessionagent-looptoolssystem-promptsandbox-policyagent-presets。它们是 Web profile 里最容易影响体验的功能分组。

可以先用文本过滤把关键行拎出来:

# 假设输出顶层是 YAML 列表 yq '.[] | select(.name == "llm" or .name == "session" or .name == "agent-loop" or .name == "tools" or .name == "system-prompt" or .name == "sandbox-policy" or .name == "agent-presets")' /tmp/base.yml

如果你机器上没有yq,也可以直接用grep -n

grep -nE 'name: (llm|session|agent-loop|tools|system-prompt|sandbox-policy|agent-presets)' /tmp/base.yml

此时你大概率会看到llm行的config里没有apiKey,也可能没有baseUrl。这是正常的,因为 bundle 默认组合不应该硬编码任何人的密钥。对 DSH 初学者来说,这一步的核心不是“修好它”,而是先确认:默认组合提供了什么,用户补丁层应该补什么

如果你还没有 Key,可以先去 TaoToken 控制台创建:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=dsh_default_only_keys 。创建时用YOUR_API_KEY作为占位符写在配置里,真实 Key 不要提交到 Git。

2. diff 两份配置树:bundle 层与用户补丁层分别多了什么

练习 1 的验收目标,是能不看文件说出 base 的七个功能分组:基础设施、编排、设置凭据、持久化、安全、模型面工具、委派。你可以先把/tmp/base.yml/tmp/full.yml做结构化对比,而不是一行行肉眼扫。

# 把两份都转成按 name 排序的简表,方便看差异 yq -r '.[] | [.name, (.disabled // false)] | @tsv' /tmp/base.yml | sort > /tmp/base.names.tsv yq -r '.[] | [.name, (.disabled // false)] | @tsv' /tmp/full.yml | sort > /tmp/full.names.tsv diff -u /tmp/base.names.tsv /tmp/full.names.tsv

你可能会发现,full.yml多出来的行不一定来自 profile 补丁,也可能来自家目录级补丁。DSH 的组合层优先级大致是:

bundle 默认 → profile 补丁 → 家目录补丁 → 命令行 --patch

越靠后,优先级越高;同一行如果后写,就会覆盖前面的值。注意这里说的是“行级覆盖”和“整行替换”,不是把两个对象的字段深度合并。很多初学者写补丁时只写:

- name: llm config: apiKey: YOUR_API_KEY

结果providermodeltimeout等默认字段全没了,然后开始怀疑 DSH 是不是坏了。其实是你把整行替换成了一个不完整的llm行。正确做法是:你想覆盖llm行,就重述这一行里你希望最终存在的字段

回到七个分组,可以这样建立直觉:

分组代表行你该关注什么
基础设施session会话生命周期、存储位置、恢复策略
编排agent-loop主循环、停止条件、工具调用节奏
设置凭据llmbaseUrlapiKey、模型名、超时
持久化session相关配置历史记录、工作区状态、缓存
安全sandbox-policyshell 沙箱、文件访问边界
模型面工具tools暴露给模型的工具面
委派agent-presets子代理、预设、角色委派

system-prompt往往横跨“设置”和“编排”,它决定 persona 和系统提示词;sandbox-policy则和安全强相关。至于bash-sandboxpwsh-sandbox为什么互斥,可以理解成:同一个宿主运行时里,默认 shell 沙箱只能选中一个。它们依赖的底层服务和平台能力不同,两个都激活会争抢同一个服务键或同一个执行入口,所以组合层通常用互斥方式表达。你在full.yml里看到其中一个处于启用状态,另一个可能是disabled: true,而不是被删除。

这里有一个重要习惯:不要通过删行来禁用功能。上层补丁如果还想覆盖这一行,删掉后可能找不到目标,补丁会静默失效。DSH 的 web-app 层更推荐“禁用而非删除”:

- name: pwsh-sandbox disabled: true

这样配置树里仍然有这一行,只是不激活。后续要排查bash-sandboxpwsh-sandbox的互斥关系,也能从disabled状态一眼看出来。

3. 给 llm 行补 TaoToken:Base URL、Key 与整行替换规则

现在进入本篇最关键的动作:给默认llm行补凭据。你需要 TaoToken 的 API Key,入口在官网:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=dsh_llm_credential 。创建后先放到环境变量里,避免把明文写进补丁文件:

export TAOTOKEN_API_KEY=YOUR_API_KEY

然后编辑 profile 级补丁。路径通常是$DSH_HOME/profiles/web/cordis.patch.yml,其中$DSH_HOME默认是~/.dsh

mkdir -p ~/.dsh/profiles/web $EDITOR ~/.dsh/profiles/web/cordis.patch.yml

写入一个完整的llm行。注意name以你--dump-config实际输出的包名为准,下面用llm表示该行:

# ~/.dsh/profiles/web/cordis.patch.yml - name: llm disabled: false config: provider: openai-compatible baseUrl: https://taotoken.net/api apiKey: !!js process.env.TAOTOKEN_API_KEY model: claude-sonnet-4-5 timeoutMs: 60000

这里有两个重点:

第一,baseUrl必须用https://taotoken.net/api,不要写成https://taotoken.net/api/v1或其他猜测路径。Base URL 是给 DSH 的 LLM 插件拼接请求用的,多一层少一层都可能导致 404。

第二,apiKey!!js process.env.TAOTOKEN_API_KEY,表示在挂载时读取环境变量。如果你暂时不想用环境变量,也可以先写占位符:

apiKey: YOUR_API_KEY

但不要把真实 Key 提交到仓库。对初学者来说,更稳妥的方式是本地 shell 里export,补丁文件里只保留!!js process.env.TAOTOKEN_API_KEY

改完后重新导出完整配置:

pnpm dsh --profile web --dump-config > /tmp/full-with-taotoken.yml # 只看 llm 行最终值 yq '.[] | select(.name == "llm")' /tmp/full-with-taotoken.yml

如果输出里baseUrlhttps://taotoken.net/apiapiKey已经被替换成你的环境变量值或占位符,说明用户补丁层已经生效。接下来做一次“叠加验证”:

# 用 --patch 临时再覆盖一次,观察后写层是否赢 pnpm dsh --profile web --dump-config \ --patch /tmp/override-llm.yml > /tmp/full-with-patch.yml

其中/tmp/override-llm.yml可以写:

- name: llm config: provider: openai-compatible baseUrl: https://taotoken.net/api apiKey: YOUR_API_KEY model: claude-sonnet-4-5 timeoutMs: 120000

对比timeoutMs60000还是120000,你就能亲眼看到“后写的层赢”。同时也要注意:--patch同样是整行替换,所以上面把五个字段都重述了。如果你只写timeoutMs: 120000,那前面 profile 补丁里的apiKeybaseUrl可能会消失,最终llm行变成不完整配置。

4. 把覆盖写进 profile 补丁:家目录级、profile 级与 --patch 的优先级

练习 1 的产物不只是/tmp/base.yml,还包括一份你自己写的 profile 补丁。它以后会成为所有 DSH 排障的对照基线。你现在可以按下面顺序做一次完整实验。

第一步,确认 profile 级补丁:

cat ~/.dsh/profiles/web/cordis.patch.yml

第二步,再写一条家目录级补丁,让它对所有 profile 生效:

$EDITOR ~/.dsh/cordis.patch.yml

内容可以覆盖llm的默认模型,但记得重述整行:

# ~/.dsh/cordis.patch.yml - name: llm disabled: false config: provider: openai-compatible baseUrl: https://taotoken.net/api apiKey: !!js process.env.TAOTOKEN_API_KEY model: claude-sonnet-4-5 timeoutMs: 90000

第三步,观察优先级。根据 DSH 的规则,家目录级补丁优先于 profile 级补丁。所以如果 profile 级写了timeoutMs: 60000,家目录级写了90000,最终应该看到90000

pnpm dsh --profile web --dump-config > /tmp/final.yml yq '.[] | select(.name == "llm")' /tmp/final.yml

第四步,再用--patch临时覆盖,验证最高优先级:

pnpm dsh --profile web --dump-config \ --patch /tmp/override-llm.yml > /tmp/final-with-cli-patch.yml yq '.[] | select(.name == "llm")' /tmp/final-with-cli-patch.yml

这样你就能画出一行配置的最终值推导过程:

bundle 默认 llm.apiKey = 空 → profile 补丁 llm.apiKey = !!js process.env.TAOTOKEN_API_KEY → 家目录补丁 llm.baseUrl = https://taotoken.net/api → --patch llm.timeoutMs = 120000 最终 llm 行 = 最后写入层提供的完整字段集

这里有几个初学者最容易踩的卡点。

第一,补丁文件为空或只有注释会加载失败。因为补丁文件需要能被解析成列表;空文件解析结果不是列表,只有注释也可能被当成空内容。处理方式是保留合法列表项,或者暂时不要创建这个补丁文件。

第二,禁用某行不要删行,用disabled: true。删掉之后,上层补丁想覆盖它时可能找不到目标,导致你以为补丁写了,实际没生效。

第三,每改一行配置,先想清楚它属于哪个平面:是宿主组合,还是 agent preset。宿主组合影响 DSH 进程本身;agent preset 影响模型被注入怎样的提示词、工具和委派规则。把两层混在一起改,排查会非常痛苦。对练习 1 来说,llm行属于宿主组合里的设置凭据平面,不要把它写到 agent preset 里。

如果你在验证过程中发现apiKey没生效,可以按三步排查:--dump-config看最终值,diff定位来源层,修改对应层后再导出验证。不要靠猜。

5. 读懂 !!js 与 inject:为什么行序不重要,服务键才重要

练习 1 还要求你建立对!!js和加载顺序的直觉。虽然本篇重点是默认组合和补凭据,但如果不理解这两个概念,补丁很容易写错。

!!js的核心规则是:在挂载时求值,不是每次读取时求值。也就是说,DSH 加载配置树时会把表达式算一次,之后插件读到的就是那个结果。它可用的 Loader 上下文包括processctxdshHomePathbaseUrl等。

例如:

- name: llm config: apiKey: !!js process.env.TAOTOKEN_API_KEY baseUrl: !!js baseUrl ?? 'https://taotoken.net/api'

这里process.env.TAOTOKEN_API_KEY在挂载时读取环境变量。如果你启动 DSH 的 shell 里没有TAOTOKEN_API_KEY,求值结果就是undefined,之后再怎么刷新 Web UI 也不会自动补上。另一个表达式baseUrl ?? 'https://taotoken.net/api'表示优先使用 Loader 上下文里的baseUrl,没有就回退到 TaoToken 的 API 地址。但为了避免不确定性,给 DSH 的llm行补凭据时,建议直接写死baseUrl: https://taotoken.net/api,只在apiKey这类敏感字段上用!!js process.env...

再比如ctx.serviceName,它只有在inject激活之后才可引用。你不能在一个插件还没等到依赖服务时,就假设ctx.serviceName可用。这也是 DSH 里“加载顺序”和“激活顺序”容易混淆的地方。

在组合文件中,行的先后顺序没有语义。你把llm行放在第一行还是最后一行,不会决定它是否先激活。真正决定激活的是服务依赖:

- name: session inject: [llm] - name: agent-loop inject: [llm, session, tools]

如果某一行声明了inject: [llm],那么它进入 waiting 状态,直到llm服务出现并激活。所以调试“为什么某个插件没跑”时,不应该盯着 YAML 行序,而应该看服务键:

grep -n "inject" /tmp/full.yml grep -n "name:" /tmp/full.yml | head -80

如果llm本身被disabled: true,那么依赖它的sessionagent-loop就可能一直等不到服务。此时你要检查的是llm行的disabled状态、baseUrlapiKey,而不是把它挪到文件最上面。

回到练习 1 的验收:你应该能不看文件说出 base 的七个功能分组,并解释bash-sandboxpwsh-sandbox为什么互斥。前者是基础设施/安全层面的 shell 执行沙箱,后者是另一种 shell 沙箱;它们在同一条激活链上争夺同一个执行服务,所以组合层会禁用其中一个。你还应该能说清楚:行声明了什么服务依赖,比它写在文件哪个位置重要得多

6. 同一台机器上的 Claude Code、Codex、CC Switch 如何统一到 TaoToken

DSH 补完凭据后,很多人会顺手把 Claude Code、Codex、CC Switch 也配到同一个供应商。这里必须分清工具,不能把ANTHROPIC_*套到 Codex 上。

Claude Code 使用settings.json,常见位置是~/.claude/settings.json或项目级.claude/settings.json

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "YOUR_API_KEY", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } }

如果你使用 Claude Code 的文档配置方式,可以参考 TaoToken 的 Claude Code 文档:https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=dsh_claude_code_doc 。注意这里仍然是 Claude Code 的ANTHROPIC_*环境变量,不要混到 Codex。

Codex 使用config.toml,常见位置是~/.codex/config.toml

model = "gpt-5" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY"

然后在你启动 Codex 的 shell 里设置:

export TAOTOKEN_API_KEY=YOUR_API_KEY

注意:Codex 的配置里没有ANTHROPIC_API_KEY,也没有ANTHROPIC_BASE_URL。如果你把 Claude Code 的环境变量抄到 Codex,轻则不生效,重则报鉴权错误。

CC Switch 可以按“三件套”理解:供应商名称、Base URL、API Key。新增一个供应商时填:

供应商名称:TaoToken Base URL:https://taotoken.net/api API Key:YOUR_API_KEY 默认模型:claude-sonnet-4-5

如果 CC Switch 里还要选择协议或模型列表,按你实际使用的客户端来填。核心仍然是三件套:地址、密钥、模型。DSH 的llm行、Claude Code 的settings.json、Codex 的config.toml、CC Switch 的供应商配置,都使用同一个 Base URL:https://taotoken.net/api

如果你还没有统一 Key,可以回到 TaoToken 控制台创建:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=dsh_cc_switch_keys 。创建后建议按工具分开命名,例如dsh-webclaude-codecodex,方便以后排查和吊销。

7. 收尾:三步排查与高转化 CTA

练习 1 的最终产物应该包括两个文件:/tmp/full.yml,以及一份你写的 profile 补丁。它们是你后续所有 DSH 练习的对照基线。以后遇到“为什么行为是这样”的问题,按三步走:

  1. pnpm dsh --profile web --dump-config看最终值。
  2. diffyq定位这个值来自 bundle、profile、家目录还是--patch
  3. 修改对应层,再重新 dump 验证。

不要一上来就改 bundle,也不要用删除行的方式禁用功能。默认组合是骨架,用户补丁才是你的个人凭据和偏好。给llm行补 TaoToken 时,记住三个固定值:Base URL 用https://taotoken.net/api,Key 用YOUR_API_KEY或环境变量,补丁整行替换而不是深合并。

如果你已经完成/tmp/base.yml/tmp/full.yml的对比,下一步可以体验 TaoToken 的模型对话,确认 Key 和模型名是否匹配:https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=dsh_chat_cta 。如果准备把 DSH、Claude Code、Codex 一起接入,可以看 Coding Plan 是否适合你的使用频率:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=dsh_plan_cta 。需要创建或轮换 Key 时,从控制台进入:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=dsh_keys_cta 。Claude Code 的具体环境变量和 settings.json 写法,以文档为准:https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=dsh_doc_cta 。官网总入口在这里:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=dsh_final_checklist 。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 12:30:36

CentOS 7最小化安装后必备运维配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 12:30:27

达梦数据库6001网络异常的深度诊断与根因分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 12:27:53

深入理解LLVM与llvmpipe:从IR到256位SIMD的编译艺术

1. LLVM 项目到底是个什么东西如果你去 LLVM 官网,会看到一句话:The LLVM Project is a collection of modular and reusable compiler and toolchain technologies。翻译过来其实特别直白:LLVM 是一个模块化、可复用的编译器和工具链技术集合…

作者头像 李华
网站建设 2026/9/18 12:27:51

go2rtc统一接入多品牌摄像头:Docker部署与低延迟播放实践

1. 摄像头协议割裂的痛点,才是 go2rtc 真正擅长的事1.1 一个真实场景:三种摄像头,三套接入方式我先说一个让我彻底转向 go2rtc 的经历。前年帮一个做门店的朋友改造监控,他店里同时有海康的枪机、萤石的云台、还有一台米家的室内摄…

作者头像 李华