尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

我用 AI 给 Obsidian 写了一个“LLM-wiki”插件:TaoToken 统一 Key 配置与验证

发布时间:2026/9/26 3:42:01

资讯中心
01
ARTICLE

我用 AI 给 Obsidian 写了一个“LLM-wiki”插件:TaoToken 统一 Key 配置与验证

我用 AI 给 Obsidian 写了一个“LLM-wiki”插件:TaoToken 统一 Key 配置与验证
1. 为什么我要给 Obsidian 写一个 LLM-wiki 插件先说清楚这个插件是什么、能做什么、适合谁。LLM-wiki 是一个跑在 Obsidian 里的知识编译插件它把 vault 里的raw/原始资料交给大模型自动产出结构化的wiki/页面包括摘要、概念、实体、对比和深度分析。适合那些笔记攒了几百篇、标签越加越乱、最后干脆放弃整理的人。我试过手动给 500 篇笔记建双链坚持了不到两周就烂尾所以决定换个思路让 LLM 当编译器我只负责喂料和提问。但插件真正落地时第一个卡住我的不是 prompt也不是目录结构而是模型通道怎么统一。插件里要调 LLM就得有 API Key、有 base URL、有模型名。如果每个用户自己填 OpenAI、Anthropic、DeepSeek 各一套配置插件就没法开箱即用。所以我给插件设计了一个统一的 Key 配置层用 TaoToken 作为统一 API 通道把模型调用收敛到一份settings.json里。这篇就把这套配置骨架和连通性验证动作完整拆开你可以直接抄到自己的 Obsidian 插件里。核心检索词先摆出来Obsidian 插件开发、LLM-wiki、TaoToken 统一 Key、settings.json 配置、连通性验证。下面从问题场景讲到可复制配置再到验证和排障全程可跟做。2. TaoToken 前置统一 Key 与 API 通道准备在写插件配置之前先把通道准备好。TaoToken 在这里扮演的角色是统一 API 入口插件不需要分别对接多家模型厂商只需要一个 base URL 和一个 Key就能在模型之间切换。对插件开发者来说这意味着settings.json里只需要维护一份凭证而不是给每个 provider 写一套适配代码。你需要先拿到 API Key。打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后进入控制台在 API Keys 页面创建一个新 Key。创建时建议按用途命名比如obsidian-llm-wiki-dev方便后面区分测试和生产。Key 只在创建时完整显示一次复制后先存到安全的地方。拿到 Key 之后记住两个地址用途地址API 基址插件请求用https://taotoken.net/api控制台管理 Key、看用量https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入文档查参数和模型名https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注意API 基址不要加 UTM 参数插件请求里带查询串容易导致签名或路由异常。UTM 只用于网页跳转。模型名怎么选插件里我默认用claude-sonnet-4-5这类通用对话模型做 ingest 和 query因为知识编译需要长上下文和稳定的结构化输出。具体可用模型列表以接入文档为准不要凭记忆硬编码。如果你打算长期跑 ingest 和 lint建议单独看一下 Coding Plan 页面按量或包月的方式对高频调用更划算https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。3. 可复制配置settings.json 骨架与插件加载逻辑Obsidian 插件的配置一般存在.obsidian/plugins/plugin-id/data.json但为了和通用工具链对齐我在项目里同时维护一份settings.json作为默认骨架。插件启动时先读data.json没有就用settings.json兜底。下面这份骨架你可以直接复制。{ llmWiki: { provider: taotoken, baseUrl: https://taotoken.net/api, apiKey: , model: claude-sonnet-4-5, maxTokens: 8192, temperature: 0.3, timeoutMs: 120000, vaultRoot: , paths: { raw: raw, wiki: wiki, legacy: legacy, drafts: drafts, index: index.md, log: log.md, schema: CLAUDE.md }, features: { autoClassifyRaw: true, injectVaultPath: true, injectIndex: true, xmlIsolation: true } } }几个字段值得单独说。baseUrl固定指向 TaoToken 的 API 基址插件里所有请求都从这里拼/v1/chat/completions。apiKey留空由用户在插件设置面板里填填完写回data.json不写进源码。temperature给 0.3是因为知识编译要的是稳定复现不是创意发散。timeoutMs给到 120 秒ingest 一次要生成 5 到 10 个页面短了容易断。插件侧读取配置的代码大致长这样用 TypeScript 写import { App, Plugin, PluginSettingTab, Setting } from obsidian; interface LLMWikiSettings { provider: string; baseUrl: string; apiKey: string; model: string; maxTokens: number; temperature: number; timeoutMs: number; vaultRoot: string; paths: Recordstring, string; features: Recordstring, boolean; } const DEFAULT_SETTINGS: LLMWikiSettings { provider: taotoken, baseUrl: https://taotoken.net/api, apiKey: , model: claude-sonnet-4-5, maxTokens: 8192, temperature: 0.3, timeoutMs: 120000, vaultRoot: , paths: { raw: raw, wiki: wiki, legacy: legacy, drafts: drafts, index: index.md, log: log.md, schema: CLAUDE.md, }, features: { autoClassifyRaw: true, injectVaultPath: true, injectIndex: true, xmlIsolation: true, }, }; export default class LLMWikiPlugin extends Plugin { settings: LLMWikiSettings; async onload() { await this.loadSettings(); this.addSettingTab(new LLMWikiSettingTab(this.app, this)); } async loadSettings() { const data await this.loadData(); this.settings Object.assign({}, DEFAULT_SETTINGS, data); if (!this.settings.vaultRoot) { this.settings.vaultRoot (this.app.vault.adapter as any).getBasePath(); } } async saveSettings() { await this.saveData(this.settings); } }vaultRoot这一项很关键。LLM 通过 ACP 收到「请在 wiki/summaries/ 创建文件」时它不知道你的 vault 在磁盘上的绝对路径写不了文件。所以插件在每条操作消息里注入vaultRoot让模型知道往哪写。这个坑我在早期版本踩过模型只会回复「我打算创建以下文件」一个都不落地。设置面板里放一个 Key 输入框和一个「测试连接」按钮按钮逻辑就是下一节的验证请求。4. 验证请求连通性检查与成功结果配置写完先别急着跑 ingest做一次最小连通性验证。这一步的目的是确认 Key 有效、base URL 可达、模型名正确、返回结构符合预期。我在插件里内置了一个testConnection方法你也可以用 curl 先手动验证。curl -sS https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -d { model: claude-sonnet-4-5, messages: [ {role: system, content: You are a connectivity probe. Reply with the single word: OK}, {role: user, content: ping} ], max_tokens: 16, temperature: 0 }成功时你会拿到类似这样的返回{ id: chatcmpl-xxxx, object: chat.completion, model: claude-sonnet-4-5, choices: [ { index: 0, message: { role: assistant, content: OK }, finish_reason: stop } ], usage: { prompt_tokens: 24, completion_tokens: 2, total_tokens: 26 } }看到choices[0].message.content是OK说明通道通了。插件里的验证方法可以复用同一套请求只是把结果映射成布尔值和错误信息async testConnection(): Promise{ ok: boolean; message: string } { const { baseUrl, apiKey, model, timeoutMs } this.settings; if (!apiKey) return { ok: false, message: API Key 未填写 }; const controller new AbortController(); const timer setTimeout(() controller.abort(), timeoutMs); try { const res await fetch(${baseUrl}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${apiKey}, }, body: JSON.stringify({ model, messages: [ { role: system, content: Reply with the single word: OK }, { role: user, content: ping }, ], max_tokens: 16, temperature: 0, }), signal: controller.signal, }); if (!res.ok) { const text await res.text(); return { ok: false, message: HTTP ${res.status}: ${text.slice(0, 200)} }; } const data await res.json(); const content data?.choices?.[0]?.message?.content ?? ; return content.includes(OK) ? { ok: true, message: 连接正常 } : { ok: false, message: 返回内容异常: ${content.slice(0, 100)} }; } catch (err: any) { return { ok: false, message: 请求失败: ${err.message} }; } finally { clearTimeout(timer); } }验证通过后再跑一次真实的 ingest 小样。往raw/tech/丢一篇短文章输入/ingest raw/tech/demo.md观察wiki/summaries/下是否生成了对应页面index.md是否被追加log.md是否记录了本次操作。三个都动了说明整条链路从配置到写文件全部打通。5. 本篇常见错排查配置和验证过程中最容易撞上的几类问题我列在下面按出现频率排序。401 或 403Key 无效或没带上。先确认Authorization头是Bearer key格式中间有一个空格。再确认 Key 没有多余换行从控制台复制时容易带上尾部空白。如果 Key 是在别的环境生成的检查是否被禁用或过期。404base URL 拼错。常见错误是写成https://taotoken.net/api/v1又在代码里拼了一次/v1变成/api/v1/v1/chat/completions。记住baseUrl只到/api路径拼接由请求代码负责。模型名不存在。报错信息里通常会带model not found。不要凭记忆写模型名去接入文档确认当前可用列表。插件里把模型名做成下拉选择而不是自由输入能省掉一大半这类问题。请求超时。ingest 一次生成多个页面耗时可能超过 60 秒。把timeoutMs提到 120000 以上并且用AbortController做超时控制避免请求悬挂。如果频繁超时考虑把单次 ingest 拆成「先生成摘要再生成概念页」两步。模型只讨论不执行。这是 prompt 层面的坑不是配置问题。表现是模型回复一大段分析但一个文件都没创建。解决办法是在系统规范里明确写「收到指令后立即执行所有步骤不要停下来询问确认」并且把源文件内容用 XML 标签隔离避免文章里的描述被当成指令执行。写文件路径为空。如果vaultRoot没注入模型不知道往哪写。检查loadSettings里是否用getBasePath()兜底以及每条操作消息是否带上了绝对路径。重复注入规范导致 token 浪费。如果模型运行时会自动读取工作目录下的CLAUDE.md插件就不要再把全文拼进每条消息。改成一句「Follow the wiki schema defined in CLAUDE.md」即可既省钱又减少混淆。排障时如果卡在接入层优先看 API Keys 和接入文档两个页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 和 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。想先在网页里验证模型是否正常可以直接用模型对话页面发一条消息https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。6. 把配置沉淀成可复用骨架走到这里你的 Obsidian 插件应该已经能用一份settings.json完成 TaoToken 统一 Key 配置并且通过连通性验证。我建议把这份骨架单独抽成一个config.ts把默认值、读取、保存、验证四个函数放在一起插件主逻辑只依赖接口不直接碰字段。这样以后换模型、加 provider、调超时都只改一个文件。如果你打算长期跑知识编译ingest 和 lint 的调用频率不低可以看一下 Coding Plan 的额度方式比按次调用更可控https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。需要管理多个 Key 或查看用量控制台在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后留一个我踩过的坑作为收尾/init不要依赖 LLM 执行。最初我把「请创建目录结构」发给模型结果它有时候创建、有时候只描述。后来改成插件本地用 Obsidian 的 Vault API 直接建目录和文件零 LLM 依赖几百毫秒完成百分之百可靠。配置层同理能本地校验的先本地校验把 LLM 留给真正需要它的编译和问答环节。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。