
深度剖析providers.shclaudish-to-english如何用纯bash安全调用三大LLM API【免费下载链接】claudish-to-english项目地址: https://gitcode.com/gh_mirrors/cl/claudish-to-englishclaudish-to-english是一个 Claude Code 纯bash插件它的 provider 层 providers.sh 仅凭curljq两个小工具就能安全地调用 Ollama、Anthropic 与 OpenAI 三大 LLM API把助手的每条回复改写成通俗易懂的白话文。密钥不出命令行、任何失败都自动降级——本文带你逐行拆解这个不到 300 行的 bash 脚本。一分钟看懂providers.sh 在项目中的角色 claudish-to-english 只有两个钩子脚本rewrite.sh助手消息上屏时追加或替换一段白话版rewrite-md.sh可选写盘/编辑 Markdown 文件时把正文改写成通俗英语两者都通过source加载同一个 provider 层 providers.sh它对外只暴露一个函数llm_complete SYSTEM USER——传入系统提示词和内容向当前配置的 provider 发起一次 chat 补全结果写回一组全局变量。钩子脚本自己决定失败时怎么办。全局变量含义rewrite改写后的文本任何失败都是空串curl_rccurl 退出码0 成功1 缺密钥28 超时errprovider 返回的报错信息httpHTTP 状态码仅云 providertruncated1 输出撞到 token 上限、已被丢弃一个函数、三家 API、同一套契约——这是读懂源码最关键的一点。为什么纯 bash反而是安全性的关键 对新手来说纯 bash听起来很原始但在这个项目里它恰恰决定了几条安全性质依赖极少只需curl和jqmacOS / Windows 基本都自带缺任一个rewrite.sh 立即放行原文绝不半拉子运行。密钥永远不上命令行ps能列出每个进程的完整命令行——把 API key 拼进 curl 参数本机任何用户都能看见。所以 providers.sh#L96-L106 的_llm_key_file()会把header x-api-key: ...写进一个0600 权限的私有临时文件用curl -K传入命令行上只有文件路径没有密钥本身。半截写入直接判失败临时文件写不满比如磁盘满时脚本宁可报错也不让 curl 拿着空-K文件裸奔发请求。走前必清理发起请求前注册trap ... EXIT即使钩子中途被杀密钥文件也不会残留在临时目录里。三大 Provider 逐个拆解一个函数如何适配三家 API用CLAUDISH_PROVIDER选择 provider两个钩子共享此设置providers.sh 里是一个简单的case分支。Ollama默认本地模型零密钥 ✅请求发到本机的$OLLAMA/api/chat默认 11434 端口完全不需要密钥对话内容不出机器。请求体里有两个耐看的小细节think: false关掉推理阶段——改写这种简单任务不需要隐藏思考能省下大部分延迟temperature: 0.3保证输出稳定。Anthropic Messages API密钥优先读CLAUDISH_ANTHROPIC_KEY缺省时回退环境变量ANTHROPIC_API_KEY默认模型claude-haiku-4-5补全长度的上限CLAUDISH_MAX_TOKENS默认 4096必须显式给出这是 Messages API 的硬性要求请求里刻意不写temperature——当前 Claude 模型会拒绝采样参数响应的content是块数组脚本用jq只挑出text类型块再拼接开启 thinking 的模型会先吐出非文本块OpenAI 兼容端点OpenAI、LM Studio、vLLM、OpenRouter 通吃任何实现了/chat/completions的服务器都能接基础 URL 由CLAUDISH_OPENAI_URL配置本地服务器免密钥——只有指向 OpenAI 官方端点时才要求密钥。这里藏着全脚本最精巧的一处reasoning_effort字段。默认对官方端点发送noneGPT-5.6 级别模型否则会把大量推理 token 烧在一次简单改写上对自定义本地 URL 则整个省略有些本地服务器会拒绝未知字段。而不设置和显式设为空是两种不同语义providers.sh#L65-L71 用${CLAUDISH_OPENAI_EFFORTx}这个小技巧把它们区分开——后者是强制关掉该字段的逃生舱专治完全不支持reasoning_effort的模型。三家通用的细节用 jq 构建 JSON 请求 ⚙️请求体不是手工拼字符串而是jq -n --arg ...生成——内容里的引号、换行、特殊字符全部自动转义请求 JSON 不可能被文本打断。这是纯 bash 处理任意文本时的第一道防线。HTTP 状态码的处理同样统一curl -w \n%{http_code}把状态码追加到响应尾部再交给 _llm_split_status() 拆到全局变量http000根本没连上被归一化成空值。失败也优雅半截改写直接丢弃原因一句话归因 ⚠️插件的fail-open 契约是灵魂任何失败都原样保留原文。providers.sh 还有两个更细的决策值得注意输出撞到 token 上限 → 整段丢弃。无论是 Anthropic 的stop_reason: max_tokens、OpenAI 的finish_reason: length还是 Ollama 的done_reason: length都会置truncated1并清空rewrite。理由很直接屏幕上半截改写只会让人困惑而 Markdown 钩子的覆写模式下半截文本甚至会替换掉真实文档。HTTP 报错也会被人话翻译。5xx / 429 且响应体没有可解析的错误信息时归类为服务端问题宕机、过载、限流其余非 2xx 直接提示你检查基础 URL 是否配错。最后一步是 llm_notice_why()把各种失败状态映射成一句可操作的话——缺密钥请设置 CLAUDISH_ANTHROPIC_KEY、模型不存在先 ollama pull、超时了调大超时或换小模型。rewrite.sh 每个会话只展示一次。失败不是静默用户永远知道为什么。新手上手指南三步切换 LLM Provider 选 provider在 Claude Code 的settings.json的env块写入配置别改插件缓存里的 hooks/hooks.json{ env: { CLAUDISH_PROVIDER: anthropic, CLAUDISH_ANTHROPIC_KEY: sk-ant-你的密钥 } }密钥用插件专属变量优先CLAUDISH_ANTHROPIC_KEY/CLAUDISH_OPENAI_KEY。云 provider 会自动回退读取环境里的ANTHROPIC_API_KEY/OPENAI_API_KEY——如果你 shell 里本来就 export 了这些变量切到云 provider 的那一刻消息就开始出机器了务必有意为之。重启并验证env在会话启动时就被冻结改完必须重启 Claude Code。再设CLAUDISH_DEBUG1看$TMPDIR/claudish-to-english/debug.log每次调用的 provider、状态码、字节数一目了然。更保守的选择是保持默认的本地 Ollama零密钥、内容不出机器模型没就绪时插件什么都不做——这是设计如此不是 bug。关键环境变量速查表变量默认作用CLAUDISH_PROVIDERollama选用哪家 LLMollama / anthropic / openaiCLAUDISH_MODEL各 provider 自带默认覆盖模型名如claude-haiku-4-5、gpt-5.6-lunaCLAUDISH_ANTHROPIC_KEY空Anthropic 密钥缺省回退ANTHROPIC_API_KEYCLAUDISH_OPENAI_KEY空OpenAI(-兼容) 密钥仅官方端点必填CLAUDISH_OPENAI_URLOpenAI 官方/v1指向 LM Studio、vLLM、OpenRouter 等兼容服务器CLAUDISH_MAX_TOKENS4096Anthropic provider 的补全上限CLAUDISH_TIMEOUT45展示钩子的 LLM 调用超时秒完整清单见 README.md 的 Configuration 一节版本演进记录在 CHANGELOG.md。小结值得抄进你 bash 工具箱的 4 个技巧 ️密钥不上命令行私有 0600 临时文件 curl -K传递JSON 一律jq -n --arg构建绝不手工拼转义curl -w \n%{http_code}追加状态码一次请求同时拿到响应和状态${VARx}区分未设置与设为空小把戏换来显式关闭的逃生舱下次你看到任何用 bash 调 LLM API 的项目都可以拿这三问去检验它密钥在哪失败路径是什么半截输出去了哪providers.sh 对这三个问题都给出了干净利落的回答。【免费下载链接】claudish-to-english项目地址: https://gitcode.com/gh_mirrors/cl/claudish-to-english创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考