GTX 1660 Ti 6GB 上 Ollama 跑 Qwen3-8B、Claude Code 当 AI Agent 这套组合,卡在 Agent 的模型通道:TaoToken 补它,Key 从 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 建,Base URL 填 https://taotoken.net/api,其余都在 ~/AI_Project_2026/.claude/settings.json 和 qwen3_mcp.py 里。这套拆法的妙处在于分工清楚:6GB 显存里那颗 Qwen3-8B 只干"被派下来的活",而决定"派什么活、按什么顺序派、上一轮结果怎么接进下一轮"的那颗脑子,跑在另一条通道上。很多人第一次搭的时候会把这两件事混成一件,结果本地模型一加载就发现 Claude Code 主循环开始转圈,或者反过来,MCP 挂上了但 Agent 从来不主动调用它。
1. 为什么本地 Qwen3-8B 不能兼任 Agent 的模型通道
1.1 Ollama 里那个 qwen3:8b 只被派活,不做规划
先把两个角色的边界说清楚。Ollama 上跑的 qwen3:8b 是一个"执行单元",它收到的输入是一句已经被人拆干净的问题,比如"online softmax 里 running max 的更新顺序是什么",它不需要知道整个任务的目标,也不需要记得三轮之前讨论过什么。Claude Code 这边则是"调度单元",它要维护任务清单、决定下一步问谁、把工具返回的内容塞回上下文、判断什么时候收工。
这两件事的输入长度完全不是一个量级。执行单元每次只吃几百 token,6GB 显存绰绰有余;调度单元每一轮都要把系统提示、工具定义、历史消息、上一次工具返回一起重新送进模型,轮次一多,上下文就是几千到几万 token 的量级。把调度塞进本地 8B,不只是慢,是显存直接扛不住,而且小模型在多工具编排上的稳定性也撑不起来。
1.2 长会话里 Token 到底烧在哪
把"写一个 Flash Attention 的 PyTorch 实现"这种任务拆开看,一次完整的编排大概长这样:
- 第 1 轮:系统提示 + 工具清单 + 用户目标,模型输出一个任务拆解。
- 第 2 到第 5 轮:每轮都要带上之前所有对话,加上调用
ask_qwen3的入参。 - 第 6 轮往后:上一轮本地 Qwen3 返回的那段代码或解释,作为
tool_result又被塞回上下文。
关键点在这里:上下文是累积重发的。第 6 轮的请求里,包含第 1 到第 5 轮的全部内容。所以消耗不是线性涨的,是随轮次近似平方地涨。本地 Qwen3 每次只被调用一次、只吃一个问题,它消耗的是显存和时间,不是 Token;而主循环每转一圈都在消耗 Token。
这就解释了为什么"本地部署省 Token"这个说法只对了一半——省掉的是执行侧的 Token,编排侧的账照样要记。而那部分账,需要一个稳定的、按量计费的兼容通道来接。
2. GTX 1660 Ti 6GB 的环境底子:驱动、Ollama 与 qwen3:8b
2.1 先看 nvidia-smi 和 Ollama 版本,别急着 pull
动手前先确认两件事,能省掉后面一大半莫名其妙的问题:
nvidia-smi ollama --version ollama psnvidia-smi看得见 1660 Ti 和显存总量、驱动版本就够了,如果驱动过旧,Ollama 可能识别不到 GPU,会静默退回 CPU 推理,表现是"能跑但慢到离谱"。驱动升级这件事得你自己在本地做,它不是 AI 工具链的活儿,装了新驱动之后记得重启一次再回头看nvidia-smi。
ollama ps用来确认当前有没有模型常驻在显存里。有时候你以为显存不够,其实是有个上次没卸载的模型还挂着。
提示:整个流程里,Ollama 的安装、模型的拉取、驱动的更新都在你本机完成,不要指望 Agent 替你做这些。它能做的是读日志、解释报错、给出下一步命令。
2.2 ollama pull qwen3:8b 与 6GB 显存的取舍
ollama pull qwen3:8b ollama run qwen3:8b "用一句话解释什么是 online softmax"8B 参数在 4bit 量化下大约占 5GB 左右的显存,6GB 卡属于"刚好放下,但没有余量"。几个能立刻松一口气的调整:
| 参数 | 作用 | 建议 |
|---|---|---|
num_ctx | 单次上下文窗口 | 从默认往下调,4096 通常够用 |
num_gpu | 卸载到 GPU 的层数 | 出现 OOM 时可适当下调,代价是变慢 |
OLLAMA_MAX_LOADED_MODELS | 同时驻留的模型数 | 设成 1,避免多模型抢显存 |
如果你在ollama run的输出里看到大段思考过程,可以在这类模型的对话里用/no_think之类的关闭方式,或者在请求体里显式关掉思考模式——具体字段以你本机 Ollama 版本的支持情况为准,别照抄别人的写法。
拉取和运行都在本机执行,这一步不需要任何云端 Key。真正需要去建 Key 的,是接下来给 Claude Code 用的那条模型通道。
2.3 顺手把 Key 建好
去 TaoToken 注册账号,进控制台创建一把 API Key,复制出来先存进密码管理器。这把 Key 后面会写进~/AI_Project_2026/.claude/settings.json的ANTHROPIC_AUTH_TOKEN字段,占位符统一记作YOUR_API_KEY。
创建完之后留在页面上别急着关,顺手看一眼模型广场里当前可用的模型 ID 列表。ANTHROPIC_MODEL必须填一个列表里真实存在的 ID,写成记忆里的某个名字,后面会直接撞上"模型不存在"的报错。模型 ID 以 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 模型广场当时列表为准,本文刻意不写具体字符串。
3. qwen3_mcp.py:用 stdio 把本地 Qwen3-8B 包成 MCP Server
3.1 ask_qwen3 工具函数的输入输出
MCP Server 在这套架构里就是一个"翻译层":Claude Code 通过 stdio 把 JSON-RPC 消息发过来,脚本把它转成一次对本地 Ollama 的 HTTP 请求,再把返回的文本原样送回去。工作目录就用原文里的~/AI_Project_2026/。
# ~/AI_Project_2026/qwen3_mcp.py import httpx from mcp.server.fastmcp import FastMCP OLLAMA_CHAT = "http://127.0.0.1:11434/api/chat" LOCAL_MODEL = "qwen3:8b" mcp = FastMCP("qwen3_local") @mcp.tool() def ask_qwen3(prompt: str, system: str = "你是严谨的 PyTorch 工程师,只回答被问到的这一问,不要展开成整篇教程。") -> str: """把单个子问题交给本机 Ollama 上的 Qwen3-8B 执行,返回纯文本结果。""" payload = { "model": LOCAL_MODEL, "stream": False, "messages": [ {"role": "system", "content": system}, {"role": "user", "content": prompt}, ], "options": {"num_ctx": 4096}, } with httpx.Client(timeout=600) as client: resp = client.post(OLLAMA_CHAT, json=payload) resp.raise_for_status() return resp.json()["message"]["content"] if __name__ == "__main__": mcp.run()依赖装一次就行:
pip install "mcp[cli]" httpxask_qwen3的签名要克制。参数越多,工具定义占的上下文越长,主循环每一轮都要把这段定义重发一遍。一个prompt加一个可选的system就够了,别把temperature、top_p、num_ctx全暴露成工具参数。
3.2 本地先冒烟一次,再让 Claude Code 去连
不要让 Claude Code 当第一个测试者。先在终端里直接跑一遍,确认脚本能起、Ollama 能应答:
cd ~/AI_Project_2026 python3 -c " from qwen3_mcp import ask_qwen3 print(ask_qwen3('用两句话说明 Flash Attention 为什么省显存')) "能打出正常文本,说明 stdio 之外的链路是通的。这一步跑不通,后面配了 MCP 也只会看到 Claude Code 那边工具一直处于"未响应"状态,反而更难定位。
第一次调用会明显卡一下,那是 Ollama 在把权重从磁盘加载进显存,属于正常现象。想避开的话,先在另一个终端ollama run qwen3:8b挂一次预热。
4. ~/AI_Project_2026/.claude/settings.json:Claude Code 的模型通道指向 TaoToken
4.1 env 三件套:ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN / ANTHROPIC_MODEL
这是整篇最容易被写错的一段,因为三个变量里有两个长得像、作用完全不同。ANTHROPIC_BASE_URL决定请求发去哪,ANTHROPIC_AUTH_TOKEN是身份凭证,ANTHROPIC_MODEL是你要哪个模型。
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "YOUR_MODEL_ID" } }三个硬性注意点:
- Base URL 后面不要加
/v1,客户端会自己拼路径,多写一段就是 404。 - 这个地址不要带任何查询参数,UTM 是给浏览器里点开的页面用的,填进配置文件只会让请求 404 或者 401。
YOUR_MODEL_ID换成模型广场里真实存在的 ID,别凭印象写。
如果你更喜欢用环境变量而不是配置文件,等价写法是:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_AUTH_TOKEN="YOUR_API_KEY" export ANTHROPIC_MODEL="YOUR_MODEL_ID"两种方式选一种就行,同时存在时配置文件的优先级更高,容易让人怀疑自己改了没生效。
4.2 mcpServers 里挂上 ask_qwen3
通道配好之后,再把本地执行链挂上去。这段要跟env写在同一个文件里:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "YOUR_MODEL_ID" }, "mcpServers": { "ask_qwen3": { "command": "python3", "args": ["/home/yourname/AI_Project_2026/qwen3_mcp.py"], "env": { "PYTHONUNBUFFERED": "1" } } } }几个细节值得单独拎出来:
args里写绝对路径。写相对路径时,MCP 进程的工作目录不一定是你启动 Claude Code 的那个目录,找不到文件就会直接退出。command里的python3必须是装好了mcp和httpx的那个解释器。系统里有多个 Python 的时候,很容易出现"我明明 pip install 过了"但其实装到了另一个解释器下。- 顺序上建议先只配
env、发一条消息确认通道走通,再回头加mcpServers。两个变量同时动,出错时你分不清是通道问题还是 MCP 问题。
这个脚本只负责把问题转给本机 Ollama,它不接管 Ollama 的模型拉取,也不接管 MCP 的 stdio 转发逻辑本身——转发是客户端和进程之间的事,脚本只提供一个工具入口。
4.3 完整文件示例与常见写错点
把上面两段合成一个文件之后,保存路径必须是~/AI_Project_2026/.claude/settings.json。放在别的目录不会被读取,表现就是"配了半天,Claude Code 完全不知道有工具"。
还有一个容易忽略的点:JSON 里不能有注释,也不能有尾随逗号。很多人调试时习惯加一行// 测试用,然后整个文件解析失败,客户端静默退回默认配置,看起来像是"配置被忽略了"。
最后,配置文件里填的是https://taotoken.net/api,而这个地址末尾不带斜杠、不带/v1、不带任何参数。这一点怎么强调都不过分,它和浏览器里打开的落地页是两回事。
5. 验证:先发一条普通请求,再把 Flash Attention 拆成 4 个子问题
5.1 第一步只问一句废话,确认通道通
在~/AI_Project_2026/下启动 Claude Code,先发一句跟任务无关的话,比如"用一句话说明你现在是什么模型"。这一步只验证一件事:请求有没有打到https://taotoken.net/api,Key 有没有被接受。
如果这一步就报错,别往下走,先把 401 / 404 排在 §6 里对一遍。想交叉验证的话,可以另开一个窗口,用同一把 Key 在 TaoToken 模型对话 里发一条消息,两边都能通,说明 Key 和模型 ID 本身没问题,问题在客户端的配置格式上。
通道通了之后再重启一次 Claude Code,让mcpServers生效。
5.2 第二步看 Agent 怎么拆:四个子问题的边界
确认工具列表里出现了ask_qwen3之后,把任务原样丢进去:写一个 Flash Attention 的 PyTorch 实现。好的拆解大致会落在四个方向上:
- 输入输出张量形状与 mask 约定是什么,
(B, H, S, D)这套维度里每一步怎么变形。 - 分块之后 online softmax 的 running max 和 running sum 按什么顺序更新,为什么必须先减最大值再取指数。
- 反向传播需要保存哪些中间量,重计算的代价落在哪个循环上。
- 怎么退化成一份朴素 attention 参考实现,用来做数值对齐。
这四个问题有个共同特点:每个都能独立回答,且答案都很短。这正是把子任务交给本地 8B 的前提。如果拆出来的子问题是"请完整实现 Flash Attention 并解释每一行",那本地模型一定会答得又长又飘。
5.3 第三步看谁在消耗 Token
任务跑起来之后,注意观察一件事:每次ask_qwen3被调用,本地 Qwen3 吃掉的是显存和时间,返回的文本被塞回主循环上下文之后,才是真正的 Token 消耗点。
所以一次成功的编排里,Token 账本大致是这样分布的:
- 主模型:系统提示 + 工具定义 + 每一轮的历史回放 + 四段子问题的结果,全部重发。
- 本地模型:零 Token,纯本地算力。
这也意味着,子问题返回的内容越长,主循环的账越贵。让ask_qwen3的系统提示里明确要求"只回答被问到的这一问",不只是为了答案质量,也是在控制成本。这条通道的消耗都会记在 TaoToken 的账上,跑完一轮之后值得去后台对一眼。
6. 排障清单:404、401、MCP 不出现、显存打满
6.1 通道类报错对照表
| 现象 | 大概率原因 | 处理 |
|---|---|---|
| 请求返回 404 | Base URL 末尾多写了/v1或带了参数 | 改成https://taotoken.net/api |
| 请求返回 401 | ANTHROPIC_AUTH_TOKEN为空、含空格,或复制时漏了字符 | 重新从控制台复制一次,注意首尾空白 |
| 提示模型不存在 | ANTHROPIC_MODEL与模型广场里的 ID 不一致 | 回模型广场核对当时的可用列表 |
| 改了配置没反应 | settings.json 不在~/AI_Project_2026/.claude/下,或 JSON 解析失败 | 用python3 -m json.tool校验一遍 |
404 和 401 这两类基本都出在配置的字面量上,跟网络环境无关,逐字符对一遍通常就能解决。别急着怀疑 Key 本身。
6.2 本地执行链类报错对照表
| 现象 | 大概率原因 | 处理 |
|---|---|---|
工具列表里看不到ask_qwen3 | args用了相对路径,或文件路径写错 | 换成绝对路径后重启客户端 |
| MCP 进程立刻退出 | ModuleNotFoundError: mcp | command换成装了依赖的那个解释器 |
| 调用长时间无响应 | 模型首次加载进显存,或显存不足被换出 | 另开终端ollama run qwen3:8b预热;确认ollama ps |
| 推理中途报显存不足 | num_ctx过大,或同时驻留了多个模型 | 下调num_ctx,限制同时加载的模型数 |
| 返回内容里带大段思考过程 | 思考模式没关 | 在调用侧关掉思考模式,具体方式以本机 Ollama 版本为准 |
排查顺序建议从下往上:先确认python3 -c "from qwen3_mcp import ask_qwen3"能跑,再确认 MCP 进程能起来,最后看工具能不能被调用。本地链路通了之后再去查通道配置,一次只动一个变量。
7. 跑通之后:去控制台对一下这次 Claude Code 调用
7.1 在模型对话页用同一把 Key 复测
拆完 Flash Attention 那四个子问题之后,回到 TaoToken 模型对话,用同一把 Key 再发一条消息。这一步的作用是隔离问题域:如果网页端正常、Claude Code 也正常,说明配置没问题;如果网页端正常而客户端异常,问题一定在settings.json的格式或环境变量优先级上。
顺带把这一轮的调用记录对一眼,看看长会话重发带来的消耗是不是符合预期。第一次看到多轮对话的用量曲线时,很多人会重新理解"本地部署省 Token"这句话的边界。
7.2 长期写代码前看一眼 Coding Plan 和接入文档
把这套东西当日常工具用之前,有两件事值得花五分钟:一是去 Coding Plan 看套餐是否匹配你的日常轮次;二是如果你还会在别的兼容客户端里复用同一把 Key,把 Key 统一在 控制台 API Keys 管理,方便按项目拆分和随时吊销。
环境变量的完整对照和更多示例写在 Claude Code 接入文档 里,遇到官方版本的字段变更,以文档为准。
这套架构最舒服的状态是:本地 Qwen3-8B 安静地待在 6GB 显存里等着被叫号,Claude Code 在另一条通道上负责拆任务、串流程、判断什么时候收工。两边各管一段,谁也不越界。真正需要动手调的只有settings.json里那几个字段,和qwen3_mcp.py里那个工具函数的签名。