1 这一阶段的背景

上一篇博客记录了 Agent 框架在 Renderer 侧的搭建过程——类型定义、Prompt 模板、LLM 客户端、工具注册、输出解析,基础设施在 P0 阶段已经完整建立。但随着工作推进,一个架构层面的问题需要正视:整个 Agent 执行层放在 Renderer 进程里,从安全性角度看是有问题的。

Renderer 进程本质上是浏览器沙箱环境,受 CSP 和 CORS 限制,直接向第三方 LLM API 发起请求并不稳定;更重要的是,API Key 这类敏感凭据不应当存在于 Renderer 的运行时里。P0 阶段为了尽快跑通功能链路,暂时在 Renderer 侧实现了完整的 LLM 调用逻辑,这笔技术债在这一阶段需要还掉。

这一阶段的核心工作,是把 Agent 执行层整体迁移至 Main 进程,同时引入 Vercel AI SDK 替换原有的手写 fetch 客户端,统一多 Provider 的接入方式。

2 本阶段完成工作

  • 在 Main 进程新建 src/main/agent/ 目录,实现 agentRuntime.tsgitTools.ts 两个核心模块
  • 注册 agent:runTaskagent:pingLlm 两条 IPC 通道,打通 Renderer 与 Main 进程之间的 Agent 调用链路
  • 将 Renderer 侧 agentRuntime.ts 改写为纯 IPC 转发层,删除不再需要的 llmClient.tstoolRegistry.tsgitTools.ts
  • 通过 contextBridge 在 Preload 层安全暴露 runAgentTaskpingLlmConfig 两个桥接方法
  • 引入 Vercel AI SDK(ai@ai-sdk/openai@ai-sdk/anthropic),替代原有手写 fetch 客户端
  • 排查并修复迁移过程中暴露的两个问题:连接测试机制不合理、OpenAI 兼容接口始终返回 404

3 迁移涉及的主要改动

迁移的核心思路是:把 LLM 调用和工具执行的职责收敛到 Main 进程,Renderer 侧只保留一个薄封装,负责把任务序列化后通过 IPC 发送过去,拿到 rawOutput 后再做解析。

Main 进程侧新增的两个文件:

agentRuntime.ts 是执行核心。它根据 LlmConfig.provider 判断使用 Anthropic 客户端还是 OpenAI 兼容客户端,创建对应的模型实例,通过 Vercel AI SDK 的 generateText 驱动 LLM 调用。多轮 tool call 由 maxSteps 参数控制迭代次数,30 秒超时通过 AbortController 实现。此外,pingLlmConfig 的连接检测逻辑也在这里重新实现,具体改动见下一节。

gitTools.ts 定义了 18 个供 Agent Tool Call 使用的 Git 工具,涵盖状态查询、diff 获取、暂存操作、提交与分支管理、合并冲突处理五类。工具参数结构用 Vercel AI SDK 的 jsonSchema() 声明,实际执行通过 SidecarManager 路由到 Go Sidecar 完成。工具集按需加载——getGitToolsForTask 函数根据任务类型过滤返回工具子集,不同场景只暴露对应的工具,避免每次 LLM 调用都携带全量定义。

Renderer 侧的改动:

原有的完整执行逻辑从 agentRuntime.ts 中全部移除,改写为 IPC 转发层。runAgent<T> 函数将任务序列化为 AgentRunRequest,通过 window.electronAPI.runAgentTask 发送至 Main 进程,返回的 rawOutput 再由调用方传入的 parseResult 函数负责解析。降级逻辑(runAgentWithFallback)保留,LLM 不可用或解析失败时仍走原有的模板降级路径。

4 迁移过程中的两个问题

迁移的结构改动本身并不复杂,但过程中遭遇了两个问题,这里分别记录。

4.1 连接测试机制的改造

原有的 pingLlmConfiggenerateText 做连通性检测——实际上是在向 LLM 发起一次真实请求,速度慢、消耗 token,网络抖动时也容易产生误报。迁移时把这个逻辑一并改掉:改为直接向各 Provider 的 GET /models 端点发起请求,只验证接口连通性和鉴权是否有效,不产生任何 token 消耗。

Anthropic 和 OpenAI 兼容接口的鉴权方式不同,分开处理:Anthropic 使用 x-api-key + anthropic-version: 2023-06-01 Header,OpenAI 兼容接口使用 Authorization: Bearer <key>。响应非 2xx 时从 JSON 错误体中提取 error.message,错误信息返回前做脱敏处理,用正则把 sk-xxx 格式的 API Key 替换掉。

4.2 OpenAI 兼容接口始终返回 404

接入 Vercel AI SDK 后,用 DeepSeek、通义千问等 OpenAI 兼容接口时,AI 生成提交信息功能始终走降级路径,控制台里是 HTTP 404,没有其他有效报错。

排查过程需要翻 SDK 的 changelog 才能定位根因。@ai-sdk/openai v3 引入了一个 Breaking Change:createOpenAI()(modelId) 现在默认创建 OpenAIResponsesLanguageModel,请求会被路由到 /v1/responses(OpenAI Responses API)。而 DeepSeek、通义千问等兼容接口只实现了 /v1/chat/completions/v1/responses 根本不存在,因此返回 404。

修复方式是把 client(config.modelName) 改为 client.chat(config.modelName),显式创建 OpenAIChatLanguageModel,强制走 Chat Completions 路径。改动只有一行,但定位到这里需要知道这个版本变更的存在。

这类问题有一个特点,比直接报错更难排查:功能表面上还在运行,只是静默地走了降级分支,没有任何异常日志提示根因在 SDK 层。依赖库升级后,默认行为的变更需要格外留意。

5 阶段小结

迁移完成后,Agent 的执行权限和安全边界在架构上清晰了:LLM 调用和 API Key 管理收敛在 Main 进程,Renderer 侧不再持有任何敏感凭据,也不直接与第三方 API 通信,符合 Electron 的安全模型预期。Vercel AI SDK 统一了多 Provider 的接入方式,后续扩展新的模型 Provider 不需要再手写 fetch 适配逻辑。

这次迁移也是 NLP Git 助手得以完整实现的前提——下一篇记录这个功能的具体实现过程。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐