IntelliGit 项目个人博客(5)Agent 框架
1 这一阶段的背景
队友在前几周完成了前端核心视图的实现——Changes View、History View、仓库管理、布局系统,Go Sidecar 后端的 branch / commit / diff / merge / remote / staging 等操作也已全部到位。
需求文档里定义的智能化特性——AI 辅助提交、冲突智能管控、自然语言 Git 操作——在这个阶段还未完成。
这一阶段我的工作是完成项目规划文档里定义的 P0: Agent 框架与配置集成,为后续三个 P1 智能工作流(智能提交、冲突管控、自然语言助手)搭建可复用的底层基础。
2 本阶段完成工作
- 在
src/renderer/src/agent/下建立完整 Agent 基础层,覆盖 LLM 客户端、工具注册、Prompt 模板、安全策略、输出解析、降级处理、运行时核心七个模块 - 扩展全局配置类型,支持多 LLM Provider 配置与持久化
- 实现 GlobalSettingsPanel 完整配置界面,替换原有占位 UI
- 修复配置持久化逻辑中的覆盖问题
- 将 StatusBar 的 AI 状态指示灯改为动态状态显示
3 架构设计:为什么要单独建一个 Agent 层
在动手之前,有一个问题需要先想清楚:AI 能力以什么形式接入现有代码?
最直接的做法是在需要 AI 的地方直接调用 LLM API,比如在提交面板的"AI 生成"按钮里写一段 fetch 调用,拿到结果填入输入框。这样实现最快,但有几个明显的问题:三个 P1 工作流都需要调用 LLM,每处各自实现意味着错误处理、降级逻辑、安全校验都要重复写;LLM 的输出是非结构化文本,每个调用方都要自己做解析,容错处理很容易遗漏;Provider 切换(从 OpenAI 换到 DeepSeek)需要改动多处代码。
所以我们决定先建一个独立的 Agent 层,把 LLM 调用、工具注册、Prompt 管理、安全策略、输出解析、降级处理统一封装,P1 工作流只需要描述任务,不需要关心底层细节。
最终 agent/ 目录的结构如下:
agent/
types.ts # 核心类型定义
llmClient.ts # LLM HTTP 客户端
toolRegistry.ts # Tool 注册与调用
prompts/ # Prompt 模板管理
safety.ts # 风险分级策略
outputParser.ts # 结构化输出解析
fallback.ts # 降级处理
agentRuntime.ts # Runtime 核心
index.ts # 统一导出
每个文件职责单一,P1 工作流接入时只需要调用 agentRuntime.ts 暴露的接口,内部细节对上层透明。
4 LLM 客户端:不引入 SDK,直接用 fetch 实现
LLM 客户端(llmClient.ts)的设计原则是尽量轻,目前没有引入第三方 SDK,直接用 fetch 实现,支持两套协议:
OpenAI 兼容协议,覆盖 OpenAI 官方、DeepSeek、通义千问、以及本地部署的模型(只要兼容 /v1/chat/completions 接口格式):
// POST /v1/chat/completions
// Authorization: Bearer {apiKey}
Anthropic 协议,对应 Claude 系列模型:
// POST /v1/messages
// x-api-key: {apiKey}
// anthropic-version: 2023-06-01
两套协议实现为两个独立的 Client 类,对外暴露统一接口:
export interface LlmClient {
chat(messages: AgentMessage[], tools?: ToolDefinition[]): Promise<LlmResponse>
ping(): Promise<void>
}
export function createLlmClient(config: LlmConfig): LlmClient {
if (config.provider === 'anthropic') return new AnthropicClient(config)
return new OpenAICompatibleClient(config)
}
用工厂函数统一创建,上层代码不感知 Provider 差异。ping() 方法用于连接检测,发送最小请求验证 API Key 有效性,结果写入 llmConfigStore,在 StatusBar 里实时反映。
配置类型定义在 src/shared/types/sidecar.ts 中,作为前后端共享的类型契约:
export type LlmProvider = 'openai' | 'anthropic'
export interface LlmConfig {
provider: LlmProvider
apiKey: string
baseUrl?: string // OpenAI 兼容模式下可覆盖,用于接入国产模型
modelName: string
temperature?: number
maxTokens?: number
}
baseUrl 字段的设计值得说一下。OpenAI 兼容协议现在已经是国内大模型的事实标准,DeepSeek、通义千问都支持。通过允许覆盖 baseUrl,用户可以在不改任何代码的情况下切换到这些模型,只需要在设置界面填入对应的 API 地址即可。
5 工具注册系统
Tool Call 是让 LLM 与应用功能交互的标准机制。Agent 层预声明了 13 个 Git 工具定义,P1 工作流在接入时注入具体的执行逻辑:
export const GIT_TOOL_NAMES = {
GET_STATUS: 'git.getStatus',
GET_DIFF: 'git.getDiff',
GET_STAGED_DIFF: 'git.getStagedDiff',
STAGE_FILE: 'git.stageFile',
STAGE_ALL: 'git.stageAll',
CREATE_COMMIT: 'git.createCommit',
GET_CONFLICT_FILES: 'git.getConflictFiles',
GET_TRIPLET_CONTENT: 'git.getTripletContent',
APPLY_PATCH: 'git.applyPatch',
CONTINUE_MERGE: 'git.continueMerge',
ABORT_MERGE: 'git.abortMerge',
// ...
}
P0 阶段只声明定义,不注册实现——因为实现依赖 Sidecar IPC 调用,属于各 P1 工作流自己的职责。P1 接入时只需要两步:
// 第一步:注册工具实现
toolRegistry.register({
definition: GIT_TOOL_DEFINITIONS['git.stageFile'],
execute: async ({ filePath }) => { /* 调用 sidecar */ }
})
// 第二步:调用 Agent
const result = await runAgentWithFallback(
getCurrentLlmConfig(),
{
taskType: 'commit.generateMessage',
systemPrompt: COMMIT_SYSTEM_PROMPT,
userMessage: renderCommitMessagePrompt(diff),
tools: ['git.getStagedDiff']
},
(raw) => parseStructured(raw, COMMIT_MESSAGE_SCHEMA)
)
这种"声明在 P0,实现在 P1"的分层设计,让 Agent 框架本身不依赖具体的 Git 操作实现,可以独立测试和维护。
6 处理 LLM 输出的不确定性
LLM 的输出是自然语言文本,即便在 Prompt 里明确要求返回 JSON,模型有时仍会在 JSON 前后附加说明文字,或者把 JSON 包在 markdown 代码块里。outputParser.ts 实现了三层提取逻辑:
export function extractJson(text: string): unknown {
// 第一层:提取 ```json ... ``` 代码块内容
// 第二层:提取第一个完整的 { ... } 块
// 第三层:整体尝试 JSON.parse
}
三层兜底能覆盖绝大多数模型的输出格式差异。在此基础上,针对三个 P1 工作流预置了五个 Schema(CommitMessage / CommitGroups / ConflictRisk / ConflictResolve / NlIntent),P1 接入时直接用 parseStructured(raw, SCHEMA) 验证并转换输出,不需要各自处理格式问题。
7 心得体会
这次工作和之前几周有明显不同——之前主要是理解已有代码、跑通通信链路,这次是在相对空白的地方从零建立一套新的基础设施。
设计 Agent 层的过程中,对"接口先于实现"这件事有更具体的体会。Tool 注册系统的工具定义和执行实现分开,Output Parser 的 Schema 和解析逻辑分开,Fallback 的 taskType 和降级策略分开——这些分离看起来在 P0 阶段没有立竿见影的收益,但它们决定了 P1 工作流能否真正独立推进,而不是每个人都在改同一层代码。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)