跳到主要内容

数据截至 (上游 commit 3dcf4cad0124)

Jan — 架构与原理

30 秒导读: Jan 是一个装在你电脑上的开源聊天客户端。它既能把模型跑在本地(GGUF 走 llama.cpp、macOS 上还有 MLX),也能接 OpenAI / Anthropic 这类云端 provider;对话里可以调 MCP 工具去干真事,而每次工具执行前都要过一道用户审批;它还反过来在 localhost:1337 开一个 OpenAI 兼容接口,让别的程序把它当模型服务用(依据:README.md 的 Features 段)。

本页是多文件文档的入口。读完这一页,你应该能判断:Jan 大概怎么转、要不要继续往下读、该跳哪一章。 具体机制一律不在这里展开,全部下放到六个章节。


1. 这是什么(零基础也能懂)

一句话定义。 Jan 是一个本地优先(local-first)的桌面聊天应用,壳是 Tauri(Rust 主进程 + 系统 webview 前端),把"下载模型、跑模型、聊天、调工具"四件事装进一个可安装的 App。

给谁用、解决什么。 假设你想用大模型,但不愿意把对话交给别人的服务器;或者你已经在用 Claude、GPT,但想让它读你本地的文件、调你本地的工具。那你就得自己搞定"去哪下模型、下完怎么启动推理进程、显存不够怎么办、聊天记录存哪、工具怎么接"这一堆脏活。Jan 就是把这些脏活包起来,给你一个装完就能用的窗口。

它能做什么。 依据 README.md 的 Features 段:

能力说明
本地模型从 HuggingFace 下载 GGUF(Llama / Gemma / Qwen / GPT-oss 等)并在本机运行
云端 provider同一个界面里切到 OpenAI、Anthropic、Google、Mistral、Groq、xAI 等,以及任意 OpenAI 兼容端点
自定义 assistant给不同任务预设不同的 system 指令与采样参数
MCP 工具接 Model Context Protocol 服务器(本地子进程 / SSE / Streamable HTTP),让模型能真的动手
附件与 RAG给对话挂文档,自动切块、向量化,再由模型自己调内置检索工具取回
本地 API 服务localhost:1337 暴露 OpenAI / Anthropic 兼容接口,给其他应用调用

用起来什么样(开发者视角)。 从源码跑起来只有三步(依据:README.md 的 Build from Source、package.jsonscripts):

git clone https://github.com/janhq/jan
cd jan
make dev # 等价于 yarn install + yarn build + yarn dev:tauri

yarn dev 最终落到 tauri dev(package.json:13,27),也就是"编译 Rust 宿主 + 起 Vite 前端 + 开一个原生窗口"。

用起来什么样(外部程序视角)。 打开设置里的 Local API Server 之后,别的程序可以直接把它当 OpenAI 端点:

curl http://127.0.0.1:1337/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-4b",
"messages": [{"role": "user", "content": "列出我桌面上的文件"}],
"max_turns": 5
}'

打开"服务端工具执行"开关后,这一个请求内部会自动跑完「模型要调工具 → Rust 侧调 MCP → 把结果喂回模型」的多轮循环,最后只返回一条最终答案(src-tauri/src/core/server/proxy.rs:1136,run_server_side_openai_orchestration)。

一句话直觉。 把 Jan 当成一台本地装配好的 AI 工作站:webview 是操作台(界面和一轮对话的编排),Rust 主进程是机房(长连接、子进程、端口、文件全归它管),MCP 服务器和 llama-server 是插在机房上的外设。


2. 顶层全景(它大概怎么转)

2.1 三层进程,外加横跨的扩展层

怎么读这张图: 从上往下是调用方向。前端只发命令名,不碰进程和端口;所有有状态的东西(MCP 连接、模型进程、HTTP 服务)都活在 Rust 主进程里。

┌────────────────────────────────────────┐
你 ───────▶│ ① 前端 webview (React + Vercel AI SDK) │
│ 对话编排 · 工具审批弹窗 · 扩展宿主 │
└────────────────────┬───────────────────┘
│ invoke("call_tool" / "list_threads" …)

┌────────────────────────────────────────┐
│ ② Rust 主进程 (Tauri) │
│ AppState:所有长连接与句柄的唯一持有者 │
└───┬───────────────┬──────────────┬─────┘
│ │ │
▼ ▼ ▼
③ MCP 服务器 ③ llama-server ③ 本地兼容 API
子进程 / SSE router 模式 :1337 /v1
/ HTTP (或 MLX) (可反向调用 MCP)

还有横跨的第四块:扩展(extensions/,7 个包)。它是 TypeScript,跑在第 ① 层里,只是被单独打包、单独安装,像浏览器插件一样可插拔。三层 + 扩展的完整拆解见 01 章

三个 TypeScript 包的分工:

干什么是不是根 workspace 成员
web-app/React 界面 + 一轮对话的编排
core/(@janhq/core)扩展 SDK:抽象基类 + 类型枚举 + 事件总线
extensions/(7 个)llamacpp · mlx · rag · vector-db · assistant · conversational · download,独立 workspace

package.jsonworkspaces.packages 只列了 coreweb-app(package.json:5-9);extensions/ 和 Rust 侧的插件 API 包各有自己的 workspace,构建时单独 yarn install(package.json:50build:extensionspackage.json:43build:tauri:plugin:api)。

2.2 五个 Tauri 插件

Rust 宿主本身只是个 tauri::Builder,重活拆成插件挂上去。插件链在 src-tauri/src/lib.rs:231-254(run):

插件干什么何时挂载
tauri_plugin_llamacpp起 / 停 llama.cpp router 进程、加载卸载模型总是(lib.rs:222)
tauri_plugin_vector_db本地向量库读写总是(lib.rs:223)
tauri_plugin_rag文档切块、嵌入、检索工具总是(lib.rs:224)
tauri_plugin_mlxApple Silicon 上的 MLX 推理后端仅 macOS(lib.rs:233,依赖声明在 Cargo.toml:164-165 的 macOS target 块)
tauri_plugin_hardware读 CPU / 内存 / GPU 信息非移动端(lib.rs:238)

五个插件的源码都在仓库内:src-tauri/plugins/tauri-plugin-{llamacpp,mlx,rag,vector-db,hardware},路径依赖见 src-tauri/Cargo.toml:98-102

2.3 部件一句话职责

部件干什么在哪个文件
CustomChatTransport一轮对话的编排中枢:选模型、装工具、裁上下文、调 streamTextweb-app/src/lib/custom-chat-transport.ts:725
useChat包一层 AI SDK 的 useChat,让换模型不用重建 transportweb-app/src/hooks/use-chat.ts:30
线程页面onToolCall 收集工具、跑审批与执行、决定是否自动续轮web-app/src/routes/threads/$threadId.tsx
useToolApprovalRequests审批待批队列(不落盘);白名单持久化拆在 useToolApprovalweb-app/src/hooks/useToolApprovalRequests.ts:40
MCPOrchestrator服务器多了以后,挑出跟这句话相关的那几台再取工具web-app/src/lib/mcp-orchestrator/mcp-orchestrator.ts:79
ServiceHub前端统一的服务门面(mcp / rag / threads / models …),按平台换实现web-app/src/services/index.ts:56,81
ExtensionManager运行时 import() 扩展 JS、注册、按 ExtensionTypeEnum 取用web-app/src/lib/extension.ts:62
BaseExtension扩展的抽象基类,规定 onLoad / onUnload / type()core/src/browser/extension.ts:32
AppStateRust 侧全局状态:MCP 连接表、下载管理器、服务句柄、取消令牌src-tauri/src/core/state.rs:59
MCP 命令层连服务器、列工具、call_tool、按服务器筛工具、取消src-tauri/src/core/mcp/commands.rs:298,308,329,389
llamacpp 扩展管 router 进程、模型加载顺序与容量上限extensions/llamacpp-extension/src/index.ts:3425
router 进程封装llama-server argv、拉起、健康检查、优雅停src-tauri/plugins/tauri-plugin-llamacpp/src/router.rs:89,120
threads 存储线程 / 消息 / 线程级 assistant 的持久化src-tauri/src/core/threads/commands.rs:24
本地 API 服务localhost:1337 的反向代理 + 服务端工具循环src-tauri/src/core/server/proxy.rs:1285,1135

2.4 主线走一遍(高层,不进代码)

怎么读这张图: 从上往下是一轮对话;第 ⑥ 步产出的工具结果回灌到第 ② 步,开始下一轮。

你敲下回车


① UI 收到消息 ──▶ ② CustomChatTransport 组装这一轮
· 选哪个模型 / provider
· 该带哪些工具(MCP + RAG)
· 上下文超了就裁 / 压


③ streamText 流式产出
文本 / 推理过程 / 工具调用

┌──────────────┴───────────────┐
▼ ▼
文本直接上屏 ④ onToolCall 只「收集」不执行


⑤ 审批闸门:逐个问你
允许一次 / 一直允许 / 拒绝


⑥ 服务层执行(RAG 直放 / MCP 落到 Rust)

└──▶ 结果回灌,回到 ②

六步各自的落点:

落在哪
② 组装custom-chat-transport.ts:1102 sendMessages
③ 流式custom-chat-transport.ts:1369 streamText
④ 收集$threadId.tsx:546-548 onToolCall
⑤ 审批useToolApprovalRequests.ts:43 requestApproval;UI 四个按钮在 tool.tsx:348-370
⑥ 执行$threadId.tsx:422,430 serviceHub.rag()/mcp().callTool → Rust mcp/commands.rs:405 call_tool
续轮$threadId.tsx:549 sendAutomaticallyWhen: followUpMessage

一个要点先说在前面: AI SDK 本身支持工具自动执行,Jan 偏偏不用——onToolCall 只把工具调用推进一个数组,真正的执行放在应用层的循环里,好在中间插进"问用户"这一步。这是整个项目最值得看的设计,详见 03 章


3. 阅读地图

建议按顺序读:先建立"进程和扩展"的地形感,再跟着一次对话走完全程,然后分别下钻工具、推理、记忆三条支线,最后看反向暴露的 API。

顺序章节这章讲什么适合谁
1骨架:三层进程与可插拔扩展系统webview / Rust 主进程 / 外部进程如何分工,window.core.api 桥怎么把驼峰路由变成 Tauri 命令,扩展如何被动态 import 与按类型解析先看这个再看别的
2一次对话怎么跑完:CustomChatTransport 与 AI SDKsendMessages 的完整流水线:建模型、装工具、九个消息清洗器、streamText、流元数据与 token 速率回填想改对话行为的人
3手脚:MCP 客户端、审批闸门与工具路由rmcp 三种传输、健康监控与指数退避重连、审批三态状态机、服务器超过阈值时的关键词 + LLM 双层路由关心 agent 安全与工具选择
4本地推理运行时:llama.cpp router 与后端分发router 模式的 argv 与就绪探测、多模型 FIFO 驱逐、后端下载与依赖校验、OOM 识别与优雅退出关心本地推理工程
5记性:线程持久化、分支、上下文压缩与 RAG线程落盘(桌面 JSONL / 移动 SQLite)、父指针消息树与版本切换、trim 与 auto-compact、RAG 三件套工具与向量库关心记忆与检索
6反向暴露:本地兼容 API 与服务端工具循环/v1 代理如何解析上游、Anthropic ↔ OpenAI 双向翻译、max_turns 有界循环与 schema 归一化想把 Jan 当后端用

只想抓重点的话: 读 01 建立地图,再读 03 —— 这两章覆盖了 Jan 作为 "agent 宿主"最有工程含量的部分。


4. 巧妙之处速览

这一节只点破"妙在哪 + 在哪能看到",细节在对应章节。

① 审批闸门放在"流结束之后",而不是塞进模型的执行回调。 AI SDK 允许在工具定义里直接写 execute。Jan 偏不:给工具只声明 description + inputSchema(custom-chat-transport.ts:950)。于是模型只能"提出"调用,SDK 无处执行,调用被 onToolCall 攒进一个数组($threadId.tsx:546-548),由 UI 层串行地过审批再执行——被拒就写回一条 output-error: 'Tool execution denied by user' 继续下一个($threadId.tsx:409),内置 RAG 工具显式豁免审批($threadId.tsx:401)。好处很实在:审批要等人点按钮,塞进流式回调会阻塞整条流;拆开之后流可以干净地结束,待办队列再慢慢消化,还能整队 abort。→ 03 章

② 服务器 ≤ 5 台时,根本不启动智能路由。 ROUTING_THRESHOLD = 5(intent-classifier.ts:4)。getRelevantTools 开头就判断 summaries.length <= ROUTING_THRESHOLD 则直接取全量工具返回(mcp-orchestrator.ts:96-113)。妙在:小规模场景下,多一次 LLM 路由调用带来的延迟远大于它省下的 token,于是干脆不做。超过阈值才走"关键词打分(能力名精确命中 +4、部分命中 +2、描述命中 +1,intent-classifier.ts:33;要求 score ≥ 2,:83)→ 可选的轻量 LLM router → 拿不到就回退全量"这条链(mcp-orchestrator.ts:116-165)。→ 03 章

③ 一个 router 进程托管多模型,超额时按 FIFO 驱逐。 Jan 不给每个模型开一个 llama-server,而是用 --models-preset + --models-max一个 router 进程(router.rs:452 router_args)。前端维护一份 loadedChatOrder 数组当队列,加载新模型前若已到上限就 shift() 出最老的那个卸掉(extensions/llamacpp-extension/src/index.ts:3495 evictChatIfAtCapacity)。细节讲究:嵌入模型不参与驱逐,免得后台跑一次嵌入就把你的聊天模型顶下去(index.ts:2727-2728);拿不到 router 的真实已加载列表时,宁可拿本地队列过度驱逐也不违反上限(index.ts:2755-2758)。退出时还有一道礼貌门:主窗口关闭前先问 router "还有模型在忙吗",忙就先不退、发事件让 UI 提示(src-tauri/src/lib.rs:170 handle_graceful_exit)。→ 04 章

④ 消息不是数组,是一棵父指针树。 编辑一条旧消息、或对同一个问题重新生成,在 Jan 里都不是覆盖,而是新建一个兄弟版本。每条消息 metadata.parentId 指向前驱,metadata.activeChildId 指定当前展示哪个分支;可见对话 = 从活跃根沿着活跃子一路走下来的那条路径(message-branching.ts:95 computeActivePath)。老线程没有这些字段,照样当线性对话渲染,直到第一次分叉时才回填父指针(message-branching.ts:142 backfillParentIds)。这是"新数据模型兼容旧数据"的一个干净范例——而且没动任何存储 schema。→ 05 章

⑤ 上下文超预算时,先总结再截断,总结完还要再截一次。 compactMessages 会把将被丢弃的旧消息喂给同一个模型做摘要,摘要以 role: 'system' 注入(而不是伪装成用户发言,以免打乱轮次交替)。关键的一步是:摘要本身也占 token,所以合并之后再跑一次 trimMessages 才能保证真的装得下;摘要失败则静默退回纯截断(context-manager.ts:124 compactMessages:69 trimMessages)。→ 05 章

⑥ 给 Anthropic 单独把串行 tool-use 拆成 wave。 Claude 的 API 要求 tool_use / tool_result 严格配对,而一条 assistant 消息里"工具 → 文本 → 又工具"的交错会转出非法结构。Jan 只对 apiType === 'anthropic' 的 provider 做一次 flatMap:扫 parts,遇到"工具段之后出现非工具段"就切一刀,把一条消息切成 id_w0id_w1……多条(custom-chat-transport.ts:530-565 splitAssistantToolWaves)。妙在这是纯前置改写,不污染其它 provider 的路径——同一段流水线上还收着"Qwen 模板要求窗口里有真实用户提问""模型不支持视觉时先剥图片"等一串同类补丁。→ 02 章

⑦ 前端到 Rust 的桥是"路由名自动转命令名"。 window.core.api 不是手写几十个包装函数,而是把一张路由名数组批量映射成代理:驼峰名 listThreads 用一条正则转成 list_threadsinvoke(web-app/src/lib/service.ts:40,47,名单在同文件 :6-27)。这让扩展代码写 window.core.api.listThreads() 就够了,新增命令只要往数组里加一个名字。→ 01 章

⑧ 本地 API 服务在服务端自己跑工具循环。 外部程序调 localhost:1337 时可以带一个 max_turns(默认 8,夹在 1..20),Rust 侧就在服务端跑"请求 → 抽 tool_calls → 执行 MCP → 把 tool 结果 append 回 messages → 再请求"的循环,直到模型不再要工具(proxy.rs:1199-1203:1135 run_server_side_openai_orchestration)。跑满仍在要工具就报错并把最后一次响应原样带回(proxy.rs:1277-1282)。妙在:调用方只发一个普通的 chat completions 请求,agent 循环整个藏在服务端。→ 06 章


5. 边界(先说清楚,免得读错)

  • 不是服务端产品。 整套设计围绕"一台个人电脑上的一个 App":单实例(lib.rs:210single_instance 插件)、数据放本地目录、localhost:1337 默认只绑本机。
  • MLX 只有 macOS。 插件依赖写在 macOS target 块里(Cargo.toml:164-165),构建脚本也把 @janhq/mlx-extension 从 win32 / linux 的构建里排除(package.json:52-53)。
  • 审批是"人在回路"的,不是沙箱。 闸门管的是"要不要执行",执行本身直接跑 MCP 服务器,没有额外隔离;而且服务端那条循环完全没有这道闸门(见 06 章 §9),它靠"默认关闭 + 端口访问控制"防守。
  • 移动端是裁剪版。 lib.rs:249-254 显示 iOS / Android 分支不挂 updater、走另一套 remote provider 命令;扩展也在编译期就定死,目前只有 conversational 一个。

6. 代码地图(全项目导航索引)

按主题分组,给出文件路径和可 grep 的真实符号名;grep 符号名比按行号更抗上游漂移。

入口与宿主

主题文件符号锚点
Rust 宿主启动、插件链src-tauri/src/lib.rsrunlib.rs:206,216-238
前端可调用的全部 Tauri 命令清单src-tauri/src/lib.rsinvoke_commands_with_extras!lib.rs:24
优雅退出:等 router 空闲再关src-tauri/src/lib.rshandle_graceful_exitlib.rs:155
全局可变状态(MCP 连接、下载、服务器句柄)src-tauri/src/core/state.rsAppStateRunningServiceEnumstate.rs:50,44
首次启动 / 升级时的扩展安装与 MCP 迁移src-tauri/src/core/setup.rsinstall_extensionsmigrate_mcp_serverssetup.rs:27,169

扩展系统

主题文件符号锚点
扩展抽象基类与设置合并core/src/browser/extension.tsBaseExtensionregisterSettingsextension.ts:31,114
扩展类型枚举(当接口名用)core/src/browser/extension.tsExtensionTypeEnumextension.ts:4
运行时注册与按类型 / provider 检索web-app/src/lib/extension.tsExtensionManageractivateExtensionregisterActiveextension.ts:62,190,227
扩展装载的 React 入口web-app/src/providers/ExtensionProvider.tsxExtensionProvidersetupExtensionsExtensionProvider.tsx:24,28
前端 → Rust 命令桥web-app/src/lib/service.tsAPIsAppRoutesservice.ts:40,6-27
前端服务门面(按平台换实现)web-app/src/services/index.tsServiceHubPlatformServiceHubinitializeServiceHubindex.ts:56,81

对话主线

主题文件符号锚点
一轮对话的组装与流式web-app/src/lib/custom-chat-transport.tsCustomChatTransportsendMessagescustom-chat-transport.ts:559,850
工具清单装配(RAG + MCP + 禁用过滤 + 重名告警)web-app/src/lib/custom-chat-transport.tsrefreshToolsresolveRouterModelcustom-chat-transport.ts:643,788
Anthropic 串行 tool-use 拆 waveweb-app/src/lib/custom-chat-transport.tssplitAssistantToolWavescustom-chat-transport.ts:530
消息清洗器与早失败守卫web-app/src/lib/custom-chat-transport.tsstripUnsupportedImagePartsresolveOrphanToolCallshasGenuineUserQuerycustom-chat-transport.ts:353,405,465
模型工厂(各 provider → AI SDK 模型)web-app/src/lib/model-factory.tsModelFactory.createModelcreateLlamaCppModelmodel-factory.ts:705,760
useChat 包装(换模型不重建 transport)web-app/src/hooks/use-chat.tsuseChatuse-chat.ts:30
线程页面:工具收集、审批、执行、续轮web-app/src/routes/threads/$threadId.tsxonToolCallfollowUpMessage$threadId.tsx:546,158

工具与 MCP

主题文件符号锚点
审批待批队列(不落盘)web-app/src/hooks/useToolApprovalRequests.tsuseToolApprovalRequestsrequestApprovalresolveApprovaluseToolApprovalRequests.ts:27,43,69
审批持久化白名单web-app/src/hooks/useToolApproval.tsuseToolApprovalapproveToolForThreadapproveServerisToolApproveduseToolApproval.ts:26,62
审批 UI(拒绝 / 允许一次 / 一直允许)web-app/src/components/ai-elements/tool.tsxToolApprovalActionstool.tsx:225,245-262
工具路由(阈值 + 关键词 + LLM)web-app/src/lib/mcp-orchestrator/mcp-orchestrator.tsMCPOrchestratorgetRelevantToolsmcp-orchestrator.ts:79,85
路由阈值与关键词打分web-app/src/lib/mcp-orchestrator/intent-classifier.tsROUTING_THRESHOLDMAX_ROUTED_SERVERSclassifyIntentscoreServerintent-classifier.ts:4,6,62,33
LLM router 调用web-app/src/lib/mcp-orchestrator/mcp-router-llm.tsselectServersWithLlmmcp-router-llm.ts:35
MCP 命令层(列工具 / 调工具 / 取消)src-tauri/src/core/mcp/commands.rsget_toolsget_tools_for_serversget_server_summariescall_toolcancel_tool_callcommands.rs:298,308,329,389,519
MCP 连接、三种传输、健康监控src-tauri/src/core/mcp/helpers.rsstart_mcp_serverschedule_mcp_start_taskmonitor_mcp_server_handlehelpers.rs:324,385,163
MCP 运行时设置(超时、退避、路由开关)src-tauri/src/core/mcp/models.rsMcpSettingsMcpServerConfigServerSummarymodels.rs:53,8,106

本地推理运行时

主题文件符号锚点
router 启动 / 停止 / 强杀src-tauri/plugins/tauri-plugin-llamacpp/src/router.rsrouter_argsstart_routertry_graceful_stop_routerforce_kill_router_treerouter.rs:89,120
load / unload 的 HTTP 翻译与轮询src-tauri/plugins/tauri-plugin-llamacpp/src/commands.rspost_loadwait_until_loadedfind_session_by_modelcommands.rs:42,75,402
模型加载与 FIFO 驱逐extensions/llamacpp-extension/src/index.tsloadperformLoadensureRouterReadyevictChatIfAtCapacityindex.ts:2680,2715,2706,2749
router preset 文件生成extensions/llamacpp-extension/src/preset.tsgeneratePresetMTP_MIN_BUILDpreset.ts:75
后端二进制选型与依赖校验extensions/llamacpp-extension/src/backend.ts · .../src/backend.rslistSupportedBackends · prioritize_backendsverify_backend_installation
MLX 后端(macOS)src-tauri/plugins/tauri-plugin-mlxextensions/mlx-extensionMlxStatemlx_extension.load
硬件信息src-tauri/plugins/tauri-plugin-hardware

记忆与检索

主题文件符号锚点
线程 / 消息命令(桌面文件 / 移动 SQLite 分叉)src-tauri/src/core/threads/commands.rslist_threadscreate_messagemodify_messagecommands.rs:24,159
存储后端选择与 JSONL 读写、每线程锁src-tauri/src/core/threads/helpers.rsshould_use_sqlitewrite_messages_to_fileMESSAGE_LOCKShelpers.rs:17,34,14
移动端 SQLite 初始化与幂等写src-tauri/src/core/threads/db.rsinit_databasedb_create_messagedb_modify_messagedb.rs:27
消息版本树与活跃路径web-app/src/lib/message-branching.tscomputeActivePathbackfillParentIdsmakeSiblingmessage-branching.ts:90,137,146
上下文裁剪与自动压缩web-app/src/lib/context-manager.tstrimMessagescompactMessagesCHARS_PER_TOKENcontext-manager.ts:69,124,11
前端线程 API(经扩展转发)extensions/conversational-extension/src/index.tsJanConversationalExtensionindex.ts:12
RAG 内置工具定义extensions/rag-extension/src/tools.tsgetRAGToolstools.ts:8
向量库封装与集合命名extensions/vector-db-extension/src/index.tsVectorDBExtingestFileindex.ts:5

本地 API 服务与下载

主题文件符号锚点
服务器启停src-tauri/src/core/server/commands.rsStartServerConfigstart_serverstop_servercommands.rs:12,23
请求总入口与上游解析src-tauri/src/core/server/proxy.rsproxy_requestresolve_upstream_for_modelproxy.rs:1285,888
服务端工具循环src-tauri/src/core/server/proxy.rsrun_server_side_openai_orchestrationcollect_mcp_openai_toolsexecute_mcp_tool_callsproxy.rs:1135,958,1014
前端配置存储(端口、前缀、可信主机、工具开关)web-app/src/hooks/useLocalApiServer.tsuseLocalApiServerserverPortuseLocalApiServer.ts:21,60
模型下载src-tauri/src/core/downloads/commands.rsdownload_filescancel_download_taskpause_download_taskcommands.rs:11,75
下载扩展(HF token、进度事件)extensions/download-extension/src/index.tsDownloadManagerindex.ts:23