[{"data":1,"prerenderedAt":1701},["ShallowReactive",2],{"content:\u002F2026\u002Flocal-ai-reverse-proxy":3,"surround:\u002F2026\u002Flocal-ai-reverse-proxy":1696},{"id":4,"title":5,"body":6,"categories":1672,"date":1674,"description":1675,"draft":1676,"extension":1677,"image":1678,"meta":1679,"navigation":1682,"path":1683,"permalink":1684,"published":1684,"readingTime":1685,"recommend":1684,"references":1684,"seo":1690,"sitemap":1691,"stem":1692,"tags":1693,"type":1694,"updated":1684,"__hash__":1695},"content\u002Fposts\u002F2026\u002Flocal-ai-reverse-proxy.md","把桌面 AI 软件变成本地 API：手把手反代教程",{"type":7,"value":8,"toc":1619},"minimark",[9,13,17,29,32,42,46,94,97,111,114,118,121,132,142,149,152,154,158,161,172,176,187,192,200,207,220,224,227,235,240,273,278,280,284,288,332,343,347,351,357,369,376,379,383,386,394,403,412,414,418,425,479,485,489,496,504,518,521,541,543,547,553,558,564,569,585,587,591,596,599,666,670,673,679,685,689,734,738,743,839,842,848,856,858,862,871,878,882,885,891,895,964,972,979,985,994,996,1000,1003,1007,1013,1018,1024,1043,1061,1065,1071,1077,1081,1087,1099,1102,1108,1115,1127,1129,1133,1136,1182,1187,1215,1220,1222,1226,1232,1236,1243,1246,1250,1256,1261,1264,1273,1282,1288,1291,1309,1311,1315,1321,1325,1331,1337,1341,1347,1353,1391,1397,1403,1411,1416,1422,1429,1441,1443,1446,1560,1562,1565,1568,1590,1596,1599,1604,1606,1610,1613],[10,11,12],"h2",{"id":12},"先说清楚这篇讲什么",[14,15,16],"p",{},"场景很具体：",[14,18,19,20,24,25,28],{},"你电脑上装了腾讯主推的一款 AI 办公软件（下面简称「",[21,22,23],"strong",{},"该软件","」），已经登录、能正常聊天。但你还想让",[21,26,27],{},"别的工具","也用上它的模型——比如编辑器插件、自动化脚本、Agent 框架、测试平台。",[14,30,31],{},"正常做法是去申请官方 API Key。但可能要付费、要企业认证、要走审批流程。",[14,33,34,37,38,41],{},[21,35,36],{},"这篇教程讲的是另一条路","：桌面版登录之后，登录凭证就存在你本地的文件里。写一个很小的本地服务读这份凭证，冒充官方客户端向上游发请求，对外暴露一个 ",[21,39,40],{},"OpenAI 兼容接口","。其他工具连这个本地接口，就等于在用你的账号调模型。",[43,44,45],"h3",{"id":45},"需要准备什么",[47,48,49,62],"table",{},[50,51,52],"thead",{},[53,54,55,59],"tr",{},[56,57,58],"th",{},"项目",[56,60,61],{},"要求",[63,64,65,78,86],"tbody",{},[53,66,67,71],{},[68,69,70],"td",{},"桌面端",[68,72,73,74,77],{},"已安装并",[21,75,76],{},"成功登录","（能正常聊天）",[53,79,80,83],{},[68,81,82],{},"Python",[68,84,85],{},"3.9 以上",[53,87,88,91],{},[68,89,90],{},"网络",[68,92,93],{},"能正常访问该软件的服务端",[43,95,96],{"id":96},"这篇的组织方式",[14,98,99,100,103,104,107,108],{},"按\"第 1 步、第 2 步\"的顺序走。每一步都写清",[21,101,102],{},"怎么做","和",[21,105,106],{},"看到什么算成功","。最后有错误码对照表和常见坑清单——",[21,109,110],{},"卡住了先去那两张表找。",[112,113],"hr",{},[10,115,117],{"id":116},"第-0-步先理解原理只要三步","第 0 步：先理解原理，只要三步",[14,119,120],{},"不用懂代码也能看懂这张图：",[122,123,128],"pre",{"className":124,"code":126,"language":127},[125],"language-text","① 桌面版登录  →  凭证（token）写入本地文件\n② 反代启动    →  读取凭证文件，拿到 token\n③ 下游请求    →  反代补上协议要求的请求头 → 转发给上游 → 原样返回结果\n","text",[129,130,126],"code",{"__ignoreMap":131},"",[14,133,134,137,138,141],{},[21,135,136],{},"一个关键设计","：反代",[21,139,140],{},"每次启动时","实时读凭证文件，不缓存。",[14,143,144,145,148],{},"这个特性带来一个好处：",[21,146,147],{},"换账号只需要「桌面版重新登录 + 重启反代」","，不用改任何代码。第 9 步会详细讲。",[14,150,151],{},"理解了这三步，后面的排查就有方向了——出问题无非是这三个环节之一。",[112,153],{},[10,155,157],{"id":156},"第-1-步确认你用的是哪条产品线","第 1 步：确认你用的是哪条产品线",[14,159,160],{},"产品线搞错的话，后面所有排查都在一个错误的地址上进行——你会反复试 User-Agent 和模型名，怎么试都不对。",[14,162,163,164,167,168,171],{},"这类产品往往有",[21,165,166],{},"多个品牌线","，而它们的",[21,169,170],{},"网关地址不一样","。用错地址，请求会一直返回 401。",[43,173,175],{"id":174},"_11-读配置文件最权威","1.1 读配置文件（最权威）",[14,177,178,179,182,183,186],{},"安装目录里有个 ",[129,180,181],{"code":181},"product.json","，它的 ",[129,184,185],{"code":185},"endpoint"," 字段就是你要用的网关地址。",[14,188,189],{},[21,190,191],{},"【Windows】PowerShell：",[122,193,198],{"className":194,"code":196,"language":197,"meta":131},[195],"language-powershell","python -c \"import json,io;d=json.load(io.open(r'\u003C安装目录>\\resources\\app.asar.unpacked\\cli\\product.json',encoding='utf-8'));print('endpoint =',d.get('endpoint'));print('productName =',d.get('productName'))\"\n","powershell",[129,199,196],{"__ignoreMap":131},[14,201,202,203,206],{},"把 ",[129,204,205],{"code":205},"\u003C安装目录>"," 换成你实际的安装路径。",[14,208,209,211,212,215,216,219],{},[21,210,106],{},"：输出里有 ",[129,213,214],{"code":214},"endpoint = https:\u002F\u002F..."," 一行，",[21,217,218],{},"把那个地址记下来","，第 5 步要用。",[43,221,223],{"id":222},"_12-解-jwt-确认账号归属","1.2 解 JWT 确认账号归属",[14,225,226],{},"登录凭证里那个 token 是个 JWT，解开就能看到它属于哪条产品线。",[122,228,233],{"className":229,"code":231,"language":232,"meta":131},[230],"language-python","import base64, json\n\ntok = \"\u003C你的 accessToken>\"\np = tok.split('.')[1]\np += '=' * (-len(p) % 4)\nprint(json.loads(base64.urlsafe_b64decode(p))['iss'])\n","python",[129,234,231],{"__ignoreMap":131},[14,236,237],{},[21,238,239],{},"怎么看结果：",[47,241,242,255],{},[50,243,244],{},[53,245,246,252],{},[56,247,248,251],{},[129,249,250],{"code":250},"iss"," 里包含",[56,253,254],{},"结论",[63,256,257,265],{},[53,258,259,262],{},[68,260,261],{},"国际域名",[68,263,264],{},"用的是国际版，网关按 1.1 读出来的填",[53,266,267,270],{},[68,268,269],{},"国内域名",[68,271,272],{},"用的是国内版，网关同样以 1.1 为准",[14,274,275],{},[21,276,277],{},"两条产品线的网关不一样，以 1.1 读出来的为准。",[112,279],{},[10,281,283],{"id":282},"第-2-步找到登录凭据文件","第 2 步：找到登录凭据文件",[43,285,287],{"id":286},"_21-位置","2.1 位置",[47,289,290,300],{},[50,291,292],{},[53,293,294,297],{},[56,295,296],{},"平台",[56,298,299],{},"路径",[63,301,302,312,322],{},[53,303,304,307],{},[68,305,306],{},"Windows",[68,308,309],{},[129,310,311],{"code":311},"%LOCALAPPDATA%\\\u003C产品目录>\\Data\\Public\\auth\\",[53,313,314,317],{},[68,315,316],{},"macOS",[68,318,319],{},[129,320,321],{"code":321},"~\u002FLibrary\u002FApplication Support\u002F\u003C产品目录>\u002FData\u002FPublic\u002Fauth\u002F",[53,323,324,327],{},[68,325,326],{},"Linux",[68,328,329],{},[129,330,331],{"code":331},"~\u002F.local\u002Fshare\u002F\u003C产品目录>\u002FData\u002FPublic\u002Fauth\u002F",[14,333,334,335,338,339,342],{},"文件名各版本不一样，可能是 ",[129,336,337],{"code":337},"\u003C产品>-desktop.info","，也可能是 ",[129,340,341],{"code":341},"\u003C产品>-desktop-ai.info","。以你实际找到的为准。",[43,344,346],{"id":345},"_22-一条命令找出来","2.2 一条命令找出来",[14,348,349],{},[21,350,191],{},[122,352,355],{"className":353,"code":354,"language":197,"meta":131},[195],"Get-ChildItem \"$env:LOCALAPPDATA\" -Recurse -Filter \"*.info\" -ErrorAction SilentlyContinue |\n  Where-Object { $_.FullName -match \"auth\" } |\n  Select-Object -ExpandProperty FullName\n",[129,356,354],{"__ignoreMap":131},[14,358,359,361,362,365,366],{},[21,360,106],{},"：列出至少一个 ",[129,363,364],{"code":364},".info"," 文件的完整路径。",[21,367,368],{},"把它记下来。",[14,370,371],{},[372,373],"img",{"alt":374,"src":375},"PowerShell 搜出凭据文件的完整路径","\u002Frp-01-find-credential.png",[14,377,378],{},"如果什么都没输出，说明桌面版还没登录过——回去打开软件登录一次再试。",[43,380,382],{"id":381},"_23-文件里有什么","2.3 文件里有什么",[14,384,385],{},"用记事本或 VS Code 打开那个文件，是个 JSON：",[122,387,392],{"className":388,"code":390,"language":391,"meta":131},[389],"language-json","{\n  \"auth\": {\n    \"accessToken\": \"eyJhbGciOi...\",\n    \"refreshToken\": \"...\",\n    \"expiresAt\": 1234567890\n  },\n  \"account\": {\n    \"uid\": \"...\",\n    \"email\": \"...\"\n  }\n}\n","json",[129,393,390],{"__ignoreMap":131},[14,395,396],{},[21,397,398,399,402],{},"你要的是 ",[129,400,401],{"code":401},"auth.accessToken"," 这个字段的值。",[404,405,406],"blockquote",{},[14,407,408,409],{},"⚠️ ",[21,410,411],{},"这个文件等于你的登录态。",[112,413],{},[10,415,417],{"id":416},"第-3-步挑一个反代项目","第 3 步：挑一个反代项目",[14,419,420,421,424],{},"GitHub 上有现成的开源实现，搜关键词 ",[129,422,423],{"code":423},"\u003C产品名>2api"," 就能找到几个。",[47,426,427,440],{},[50,428,429],{},[53,430,431,434,437],{},[56,432,433],{},"类型",[56,435,436],{},"语言",[56,438,439],{},"特点",[63,441,442,458,468],{},[53,443,444,449,451],{},[68,445,446],{},[21,447,448],{},"单文件版",[68,450,82],{},[68,452,453,454,457],{},"✅ ",[21,455,456],{},"首选","：依赖只有 fastapi + uvicorn，支持 tools 透传",[53,459,460,463,465],{},[68,461,462],{},"功能全版",[68,464,82],{},[68,466,467],{},"带账号池、用量统计，但要 MySQL + Redis，部署重",[53,469,470,473,476],{},[68,471,472],{},"Go 版",[68,474,475],{},"Go",[68,477,478],{},"有现成 exe，但要编译环境",[14,480,481,484],{},[21,482,483],{},"新手直接选第一种","，单文件、依赖少、好排查。",[43,486,488],{"id":487},"_31-装之前先做安全检查","3.1 装之前先做安全检查",[14,490,491,492,495],{},"第三方项目拿到手，",[21,493,494],{},"先看它往哪儿发数据","：",[122,497,502],{"className":498,"code":500,"language":501,"meta":131},[499],"language-bash","# 列出代码里所有外部地址\ngrep -ohE \"https?:\u002F\u002F[a-zA-Z0-9._\u002F-]+\" *.py | sed 's|\\(https\\?:\u002F\u002F[^\u002F]*\\).*|\\1|' | sort -u\n\n# 找危险调用\ngrep -nE \"\\beval\\(|\\bexec\\(|pickle|subprocess|os\\.system|upload|webhook\" *.py\n","bash",[129,503,500],{"__ignoreMap":131},[14,505,506,509,510,517],{},[21,507,508],{},"第一条的判读标准","：结果里",[21,511,512,513,516],{},"只应该出现 ",[129,514,515],{"code":515},"localhost"," 和你用的那个软件的官方域名","。",[14,519,520],{},"出现任何陌生的第三方域名，都值得警惕——那可能是把你的凭证往别人服务器上送。",[14,522,523,526,527,530,531,530,534,530,537,540],{},[21,524,525],{},"第二条","：出现 ",[129,528,529],{"code":529},"eval"," \u002F ",[129,532,533],{"code":533},"exec",[129,535,536],{"code":536},"pickle",[129,538,539],{"code":539},"subprocess"," 不代表一定有问题，但要人工看一眼它到底在干什么。",[112,542],{},[10,544,546],{"id":545},"第-4-步装依赖把服务跑起来","第 4 步：装依赖、把服务跑起来",[122,548,551],{"className":549,"code":550,"language":501,"meta":131},[499],"# 装依赖（一般就这两个）\npip install fastapi uvicorn\n\n# 启动（用 -u，否则日志被缓冲，看不到实时输出）\npython -u server.py\n",[129,552,550],{"__ignoreMap":131},[14,554,555,557],{},[21,556,106],{},"：终端里出现监听日志，类似：",[122,559,562],{"className":560,"code":561,"language":127},[125],"Uvicorn running on http:\u002F\u002F127.0.0.1:8787\n",[129,563,561],{"__ignoreMap":131},[14,565,566],{},[21,567,568],{},"端口默认是 8787，但项目之间不一样，以日志里打印的为准。",[404,570,571],{},[14,572,573,576,577,580,581,584],{},[21,574,575],{},"关于绑定地址","：默认绑 ",[129,578,579],{"code":579},"127.0.0.1","。绑 ",[129,582,583],{"code":583},"0.0.0.0"," 的话，局域网里任何设备都能连上。\n需要虚拟机访问的话，走第 10 步的 portproxy 方案。",[112,586],{},[10,588,590],{"id":589},"第-5-步修四处协议不匹配最容易卡住的地方","第 5 步：修四处协议不匹配（最容易卡住的地方）",[14,592,593],{},[21,594,595],{},"这是整篇教程最关键的一步。",[14,597,598],{},"开源项目多半是按旧版本或国内版写的，直接跑会失败。要修的是四个地方：",[47,600,601,614],{},[50,602,603],{},[53,604,605,608,611],{},[56,606,607],{},"编号",[56,609,610],{},"问题",[56,612,613],{},"症状",[63,615,616,627,640,653],{},[53,617,618,621,624],{},[68,619,620],{},"a",[68,622,623],{},"上游 host 写死成旧的",[68,625,626],{},"401",[53,628,629,632,635],{},[68,630,631],{},"b",[68,633,634],{},"缺 User-Agent",[68,636,637],{},[129,638,639],{"code":639},"code 12403 check ua",[53,641,642,645,648],{},[68,643,644],{},"c",[68,646,647],{},"首条消息不是 system prompt",[68,649,650],{},[129,651,652],{"code":652},"code 11128",[53,654,655,658,661],{},[68,656,657],{},"d",[68,659,660],{},"模型名不是\"档位名\"",[68,662,663],{},[129,664,665],{"code":665},"code 11102",[43,667,669],{"id":668},"_51-关键做法不直接改第三方文件","5.1 关键做法：不直接改第三方文件",[14,671,672],{},"第三方项目还会更新，你改了下一次就冲突。",[14,674,675,678],{},[21,676,677],{},"正确姿势是写一个自己的启动器","，在运行时 monkey-patch：",[122,680,683],{"className":681,"code":682,"language":232,"meta":131},[230],"import \u003C反代项目的模块名> as _cda\n\n# (a) 强制正确的上游 host\n_orig_init = _cda.ApiClient.__init__\ndef _patched_init(self, base_url, token_info, safe_mode=False):\n    _orig_init(self, \"https:\u002F\u002Fwww.\u003C你的网关域名>\", token_info, safe_mode)\n_cda.ApiClient.__init__ = _patched_init\n\n# (b) 补上 User-Agent\n_orig_headers = _cda.ApiClient._build_headers\ndef _patched_headers(self, extra=None, stream=False, model=\"\"):\n    h = _orig_headers(self, extra=extra, stream=stream, model=model)\n    h.setdefault(\"User-Agent\", \"\u003C产品标识>\u002F0.0.0\")\n    return h\n_cda.ApiClient._build_headers = _patched_headers\n\n# (c) 保证首条是 system prompt，并把模型名映射成档位名\n_orig_chat = _cda.ApiClient.chat_completion\ndef _patched_chat(self, messages, model=\"\", **kw):\n    model = {\"deepseek-v4-flash\": \"fast-model\", \"deepseek-v4-pro\": \"primary-model\"}.get(model, model)\n    if not messages or (messages[0] or {}).get(\"role\") != \"system\":\n        messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}] + list(messages)\n    return _orig_chat(self, messages, model=model, **kw)\n_cda.ApiClient.chat_completion = _patched_chat\n\n# (d) 只暴露账号真实可用的档位名\nTIERS = {\"fast-model\", \"balanced-model\", \"primary-model\", \"deep-model\"}\n_cda.KNOWN_CHAT_MODELS = set(TIERS)\n_cda.ALL_SUPPORTED_MODELS = set(TIERS)\n_cda.FREE_MODELS = set()\n",[129,684,682],{"__ignoreMap":131},[43,686,688],{"id":687},"_52-两个占位符怎么填","5.2 两个占位符怎么填",[47,690,691,701],{},[50,692,693],{},[53,694,695,698],{},[56,696,697],{},"占位符",[56,699,700],{},"从哪来",[63,702,703,717],{},[53,704,705,710],{},[68,706,707],{},[129,708,709],{"code":709},"\u003C反代项目的模块名>",[68,711,712,713,716],{},"第三方项目里那个主模块的名字，看它的 ",[129,714,715],{"code":715},"import"," 或启动文件就知道",[53,718,719,724],{},[68,720,721],{},[129,722,723],{"code":723},"\u003C产品标识>",[68,725,726,727,730,731,733],{},"必须和官方客户端",[21,728,729],{},"完全一致","。通常就是\"产品名\u002F版本号\"的形式，从第 1 步读的 ",[129,732,181],{"code":181}," 里能找到",[43,735,737],{"id":736},"_53-错误码对照表","5.3 错误码对照表",[14,739,740],{},[21,741,742],{},"排查时对着这张表走：",[47,744,745,758],{},[50,746,747],{},[53,748,749,752,755],{},[56,750,751],{},"现象",[56,753,754],{},"含义",[56,756,757],{},"怎么修",[63,759,760,773,789,800,813,826],{},[53,761,762,767,770],{},[68,763,764,766],{},[21,765,626],{}," + 返回一页 HTML",[68,768,769],{},"网关地址用错了",[68,771,772],{},"换成第 1 步读出来的 host",[53,774,775,781,783],{},[68,776,777,780],{},[129,778,779],{"code":779},"code 12403"," \"check ua\"",[68,782,634],{},[68,784,785,786],{},"补上 ",[129,787,788],{"code":788},"\u003C产品标识>\u002F\u003C版本>",[53,790,791,795,797],{},[68,792,793],{},[129,794,652],{"code":652},[68,796,647],{},[68,798,799],{},"注入一条 system 消息",[53,801,802,807,810],{},[68,803,804,806],{},[129,805,665],{"code":665}," \"service info not found\"",[68,808,809],{},"模型名不对",[68,811,812],{},"改用档位名（见第 6 步）",[53,814,815,820,823],{},[68,816,817],{},[129,818,819],{"code":819},"code 11101",[68,821,822],{},"探活请求太短（网关要求带 system）",[68,824,825],{},"同上，补 system",[53,827,828,833,836],{},[68,829,830],{},[129,831,832],{"code":832},"code 11140",[68,834,835],{},"套餐权限不足",[68,837,838],{},"换账号或换套餐",[14,840,841],{},"三种典型报错长这样：",[14,843,844],{},[372,845],{"alt":846,"src":847},"三种协议不匹配的报错：401、code 12403、code 11102","\u002Frp-02-error-codes.png",[404,849,850],{},[14,851,852,855],{},[21,853,854],{},"排查顺序是固定的：host → User-Agent → 请求格式 → 模型名。","\n每一步的报错码都不一样，按顺序走效率最高——直接跳到模型名去试，往往白花半小时。",[112,857],{},[10,859,861],{"id":860},"第-6-步搞清楚模型名第二个大坑","第 6 步：搞清楚模型名（第二个大坑）",[14,863,864],{},[21,865,866,867,870],{},"你可能会以为可以直接用 ",[129,868,869],{"code":869},"deepseek-v4-flash"," 这种具体模型名去调。不行。",[14,872,873,874,877],{},"这套账号体系里，模型是按",[21,875,876],{},"档位","暴露的。",[43,879,881],{"id":880},"_61-可用清单只能从报错里拿","6.1 可用清单只能从报错里拿",[14,883,884],{},"故意用一个错的模型名去调，上游会把真实可用的清单告诉你：",[122,886,889],{"className":887,"code":888,"language":127},[125],"400 model [xxx] service info not found\nCurrently supported models for your account:\n  - fast-model\n  - balanced-model\n  - primary-model\n  - deep-model\n",[129,890,888],{"__ignoreMap":131},[43,892,894],{"id":893},"_62-四个档位","6.2 四个档位",[47,896,897,910],{},[50,898,899],{},[53,900,901,904,907],{},[56,902,903],{},"档位名",[56,905,906],{},"定位",[56,908,909],{},"相对倍率",[63,911,912,925,938,951],{},[53,913,914,919,922],{},[68,915,916],{},[129,917,918],{"code":918},"fast-model",[68,920,921],{},"最快最省，日常首选",[68,923,924],{},"x0.34",[53,926,927,932,935],{},[68,928,929],{},[129,930,931],{"code":931},"balanced-model",[68,933,934],{},"均衡",[68,936,937],{},"x0.59",[53,939,940,945,948],{},[68,941,942],{},[129,943,944],{"code":944},"primary-model",[68,946,947],{},"主力",[68,949,950],{},"x1.70",[53,952,953,958,961],{},[68,954,955],{},[129,956,957],{"code":957},"deep-model",[68,959,960],{},"深度推理",[68,962,963],{},"x2.20",[43,965,967,968,971],{"id":966},"_63-v1models-返回的长列表不可靠","6.3 ",[129,969,970],{"code":970},"\u002Fv1\u002Fmodels"," 返回的长列表不可靠",[14,973,974,975,978],{},"那多半是反代项目",[21,976,977],{},"内置的兜底列表","，不是你的账号真实可用的模型清单。",[14,980,981,982,984],{},"实测过：",[129,983,970],{"code":970}," 返回了 32 个模型，实际能调通的只有 4 个档位名。",[14,986,987,990,991,993],{},[21,988,989],{},"正确做法","：让代理的 ",[129,992,970],{"code":970}," 只暴露这四个档位名——就是第 5 步 monkey-patch 里 (d) 段的作用。",[112,995],{},[10,997,999],{"id":998},"第-7-步三步验证","第 7 步：三步验证",[14,1001,1002],{},"服务跑起来了，现在验证它是不是真的能用。",[43,1004,1006],{"id":1005},"第一步健康检查","第一步：健康检查",[122,1008,1011],{"className":1009,"code":1010,"language":501,"meta":131},[499],"curl -s --noproxy '*' http:\u002F\u002F127.0.0.1:8787\u002Fhealth\n",[129,1012,1010],{"__ignoreMap":131},[14,1014,1015],{},[21,1016,1017],{},"期望看到类似：",[122,1019,1022],{"className":1020,"code":1021,"language":391,"meta":131},[389],"{\"status\":\"ok\",\"\u003C产品前缀>_configured\":true}\n",[129,1023,1021],{"__ignoreMap":131},[404,1025,1026],{},[14,1027,1028,1029,517,1032],{},"字段名可能带产品前缀，也可能就叫 ",[129,1030,1031],{"code":1031},"configured",[21,1033,1034,1035,1038,1039,1042],{},"只要 ",[129,1036,1037],{"code":1037},"status"," 是 ",[129,1040,1041],{"code":1041},"ok","，就说明服务起来了。",[404,1044,1045],{},[14,1046,408,1047,1053,1054,1057,1058,1060],{},[21,1048,1049,1052],{},[129,1050,1051],{"code":1051},"--noproxy '*'"," 是关键。"," 本机开着代理软件时，",[129,1055,1056],{"code":1056},"HTTP_PROXY"," 环境变量会把发往 ",[129,1059,579],{"code":579}," 的请求也劫走，导致连不上本地服务。",[43,1062,1064],{"id":1063},"第二步看模型列表","第二步：看模型列表",[122,1066,1069],{"className":1067,"code":1068,"language":501,"meta":131},[499],"curl -s --noproxy '*' http:\u002F\u002F127.0.0.1:8787\u002Fv1\u002Fmodels \\\n  -H \"Authorization: Bearer \u003C本地key>\"\n",[129,1070,1068],{"__ignoreMap":131},[14,1072,1073,1076],{},[21,1074,1075],{},"期望只看到 4 个档位名。"," 如果返回一长串，说明第 5 步的 (d) 段没生效。",[43,1078,1080],{"id":1079},"第三步真实调用","第三步：真实调用",[122,1082,1085],{"className":1083,"code":1084,"language":501,"meta":131},[499],"curl -s --noproxy '*' -X POST http:\u002F\u002F127.0.0.1:8787\u002Fv1\u002Fchat\u002Fcompletions \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer \u003C本地key>\" \\\n  -d '{\"model\":\"fast-model\",\"messages\":[{\"role\":\"user\",\"content\":\"1+1=?\"}],\"stream\":false}'\n",[129,1086,1084],{"__ignoreMap":131},[14,1088,1089,1092,1093,1038,1096,517],{},[21,1090,1091],{},"期望"," ",[129,1094,1095],{"code":1095},"choices[0].message.content",[129,1097,1098],{"code":1098},"\"2\"",[14,1100,1101],{},"三次请求的完整输出长这样：",[14,1103,1104],{},[372,1105],{"alt":1106,"src":1107},"三步验证的完整输出：\u002Fhealth、\u002Fv1\u002Fmodels、真实调用","\u002Frp-03-verify.png",[14,1109,1110,1111,1114],{},"用 ",[129,1112,1113],{"code":1113},"stream: false","（非流式）测试更容易看清返回结构。通了之后再切流式。",[404,1116,1117],{},[14,1118,1119,1122,1123,1126],{},[21,1120,1121],{},"如果返回的是固定占位内容","（比如永远是\"（完成）\"这种），说明",[21,1124,1125],{},"请求根本没打到上游","，反代走了 fallback 分支。回到第 5.3 节的错误码表按顺序排查。",[112,1128],{},[10,1130,1132],{"id":1131},"第-8-步接进你的工具里","第 8 步：接进你的工具里",[14,1134,1135],{},"三步验证都过了，就可以把它接到别的工具上了。要填的就三个值：",[47,1137,1138,1148],{},[50,1139,1140],{},[53,1141,1142,1145],{},[56,1143,1144],{},"字段",[56,1146,1147],{},"填什么",[63,1149,1150,1160,1172],{},[53,1151,1152,1155],{},[68,1153,1154],{},"Base URL \u002F API 地址",[68,1156,1157],{},[129,1158,1159],{"code":1159},"http:\u002F\u002F127.0.0.1:8787\u002Fv1",[53,1161,1162,1165],{},[68,1163,1164],{},"API Key",[68,1166,1167,1168,1171],{},"反代自己设定的那个本地 key（",[21,1169,1170],{},"不是","你的账号 token）",[53,1173,1174,1177],{},[68,1175,1176],{},"Model",[68,1178,1179,1180],{},"四个档位名之一，比如 ",[129,1181,918],{"code":918},[14,1183,1184],{},[21,1185,1186],{},"几个容易填错的地方：",[1188,1189,1190,1203,1209],"ul",{},[1191,1192,1193,1199,1200,1202],"li",{},[21,1194,1195,1196],{},"Base URL 结尾带不带 ",[129,1197,1198],{"code":1198},"\u002Fv1"," —— 看工具的说明。有的工具要求填到 ",[129,1201,1198],{"code":1198},"，有的只填到端口，然后自己在后面拼路径。填错了会 404",[1191,1204,1205,1208],{},[21,1206,1207],{},"地址填本机"," —— 有些工具默认让你填 API 域名，这里要填的是本机地址",[1191,1210,1211,1214],{},[21,1212,1213],{},"API Key 是反代发给下游的","，跟你的账号无关。在反代的配置里能看到或自定义",[14,1216,1217,1219],{},[21,1218,106],{},"：工具里发一条消息，能正常返回内容。",[112,1221],{},[10,1223,1225],{"id":1224},"第-9-步换账号","第 9 步：换账号",[14,1227,1228,1231],{},[21,1229,1230],{},"原理","：反代每次启动实时读凭证，不缓存。所以换号只要两步。",[43,1233,1235],{"id":1234},"步骤-1桌面端换账号","步骤 1：桌面端换账号",[14,1237,1238,1239,1242],{},"打开桌面版 → ",[21,1240,1241],{},"退出登录"," → 用新账号登录。",[14,1244,1245],{},"这会把新 token 写进第 2 步找到的那个凭据文件。",[43,1247,1249],{"id":1248},"步骤-2重启反代","步骤 2：重启反代",[122,1251,1254],{"className":1252,"code":1253,"language":501,"meta":131},[499],"# 找到旧实例\nnetstat -ano | grep :8787\n\n# 杀掉（把 \u003Cpid> 换成上面查到的进程号）\ntaskkill \u002FPID \u003Cpid> \u002FF\n\n# 按原来的方式重新启动\npython -u server.py\n",[129,1255,1253],{"__ignoreMap":131},[14,1257,1258],{},[21,1259,1260],{},"不重启就还在用旧 token。",[43,1262,1263],{"id":1263},"怎么确认真的换了账号",[14,1265,1266,1269,1270,517],{},[129,1267,1268],{"code":1268},"\u002Fhealth"," 只能说明\"已配置\"，",[21,1271,1272],{},"不能说明是哪个账号",[14,1274,1275,1276,1278,1279,495],{},"要确认，解 JWT 看 ",[129,1277,250],{"code":250}," 和 ",[129,1280,1281],{"code":1281},"account",[122,1283,1286],{"className":1284,"code":1285,"language":232,"meta":131},[230],"import json, io, glob, os, base64\n\nd = os.path.expandvars(r'%LOCALAPPDATA%\\\u003C产品目录>\\Data\\Public\\auth')\nfor f in glob.glob(d + r'\\*.info'):\n    j = json.load(io.open(f, encoding='utf-8'))\n    tok = (j.get('auth') or {}).get('accessToken', '')\n    p = tok.split('.')[1]\n    p += '=' * (-len(p) % 4)\n    pl = json.loads(base64.urlsafe_b64decode(p))\n    print(f)\n    print('  iss     =', pl.get('iss'))\n    print('  account =', j.get('account'))\n",[129,1287,1285],{"__ignoreMap":131},[43,1289,1290],{"id":1290},"换号后要复查的两件事",[1292,1293,1294,1303],"ol",{},[1191,1295,1296,1299,1300,1302],{},[21,1297,1298],{},"新账号的可用模型可能不同"," —— 档位名一样，权限不一定一样。报 ",[129,1301,832],{"code":832}," 就是新账号套餐不够",[1191,1304,1305,1308],{},[21,1306,1307],{},"下游工具里写死的模型名可能要改"," —— 如果某个工具里固定填了具体模型名，而新账号没有这个模型，请求会直接失败",[112,1310],{},[10,1312,1314],{"id":1313},"第-10-步让虚拟机-局域网也能用","第 10 步：让虚拟机 \u002F 局域网也能用",[14,1316,1317,1318,1320],{},"如果反代绑在 ",[129,1319,579],{"code":579},"，虚拟机是访问不到的。两个方案。",[43,1322,1324],{"id":1323},"方案-a改绑定地址简单但不安全","方案 A：改绑定地址（简单，但不安全）",[14,1326,1327,1328,1330],{},"启动时绑 ",[129,1329,583],{"code":583},"，虚拟机通过宿主机 IP 访问。",[14,1332,1333,1336],{},[21,1334,1335],{},"代价","：局域网里任何设备都能连上。",[43,1338,1340],{"id":1339},"方案-bportproxy-转发推荐","方案 B：portproxy 转发（推荐）",[14,1342,1343,1344,1346],{},"保持服务绑在 ",[129,1345,579],{"code":579},"，用 Windows 自带的端口转发把请求转进来。",[14,1348,1349,1352],{},[21,1350,1351],{},"第一步：确认虚拟机的网络模式","，找到对应的宿主机 IP：",[47,1354,1355,1365],{},[50,1356,1357],{},[53,1358,1359,1362],{},[56,1360,1361],{},"虚拟机网络模式",[56,1363,1364],{},"宿主机 IP 是哪个",[63,1366,1367,1375,1383],{},[53,1368,1369,1372],{},[68,1370,1371],{},"VMware NAT",[68,1373,1374],{},"VMnet8 的地址",[53,1376,1377,1380],{},[68,1378,1379],{},"仅主机（Host-Only）",[68,1381,1382],{},"VMnet1 的地址",[53,1384,1385,1388],{},[68,1386,1387],{},"桥接（Bridged）",[68,1389,1390],{},"真实网卡的地址",[14,1392,1393,1396],{},[21,1394,1395],{},"第二步：【Windows】用管理员身份打开 PowerShell","，执行：",[122,1398,1401],{"className":1399,"code":1400,"language":197,"meta":131},[195],"# 添加转发规则：\u003C宿主机IP>:8787 → 127.0.0.1:8787\nnetsh interface portproxy add v4tov4 listenaddress=\u003C宿主机IP> listenport=8787 connectaddress=127.0.0.1 connectport=8787\n\n# 放行防火墙\nnetsh advfirewall firewall add rule name=\"AI Proxy 8787\" dir=in action=allow protocol=TCP localport=8787\n\n# 查看已生效的规则\nnetsh interface portproxy show all\n",[129,1402,1400],{"__ignoreMap":131},[14,1404,1405,495,1407,1410],{},[21,1406,106],{},[129,1408,1409],{"code":1409},"show all"," 能列出你刚加的那条规则。",[14,1412,1413],{},[21,1414,1415],{},"第三步：【虚拟机】里验证：",[122,1417,1420],{"className":1418,"code":1419,"language":501,"meta":131},[499],"curl -s http:\u002F\u002F\u003C宿主机IP>:8787\u002Fhealth\n",[129,1421,1419],{"__ignoreMap":131},[14,1423,1424,1425,1428],{},"返回 ",[129,1426,1427],{"code":1427},"status: ok"," 就通了。",[404,1430,1431],{},[14,1432,1433,1436,1437,1440],{},[21,1434,1435],{},"注意","：portproxy 规则",[21,1438,1439],{},"重启后依然存在","（持久化的），不用每次开机重配。但如果宿主机 IP 变了（换了网络环境），规则要重建。",[112,1442],{},[10,1444,1445],{"id":1445},"常见坑清单",[47,1447,1448,1460],{},[50,1449,1450],{},[53,1451,1452,1455,1457],{},[56,1453,1454],{},"坑",[56,1456,613],{},[56,1458,1459],{},"解决",[63,1461,1462,1478,1492,1505,1516,1527,1538,1549],{},[53,1463,1464,1467,1473],{},[68,1465,1466],{},"系统代理劫持本地请求",[68,1468,1469,1470,1472],{},"连 ",[129,1471,579],{"code":579}," 都超时",[68,1474,1475,1476],{},"命令加 ",[129,1477,1051],{"code":1051},[53,1479,1480,1483,1486],{},[68,1481,1482],{},"端口被旧实例占用",[68,1484,1485],{},"启动报地址已被占用",[68,1487,1488,1491],{},[129,1489,1490],{"code":1490},"netstat -ano"," 找 PID 后杀掉",[53,1493,1494,1497,1500],{},[68,1495,1496],{},"日志看不到",[68,1498,1499],{},"启动后没有任何输出",[68,1501,1110,1502],{},[129,1503,1504],{"code":1504},"python -u",[53,1506,1507,1510,1513],{},[68,1508,1509],{},"启动后进程被回收",[68,1511,1512],{},"自动化环境里刚起来就没了",[68,1514,1515],{},"在同一个命令里完成启动 + 测试",[53,1517,1518,1521,1524],{},[68,1519,1520],{},"token 过期",[68,1522,1523],{},"突然开始 401",[68,1525,1526],{},"桌面版重新登录，重启反代",[53,1528,1529,1532,1535],{},[68,1530,1531],{},"模型名报 11102",[68,1533,1534],{},"调用失败",[68,1536,1537],{},"改用档位名",[53,1539,1540,1543,1546],{},[68,1541,1542],{},"返回固定占位内容",[68,1544,1545],{},"内容永远是同一句",[68,1547,1548],{},"请求没打到上游，按错误码表排查",[53,1550,1551,1554,1557],{},[68,1552,1553],{},"换了账号没生效",[68,1555,1556],{},"额度还是旧账号的",[68,1558,1559],{},"忘了重启反代",[112,1561],{},[10,1563,1564],{"id":1564},"结语",[14,1566,1567],{},"整个过程的核心其实就三句话：",[1292,1569,1570,1576,1582],{},[1191,1571,1572,1575],{},[21,1573,1574],{},"先分清产品线"," —— 网关地址错了，一切都是白搭",[1191,1577,1578,1581],{},[21,1579,1580],{},"四处协议不匹配要补"," —— host、User-Agent、system prompt、模型名，每一步的报错码都不一样",[1191,1583,1584,1587,1588,971],{},[21,1585,1586],{},"模型只认档位名"," —— ",[129,1589,970],{"code":970},[14,1591,1592,1593,1595],{},"做完之后，你的其他工具就能连 ",[129,1594,1159],{"code":1159},"，用桌面端账号里的模型了。",[14,1597,1598],{},"这篇里的每一步都写清了\"看到什么算成功\"，也给了错误码对照表和坑清单。但实际操作中总会遇到环境差异——你的版本号、安装路径、工具界面都可能跟示例不一样。",[14,1600,1601],{},[21,1602,1603],{},"真卡住了就把报错原样贴给 AI，让它带你定位。",[112,1605],{},[10,1607,1609],{"id":1608},"附不想自己一步步操作把这段丢给-claude","附：不想自己一步步操作？把这段丢给 Claude",[14,1611,1612],{},"下面这段整段复制给 Claude（Claude Code、Claude 桌面版都行），它会替你执行——自己找文件、装依赖、跑验证、看报错。遇到必须你本人配合的，它会告诉你。",[122,1614,1617],{"className":1615,"code":1616,"language":127,"meta":131},[125],"帮我把这台电脑上已登录的 \u003C软件名> 桌面版做成一个本地 OpenAI 兼容接口，你全程执行。\n\n1. 找到它的安装目录，读 product.json，拿到 endpoint 和产品标识\n2. 在 %LOCALAPPDATA% 下搜路径含 auth 的 *.info 文件，读出 accessToken\n3. 从 GitHub 找 \u003C软件名>2api 项目并下载，先做安全检查（列出代码里所有外部域名，应该只有 localhost 和官方域名）\n4. 装依赖，写一个启动器 monkey-patch 四处不匹配：上游 host、User-Agent、首条 system prompt、模型名映射\n5. 启动服务，三步验证：\u002Fhealth、\u002Fv1\u002Fmodels（应只有 4 个档位名）、真实调用一次\n6. 把 base_url、本地 key 和可用模型名给我\n\n报错按 host → User-Agent → 请求格式 → 模型名 的顺序排查，需要我做什么直接说。\n",[129,1618,1616],{"__ignoreMap":131},{"title":131,"searchDepth":1620,"depth":1620,"links":1621},4,[1622,1628,1629,1633,1638,1641,1642,1647,1653,1658,1659,1665,1669,1670,1671],{"id":12,"depth":1623,"text":12,"children":1624},2,[1625,1627],{"id":45,"depth":1626,"text":45},3,{"id":96,"depth":1626,"text":96},{"id":116,"depth":1623,"text":117},{"id":156,"depth":1623,"text":157,"children":1630},[1631,1632],{"id":174,"depth":1626,"text":175},{"id":222,"depth":1626,"text":223},{"id":282,"depth":1623,"text":283,"children":1634},[1635,1636,1637],{"id":286,"depth":1626,"text":287},{"id":345,"depth":1626,"text":346},{"id":381,"depth":1626,"text":382},{"id":416,"depth":1623,"text":417,"children":1639},[1640],{"id":487,"depth":1626,"text":488},{"id":545,"depth":1623,"text":546},{"id":589,"depth":1623,"text":590,"children":1643},[1644,1645,1646],{"id":668,"depth":1626,"text":669},{"id":687,"depth":1626,"text":688},{"id":736,"depth":1626,"text":737},{"id":860,"depth":1623,"text":861,"children":1648},[1649,1650,1651],{"id":880,"depth":1626,"text":881},{"id":893,"depth":1626,"text":894},{"id":966,"depth":1626,"text":1652},"6.3 \u002Fv1\u002Fmodels 返回的长列表不可靠",{"id":998,"depth":1623,"text":999,"children":1654},[1655,1656,1657],{"id":1005,"depth":1626,"text":1006},{"id":1063,"depth":1626,"text":1064},{"id":1079,"depth":1626,"text":1080},{"id":1131,"depth":1623,"text":1132},{"id":1224,"depth":1623,"text":1225,"children":1660},[1661,1662,1663,1664],{"id":1234,"depth":1626,"text":1235},{"id":1248,"depth":1626,"text":1249},{"id":1263,"depth":1626,"text":1263},{"id":1290,"depth":1626,"text":1290},{"id":1313,"depth":1623,"text":1314,"children":1666},[1667,1668],{"id":1323,"depth":1626,"text":1324},{"id":1339,"depth":1626,"text":1340},{"id":1445,"depth":1623,"text":1445},{"id":1564,"depth":1623,"text":1564},{"id":1608,"depth":1623,"text":1609},[1673],"未分类","2026-09-25","桌面端已经登录，但别的工具想用同一个账号的模型？手把手教你把登录态变成 OpenAI 兼容接口——找凭据、修四处协议不匹配、搞清模型名、三步验证，全程不用另外买 API Key。",false,"md","\u002Fai-reverse-proxy-cover.jpg",{"category":1680,"slots":1681},"技术",{},true,"\u002F2026\u002Flocal-ai-reverse-proxy",null,{"text":1686,"minutes":1687,"time":1688,"words":1689},"20 min read",19.61,1176600,3922,{"title":5,"description":1675},{"loc":1683},"posts\u002F2026\u002Flocal-ai-reverse-proxy",[],"tech","IvBhZjR0ScN0ypAtbdlwufAxc4F8Pol-chqwdxE1mEM",[1697,1684],{"title":1698,"path":1699,"stem":1700,"date":1674,"type":1694,"children":-1},"Cloudflare 部署全教程：从注册账号到网站上线","\u002F2026\u002Fcloudflare-deploy-guide","posts\u002F2026\u002Fcloudflare-deploy-guide",1790348237538]