1. 为什么你的 claude code 需要一个本地知识库用 claude code 写代码久了你会发现一个尴尬的事实模型对通用框架了如指掌但对你项目里的业务规则、历史决策、踩过的坑一无所知。你问它「这个订单接口为什么必须幂等」它只能给你一段教科书式的通用回答而不是你团队三年前那次事故换来的教训。这就是 claude code 知识库要解决的问题。简单说知识库就是给 claude code 外挂一套「项目记忆」让它在回答前先去你的本地文档里检索相关片段再结合这些片段生成答案。适合谁适合所有已经用 claude code 做日常开发、但反复被「模型不懂我项目」折磨的个人开发者和团队。落地路径有两条。一条是传统 RAG把文档切片、向量化、存进向量库查询时做相似度召回。另一条是 File-Based 知识库用 Markdown/YAML 文件加目录结构做弱结构化记忆靠 INDEX 路由按需加载。前者擅长「帮你找资料」后者擅长「让 AI 记住你的项目」。这篇教程把两条路都跑通并且用 TaoToken 统一 Key 把模型调用链路收口避免你在多个平台之间来回切换 Key。我试过把两种方式混用向量检索负责大范围召回文件索引负责精确命中项目决策。下面从目录结构开始一步步搭出最小可用知识库。2. TaoToken 前置准备统一 Key 打通模型调用链路在动手写检索脚本之前先把模型调用这一层理顺。claude code 知识库的检索问答环节需要调用大模型如果你直接用官方渠道会面临两个问题一是 Key 分散在不同平台二是网络和计费不透明。TaoToken 的作用就是提供一个统一的 API 入口你只需要一个 Key就能调用包括 Claude 系列在内的多种模型。先注册并拿到 Key。访问官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 完成账号注册然后进入控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 在「API Keys」页面点击新建复制生成的 Key 保存好。API 基础地址统一用 https://taotoken.net/api 注意这个地址不带任何查询参数。如果你用的是 Claude Code 这类命令行工具需要配置三件套Base URL、API Key、Model ID。Base URL 填 https://taotoken.net/api Key 填你刚创建的Model ID 根据你需要的模型填写比如 claude-sonnet-4-20250514 这类标识。配置方式可以写进环境变量也可以写进工具的配置文件。对于长期做编码和 Agent 任务的场景可以了解 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 它更适合高频调用。如果你只是想先验证模型能不能正常对话可以用模型对话页面 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 快速测试。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 遇到参数问题可以对照查阅。这里要强调一点TaoToken 是合规的 API 聚合入口不是让你绕过任何限制的工具。你拿到的 Key 就是正常调用模型的凭证所有请求都走标准 HTTP 接口。把 Key 配好之后后面的检索脚本才能顺利调用模型做问答。3. 可复制配置目录结构、切片脚本与检索配置这一节给出可以直接复制的配置。先建目录结构再写切片脚本最后配检索参数。目录结构建议这样组织兼顾向量检索和文件索引knowledge-base/ ├── raw/ # 原始文档放 Markdown、txt │ ├── api/ │ ├── decisions/ │ └── bugs/ ├── chunks/ # 切片后的 JSON 文件 ├── index/ # 向量索引持久化目录 ├── knowledge/ # File-Based 知识库 │ ├── INDEX.md # 路由入口 │ ├── concepts/ │ ├── patterns/ │ ├── decisions/ │ └── bugs/ ├── config/ │ └── settings.json # 检索与模型配置 └── scripts/ ├── chunk.py # 文档切片 ├── embed.py # 向量化 └── query.py # 检索问答配置文件config/settings.json内容如下把 Key 换成你自己的{ base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key, model_id: claude-sonnet-4-20250514, embedding_model: text-embedding-3-small, chunk_size: 500, chunk_overlap: 80, top_k: 5, index_path: ./index/faiss.index, chunks_path: ./chunks/chunks.json }切片脚本scripts/chunk.py按段落和固定长度切分保留重叠避免语义断裂import json import os from pathlib import Path def chunk_text(text, size500, overlap80): chunks [] start 0 while start len(text): end start size chunks.append(text[start:end]) start end - overlap return chunks def process_dir(raw_dir, out_file): all_chunks [] for path in Path(raw_dir).rglob(*.md): text path.read_text(encodingutf-8) for i, c in enumerate(chunk_text(text)): all_chunks.append({ id: f{path.stem}-{i}, source: str(path), text: c }) os.makedirs(os.path.dirname(out_file), exist_okTrue) with open(out_file, w, encodingutf-8) as f: json.dump(all_chunks, f, ensure_asciiFalse, indent2) print(f生成 {len(all_chunks)} 个切片) if __name__ __main__: process_dir(./raw, ./chunks/chunks.json)向量化脚本scripts/embed.py调用 TaoToken 的 embedding 接口import json import requests import numpy as np import faiss with open(./config/settings.json, encodingutf-8) as f: cfg json.load(f) with open(cfg[chunks_path], encodingutf-8) as f: chunks json.load(f) texts [c[text] for c in chunks] resp requests.post( f{cfg[base_url]}/embeddings, headers{Authorization: fBearer {cfg[api_key]}}, json{model: cfg[embedding_model], input: texts} ) vectors np.array([d[embedding] for d in resp.json()[data]], dtypefloat32) faiss.normalize_L2(vectors) index faiss.IndexFlatIP(vectors.shape[1]) index.add(vectors) faiss.write_index(index, cfg[index_path]) print(f索引写入完成共 {index.ntotal} 条)File-Based 知识库的knowledge/INDEX.md充当路由器内容示例# 项目知识索引 ## concepts - [订单幂等](./concepts/order-idempotent.md) - [库存扣减](./concepts/stock-deduct.md) ## decisions - [为什么用 Redis 做锁](./decisions/redis-lock.md) ## bugs - [超卖问题复盘](./bugs/oversell.md)claude code 在回答前先读 INDEX.md再按需深入对应文件。这样既省 token又能精确命中项目记忆。4. 验证请求从提问到命中的完整跑通配置写完了现在跑一次完整验证。先执行切片和向量化cd knowledge-base python scripts/chunk.py python scripts/embed.py预期输出类似生成 128 个切片 索引写入完成共 128 条接着写检索问答脚本scripts/query.pyimport json import requests import numpy as np import faiss with open(./config/settings.json, encodingutf-8) as f: cfg json.load(f) with open(cfg[chunks_path], encodingutf-8) as f: chunks json.load(f) index faiss.read_index(cfg[index_path]) def search(question): resp requests.post( f{cfg[base_url]}/embeddings, headers{Authorization: fBearer {cfg[api_key]}}, json{model: cfg[embedding_model], input: [question]} ) qv np.array([resp.json()[data][0][embedding]], dtypefloat32) faiss.normalize_L2(qv) scores, ids index.search(qv, cfg[top_k]) return [chunks[i] for i in ids[0]] def ask(question): contexts search(question) context_text \n\n.join([c[text] for c in contexts]) prompt f根据以下项目资料回答问题\n{context_text}\n\n问题{question} resp requests.post( f{cfg[base_url]}/chat/completions, headers{Authorization: fBearer {cfg[api_key]}}, json{ model: cfg[model_id], messages: [{role: user, content: prompt}] } ) return resp.json()[choices][0][message][content] if __name__ __main__: print(ask(订单接口为什么必须幂等))运行python scripts/query.py成功时你会看到模型基于你raw/目录里的文档给出回答而不是泛泛而谈。如果raw/decisions/里有一篇讲幂等的文档回答里会带上你项目特有的细节比如「因为支付回调会重复触发」。这就是命中的标志。再验证 File-Based 路径在 claude code 里让它先读knowledge/INDEX.md然后问「之前 Redis 锁那个决策是怎么定的」。它会顺着索引找到decisions/redis-lock.md回答里带上当时的取舍理由。两条链路都跑通最小可用知识库就成立了。5. 本篇常见错排查401、local proxy failed 与 reading choices搭建过程中最容易卡在几个报错上逐个说清楚。第一个是 401 Unauthorized。这个几乎都是 Key 没配对。检查config/settings.json里的api_key是不是完整的sk-开头字符串有没有多余空格。如果你把 Key 写进了环境变量确认脚本读取的是同一个变量名。还有一种情况是 Key 被复制时带了换行用echo $TAOTOKEN_KEY | tr -d \n清理一下。401 不会因为模型选错而出现所以先查 Key。第二个是 local proxy failed。这个报错通常出现在你本地配了某些网络转发工具导致请求发不出去。TaoToken 的 API 地址是标准 HTTPS不需要任何额外转发。检查你的环境变量里有没有HTTP_PROXY、HTTPS_PROXY这类设置有的话临时清掉再跑。命令是unset HTTP_PROXY HTTPS_PROXY然后重新执行脚本。如果用的是 Claude Code 命令行检查它的配置文件里有没有残留的代理字段。第三个是 reading choices 相关报错典型信息是Cannot read properties of undefined (reading choices)。这说明接口返回的结构和你预期的不一样通常是请求体格式错了。检查chat/completions请求里messages是不是数组、model字段有没有拼错。还有一种可能是返回了错误对象而不是正常响应打印resp.json()看完整内容里面会有error.message告诉你具体原因。第四个是 OAuth 相关报错。如果你在 Claude Code 里看到 OAuth 认证失败说明工具还在走它默认的登录流程没有用你配的 Base URL 和 Key。这时候要确认三件套是否写全Base URL 填https://taotoken.net/apiKey 填你的 TaoToken KeyModel ID 填对应模型标识。三者缺一不可只填 Key 不填 Base URL 会继续走默认端点。排障时建议打开详细日志把请求 URL、请求体、响应体都打印出来。大部分问题看一眼原始响应就能定位。如果确认配置无误还是报错对照接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 检查参数或者到 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 重新生成一个 Key 试试排除 Key 本身失效的可能。6. 把知识库接进日常编码流最小可用知识库跑通之后下一步是让它融入日常。我的做法是在项目根目录放一个knowledge/文件夹每次做完一个决策、修完一个 bug就顺手往对应目录写一个 Markdown 文件并在INDEX.md里加一行链接。这样知识库会随着项目一起生长越用越准。向量检索那条链路适合处理大量历史文档比如把接口文档、设计稿说明批量切片入库。文件索引那条链路适合沉淀高频决策和踩坑记录因为它的命中更精确token 消耗也更低。两者不冲突可以同时用。如果你用 Claude Code 做长期编码任务建议把 Coding Plan 用起来地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 高频调用下更划算。想快速验证某个模型对知识库问答的效果用模型对话页面 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 直接试。最后给一个实用技巧在INDEX.md顶部写一段「使用说明」告诉 claude code 先读索引再回答并且优先引用decisions/和bugs/里的内容。这样它每次都会走你设计的检索路径而不是自由发挥。知识库的价值不在于文件多少而在于每次提问都能命中那条你真正需要的项目记忆。