掘金 人工智能 前天 10:17
Gemini CLI Web简化版
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了`packages/web-simple`的实现,这是一个基于Gemini CLI Core包构建的Web扩展,旨在将强大的命令行工具转化为易于使用的Web应用。该项目通过“薄Web层 + 重核心复用”的架构设计,复用现有核心逻辑,快速构建功能完整的Web AI助手。文章详细介绍了服务器初始化、实时流式响应处理、工具调用执行引擎等关键技术,并阐述了前端WebSocket客户端架构和双协议支持策略,以及智能错误处理和用户体验优化。项目展示了如何优雅地复用代码,快速构建功能丰富的Web应用。

💻 **核心架构设计**: web-simple采用“薄Web层 + 重核心复用”的架构,Web层负责协议转换,核心逻辑复用CLI的core包,确保Web版本与CLI版本AI能力一致,并易于维护。

⚙️ **服务器初始化与配置集成**: 通过复用 @google/gemini-cli-core 的 Config 类,Web应用获得与CLI相同的配置能力,并集成文件操作、Shell执行、Web搜索等工具,同时适配Web环境,实现自动执行。

💬 **实时流式响应处理**: Web版本支持实时流式响应,通过处理Content、Thought、ToolCallRequest等事件,并实时推送内容片段,实现打字机效果,让用户能够实时看到AI的思考过程。

🛠️ **工具调用执行引擎**: Web版本完全复用Gemini CLI的工具调用能力,支持工具透明执行、多轮对话以及错误恢复,使得Web应用能够执行各种工具,并基于执行结果继续对话。

Gemini CLI Web简化版:基于Core包的智能Web扩展架构详解

项目地址:github.com/lovelyqun/g…

前言

在AI应用开发领域,如何将强大的命令行工具转化为易用的Web应用是一个常见挑战。本文将深入分析 packages/web-simple 的实现,这是一个基于 Gemini CLI Core 包构建的Web扩展,展示了如何优雅地复用现有核心逻辑,快速构建功能完整的Web AI助手。

整体架构设计

核心设计理念

web-simple 采用了"薄Web层 + 重核心复用"的架构设计:

┌─────────────────────────────────────────┐│                前端层                    ││  ┌─────────────┐  ┌─────────────────┐   ││  │  HTML/CSS   │  │  WebSocket客户端 │   ││  └─────────────┘  └─────────────────┘   │└─────────────────────────────────────────┘                    │                    │ WebSocket/HTTP                    ▼┌─────────────────────────────────────────┐│              Express服务层               ││  ┌─────────────┐  ┌─────────────────┐   ││  │  REST API   │  │  WebSocket服务   │   ││  └─────────────┘  └─────────────────┘   │└─────────────────────────────────────────┘                    │                    │ 直接调用                    ▼┌─────────────────────────────────────────┐│          @google/gemini-cli-core        ││  ┌─────────────┐  ┌─────────────────┐   ││  │   Config    │  │  GeminiClient   │   ││  │ ToolRegistry│  │  工具执行引擎    │   ││  └─────────────┘  └─────────────────┘   │└─────────────────────────────────────────┘

这种设计的优势在于:

核心代码实现

1. 服务器初始化与配置集成

服务器启动时,最关键的步骤是初始化Gemini配置:

async function initializeGeminiConfig() {    try {        const cwdDir = process.env.CWD || process.cwd();                // 检查环境变量        if (!process.env.GEMINI_API_KEY) {            throw new Error('GEMINI_API_KEY 环境变量未设置');        }        // 创建会话ID        currentSessionId = generateSessionId();                // 创建文件发现服务        const fileService = new FileDiscoveryService(cwdDir);        // 核心配置参数        const configParams = {            sessionId: currentSessionId,            embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,            targetDir: cwdDir,            debugMode: process.env.DEBUG === 'true',            // 启用核心工具集合            coreTools: ['LSTool','ReadFileTool','ReadManyFilesTool',                        'WriteFileTool', 'EditTool', 'GrepTool','GlobTool',                        'ShellTool','WebFetchTool','WebSearchTool','MemoryTool'],            approvalMode: ApprovalMode.YOLO, // Web环境自动执行            fileDiscoveryService: fileService,            model: process.env.GEMINI_MODEL || DEFAULT_GEMINI_MODEL,            maxSessionTurns: 100,            noBrowser: true        };        // 创建并初始化配置实例        geminiConfig = new Config(configParams);        await geminiConfig.initialize();        await geminiConfig.refreshAuth(AuthType.USE_GEMINI);        return true;    } catch (error) {        console.error('❌ 初始化Gemini配置失败:', error.message);        return false;    }}

核心要点分析:

    直接复用Config类:通过 @google/gemini-cli-coreConfig 类,Web应用获得了与CLI完全相同的配置能力工具集成:通过 coreTools 参数启用文件操作、Shell执行、Web搜索等工具适配Web环境:设置 approvalMode: ApprovalMode.YOLO 实现自动执行,避免Web环境中的交互提示

2. 实时流式响应处理

Web版本的核心亮点是支持实时流式响应,让用户能看到AI的思考过程:

async function handleWebSocketChat(ws, connectionId, data) {    const { message } = data;        // 获取核心组件    const client = geminiConfig.getGeminiClient();    const toolRegistry = await geminiConfig.getToolRegistry();        try {        const messageContent = [{ text: message }];        const prompt_id = `ws-${connectionId.slice(0, 8)}-${Date.now()}`;                // 创建流式响应        const messageStream = client.sendMessageStream(            messageContent,            abortController.signal,            prompt_id        );        let fullResponse = '';        const pendingToolCalls = [];        // 实时处理事件流        for await (const event of messageStream) {            switch (event.type) {                case GeminiEventType.Content:                    fullResponse += event.value;                    // 实时推送内容片段                    ws.send(JSON.stringify({                        type: 'content',                        data: { content: event.value, isComplete: false }                    }));                    break;                case GeminiEventType.Thought:                    // 推送AI思考过程                    ws.send(JSON.stringify({                        type: 'thought',                        data: {                            subject: event.value.subject,                            description: event.value.description                        }                    }));                    break;                case GeminiEventType.ToolCallRequest:                    // 收集工具调用请求                    pendingToolCalls.push(event.value);                    ws.send(JSON.stringify({                        type: 'tool_call',                        data: { toolInfo: event.value, status: 'pending' }                    }));                    break;            }        }        // 处理工具调用        if (pendingToolCalls.length > 0) {            await executeToolCalls(pendingToolCalls, client, toolRegistry, ws, prompt_id);        }    } catch (error) {        // 错误处理        ws.send(JSON.stringify({            type: 'chat_error',            error: formatApiError(error.message)        }));    }}

技术创新点:

    完整事件流处理:支持 ContentThoughtToolCallRequest 等多种事件类型实时推送:每个内容片段都立即推送给前端,实现打字机效果透明工具调用:用户可以实时看到AI调用的工具和执行结果

3. 工具调用执行引擎

工具调用是Gemini CLI最强大的功能之一,Web版本完全复用了这一能力:

// 执行工具调用的核心逻辑for (const toolCallRequest of pendingToolCalls) {    try {        // 获取工具实例        const tool = toolRegistry.getTool(toolCallRequest.name);        if (!tool) {            throw new Error(`工具 "${toolCallRequest.name}" 未找到`);        }        // 执行工具        const toolResult = await tool.execute(            toolCallRequest.args,            abortController.signal        );        // 推送执行结果        ws.send(JSON.stringify({            type: 'tool_call',            data: {                toolInfo: toolCallRequest,                toolResult: toolResult,                status: 'completed'            }        }));        // 构建工具响应给AI        const toolResponsePart = {            functionResponse: {                name: toolCallRequest.name,                response: {                     output: typeof toolResult.llmContent === 'string'                         ? toolResult.llmContent                         : JSON.stringify(toolResult.llmContent)                 }            }        };        toolResponseParts.push(toolResponsePart);    } catch (toolError) {        // 工具执行错误处理        console.error(`工具调用失败: ${toolCallRequest.name}`, toolError);    }}// 将工具结果发送给AI继续对话if (toolResponseParts.length > 0) {    const continueStream = client.sendMessageStream(        toolResponseParts,        abortController.signal,        prompt_id    );        // 处理AI的后续响应    for await (const continueEvent of continueStream) {        if (continueEvent.type === GeminiEventType.Content) {            fullResponse += continueEvent.value;            ws.send(JSON.stringify({                type: 'content',                data: { content: continueEvent.value, isComplete: false }            }));        }    }}

关键特性:

    工具透明执行:Web环境下工具自动执行,无需用户确认多轮对话支持:工具执行完毕后,AI可以基于结果继续回复错误恢复:单个工具失败不影响整体对话流程

前端交互设计

WebSocket客户端架构

前端采用现代WebSocket架构,支持实时双向通信:

class GeminiWebSocketClient {    constructor() {        this.ws = null;        this.isConnected = false;        this.reconnectAttempts = 0;        this.maxReconnectAttempts = 5;    }        // 建立连接    connect() {        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';        const wsUrl = `${protocol}//${window.location.host}`;        this.ws = new WebSocket(wsUrl);                this.ws.onmessage = (event) => {            const data = JSON.parse(event.data);            this.processMessage(data);        };    }        // 处理服务器消息    processMessage(data) {        switch (data.type) {            case 'content':                this.handleContent(data.data);                break;            case 'thought':                this.showThinking(data.data.subject, data.data.description);                break;            case 'tool_call':                this.handleToolCall(data.data);                break;        }    }        // 实时内容更新    handleContent(data) {        let aiMessage = this.getCurrentAIMessage();        if (!aiMessage) {            aiMessage = this.addMessage('ai', '');            aiMessage.dataset.rawContent = '';        }                // 累积内容并格式化显示        aiMessage.dataset.rawContent += data.content;        const contentElement = aiMessage.querySelector('.message-text');        const formattedContent = this.formatMessageContent(aiMessage.dataset.rawContent);        contentElement.innerHTML = formattedContent;                // 添加打字机效果        contentElement.classList.add('typing-content');        this.scrollToBottom();    }}

实时格式化渲染

前端支持丰富的Markdown渲染和代码高亮:

formatMessageContent(content) {    // 1. 处理工具调用标记    content = this.formatToolCalls(content);        // 2. 处理代码块    content = this.formatCodeBlocks(content);        // 3. 处理行内代码    content = this.formatInlineCode(content);        // 4. 处理基本Markdown    content = this.formatBasicMarkdown(content);        return content;}formatCodeBlocks(content) {    return content.replace(/```(\w*)\n?([\s\S]*?)```/g, (match, language, code) => {        const lang = language || 'text';        const cleanCode = code.trim();        return `<div class="code-block">            <div class="code-header">                <span class="code-language">${lang}</span>                <button class="copy-btn" onclick="window.geminiClient.copyCode(this)">复制</button>            </div>            <pre class="code-content"><code class="language-${lang}">${this.escapeHtml(cleanCode)}</code></pre>        </div>`;    });}

双协议支持策略

WebSocket vs REST API

web-simple 巧妙地支持两种通信协议:

    WebSocket协议(推荐):

      实时流式响应支持AI思考过程展示双向通信,支持取消操作自动重连机制

    REST API协议(兼容性):

      传统HTTP请求响应模式适合简单集成场景返回完整响应结果
// REST API实现app.post('/api/chat', async (req, res) => {    const { message } = req.body;        // 复用相同的core逻辑    const client = geminiConfig.getGeminiClient();    const messageContent = [{ text: message }];        let fullResponse = '';    const messageStream = client.sendMessageStream(messageContent, signal, prompt_id);        // 收集完整响应    for await (const event of messageStream) {        if (event.type === GeminiEventType.Content) {            fullResponse += event.value;        }    }        // 返回完整结果    res.json({        response: fullResponse.trim(),        sessionId: currentSessionId    });});

错误处理与用户体验

智能错误处理

function formatApiError(error) {    // 结构化错误处理    if (error && typeof error === 'object' && 'message' in error) {        let text = `[API Error: ${error.message}]`;        if (error.status === 429) {            text += '\n可能的原因:API配额已用完或请求过于频繁,请稍后重试。';        }        return text;    }        // 解析JSON错误    const jsonStart = error.indexOf('{');    if (jsonStart !== -1) {        try {            const parsedError = JSON.parse(error.substring(jsonStart));            if (parsedError.error && parsedError.error.message) {                return `[API Error: ${parsedError.error.message}]`;            }        } catch (e) {            // 忽略解析错误        }    }        return `[API Error: ${error}]`;}

连接管理

// 心跳检测机制setInterval(() => {    wss.clients.forEach((ws) => {        const connection = [...connections.values()].find(conn => conn.ws === ws);        if (connection) {            if (!connection.isAlive) {                ws.terminate();                connections.delete(connection.connectionId);                return;            }            connection.isAlive = false;            ws.ping();        }    });}, 30000);

配置

环境配置

# 必需环境变量GEMINI_API_KEY=your_gemini_api_key# 可选配置GEMINI_MODEL=gemini-proDEBUG=trueCWD=/path/to/working/directoryPORT=3000

最后

    最大化复用现有代码:通过直接集成 @google/gemini-cli-core,Web版本获得了与CLI相同的强大功能优雅的协议转换:将命令行交互转换为Web友好的实时流式体验现代Web技术栈:结合WebSocket、Express.js等技术提供流畅的用户体验渐进式增强:同时支持WebSocket和REST API,适应不同使用场景通过薄Web层和重核心复用的策略,开发者可以快速将命令行AI工具转化为功能丰富的Web应用。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Gemini CLI Web扩展 架构设计 WebSocket 人工智能
相关文章