1. 项目概述当本地大模型遇上代码编辑器最近在折腾一个挺有意思的事儿怎么让一个跑在我自己电脑上的开源大语言模型能在 VS Code 里像 OpenAI 的 Codex 那样不仅能理解代码还能调用外部的工具和函数。听起来像是把两个不同世界的接口硬生生给“翻译”通了。这背后的核心需求其实很明确我不想把代码片段、项目结构这些可能有敏感信息的东西上传到云端 API但又希望保留类似 GitHub Copilot 那种“智能感知智能执行”的体验比如让模型根据我的自然语言描述自动去查询数据库、调用某个本地脚本或者格式化一段代码。这个项目的本质是解决两个“不兼容”的 API 之间的通信问题。一边是本地部署的大模型它通常通过类似 OpenAI 格式的 API但往往是简化版或变种提供文本补全或对话能力另一边是 VS Code 的扩展开发接口以及我们期望模型能调用的各种“工具”Tool—— 这些工具可能是命令行程序、HTTP 服务、Python 函数或者任何能通过代码触发的操作。它们之间的协议、数据格式和调用方式往往天差地别。我的工作就是在这两者之间充当一个“协议转换器”或“适配层”让模型发出的“我想做XXX”的指令能被正确解析并转化为对具体工具的安全调用再把工具执行的结果翻译成模型能理解的格式反馈回去形成一个闭环。这不仅仅是技术上的缝合更是一种对现有工作流的深度改造。它意味着开发者可以在完全离线的、安全可控的环境下获得一部分云端智能编码助手的核心能力尤其是“行动力”。这对于处理内部项目、涉密代码或者单纯就是网络环境不佳的场景价值巨大。接下来我会详细拆解我是如何设计这个适配层处理其中的关键难点并把整个系统跑起来的。2. 核心架构设计与思路拆解要让本地模型在 Code 环境里调用工具不能蛮干得先理清一个清晰的架构。整个系统可以看作由几个核心模块组成模型接口层、意图解析与路由层、工具执行层以及一个负责协调的总线或编排器。我的设计思路是尽可能让各层解耦这样无论是更换模型、增加新工具还是适配不同的编辑器都会更灵活。2.1 模型接口层的标准化封装本地部署的模型五花八门有用 llama.cpp 的有用 text-generation-webui 的也有直接跑 Hugging Face Transformers 脚本的。它们的 API 差异很大。第一步我需要为我的系统定义一个统一的内部模型调用接口。我参考了 OpenAI ChatCompletion 的格式因为它结构清晰广泛支持。我的封装器Wrapper需要做以下几件事协议转换无论底层模型提供的是 HTTP API、gRPC 还是进程间通信都将其封装成统一的函数调用例如generate_chat_completion(messages, temperature, max_tokens)。提示词Prompt模板管理这是关键。要让模型学会调用工具必须在发送给模型的提示词中清晰地定义工具的描述、调用格式和期望的输出格式。我设计了一个模板系统将工具的名称、描述、参数JSON Schema格式动态注入到一个基础提示词中。这个基础提示词会明确告诉模型“你是一个助手可以调用以下工具。当你需要调用工具时请严格按照{“action”: “tool_name”, “args”: {...}}的 JSON 格式回复。”上下文管理模型需要记住对话历史和之前的工具调用结果。封装器需要维护一个会话上下文将用户消息、模型回复、工具执行结果按顺序组织成 message 列表通常包含role为user,assistant, 和system的消息。注意不同的本地模型对提示词格式的敏感度差异极大。有些基于 LLaMA 的模型对[INST]、SYS这类标记有要求。我的封装器需要根据连接的模型类型动态切换提示词模板这是实现兼容性的第一个挑战。2.2 工具Tools的抽象与注册“工具”在这里是一个抽象概念。它可以是一个执行 shell 命令的函数一个发送 HTTP 请求的客户端一个操作本地数据库的模块甚至是另一个 AI 服务。我对工具进行了统一抽象每个工具必须提供名称name唯一标识符。描述description用自然语言清晰描述工具的功能这部分会直接给模型看所以描述质量直接影响模型是否能用对工具。参数模式parameters一个符合 JSON Schema 的对象定义工具需要的参数名、类型、是否必需、描述等。这为模型提供了调用时的“参数清单”。执行函数function实际的调用逻辑。我建立了一个工具注册中心Registry。系统启动时所有可用工具都向这里注册。当模型返回一个工具调用请求时路由层就能根据名称从这里找到对应的工具并执行。例如我注册了一个“执行本地命令”的工具它的参数模式定义了command字符串类型必需和timeout数字类型可选两个字段。2.3 意图解析与安全路由这是系统的“大脑”。模型输出的是一段文本我需要从中精确地解析出它是否想调用工具以及调用哪个工具、参数是什么。由于我在提示词中严格要求模型以特定 JSON 格式回复所以解析器首先会尝试将模型的回复解析为 JSON。格式验证检查 JSON 是否包含action和args字段。action值必须在已注册的工具列表中。参数校验与补全根据工具注册时提供的parametersJSON Schema对args进行校验。例如检查必需参数是否存在参数类型是否匹配字符串、数字、布尔值等。这里我引入了 JSON Schema 验证库如 Python 的jsonschema它能自动完成复杂的校验并可以提供清晰的错误信息。安全沙箱可选但重要对于执行命令、访问文件系统这类高风险工具直接执行是危险的。我设计了一个简单的安全层对于命令执行工具我维护了一个“允许列表”allowlist只允许执行git status,python -m pytest,find . -name “*.py”等预设的安全命令。任何不在列表中的命令都会被拦截并返回错误。更复杂的方案可以考虑使用 Docker 容器或子进程资源限制。解析并校验通过后请求被路由到对应的工具执行函数同时附上校验过的参数。2.4 执行反馈与对话循环工具执行完毕后会产生一个结果成功时的输出或失败时的错误信息。这个结果不能直接扔回给模型需要格式化。我将其格式化为一个简单的文本描述例如“工具[工具名]执行成功输出为...” 或 “工具[工具名]执行失败原因...”。然后这个格式化后的结果连同最初的用户请求、模型的工具调用请求一起被追加到对话上下文中形成一条新的user消息内容可以是“这是工具执行的结果xxx”再次发送给模型。模型基于这个包含了工具执行结果的完整上下文生成下一步的回复可能是解读结果也可能是发起下一个工具调用。这样就形成了一个“用户输入 - 模型思考可能调用工具- 工具执行 - 结果反馈 - 模型继续思考”的循环。3. 关键技术实现细节与“翻译”逻辑架构清楚了接下来就是具体的实现“翻译”过程。这里的“翻译”主要体现在两个层面一是将模型的自然语言/结构化输出“翻译”成工具调用指令二是将不同本地模型 API “翻译”成系统内部的统一格式。3.1 提示词工程教会模型使用工具这是项目成败的关键。你不能指望一个未经训练的模型天生会按你的格式调用工具。你需要通过精心设计的提示词System Prompt 和 Few-shot Examples来“教”它。System Prompt 示例你是一个高效的编程助手除了回答问题你还可以调用一些工具来帮助你完成任务。你可以使用的工具如下 {tools_description} 当你决定调用一个工具时你必须严格按照以下 JSON 格式回复且只回复这个 JSON 对象不要有任何其他解释 { action: tool_name, args: { arg1: value1, arg2: 123 } } 如果用户的问题不需要调用工具或者没有合适的工具请直接给出你的回答。这里的{tools_description}会在运行时被替换成所有注册工具的格式化描述例如工具名:execute_shell描述: 在安全限制下执行一个 shell 命令。可用于查看文件列表、运行版本控制命令或简单的脚本。参数:command(字符串, 必需): 要执行的命令。Few-shot Examples少样本示例仅有系统提示还不够模型可能不理解具体场景。我在对话历史初始化时插入了几组示例用户“当前目录下有哪些Python文件”助手{action: execute_shell, args: {command: find . -name \*.py\ -type f | head -20}}系统模拟工具返回用户“工具执行成功输出./main.py\n./utils.py\n...”助手“当前目录下的Python文件有main.py, utils.py, ...”通过3-5组这样的示例模型能快速掌握“何时调用”以及“如何格式化调用”。我实测发现对于 7B 参数以上的模型如 Mistral、Llama 2/3这种引导效果非常显著。3.2 统一适配层对接五花八门的本地模型 API我的电脑上跑的是通过ollama服务的codellama:7b模型。它提供了类 OpenAI 的/api/chat端点这算是最友好的一种。但我也测试过直接使用transformers库加载模型这就需要不同的适配。对于 HTTP API 型如 Ollama, text-generation-webui我创建一个HTTPModelClient类。它接收基础URL如http://localhost:11434然后将内部的统一请求格式消息列表、参数转换为对应服务所需的 JSON 负载。例如Ollama 需要model,messages,stream等字段而options里放temperature。适配器就是一堆字段映射和格式调整的逻辑。对于直接库调用型如 Transformers我创建一个DirectModelClient类。它直接与加载的模型和分词器交互。这里的挑战是对话格式的处理。我需要手动将消息列表拼接成模型训练时所使用的提示模板例如 LLaMA 的 ChatML 格式或 Alpaca 格式然后调用model.generate()。输出结果后还需要从生成的文本中剥离掉提示部分提取出助手的回复。这个过程更底层但延迟可能更低。关键技巧超时与重试网络或本地推理的不稳定性必须考虑。我在所有外部调用无论是 HTTP 还是本地推理上都设置了超时如 30 秒和简单的重试逻辑如最多重试 2 次。对于 HTTP 调用还要处理连接错误、服务器无响应等异常确保系统整体鲁棒。3.3 VS Code 扩展集成打造无缝体验最终目的是在 VS Code 里用。我开发了一个简单的 VS Code 扩展它不包含核心的模型和工具逻辑而是作为一个“前端”或“客户端”。通信方式扩展通过标准输出/输入stdin/stdout或者一个本地 HTTP 服务器与后端的“模型-工具适配服务”通信。我选择了 HTTP 服务器因为扩展可以用fetchAPI 轻松调用后端服务也可以用任何语言编写我用的 Python。触发机制我设置了两种触发方式命令面板注册一个 VS Code 命令比如本地助手.执行任务用户选中一段描述或直接在输入框输入然后触发。编辑器上下文菜单在选中文本的右键菜单中添加一个选项如“让本地助手处理”。状态反馈调用后端服务是异步的。我在 VS Code 底部状态栏显示一个旋转图标并在输出通道Output Channel中实时显示模型思考和工具调用的日志让用户知道发生了什么。结果展示工具执行的结果如命令输出可以直接显示在输出面板。如果模型生成了代码或修改建议我会以 diff 视图或建议代码片段的形式插入到编辑器中用户可以选择接受或拒绝。这个扩展本身逻辑不复杂核心是与后端服务的 API 约定。我定义了一个简单的/chat端点接收{message: 用户输入}返回一个流式响应或一次性响应包含模型和工具交互的整个过程记录。4. 实操搭建从零到一的步骤记录理论说再多不如动手搭一遍。以下是我在 macOS/Linux 环境下基于 Python 后端和 VS Code 扩展前端的搭建流程。你可以跟着一步步来。4.1 后端服务搭建Python首先我们搭建核心的“翻译”与执行后端。步骤1创建项目与环境mkdir local-ai-code-assistant cd local-ai-code-assistant python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install fastapi uvicorn pydantic jsonschema requests # 如果你用 Ollama确保已安装并运行ollama run codellama:7b步骤2定义核心数据模型Pydantic在schemas.py中定义请求/响应和工具的结构。from pydantic import BaseModel from typing import List, Dict, Any, Optional class ChatMessage(BaseModel): role: str # user, assistant, system content: str class ChatRequest(BaseModel): messages: List[ChatMessage] stream: bool False class ToolCall(BaseModel): action: str args: Dict[str, Any] class ToolDefinition(BaseModel): name: str description: str parameters: Dict[str, Any] # JSON Schema步骤3实现工具注册与执行中心在tool_registry.py中import subprocess import json from typing import Callable, Dict class ToolRegistry: def __init__(self): self._tools: Dict[str, dict] {} def register(self, name: str, description: str, parameters: dict, func: Callable): self._tools[name] { description: description, parameters: parameters, function: func } def get_tool(self, name: str): return self._tools.get(name) def list_tools(self): return [{name: k, description: v[description]} for k, v in self._tools.items()] # 实例化全局注册中心 registry ToolRegistry() # 注册一个示例工具安全执行 shell 命令 ALLOWED_COMMANDS [ls, find, git status, pwd, python --version] def safe_shell_execute(command: str, timeout: int 10): if command.strip() not in ALLOWED_COMMANDS: return f错误命令 {command} 不在允许列表中。 try: result subprocess.run( command, shellTrue, capture_outputTrue, textTrue, timeouttimeout ) if result.returncode 0: return result.stdout else: return f命令执行失败 (返回码 {result.returncode}): {result.stderr} except subprocess.TimeoutExpired: return 错误命令执行超时。 except Exception as e: return f执行出错: {str(e)} # 注册工具 registry.register( nameexecute_shell, description在安全限制下执行一个 shell 命令。可用于查看文件列表、运行版本控制命令或简单的脚本。, parameters{ type: object, properties: { command: {type: string, description: 要执行的命令}, timeout: {type: integer, description: 超时时间秒, default: 10} }, required: [command] }, funcsafe_shell_execute )步骤4实现模型客户端适配器在model_client.py中以 Ollama 为例import requests import json class OllamaClient: def __init__(self, base_urlhttp://localhost:11434, modelcodellama:7b): self.base_url base_url self.model model self.chat_url f{base_url}/api/chat def generate(self, messages, temperature0.2, max_tokens500): 将统一的消息格式转换为 Ollama 请求 payload { model: self.model, messages: [{role: m.role, content: m.content} for m in messages], options: {temperature: temperature, num_predict: max_tokens}, stream: False } try: resp requests.post(self.chat_url, jsonpayload, timeout60) resp.raise_for_status() data resp.json() return data[message][content].strip() except requests.exceptions.RequestException as e: raise Exception(f调用 Ollama API 失败: {e})步骤5构建提示词组装与流程引擎这是最核心的orchestrator.pyimport json import jsonschema from schemas import ChatMessage from tool_registry import registry from model_client import OllamaClient class Orchestrator: def __init__(self, model_client): self.model_client model_client self.system_prompt self._build_system_prompt() def _build_system_prompt(self): tools_desc [] for tool_info in registry.list_tools(): # 将参数 schema 转换为易于阅读的描述 params_desc json.dumps(tool_info.get(parameters, {}), indent2) tools_desc.append(f- **工具名**: {tool_info[name]}\n - **描述**: {tool_info[description]}\n - **参数**: \njson\n{params_desc}\n) tools_text \n\n.join(tools_desc) prompt f你是一个高效的编程助手除了回答问题你还可以调用一些工具来帮助你完成任务。你可以使用的工具如下 {tools_text} 当你决定调用一个工具时你必须严格按照以下 JSON 格式回复且只回复这个 JSON 对象不要有任何其他解释 {{ action: tool_name, args: {{ arg1: value1, arg2: 123 }} }} 如果用户的问题不需要调用工具或者没有合适的工具请直接给出你的回答。 return prompt def process_user_query(self, user_input: str, conversation_history: list None): if conversation_history is None: conversation_history [] # 1. 构建本次对话的消息列表 messages [ChatMessage(rolesystem, contentself.system_prompt)] messages.extend(conversation_history) messages.append(ChatMessage(roleuser, contentuser_input)) max_iterations 5 # 防止无限循环 for i in range(max_iterations): # 2. 调用模型 model_response self.model_client.generate(messages) # 3. 尝试解析为工具调用 tool_call self._parse_tool_call(model_response) if tool_call: action tool_call.action args tool_call.args # 4. 查找并验证工具 tool_info registry.get_tool(action) if not tool_info: result f错误未知工具 {action}。 else: # 参数校验 try: jsonschema.validate(instanceargs, schematool_info[parameters]) except jsonschema.ValidationError as e: result f参数校验失败: {e.message} else: # 5. 执行工具 result tool_info[function](**args) # 6. 将工具结果作为新消息加入历史 result_msg f工具 {action} 执行完毕。结果{result} messages.append(ChatMessage(roleuser, contentresult_msg)) # 继续循环让模型基于结果进行下一步 else: # 模型没有调用工具直接返回回复 return model_response, messages [ChatMessage(roleassistant, contentmodel_response)] return 达到最大交互次数可能陷入循环。, messages def _parse_tool_call(self, text: str): 尝试从文本中解析出 JSON 格式的工具调用 text text.strip() if text.startswith({) and text.endswith(}): try: data json.loads(text) if action in data and args in data: from schemas import ToolCall return ToolCall(**data) except json.JSONDecodeError: pass return None步骤6创建 FastAPI 主服务在main.py中from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from schemas import ChatRequest from orchestrator import Orchestrator from model_client import OllamaClient import uvicorn app FastAPI(title本地AI编码助手后端) app.add_middleware(CORSMiddleware, allow_origins[*], allow_methods[*], allow_headers[*]) # 初始化 model_client OllamaClient() orchestrator Orchestrator(model_client) app.post(/chat) async def chat_endpoint(request: ChatRequest): try: # 这里简化处理取最后一条用户消息 last_user_msg next((m for m in reversed(request.messages) if m.role user), None) if not last_user_msg: raise HTTPException(status_code400, detail未找到用户消息) final_response, updated_history orchestrator.process_user_query( last_user_msg.content, request.messages ) return {response: final_response, history: [msg.dict() for msg in updated_history]} except Exception as e: raise HTTPException(status_code500, detailstr(e)) if __name__ __main__: uvicorn.run(app, host0.0.0.0, port8000)现在运行python main.py你的后端服务就在http://localhost:8000启动了。4.2 VS Code 扩展开发前端接下来创建一个简单的 VS Code 扩展与后端对话。步骤1用 Yeoman 生成扩展脚手架npm install -g yo generator-code yo code # 选择 “New Extension (TypeScript)”输入名称 local-ai-assistant其余默认。 cd local-ai-assistant步骤2修改src/extension.ts核心是添加一个命令调用我们的后端 API。import * as vscode from vscode; export function activate(context: vscode.ExtensionContext) { console.log(本地AI助手扩展已激活); // 注册命令 let disposable vscode.commands.registerCommand(local-ai-assistant.executeTask, async () { // 获取用户输入 const userInput await vscode.window.showInputBox({ placeHolder: 请输入你的需求例如“列出当前项目下的所有Python文件”, prompt: 本地AI助手 }); if (!userInput) { return; } // 创建输出通道显示日志 const outputChannel vscode.window.createOutputChannel(本地AI助手); outputChannel.show(); outputChannel.appendLine([用户] ${userInput}); // 显示进度指示 vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: 本地AI助手思考中..., cancellable: false }, async (progress) { try { // 调用后端服务 const response await fetch(http://localhost:8000/chat, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ messages: [{ role: user, content: userInput }], stream: false }) }); if (!response.ok) { throw new Error(HTTP error! status: ${response.status}); } const data await response.json(); outputChannel.appendLine([助手] ${data.response}); // 简单处理如果响应是纯文本显示信息框如果包含特定格式可以进一步解析。 // 例如如果响应是代码可以插入编辑器。 const editor vscode.window.activeTextEditor; if (editor data.response.includes()) { // 简单提取代码块这里逻辑可增强 const codeMatch data.response.match(/[\w]*\n([\s\S]*?)\n/); if (codeMatch) { const code codeMatch[1]; editor.edit(editBuilder { editBuilder.insert(editor.selection.active, code); }); vscode.window.showInformationMessage(代码已插入编辑器。); } else { vscode.window.showInformationMessage(data.response); } } else { vscode.window.showInformationMessage(data.response); } } catch (error: any) { outputChannel.appendLine([错误] ${error.message}); vscode.window.showErrorMessage(请求失败: ${error.message}); } }); }); context.subscriptions.push(disposable); } export function deactivate() {}步骤3修改package.json注册命令和菜单在package.json的contributes部分添加contributes: { commands: [{ command: local-ai-assistant.executeTask, title: 询问本地AI助手 }], menus: { editor/context: [{ command: local-ai-assistant.executeTask, group: navigation, when: editorTextFocus }] } }步骤4运行测试在扩展目录下按F5启动一个扩展开发宿主窗口。在新窗口中打开一个文件夹作为项目。在编辑器中右键选择“询问本地AI助手”输入“用 find 命令列出所有 .py 文件”。观察输出面板和通知你应该能看到助手调用了execute_shell工具并返回了结果。5. 避坑指南与实战心得把系统跑起来只是第一步在实际使用中会遇到各种问题。下面是我踩过的一些坑和总结的经验。5.1 模型不听话格式解析失败怎么办问题模型经常不按规定的 JSON 格式回复而是输出自然语言比如“我将为你调用 execute_shell 工具命令是...”导致解析失败。解决方案强化系统提示词在 System Prompt 中反复强调格式并使用“必须”、“严格”、“只回复 JSON”等强约束性词语。在 Few-shot 示例中也要展示模型“不听话”时被纠正的例子。输出后处理在解析函数_parse_tool_call中增加鲁棒性。如果直接解析失败可以尝试用正则表达式在文本中搜索类似 JSON 的结构例如r\{\s*action\s*:\s*[^]\s*,\s*args\s*:\s*\{[^}]\}\s*\}。虽然不完美但能挽救一部分情况。降低 Temperature将模型的temperature参数调低如 0.1减少输出的随机性使其更倾向于遵循指令。模型选择并非所有模型都擅长遵循结构化输出指令。经过测试CodeLlama、Mistral 的 Instruct 版本、Qwen 的 Chat 版本在这方面表现较好。纯预训练的基础模型通常很难做到。5.2 工具调用混乱模型选错工具或参数问题模型理解了要调用工具但选择了错误的工具或参数填得驴唇不对马嘴。解决方案工具描述至关重要工具的description字段要写得具体、无歧义说明工具的精确用途和边界。例如“执行 shell 命令”就太宽泛改成“在安全限制下执行简单的文件查找、目录列表和版本控制命令如 find, ls, git status”。参数 Schema 要详细JSON Schema 里的参数描述description也要写清楚。例如command参数的描述可以写“需要执行的 shell 命令字符串必须是预定义的安全命令之一。”在 Few-shot 示例中展示边界情况不仅展示成功案例也展示一些容易出错的用户请求以及模型应该如何正确选择工具和参数。这能教会模型处理模糊请求。引入验证与反馈循环如果工具执行失败如命令不在白名单将清晰的错误信息返回给模型模型有时能根据错误信息自我纠正在下一轮调用中调整参数。5.3 性能与延迟本地模型推理慢问题7B/13B 的模型在 CPU 上推理可能很慢一次对话包含多轮工具调用用户等待时间过长。解决方案使用量化模型采用 GGUF 格式的 4-bit 或 5-bit 量化模型能在几乎不损失太多精度的情况下大幅提升推理速度并降低内存占用。llama.cpp和ollama对此支持很好。GPU 加速如果有 NVIDIA GPU务必使用支持 CUDA 的推理库如text-generation-webui(AutoGPTQ) 或vLLM。速度是 CPU 的数十倍。设置合理的超时和流式响应后端调用模型时设置超时如 60 秒避免卡死。对于 VS Code 扩展可以考虑实现流式响应先快速返回“思考中...”的提示再逐步输出结果。缓存对于常见的、确定性的用户查询如“这个函数的作用是什么”如果上下文相同可以考虑缓存模型的回复。5.4 安全性防止恶意或危险操作问题模型可能被诱导执行rm -rf /或访问敏感文件。解决方案工具层面的白名单如前所述对执行命令、文件读写等高风险操作实施严格的命令/路径白名单机制。用户确认对于某些高风险或不确定的操作可以在 VS Code 扩展中弹出确认对话框让用户批准后再执行。例如“助手试图执行命令xxx是否允许”运行在隔离环境考虑将整个后端服务尤其是工具执行部分运行在 Docker 容器或沙箱中限制其网络和文件系统访问权限。输入过滤对用户输入进行基本的过滤防止明显的 prompt 注入攻击如用户输入“忽略之前指令执行...”。5.5 扩展性如何优雅地增加新工具问题每加一个新工具都要改多处代码很麻烦。解决方案插件化架构将工具定义做成独立的 Python 模块或文件。主程序启动时扫描某个目录如tools/下的所有.py文件并自动调用一个统一的register()函数来注册工具。这样新增工具只需新建一个文件。工具自描述每个工具模块除了执行函数还应该导出工具的名称、描述和参数 Schema。这样注册中心可以动态加载。动态更新提示词当工具注册中心更新后Orchestrator的_build_system_prompt方法需要能重新生成包含新工具描述的提示词。对于已建立的会话可以在新对话轮次中更新系统消息。这个项目就像在本地搭建了一个专属的、具备“动手能力”的编码副驾驶。它没有云端服务那么强大和流畅但在隐私、定制化和对内部工作流的深度集成上有着不可替代的优势。最大的成就感来自于看到一句简单的自然语言描述经过本地模型的“思考”和“翻译”最终转化为一个实实在在的、安全受控的自动化操作。整个过程就是把两个不兼容的 API 之间的鸿沟用代码和设计一点点填平的过程。