Tabby Smart Apply 功能深度解析:基于 LLM 的代码智能插入 Prompt 设计与实现
Tabby Smart Apply 功能深度解析基于 LLM 的代码智能插入 Prompt 设计与实现【免费下载链接】tabbySelf-hosted AI coding assistant项目地址: https://gitcode.com/GitHub_Trending/tab/tabby导读本文以 Tabby 客户端tabby-agent中 Smart Apply智能应用功能的核心提示词文档clients/tabby-agent/src/chat/prompts/generate-smart-apply.md为主体深入剖析 Tabby 如何引导大模型将对话中生成的代码片段精准插入用户当前编辑的文档从 prompt 的设计原则分析差异、去重插入、保持缩进、禁止修改无关代码到两阶段定位本地模糊匹配 LLM 行号推断与流式应用GENERATEDCODE标签流式改写的完整实现链路。读完本文你将掌握 Tabby Smart Apply 的完整调用流程、generate-smart-apply.md中每一条 prompt 规则对应的源码落点以及如何参考该设计构建自己的代码插入 Agent。一、Smart Apply 是什么从生成代码到把代码放进正确的位置在 AI 编程助手的日常使用中用户往往在聊天窗口得到一段代码后还需要手动复制、定位、粘贴到编辑器里再手动调整缩进——这个过程繁琐且容易出错。Tabby 的 Smart Apply 功能正是为了解决这一痛点它接收目标文档位置 待应用的代码文本由 agent 自动完成插入位置判定 → 范围精确定位 → 流式编辑文档的完整闭环。从 tabby-agent 的协议定义 可以看到Smart Apply 是一个客户端到服务端client → server的 LSP 请求方法名tabby/chat/smartApply参数SmartApplyParams{ location: Location; text: string }——location指明目标文档 URI 与选区范围text是要应用的代码内容返回值boolean表示是否成功应用可能的错误ChatFeatureNotAvailableErrorChat 功能不可用、ChatEditDocumentTooLongError文档过长、ChatEditMutexError已有另一个 Smart Edit 正在进行在 VSCode 客户端的 webview 处理 中用户触发后编辑器会显示可取消的 Smart Apply in Progress 进度通知随后把content对话生成的代码与当前编辑器选区打包成SmartApplyParams通过 LSP 发送给 agent 服务端处理。二、generate-smart-apply.mdSmart Apply 的提示词主体clients/tabby-agent/src/chat/prompts/generate-smart-apply.md是本功能最核心的 LLM 提示词它定义了一个AI 代码插入助手的角色与全部行为准则。该文件通过构建工具以源码形式被导入作为chat.smartApply.promptTemplate的默认值注册进 agent 配置见 default.ts。2.1 角色与任务定义提示词开篇即设定角色You are an AI code insertion assistant. Your task is to accurately insert provided code into an existing document.你是一个 AI 代码插入助手任务是把提供的代码精确插入现有文档。这一定位决定了后续所有规则都围绕插入而非生成展开模型的目标不是创作新代码而是在既有文档结构约束下完成最小、最准确的改动。2.2 八条核心行为准则原文档给出了完整的 8 条指引这是整个功能正确性的关键分析差异确定插入点分析USERDOCUMENT与CODEBLOCK的内容差异判断合适的插入位置。对应源码中先定位范围、再局部编辑的两阶段策略。只插入新增/修改代码仅插入CODEBLOCK中新增或修改的代码不要重复已有的代码。这避免了模型把整段代码原样覆盖导致重复。插入时的格式要求保持周围代码的缩进风格与层级确保插入的代码与其他结构平行parallel而非不恰当地嵌套inappropriately nested不确定时优先插在变量声明之后、主逻辑之前或相关代码块之后。注释与小幅改动新注释或小改动应直接插到文档对应行之后并保留原有结构格式。禁止修改既有代码插入过程之外不得修改任何既有代码——这是防止模型顺手重构导致意外破坏的关键约束。保持语法结构保留已有代码与插入代码的语法结构和格式包括注释与多行字符串。使用 XML 标签包裹输出整个更新后的代码含既有代码与插入代码必须包裹在GENERATEDCODE/GENERATEDCODEXML 标签中。这一约定与源码中config.chat.edit.responseDocumentTag的默认值[GENERATEDCODE, /GENERATEDCODE]见 default.ts严格对应。禁止附加内容输出中不得包含任何解释或 Markdown 格式。2.3 输出格式模板提示词最后给出严格格式约束开标签GENERATEDCODE必须与代码第一行位于同一行并给出示例GENERATEDCODEfirst line of code middle lines with normal formatting USERDOCUMENT{{document}}/USERDOCUMENT CODEBLOCK{{code}}/CODEBLOCK末尾的USERDOCUMENT{{document}}/USERDOCUMENT与CODEBLOCK{{code}}/CODEBLOCK是模板占位符在运行时被真实内容替换。三、提示词模板的注入机制{{document}} 与 {{code}} 如何被填充理解了 prompt 规则后关键在于回答模板里的{{document}}和{{code}}在运行时被什么内容填充答案在 smartApply.ts 的 provideSmartApplyEditLLM 函数 中。该函数按以下步骤组装请求截取选中文本通过document.offsetAt(location.range.start/end)把 LSP 的行列位置转换为字符偏移量再substring得到selectedDocumentText即为{{document}}的实际内容。超长裁剪保护如果文档总长超过config.chat.edit.documentMaxChars默认3000字符见 default.ts则保留选中文本把其前后文按比例裁剪前缀不足一半则压缩后缀反之亦然确保最终 prompt 长度可控。正则替换模板promptTemplate.replace(/{{document}}|{{code}}/g, ...)将{{document}}替换为选中文本、{{code}}替换为用户提供的待应用代码。流式请求通过tabbyApiClient.fetchChatStream({ messages, model: , stream: true })发起流式 Chat 请求。响应流随后交给readResponseStream按responseDocumentTagGENERATEDCODE//GENERATEDCODE逐块解析出模型改写后的整段文档并以workspace/applyEdit形式流式应用回编辑器对应 protocol.ts 中server will edit the document content using ApplyEdit的说明。由于模型遵循第 2、5 条规则只输出改动后的完整代码段配合标签解析即可精确还原插入结果。四、定位先行本地模糊匹配smartRange.ts兜底在使用 LLM 前Tabby 会先在本地做一次模糊范围匹配这是generate-smart-apply.md第 1 条分析差异确定插入点的工程化实现。核心实现在 smartRange.tsgetSmartApplyRange(document, snippet)调用fuzzyApplyRange对文档按行切分后用滑动窗口 Levenshtein 编辑距离js-levenshtein库逐窗口计算与待插入代码片段的相似度选取距离最小的窗口作为目标范围若start.line end.line单行或文档为空判定为insert插入模式否则判定为replace替换模式。该本地匹配的意义在于大多数场景下待插入代码与文档中某段结构高度相似无需消耗 LLM 调用即可确定位置。只有本地匹配失败返回undefined时才回退到后端 LLM 定位。五、LLM 兜底定位provide-smart-apply-line-range.md当本地模糊匹配找不到合适范围时smartApply.ts 的 provideSmartApplyLineRange 函数 会调用第二个提示词模板clients/tabby-agent/src/chat/prompts/provide-smart-apply-line-range.md注册为chat.smartApplyLineRange.promptTemplate见 default.ts。该模板的设计思路与主模板互补把整个文档按行号 | 代码的格式逐行输入对应源码中.map((line, idx) \${idx 1} | ${line}) 的预处理待插入代码包裹在APPLYCODE/APPLYCODE标签中要求模型找出一段与待插入代码长度最相似的连续代码段并只输出闭区间行号startLine-endLine同样用GENERATEDCODE/GENERATEDCODE包裹例如GENERATEDCODE10-12/GENERATEDCODE行号是1-based 且闭区间startLine 与 endLine 均包含。服务端拿到响应后用正则/ GENERATEDCODE(.*?)\/GENERATEDCODE/s抽取行号解析出startLine/endLine转为 0-based 并做越界保护再根据startLine endLine判定 insert/replace 模式见 smartApply.ts。该模板中同样附带EXAMPLE_DOCUMENT/EXAMPLE_APPLYCODE少样本示例帮助模型理解长度相似的具体含义。六、两阶段协作的完整时序综合 smartApply.ts 的provideSmartApplyEdit主流程整个 Smart Apply 的调用链如下前置校验文档是否存在、LSP 连接是否可用、Chat 功能是否可用否则抛ChatFeatureNotAvailableError互斥锁检查mutexAbortController若已有 Smart Edit 进行中则抛ChatEditMutexError同时把请求的CancellationToken绑定到 abort controller支持用户取消阶段一本地定位getSmartApplyRange用 Levenshtein 滑动窗口匹配范围阶段二LLM 定位本地匹配失败时调用provideSmartApplyLineRange使用 provide-smart-apply-line-range.md 模板让 LLM 返回行号区间定位失败兜底两个阶段都失败则直接返回false高亮选区通过ShowDocumentParamstakeFocus: true让编辑器跳转并选中目标范围流式应用调用provideSmartApplyEditLLM使用 generate-smart-apply.md 模板让模型基于选中文本 待插入代码输出GENERATEDCODE包裹的更新后文档经readResponseStream流式写回收尾无论成功失败finally中重置互斥 abort controller。这一本地快速匹配 LLM 精确兜底 流式编辑的架构既保证了大多数场景的低延迟无需额外 LLM 往返又通过两级提示词行号定位模板 代码插入模板确保了定位与编辑的准确性。你可以直接在 tabby-agent/src/chat/prompts/ 目录下查看generate-smart-apply.md与provide-smart-apply-line-range.md的完整原文在 default.ts 中查看两者在配置中的注册位置并通过chat.smartApply.promptTemplate/chat.smartApplyLineRange.promptTemplate这两个配置项按需替换自定义提示词。七、对读者如何复用这套 Prompt 设计generate-smart-apply.md的价值不止于 Tabby 内部它本身就是一个高质量的代码插入 Agent提示词范本其设计要点值得借鉴明确输出协议用GENERATEDCODE等 XML 标签作为结构化输出协议方便程序解析规避模型夹杂解释文字的问题最小改动原则明确只插新增代码、禁止改动既有代码把破坏性风险约束到最低格式硬约束缩进保持、平行而非嵌套、开标签与首行同行等规则直接面向下游解析与缩进还原的正确性少样本示例在定位模板中提供EXAMPLE_DOCUMENT/EXAMPLE_APPLYCODE对用具体例子消除长度相似段的歧义占位符插值{{document}}/{{code}}的模板变量机制让提示词与运行时数据解耦便于多端复用与配置化替换。如果你正在构建自己的 AI 编辑 Agent例如在 IDE 插件中实现对话结果一键上屏可以直接参考本仓库的 prompts 目录 与 smartApply.ts 的实现将本地相似度匹配 LLM 行号推断 标签流式应用的三段式流程移植到你的方案中。【免费下载链接】tabbySelf-hosted AI coding assistant项目地址: https://gitcode.com/GitHub_Trending/tab/tabby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →