十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Zed 编辑预测 Teacher 提示词设计:解析 teacher.md 模板与 ep 管线中的提示工程实现

Zed 编辑预测 Teacher 提示词设计:解析 teacher.md 模板与 ep 管线中的提示工程实现 Zed 编辑预测 Teacher 提示词设计解析 teacher.md 模板与 ep 管线中的提示工程实现【免费下载链接】zedCode at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.项目地址: https://gitcode.com/GitHub_Trending/ze/zedZed 的编辑预测Edit Prediction即 Zeta 系列补全功能采用“Teacher-Student”蒸馏路线先用大参数 Teacher 模型在真实编辑样例上生成预测再蒸馏出低延迟的 Student 模型。crates/edit_prediction_cli/src/prompts/teacher.md正是发送给 Teacher 模型的提示词模板——它定义了角色、任务步骤、严格的预测规则、输入输出格式并用六个完整示例约束模型行为。本文完整继承该模板的内容结合edit_prediction_cli命令名为ep的源码讲清模板中每个占位符如何被填充、每条规则如何被解析逻辑兜底以及如何在仓库中查看这套提示工程管线。模板在 ep 管线中的位置edit_prediction_cli是 Zed 编辑预测的离线实验 CLImain.rs支持read、load-project、context、format-prompt、predict、parse-output、score、distill、synthesize等子命令。teacher.md的加载与填充发生在format-prompt阶段prompt_assets.rs 中的get_prompt(name)负责读取模板开启dynamic_promptsfeature 时从CARGO_MANIFEST_DIR/src/prompts目录读取带缓存否则通过util::fs_embed!将 prompts 目录 的内容嵌入二进制因此该文件既可直接编辑热更新也可随构建产物分发。format_prompt.rs 中TeacherPrompt::format_prompt取出模板后做四个占位符替换let prompt_template crate::prompt_assets::get_prompt(teacher.md); let prompt prompt_template .replace({{context}}, context) .replace({{edit_history}}, edit_history) .replace({{diagnostics}}, diagnostics.as_deref().unwrap_or()) .replace({{cursor_excerpt}}, cursor_excerpt);这与模板末尾的“Your task”部分一一对应# 1. User Edit History{{edit_history}}# 2. Related excerpts {{context}} # 3. Current File {{cursor_excerpt}} {{diagnostics}} ----- Based on the edit history and context above, predict the users next edit within the editable region. 也就是说teacher.md 前半部分是**静态的指令与示例**末尾才是**动态拼接的样例数据**。 ## 角色与任务定义 模板开头的 “Instructions” 部分向模型声明了角色与三步任务 You are an edit prediction assistant in a code editor. Your task is to predict the next edit to a given region of code surrounding the users cursor. 1. Analyze the edit history to understand what the programmer is trying to achieve 2. Identify any incomplete refactoring or changes that need to be finished 3. Make the remaining edits that a human programmer would logically make next (by rewriting the code around their cursor) “Focus on” 部分进一步收窄优化目标 - Completing any partially-applied changes made补全用户做了一半的修改 - Ensuring consistency with the programming style and patterns already established与既有代码风格和模式保持一致 - Making edits that maintain or improve code quality保持或提升代码质量。 这里的设计意图很明确预测的不是“模型认为更好的写法”而是“这位程序员按当前轨迹下一步会做什么”。源码中的去重与采样逻辑deduplicate_examples 使用 MinHash LSH 按 Jaccard 相似度聚类样例见 [main.rs](https://link.gitcode.com/i/57ca9bc1c778575d5ce0c42a773cf873)也印证了这一点——评测集强调的是覆盖不同“编辑轨迹”而不是覆盖不同代码主题。 ## 核心规则绝不回退用户的编辑 模板中最重的一组规则是“NEVER undo or revert the users recent edits”。逐条拆解如下 1. **删除行不可恢复**编辑历史 diff 中以 - 开头的行即使恢复它能让代码重新完整也不得还原 2. **新增行不可删除**以 开头的行不得删除或大改 3. **NO_EDITS 兜底**如果用户的编辑让代码看起来“坏了”或“不完整”正确输出是 NO_EDITS而不是通过回退去“修复” 4. **关键判别式Key test**如果你的预测会让代码**更接近用户编辑前的样子**就输出 NO_EDITS 5. **永远不要假设删除是误操作**即使删除破坏了语法或模式用户也可能正在重写中mid-rewrite不得“补全”半截文本靠恢复删除内容实现 6. **自动生成的代码可以修改**Hunk 前带有 // User accepted prediction: 标记的内容来自上一次被用户接受的预测。与用户亲手输入的内容不同这些 hunk 可以被编辑、纠正甚至替换。“never undo/revert”规则保护的是用户**当前的键入意图**自动生成的脚手架不享受此保护 7. **不要机械套模式**要结合上下文和程序员目标推理哪些修改是合理的 8. **不要只修语法错误**要识别更宽的 refactor 模式并系统性地在整个代码中应用 9. **保持既有格式**除非绝对必要 10. **历史与周边代码冲突时**优先信任编辑历史中最近的编辑因为它最能反映当前意图 11. **把光标附近的半截文本视为用户正在输入的内容**基于上下文补全 12. **宁可做出可被拒绝的实质性预测**也不要只省几个键位的最小预测 13. **散文/文档场景要保守**补全当前片段或句子即可不要额外生成自由内容行因为散文约束弱、错误续写概率高。 第 6 条是理解整个模板的关键它显式区分了“用户意图不可逆”与“模型生成的脚手架可改”。这一点与解析侧的实现相呼应——编辑历史中的 // User accepted prediction: 标记由 ep 管线在构建样例时写入模型需要据此调整对 hunk 的保护等级。 ## 输入格式三段式上下文 特殊标记 模板的 “Input Format” 一节定义了模型会收到什么 1. **User Edit History**按时间顺序的编辑历史unified diff 形式用于推断用户轨迹其中 // User accepted prediction: 前缀的 hunk 表示被接受的自动生成代码 2. **Related excerpts**代码库中相关文件摘录用于跨文件推理文件内的 … 表示中间跳过了部分代码 3. **Current file**当前文件摘录其中 - |editable_region_start| 与 |editable_region_end| 界定**可编辑区域**——模型只能预测该区域内的编辑 - |user_cursor| 标记最后一次编辑后的光标位置。 这四个特殊字符串与 [format_prompt.rs](https://link.gitcode.com/i/9a668675e9d60d64ec0955b802e850e9) 中的常量一一对应 rust impl TeacherPrompt { pub(crate) const EDITABLE_REGION_START: str |editable_region_start|\n; pub(crate) const EDITABLE_REGION_END: str \n|editable_region_end|; pub(crate) const USER_CURSOR_MARKER: str |user_cursor|; pub(crate) const NO_EDITS: str NO_EDITS; const MAX_HISTORY_LINES: usize 128; “只能编辑 editable region”的约束并非只写在提示词里解析侧同样强制TeacherPrompt::parse 只会从响应中抽取 editable region并对 region 新旧内容做 diffregion 之外的任何输出都会被丢弃见下文“输出解析”一节。 ## 占位符的填充细节源码级补充 模板静态文本之外三个数据占位符的填充逻辑值得展开因为它们决定了模板实际拿到什么样的数据 **{{edit_history}}**TeacherPrompt::format_edit_history 将历史按行截断到最近 MAX_HISTORY_LINES 128 行超出部分以 [...truncated...] 标注空历史则填 (No edit history)。模板规则“优先信任最近的编辑”与此截断策略自洽——模型看到的本来就是最靠近当前意图的那一段。 **{{context}}**format_context 从 prompt_inputs.related_files 取摘录用 format_related_files_within_budget 在 **1024 token 预算**内选取渲染为 代码块五个反引号无上下文时填 (No context)。模板中提到的 … 跳过标记就是由此类摘录的拼接方式产生。 **{{cursor_excerpt}}**format_cursor_excerpt 按“上下文前缀 editable region 标记 光标标记 上下文后缀”的结构拼装当前文件摘录外层用 {路径} 标注文件路径。 **{{diagnostics}}**只有当 zeta 格式为 V0420Diagnostics 时format_prompt 才调用 format_diagnostics 并替换为非空内容以 # 4. Diagnostics 小标题形式注入预算 2000 token其余情况该占位符被替换为空字符串。这解释了模板为何把 {{diagnostics}} 放在 # 3. Current File 之后、作为可选段存在。 ## 输出格式说明 唯一代码块 NO_EDITS 逃生阀 模板规定输出必须包含 1. 基于编辑历史与光标位置**简要说明用户当前意图** 2. 一个 markdown 代码块**只包含**应用了预测编辑后的 editable region代码块必须以 |editable_region_start| 开头、以 |editable_region_end| 结尾前后不得有其他内容 3. 若无需编辑代码已完整正确或没有清晰的下一步编辑代码块中只输出 NO_EDITS 4. 若预测结果中存在用户下一步很可能继续编辑的位置用 |user_cursor| 标出。 解析侧对这套格式的执行非常严格位于 [format_prompt.rs](https://link.gitcode.com/i/9a668675e9d60d64ec0955b802e850e9) 的 TeacherPrompt::parse被 [parse_output.rs](https://link.gitcode.com/i/1a594563877197a3aee7020d3ad7a8c4) 和 [predict.rs](https://link.gitcode.com/i/10a3da4a08aa035ce6cb095d5f435365) 复用 - 先用 extract_last_codeblock 抽取**最后一个**代码块若其内容为 NO_EDITS 直接返回空 patch——与模板第 3 条对应 - 否则用 extract_editable_regionrfind 起止标记取出 region定位其中的 |user_cursor| 得到新光标偏移再把该标记从文本中剔除 - 与 prompt 中的旧 region 做 unified_diff_with_context 对比生成 --- a/{path} / b/{path} 形式的 actual_patch - 光标位置映射为 ActualCursor用于后续评分。 也就是说模板里的“codeblock 必须且只能包含 region”不是风格建议模型若把 region 外内容混入代码块会被解析逻辑静默丢弃或导致 region 抽取失败。 ## 六个官方示例模板的 few-shot 核心 模板用六个完整示例Example 1–6覆盖了规则空间的全部关键分支。以下逐一继承原文示例并点明其对应的规则。 ### Example 1用 related excerpts 补全缺失代码 光标处缺少代码相关摘录中提供了相关类型定义应据此补全。 **Related Excerpts** struct Product { name: String, price: u32, } **User Edit History** --- a/src/calculate.rs b/src/calculate.rs -100,6 100,7 fn calculate_total(products: [Product]) - u32 { let mut total 0; for product in products { total ; } total } **Current File** src/calculate.rs fn calculate_total(products: [Product]) - u32 { |editable_region_start| let mut total 0; for product in products { total |user_cursor|; } total |editable_region_end| } **Output** The user is computing a sum based on a list of products. The only numeric field on Product is price, so they must intend to sum the prices. |editable_region_start| let mut total 0; for product in products { total product.price; } total |editable_region_end| 对应规则把光标附近半截文本视为“正在输入”并优先使用 related excerpts 做跨文件推理。 ### Example 2继续用户的打字轨迹而不是修正拼写 用户正在输入 eprintln! 调用。不能通过**删除**新输入内容来“修正拼写”必须延续用户轨迹。要打印什么并不明确——应填入显然意图的代码并把光标放在用户能继续填写的位置。 **User Edit History** --- a/src/modal.rs b/src/modal.rs -100,4 100,4 fn handle_close_button_click(modal_state: mut ModalState, evt: Event) { modal_state.close(); - modal_state.dismiss(); eprmodal_state.dismiss(); } **Current File** src/modal.rs // handle the close button click |editable_region_start| fn handle_close_button_click(modal_state: mut ModalState, evt: Event) { modal_state.close(); epr|user_cursor|modal_state.dismiss(); |editable_region_end| } **Output** The user is clearly starting to type eprintln!(), however, what they intend to print is not obvious. I should fill in the print call and string literal, with the cursor positioned inside the string literal so the user can print whatever they want. |editable_region_start| fn handle_close_button_click(modal_state: mut ModalState, evt: Event) { modal_state.close(); eprintln!(|user_cursor|); modal_state.dismiss(); |editable_region_end| 注意输出中 |user_cursor| 被放在字符串字面量内部——这是模板第 4 条输出要求标记下一个可能编辑点的直接体现。 ### Example 3函数名不确定时做合理猜测并保存键位 用户在新增函数函数名无法确知。此时应合理猜测函数名和签名并把光标放进函数体猜对了就节省可观键位文件也处于一致状态。 **User Edit History** --- a/src/modal.rs b/src/modal.rs -100,4 100,4 fn handle_close_button_click(modal_state: mut ModalState, evt: Event) { modal_state.close(); modal_state.dismiss(); } fn fn handle_keystroke(modal_state: mut ModalState, evt: Event) { **Current File** src/modal.rs // handle the close button click fn handle_close_button_click(modal_state: mut ModalState, evt: Event) { modal_state.close(); |editable_region_start| modal_state.dismiss(); } fn|user_cursor| fn handle_keystroke(modal_state: mut ModalState, evt: Event) { |editable_region_end| modal_state.begin_edit(); **Output** The user is adding a new function. The existing functions I see are handle_close_button_click and handle_keystroke, which have similar signatures. One possible function they might be adding is handle_submit. |editable_region_start| modal_state.dismiss(); } fn handle_submit(modal_state: mut ModalState, evt: Event) { |user_cursor| } fn handle_keystroke(modal_state: mut ModalState, evt: Event) { |editable_region_end| 对应规则“prefer predictions that save meaningful keystrokes, even if this requires making educated guesses” 与 “better to make a substantive prediction that might be rejected”。 ### Example 4代码已完整输出 NO_EDITS 代码已经完整且没有清晰的下一步编辑应输出 NO_EDITS。 **User Edit History** --- a/src/utils.rs b/src/utils.rs -10,7 10,7 fn add(a: i32, b: i32) - i32 { - a - b a b } **Current File** src/utils.rs |editable_region_start| fn add(a: i32, b: i32) - i32 { a b|user_cursor| } |editable_region_end| **Output** The user just fixed a bug in the add function, changing subtraction to addition. The code is now correct and complete. There is no clear next edit to make. NO_EDITS ### Example 5删除后看似不完整仍然 NO_EDITS规则的核心压力测试 用户刚删除了代码留下看起来不完整的内容。绝不能通过恢复被删内容去“补全”——那等于撤销用户的编辑。**即使代码看起来是坏的NO_EDITS 也是正确响应。** **User Edit History** --- a/config.nix b/config.nix -10,7 10,7 # /etc/modular/crashdb needs to be mutable - ln -s /tmp/crashdb $out/etc/modular/crashdb ln -s /tmp/cr $out/etc/modular/crashdb ; **Current File** config.nix |editable_region_start| # /etc/modular/crashdb needs to be mutable ln -s /tmp/cr|user_cursor| $out/etc/modular/crashdb ; |editable_region_end| **Output** The user deleted ashdb from /tmp/crashdb, leaving /tmp/cr. Although this looks like incomplete text that I could complete, doing so would restore deleted content. The user intentionally removed that text—I must not undo their deletion. NO_EDITS 这是 Key test 规则的典型场景补全 /tmp/crashdb 会让代码更接近编辑前状态因此拒绝。 ### Example 6用户接受过预测的脚手架可以被改写 用户先接受了模型生成的函数预测随后开始重命名。原参数是自动生成的带 // User accepted prediction: 标记因此**可以**随新函数名一起更新。这不是回退用户输入而是改进自动生成的脚手架。 **User Edit History** --- a/math_utils.py b/math_utils.py -3,3 3,5 def calculate_rectangle_area(width, height): return width * height de // User accepted prediction: --- a/math_utils.py b/math_utils.py -3,5 3,7 def calculate_rectangle_area(width, height): return width * height -de def calculate_rectangle_perimeter(width, height): --- a/math_utils.py b/math_utils.py -5,5 5,5 return width * height -def calculate_rectangle_perimeter(width, height): def calculate_sq_perimeter(width, height): **Current File** math_utils.py def calculate_rectangle_area(width, height): return width * height |editable_region_start| def calculate_sq|user_cursor|_perimeter(width, height): |editable_region_end| **Output** The user accepted a prediction for calculate_rectangle_perimeter(width, height), then started renaming rectangle to square. Since squares have equal sides, the arguments should change from (width, height) to (side). The arguments were auto-generated (from an accepted prediction), so modifying them is appropriate. |editable_region_start| def calculate_square_perimeter(side): |user_cursor| |editable_region_end| 注意这里同时演示了两点模型不仅改名还把 (width, height) 改为 (side)结合数学常识的系统性重构且这合法因为参数来自已接受的预测而非用户手敲。 ## 从模板到管线Teacher 后端、批处理与蒸馏 模板之外仓库源码揭示了它被使用的完整方式 **后端选择**。[main.rs](https://link.gitcode.com/i/57ca9bc1c778575d5ce0c42a773cf873) 定义了 TeacherBackend 枚举sonnet45 为默认、sonnet46、gpt52、gpt54、gpt55对应模型名如 claude-sonnet-4-5、gpt-5.2 等provider 字符串形如 teacher:sonnet46 或 teacher:gpt52。teacher.md 是 Teacher / TeacherNonBatching provider 共用的模板另有 teacher_jumps.md 供 TeacherJumps 的长程编辑预测使用带 hash region 标记模板结构相近但标记体系不同。 **批处理请求**。批处理路径通过 [anthropic_client.rs](https://link.gitcode.com/i/6c01bfd2282fbac65395853627976015) 中的 PlainLlmClient依赖 ANTHROPIC_API_KEY 环境变量把格式化好的 prompt 作为单条 user message 发给模型 API支持流式与非流式。 **解析与评分**。ep parse-output 调用上文所述的 TeacherPrompt::parse 把模型原始输出actual_output转为 actual_patchep score 对比 expected/actual patch 计算得分ep qa 用 LLM-as-a-judge 复核质量ep repair[repair.rs](https://link.gitcode.com/i/a1c8fd533d26a357eff93a6959651a4a)对低分预测重新生成并同样委托 TeacherPrompt::parse 解析——模板的解析契约在修复回路中被复用。 **蒸馏**。[distill.rs](https://link.gitcode.com/i/3a776addf1b83eab626682953e457844) 的 run_distill 将样例中实际的预测 patch若存在 repair provider 的预测则优先取用写入 expected_patches_with_cursor_positions并清空原始 prompt、predictions 与 score 字段产出只保留“输入 期望输出”的蒸馏数据集——teacher.md 的产出最终服务于训练 Student 模型。 **评测样例**。[evals 目录](https://link.gitcode.com/i/883e2501ac43c26d3612ca01b9f553e9) 中的 markdown 文件如 tree-sitter--tuple-to-struct-destructuring.md、flask--rename-accepted-prediction.md、zed--add-eprintln.md 等与模板六个示例同构可视为模板规则的回归评测集其中 flask--rename-accepted-prediction.md 正是 Example 6 场景重命名已接受的预测的评测版本。 ## 小结这份提示词模板的工程要点 - **约束闭环**模板中的每一条输出约定唯一代码块、region 标记、NO_EDITS、|user_cursor|在 TeacherPrompt::parse 中都有对应的机械解析提示词格式即解析器契约 - **意图优先**以“用户轨迹”为第一性原则用 Key test预测是否使代码回到编辑前作为 NO_EDITS 的判别式显式保护删除操作同时为已接受的自动生成代码留出可改写空间 - **预算控制**编辑历史截断 128 行、相关上下文 1024 token、诊断 2000 token 的预算在源码中硬编码保证模板在不同样例规模下输入长度可控 - **可复现**模板文件经 get_prompt 缓存或嵌入后端以 provider 字符串显式指定整个 format → predict → parse → score → distill 流程可由 ep 子命令逐步执行和复现。 对希望研究编辑器内 AI 编辑预测的团队而言[teacher.md](https://link.gitcode.com/i/7f403f1db8a8dc66f5ad956872c2c8fb) 与 [format_prompt.rs](https://link.gitcode.com/i/9a668675e9d60d64ec0955b802e850e9) 是一对值得对读的文档前者定义了“要模型做什么”后者定义了“系统如何验证模型做了”——两者共同构成 Zed 编辑预测 Teacher 侧提示工程的完整骨架。【免费下载链接】zedCode at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.项目地址: https://gitcode.com/GitHub_Trending/ze/zed创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表