PrivateGPT Workbench 演示 UI 设计:基于 OpenAPI 契约的单文件静态应用
【免费下载链接】privateGPTComplete API layer for private AI applications on local models: RAG, skills, tools, MCP, text-to-sql, and more. Works with any OpenAI-compatible inference server.项目地址: https://gitcode.com/GitHub_Trending/pr/privateGPT
本文围绕 PrivateGPT 仓库中的 Workbench PRD 展开,讲解这个位于ui/目录的轻量演示界面如何把 PrivateGPT 的 Claude 兼容 API(聊天、文档摄取、Text-to-SQL、Web 搜索、MCP、Skills、自定义工具等)变成一个可直观操作的本地应用:包括以 Fern 生成的 OpenAPI 文件为唯一契约来源的请求构建规则、localStorage持久化状态模型、会话级 API Debugger、以及浏览器端 JavaScript 自定义工具的闭环执行机制。读完本文,你可以理解 Workbench 每个界面背后的 API 调用方式与源码实现对应关系,也能照着 PRD 的分层设计思路为本地推理服务搭建自己的演示前端。
一、定位与边界:Workbench 是演示器,不是主产品
PrivateGPT 的价值主张不是本地推理本身,而是构建在任意 OpenAI 兼容本地推理后端之上的高层应用层:Chat/messages API、文件摄取、带引用的检索、Text-to-SQL、沙箱 Python 表格分析、Web 搜索与抓取、MCP、Skills、自定义工具以及 Embeddings 等底层原语。Workbench(暂定名 PrivateGPT Workbench)存在的目的,是让这些 API 能力变得"可感知":
- 对非技术用户,它应呈现为:一个免费的本地 AI 助手,可查询文档、知识库、网站、CSV 和数据库,无需依赖云端 API key;
- 对开发者,它应呈现为:一个本地 Claude 兼容 API 层,可以在其上构建应用。
PRD 明确给 Workbench 划定了边界——它必须停留在 ui/index.html 这个轻级演示器的形态里,不得演变成重量级前端应用或维护负担。这一边界在仓库中得到了严格贯彻:ui/目录下唯一的运行时实现文件就是index.html(当前约 7974 行,HTML/CSS/JS 全部内联),其余全是文档与视觉参考资产。ui/README.md 中的工作规则也规定:除非明确要求重构,否则保持实现收敛在index.html中;行为、视觉、持久化或 API 接线变化时,文档与实现必须同步更新。
目标与非目标
Primary Goals(PRD 原文四点):
- 让非技术用户体验 PrivateGPT 作为本地 AI 助手;
- 让用户配置助手可用的本地上下文:文档、数据库、Web 搜索、MCP、Skills、自定义工具;
- 让开发者通过轻量级会话级 API Debugger 观察 UI 与 API 的交互过程;
- 保持实现简单:理想形态是一个含 vanilla JS/CSS 的静态 HTML 文件加浏览器
localStorage。
Non-Goals(明确不做的事):无用户账号、无服务端 UI 数据库、无项目/文件夹/组织/工作区层级、无复杂设计系统、无云同步、除非绝对必要否则不引入重型前端框架、不试图替代浏览器 DevTools、Debugger 不做持久化存储。
二、两个 Source of Truth:OpenAPI 契约与视觉风格指南
2.1 API 契约:Fern 生成的 openapi.json
Workbench 的 API 契约由仓库根目录下的 fern/openapi/openapi.json 定义(从ui/目录看即../fern/openapi/openapi.json)。PRD 强调:该 OpenAPI 文件是端点、请求/响应体形状、Schema 名称、工具/上下文结构、消息块格式、Artifact 格式、MCP 字段的唯一权威来源;PRD 中的示例仅是示意,凡与契约不符处以契约为准。
实现者在做请求构建器之前,应先解析或人工检查该文件,对齐这些关键 Schema:ChatBody、MessageInput、ToolSpecBody、ContextFilter、FileArtifact、SqlDatabaseArtifact、McpServerConfig以及工具响应块 Schema。这些 Schema 在当前契约中均存在,可核对其字段:
ChatBody顶层字段包括model、messages、system、tools、thinking、tool_context、mcp_servers、container、stream、max_tokens,以及temperature、top_p、presence_penalty等采样参数;ToolSpecBody字段为name、type、description、inputSchema、context、deferLoading、instructions;ContextFilter字段为collection、artifacts、metadata_filter;SqlDatabaseArtifact字段为type、connection_string、schemas、ssl、enable_tables、enable_views、enable_functions、enable_procedures、description,与 PRD 中 Databases 小节的 JSON 示例完全一致;McpServerConfig字段为name、url、authorization_token、tool_configuration。
PRD 列出的重要端点(当前契约中均可在 openapi.json 的 38 个/v1/*路径中找到):
POST /v1/messages POST /v1/messages/count_tokens POST /v1/messages/validate GET /v1/models POST /v1/artifacts/ingest GET /v1/artifacts/list?collection=<collection> POST /v1/artifacts/delete POST /v1/artifacts/content POST /v1/artifacts/chunked-content POST /v1/primitives/search POST /v1/tools/semantic-search POST /v1/tools/tabular-data-analysis POST /v1/tools/database-query POST /v1/tools/web-fetch POST /v1/tools/web-searchPRD 的设计判断是:POST /v1/messages是中心端点。产品体验的大部分应通过聊天流走,Context 负责提供输入,Debugger 负责解释底层的 API 交互。
2.2 视觉与 UX:STYLE_GUIDE 与参考图
PRD 要求与视觉方向文件 ui/docs/STYLE_GUIDE.md 配套使用,它是布局、玻璃质感表面(glass surfaces)、背景处理、侧边栏行为、聊天输入区处理、Context 行与 Debugger 视觉密度的权威来源。风格指南引用了仓库本地的参考图:
- ui/references/primary-chat-layout.png
- ui/references/search-overlay.png
- ui/references/chat-tools-composer.png
- ui/references/context-knowledge-base.png
ui/docs/SOURCE_OF_TRUTH.md 进一步固化了文档分工:产品行为归docs/PRD.md,视觉规则归docs/STYLE_GUIDE.md,运行时代码归index.html,参考图归references/,且不得维护一份 UI 本地的 OpenAPI 快照副本。
三、架构:单文件静态应用 + localStorage
3.1 目录与存储结构
PRD 推荐的最初实现形态即当前仓库形态:
ui/ index.html # 单文件静态应用(HTML + CSS + JS)浏览器存储分工:
localStorage:持久化应用状态(连接设置、上下文配置、会话、外观覆盖);- 内存态:API Debugger 事件(页面刷新即清空,绝不落盘)。
3.2 默认 API 地址:PRD 与当前实现的差异
PRD 给出的默认 PrivateGPT API base URL 是http://127.0.0.1:8001,并要求允许用户在 Web 应用内覆盖、无需编辑任何配置文件。
从源码看,ui/index.html 中的实际默认值略有演化:
const DEFAULT_BASE_URL = window.location.origin === "null" ? "http://127.0.0.1:8080" : window.location.origin;即:当页面通过 Web 服务访问时默认指向服务自身的 origin(这样与 PrivateGPT 同源部署时零配置),以本地文件方式打开(origin 为null)时回落到http://127.0.0.1:8080。这印证了 PRD"本地场景优先"的 CORS 立场:应用应首先在"本地静态文件 + 本地 PrivateGPT API"场景下工作;部署到其他位置时用户仍可在 UI 内改 URL 与 token,跨域所需的服务器策略由 PrivateGPT 部署侧处理。
连接设置包含两项:PrivateGPT API base URL与可选的 HTTP Basic 认证(用户名/密码两个字段)。配置了认证时,请求头携带Authorization: Basic <base64(username:password)>——实现位于 ui/index.html 的createBasicAuthHeader()。
3.3 两个互不相干的连接概念
PRD 特别澄清了容易混淆的两层连接:
- PrivateGPT API URL 与认证——Workbench 直接调用的对象,必须在 Workbench UI 中可配置,v1 仅支持可选的 HTTP Basic 认证(用户名+密码字段);
- LLM Gateway URL 与认证——指向 PrivateGPT 底层的推理提供者(如本地 Ollama,常见默认
http://127.0.0.1:11434)。它配置在PrivateGPT 自己的配置文件(仓库根目录的 settings.yaml 等)中,Workbench v1 不得在 UI 中暴露 LLM Gateway 配置。所有 Workbench 的 API 调用只打向配置的 PrivateGPT API base URL,浏览器绝不直连 LLM Gateway。
针对开发与自动化测试,PRD 约定本地环境可能提供PGPT_BASE_URL与PGPT_TOKEN两个环境变量,实现可在本地测试脚本或 dev-server 启动时读取它们,但绝不得存储、打印、提交或硬编码实际值。
四、持久化状态模型(localStorage)
PRD 定义了 Workbench 的完整状态形状,index.html的state对象即按此实现:
{ privateGptBaseUrl: string, privateGptUsername: string, privateGptPassword: string, systemPrompt: string, useCitations: boolean, selectedModel: string | null, uiAppearance: { brief: string, brandName: string, welcomeTitle: string, welcomeSubtitle: string, customInstructions: string, palette: { accent, secondary, surface, background }, features: { databases: boolean, web: boolean, mcp: boolean, skills: boolean, customTools: boolean, apiDebugger: boolean, github: boolean, productionNotice: boolean } }, onboarding: { completed: boolean, step: 1 | 2, appearanceSkipped: boolean, lastCheck: { ok: boolean, testedAt: string, summary: string, steps: Array<{ label: string, detail: string, ok: boolean | null }> } | null }, context: { documents: { defaultCollection: string }, databases: DatabaseConfig[], mcpServers: McpServerConfig[], skills: SkillConfig[], customTools: CustomToolConfig[] }, chats: ChatSession[], activeChatId: string | null }会话对象:
type ChatSession = { id: string; title: string; createdAt: string; updatedAt: string; messages: ChatMessage[]; settings: { enabledDocuments: boolean; enabledDatabases: string[]; enabledWeb: boolean; enabledMcpServers: string[]; enabledSkills: string[]; enabledCustomTools: string[]; model: string | null; }; };(当前实现在此骨架上扩展了enabledTabular、enabledCodeExecution、reasoningEffort等字段,见 ui/docs/SOURCE_OF_TRUTH.md 的实现备注。)
刷新后必须恢复的行为清单:onboarding 成功完成后保持关闭;Context 恢复;聊天列表恢复;聊天消息恢复;每会话工具开关恢复;外观覆盖与可选功能区可见性恢复。而 Debugger 始终为空。
五、信息架构:侧边栏、屏幕与 Hash 导航
5.1 布局骨架
应用有一个常驻左侧边栏与主内容区:
Sidebar Context New Chat Chats Contract review CSV analysis Database demo Custom tool test API Debugger Settings GitHub Not for Production Main 首次启动或重跑 onboarding:引导式 onboarding 覆盖层(Step 1: URL + collection + 实时检查;Step 2: 可选外观定制) Context 选中:Context 配置屏 Settings 选中:API 连接设置与助手行为 API Debugger 选中:会话级请求/响应 trace Chat 选中:聊天界面侧边栏行为细则:
- Context——打开全局 Context 屏;
- New Chat——创建新会话,默认标题
New chat,从全局默认复制上下文设置并打开; - 聊天列表——按
updatedAt DESC排序持久化会话,当前会话高亮,支持内联重命名/删除,长标题省略号截断,且侧边栏与列表绝不出现横向滚动条; - API Debugger——打开会话级 trace,位于 Settings 之上的底部分组;
- Settings——位于 API Debugger 之下;
- GitHub——链接到 PrivateGPT 仓库,GitHub 可达时显示实时 star 数;
- Not for Production——打开说明性模态框,位于 GitHub 组件之下。
明确没有"项目"或任何分组概念。
5.2 URL Hash 导航
应用采用 hash 导航,使刷新后能恢复当前视图与 Context 标签页:
#context/{tab} Context 屏 + 具体标签(documents/databases/web/mcp/skills/customTools) #settings Settings 屏 #apiDebugger API Debugger 屏 #chat/{chatId} 指定会话实现位于 ui/index.html:syncHash()在每次render()结束和 Context 标签切换后调用;restoreFromHash()在启动首次渲染前运行一次,并在hashchange时运行以支持浏览器前进/后退。
六、Settings 屏:连接与全局助手行为
Settings 屏拥有"不属于助手上下文"的 Workbench 级配置:
- PrivateGPT API base URL;
- 可选 HTTP Basic 认证(用户名、密码);
- 可选 system prompt;
- 可选的 workspace instructions,置于 system prompt 之前;
- Use citations 开关,默认开启;
- Collection——当前活动文档集合名,用于文档摄取、列表、删除、搜索与聊天请求。PRD 特别强调它属于 Settings 而非 Context > Documents,因为它是全局指针,不是某个上下文源配置;
- 品牌文案、欢迎文案、色板与可选可见区的外观覆盖;
- 重跑 onboarding、测试 API 连接、保存设置、清空本地浏览器数据。
几个关键约定:
- system prompt 走顶层
system字段,而不是system角色的消息。用户留空时就不发 system 文本;但为携带citations.enabled这类请求级选项,system对象仍可能以无text的形式发出。 - 清空本地数据只清除本 Workbench 的浏览器状态(会话、设置、token、上下文、偏好),绝不暗示删除 PrivateGPT 侧数据(已摄取文档、后端配置等)。
从源码看,ui/index.html 的buildChatBody()体现了"system 对象按需组装"的规则:只有存在 system 文本、启用引用、扩展、内建工具或 thinking 时才生成body.system,其中system.citations.enabled由"文档启用 && useCitations 非 false"决定,system.text仅在合并后的 system 文本非空时写入。
七、Onboarding:连接验证 + LLM 生成外观
首次启动时,Workbench 在正常使用前弹出 onboarding 覆盖层。只要state.onboarding.completed !== true就会显示(状态由state.onboarding控制,见 SOURCE_OF_TRUTH.md 的实现备注)。
Step 1(连接与验证):
- 收集 PrivateGPT base URL、可选 HTTP Basic 认证、活动 collection ID,写入与 Settings 相同的持久化状态;
- 对以下端点跑实时检查:
GET /v1/modelsGET /v1/artifacts/list?collection=<collection>GET /v1/skills?collection=<collection>
- 展示简单的通过/失败清单,检查全部通过前不放行。
Step 2(外观定制,必须可跳过):
- 接收一段自然语言主题 brief,通过
POST /v1/messages调用已配置的 LLM 生成初始外观方案; - 必须在用户完成 onboarding 前展示生成结果,并允许随后手工定制品牌名、欢迎文案、workspace instructions、颜色与可选可见区;
- GitHub/Zylon 引用必须保持可见,不能通过生成或手工外观设置移除;
- 写入持久化外观变量(覆盖运行时 UI 状态与 CSS 自定义属性),之后仍可从 Settings 或重跑 onboarding 编辑。
实现侧对应applyAppearance()(ui/index.html):外观覆盖是运行时变量,state.uiAppearance同时驱动文案、功能可见性与 CSS 自定义属性;主题 brief 经聊天 API 生成后解析为 JSON,回写进用户可手工编辑的同一组外观表单字段。
"Not for Production" 披露
侧边栏常驻Not for Production入口(位于 GitHub 组件下方),点击打开可关闭的玻璃风格模态框,标题为"This demonstrator is not intended for Production use",解释该 UI 适合试用 API 能力、调试请求、探索本地 AI 工作流,但不应作为生产应用发布,并覆盖四点风险:
- 浏览器存储不是安全的密钥存储——bearer token、聊天、上下文配置与设置都保存在
localStorage; - 没有应用级访问控制——任何能访问该页面的人都可使用所配置的 API 端点、token、工具、文档与模型访问;
- 调试数据被刻意可见——API Debugger 可显示 prompt、文档摘录、头、元数据、请求与响应;
- 自定义工具运行浏览器 JavaScript——只应使用可信代码,UI 不应在没有评审过部署模型的情况下对外暴露。
八、Context 屏:定义助手能用什么
Context 屏分六个区:Documents / Databases / Web / MCP / Skills / Custom Tools,允许使用紧凑的 tab 或手风琴布局。
8.1 Documents:本地知识库管理
能力清单:
- 设置 collection 名(实际字段在 Settings,全局生效);
- 上传本地文件;
- 经
POST /v1/artifacts/ingest摄取; - 经
GET /v1/artifacts/list?collection=<collection>列出; - 经
POST /v1/artifacts/delete删除; - 可选诊断搜索框走
POST /v1/tools/semantic-search; - 可选内容预览走
POST /v1/artifacts/content。
Collection 字段必须可配置的原因:有的 PrivateGPT 部署按需创建集合,有的部署经过网关、把每个 bearer token 限制在若干允许的集合内——若部署强制 allowed collections,摄取/列表/搜索必须使用允许的 collection id,否则 API 可能拒绝对象。Workbench v1 只有一个活动 collection,不暴露聊天级集合选择器。
上传行为:文件转 base64;artifact id 由文件名+时间戳或 UUID 派生;metadata 携带file_name。PRD 给出的摄取请求示例:
{ "artifact": "contract-2026-05-14", "collection": "default", "input": { "type": "file", "value": "<base64>" }, "metadata": { "file_name": "contract.pdf" } }8.2 文档参与聊天的请求形态
当某会话启用了 Documents,/v1/messages请求应启用语义搜索工具并把它限定到配置的文档集合:
{ "model": "default", "messages": [ { "role": "user", "content": "Find the property address in the documents. Answer just with the address, no extra text." } ], "tools": [ { "name": "semantic_search", "type": "semantic_search_v1" } ], "tool_context": [ { "type": "ingested_artifact", "context_filter": { "collection": "<configured-collection>", "artifacts": [] } } ] }artifacts为空数组表示搜索该集合内所有文档。buildChatBody()的对应实现(ui/index.html)正是这条规则的直接落地。
8.3 Databases:SQL 数据库工件
仅本地存储的字段集:id、name、connection_string、description、可选的逗号分隔schemas、ssl、enable_tables、enable_views、enable_functions、enable_procedures。在聊天中被选中时转换为tool_context工件:
{ "type": "sql_database", "connection_string": "...", "schemas": null, "ssl": false, "enable_tables": true, "enable_views": true, "enable_functions": true, "enable_procedures": true, "description": "Local sales database" }这与 OpenAPI 中的SqlDatabaseArtifact字段一一对应;实现侧在 ui/index.html 中,为每个被选中的数据库工件同时追加database_query(database_query_v1)工具规格。
8.4 Web:说明性质,凭据留在后端
Context > Web 区不收集web provider 名、API key 或额外 web 配置——这些属于 PrivateGPT 后端配置(见仓库根 settings.yaml)。OpenAPI 当前暴露POST /v1/tools/web-search与POST /v1/tools/web-fetch;Workbench 在此区展示静态说明文字,由聊天级 Tools 菜单决定web_search与web_extract是否进入该次聊天请求。PRD 还特别区分了两处命名:直连诊断端点叫/v1/tools/web-fetch,而/v1/messages中的聊天工具规格写作{ "name": "web_extract", "type": "web_extract_v1" }。
8.5 MCP:连接器配置
字段:id、name、server_config_json、可选allowed_tools列表。OpenAPI 的ChatBody支持mcp_servers字段;为避免过度设计未知的 MCP 变体,UI 初期允许原始 JSON 编辑(名称输入框 + JSON 文本域 + "Validate JSON" 按钮)。被选中的 MCP 配置以解析后的对象写入请求的mcp_servers数组(实现见 ui/index.html)。
8.6 Skills:绑定到活动集合的技能
字段:id、display_title、collection、latest_version、source、loading、readonly。操作端点(作用域限定在 Workbench 的单一活动集合):
GET /v1/skills?collection=<collection>列出技能;POST /v1/skills(multipart)创建;POST /v1/skills/{skill_id}/versions(multipart)创建新版本;DELETE /v1/skills/{skill_id}?collection=<collection>删除非只读技能。
构建聊天请求时,选中的技能表示为tool_context工件:
{ "type": "skill", "skill_filter": { "collection": "<configured-collection>", "skill_or_version_ids": ["<selected-skill-id>"] } }8.7 Custom Tools:Claude 风格工具 + 浏览器 JS 处理器
字段:id、name、description、input_schema_json、javascript_handler、test_input_json、last_test_result。工具定义形状(JSON Schema 描述输入):
{ "name": "currency_converter", "description": "Convert USD to EUR using a locally configured exchange rate.", "inputSchema": { "type": "object", "properties": { "amount": { "type": "number" } }, "required": ["amount"] } }处理器形状:
async function handle(input, context) { const rate = Number(context.localStorage.getItem("usd_eur_rate") || "0.92"); return { type: "text", text: `${input.amount} USD is approximately ${input.amount * rate} EUR.` }; }处理器执行上下文:
{ fetch: window.fetch.bind(window), localStorage: window.localStorage, privateGptBaseUrl: string, currentChatId: string, currentCollection: string, log: (message: string, data?: unknown) => void }v1 直接浏览器执行、不需要额外沙箱——因为代码是用户在本地浏览器里显式编写的(这也正是"Not for Production"披露中列出的风险之一)。自定义工具测试流程:解析测试输入 JSON → 执行处理器 → 展示结果或错误 → 若当前处于聊天上下文则追加 Debugger 事件,否则仅展示本地结果。executeCustomTool()(ui/index.html)按上述上下文对象注入依赖并记录custom_tool:execute_start调试事件。
九、Chat 屏:从消息输入到 ChatBody 组装
9.1 输入区控制
Composer 工具栏(textarea 下方)内的控制项:
- 模型选择器——自定义玻璃下拉,数据来自
GET /v1/models,显示当前模型名与动画 chevron,选中后更新state.selectedModel(实现为renderModelSelect(),ui/index.html,使用#modelSelectBtn+#modelDropdown两个元素,而非原生<select>); - 模型选择器旁的刷新模型按钮;
- 推理强度(reasoning effort)内置于模型下拉,而非独立 Thinking 按钮:下拉左侧是可搜索的模型列表,右侧是按能力感知的 effort 轨道(None / Low / Medium / High / Max / XHigh);
- 选中 effort 按会话存储,作为
thinking: { enabled: Boolean(effort), type: effort }发送;不支持的选项依据所选模型响应里的capabilities.effort元数据禁用; - Tools 按钮——打开按类别切换的菜单:Documents / Web / Databases / MCP / Skills / Custom Tools。
对 Databases、MCP、Skills、Custom Tools:把已配置项渲染为可选 chips/下拉,选择结果按会话存储。文本输入按Enter发送、Shift+Enter换行。
9.2 消息渲染规则
- 用户与助手消息分开渲染;文本块按 Markdown 渲染;
tool_use与 tool result 块渲染为折叠的 details 元素(块配对与渲染逻辑见blocksToHtml(),ui/index.html);- 内联
<citation ...></citation>标签绝不允许以文本形式渲染:必须替换为仅带引用序号的小圆形可点击标记;若原始引用标签使用 0 基index属性,显示index + 1;多个内联引用可显示同一编号; - 消息底部不渲染独立的引用列表;
- 点击引用标记打开可关闭的玻璃风格弹层,展示引用元数据与源文档摘录。摘录的提取规则:对 semantic-search 的
tool_resultpayload 解析 JSON 文本,用内联引用 id 匹配nodes[].id,取命中节点的content作为摘录,且匹配器要容忍括号差异(如4C40vs[4C40]); - 错误清晰展示;聊天中不显示原始响应块——原始请求/响应细节归 Debugger;
- 等待 PrivateGPT 时显示带"呼吸"动画的 PrivateGPT 圆形头像占位。
9.3 请求行为与基本请求体
请求行为约定:
- 使用
POST /v1/messages;由聊天消息+所选上下文/工具构建ChatBody; - 模型 id 取
/v1/models响应中的选中项,未加载时回落default; - 存在用户配置的 Settings system prompt 时优先使用;无 system prompt 且无技能指令时省略 system 文本;
- Documents 启用且 Settings > Use citations 开启时发送
system.citations.enabled: true——即使没有 prompt 文本,也可能需要顶层system对象; - 系统指令始终走顶层
system字段,保证在整个请求一致生效。
PRD 给出的基本请求体:
{ "model": "default", "messages": [ { "role": "user", "content": "Summarize my documents and cite sources." } ], "system": { "text": "You are a support agent. Reply with only a short ticket title.", "use_default_prompt": false, "citations": { "enabled": true } }, "tools": [], "tool_context": [], "mcp_servers": [], "stream": false, "max_tokens": 4096 }工具/上下文组装规则:
- Documents 启用 → 追加
semantic_search工具 + 作用域到全局文档集合的ingested_artifacttool context(artifacts: []表示全集合); - 选中 Databases → 选中的 SQL 数据库工件进
tool_context; - 选中 MCP → 选中的 MCP server 配置进
mcp_servers; - 选中 Custom Tools → 选中的自定义工具定义进
tools; - 选中 Skills → 按当前后端约定附加技能 prompt/配置(实现中即
skills_v1工具 +skilltool_context 工件)。
从源码看,当前实现(ui/index.html)在 PRD 骨架之上已扩展到更多内建能力:表格分析(tabular_analysis_v1)、代码执行(code_execution_v1,且启用时把chat.id作为ChatBody.container以复用同一沙箱会话)、Web(web_search_v1+web_fetch_v1),并以stream: true发起流式请求——PRD 中"流式/异步端点可推迟"的取舍在实现中已被部分推进。
9.4 自定义工具闭环(Custom Tool Loop)
当助手响应包含某个自定义浏览器工具的tool_use块时:
- 按名称匹配自定义工具;
- 用
toolUse.input执行 JavaScript 处理器; - 把工具结果追加到同一条可见的助手消息气泡(不另起消息);
- 追加
tool_result后再发一次POST /v1/messages(沿用 API 预期的内容块形状); - 最终助手答案流式渲染回同一气泡;
- 循环中的所有 API 调用都出现在 API Debugger。
整个执行周期——初始响应、工具结果、后续回答——在聊天中呈现为单一合并的助手气泡;承载 tool 角色的隐藏消息只存在于 API 历史中,从不渲染到聊天 UI。处理器失败时:错误内联显示在气泡中,请求/响应错误记入 Debugger,并视情况发送is_error: true的 tool result。
十、API Debugger:会话级、实时、临时
设计约束三条:会话级、实时、临时——Debugger 事件绝不持久化,页面重载后为空。界面上方有一个小的非侵入 callout,说明它是当前会话的实时 trace、刷新即清空。
目的:教会开发者聊天交互如何映射为 API 调用;展示请求/响应载荷与错误;在有用时展示脱敏后的请求头。布局为"时间线列表 | 事件详情面板"。事件模型:
- 每次 API 调用对应一个时间线条目,可先以 pending 出现,随后就地更新为响应或错误;不得为同一调用显示分立的 request 与 response 条目;
- 每个事件包含:timestamp、method、URL、脱敏请求头、status、duration、请求 JSON、响应 JSON 或错误。
密钥红线:Debugger 中永不显示机密,Authorization、token 类头、API key 与 cookies 必须脱敏——实现为 ui/index.html 的redactHeaders(),在事件落缓冲前对请求头做掩码。Debugger 应覆盖当前页面生命周期内来自 Chat、Context、Settings 的全部 API 事件。
10.1 API Client 封装
PRD 要求实现一个极小的客户端封装:
async function apiFetch(path, options, debugMeta)职责:拼接privateGptBaseUrl前缀;设置 JSON 头;按配置的用户名/密码构建Authorization: Basic <base64(username:password)>;测量耗时;解析 JSON/文本响应;把请求/响应/错误记入会话级 Debugger 缓冲;抛出有用的错误。
从源码看(ui/index.html),实际apiFetch还实现了 PRD 之外的健壮性细节:GET 请求附加Cache-Control: no-cache与Pragma;对 5xx 与网络错误做最多 2 次重试,退避间隔600ms × 尝试次数,重试事件以Retry n/2标注在同一条调试条目上就地更新;4xx 则直接抛出并携带解析后的错误体(detail/error.detail.explanation/error.message逐级提取,见 ui/index.html)。此外实现中还提供了流式版apiStreamFetch()(ui/index.html),对应 PRD 中标记为"可推迟"的流式端点。
PRD 列出的客户端使用端点:
GET /v1/models POST /v1/messages POST /v1/messages/count_tokens (可选) POST /v1/messages/validate (可选) POST /v1/artifacts/ingest GET /v1/artifacts/list?collection=<collection> POST /v1/artifacts/delete POST /v1/artifacts/content (可选) POST /v1/tools/semantic-search POST /v1/tools/tabular-data-analysis (可选直连诊断) POST /v1/tools/database-query (可选直连诊断) POST /v1/tools/web-search (可选直连诊断) POST /v1/tools/web-fetch (可选直连诊断)流式/异步端点可推迟:/v1/messages/async、/v1/messages/async/{message_id}/stream(两者均已存在于当前 openapi.json 契约中,实现可在需要时直接启用)。
十一、UX 原则、MVP 验收标准与构建顺序
UX 原则:像实用的本地助手而非营销页;聊天是主表面;Context 解释助手能访问什么;Debugger 解释底层发生了什么;控制密度高但可读;避免大型装饰卡片与落地页 hero 区;朴素的工具型 UI;优先原生控件与简单 CSS;所有错误都可见且可操作。
MVP 验收标准(PRD 23 条,节选关键项):
- 用户可配置 API base URL;2. 可从 UI 配置可选 API key/bearer token;3. 可从
GET /v1/models加载模型并按会话选择;4. 可创建/重命名/删除/切换本地会话;5-6. 会话与每会话工具开关跨刷新持久化;7. 可向/v1/messages发送基础消息;8-9. 可上传摄取并列出文档;10. 可启用文档上下文;11. 文档启用的聊天请求确实追加semantic_search工具与限定到配置集合的ingested_artifacttool context;12. 可本地配置数据库工件;13. 可本地配置 MCP/Skills/自定义工具,且能看明白 web provider 凭据在 PrivateGPT 后端而非 Workbench;14. 可定义含 name/description/JSON schema/JS handler 的自定义工具;15-16. 聊天可把选中的自定义工具传给 API,并在助手发出匹配 tool call 时执行浏览器 JS 处理器;17-18. Debugger 实时展示当前浏览器会话的 API 事件且敏感头脱敏,刷新后消失;19. 不引入任何后端存储;20. 应用以静态文件运行;21. 实现以仓库内的相对 OpenAPI 文件为 API 契约,不硬编码与 schema 矛盾的 payload 假设;22. 侧边栏含 GitHub 仓库组件与 Not for Production 披露;23. Settings 含"清空本地数据"动作。
建议构建顺序:1) 静态布局(侧边栏、Context、Chat、Debugger);2)localStorage状态模型;3) API base URL 与模型加载;4) 聊天会话;5) 基础/v1/messages聊天;6) Debugger 事件记录器;7) 文档摄取/列表/删除;8) 聊天工具/上下文开关;9) Database/Web/MCP/Skills 配置表单;10) 自定义工具定义 UI;11) 浏览器 JS 处理器执行循环;12) 打磨错误、空态与刷新行为。
十二、如何验证与继续深入
- 检查
ui/文档与实现的对应关系:ui/docs/PRD.md(产品行为)、ui/docs/SOURCE_OF_TRUTH.md(权威路径与"读代码看不出的"关键实现备注)、ui/docs/STYLE_GUIDE.md(视觉规则)、ui/README.md(目录地图与工作规则); - 运行时实现只有一个文件:ui/index.html,其中的
apiFetch(#L6330)、buildChatBody(#L6973)、executeCustomTool(#L7091)、redactHeaders(#L7936)、syncHash/restoreFromHash(#L4551)是理解各章节行为的最短路径; - 全部请求/响应形状以 fern/openapi/openapi.json 为准,它同时驱动 fern/docs 中的 API 指南与 scripts/extract_openapi.py 的契约抽取流程;
- 按 ui/README.md 的说明,改动
ui/index.html后可用其提供的 node 一行脚本验证内联脚本可解析; - 后端侧的配置入口是仓库根目录的 settings.yaml 与 settings-test.yaml,其中 LLM Gateway(推理提供者)相关设置属于后端职责,与 Workbench UI 中可配置的连接项互不重叠。
适用前提与限制:Workbench 是明确标注"Not for Production"的本地演示器——localStorage不保存机密级数据、无访问控制、Debugger 刻意可见、自定义工具直接运行浏览器 JS;它只适用于本机试用 API、调试请求与探索本地 AI 工作流。本文描述的默认地址、端点集合与字段形状以当前仓库状态为准;契约随 fern/openapi/openapi.json 演化,实现细节(如流式请求、代码执行容器字段、推理强度轨道)也已在 PRD 初版示例之后持续扩展,请以源码现状为最终依据。
【免费下载链接】privateGPTComplete API layer for private AI applications on local models: RAG, skills, tools, MCP, text-to-sql, and more. Works with any OpenAI-compatible inference server.项目地址: https://gitcode.com/GitHub_Trending/pr/privateGPT
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考