第11章:上下文工程 —— 从 Handlebars 模板到 AGENTS.md
大模型的智力表现,极大程度取决于送入上下文窗口的第一道指令。在工业级端侧智能体中,系统提示词绝不是一段静态写死的文本,而是一个需要感知当前操作系统平台、当前启用的工具组合、沙箱开启状态、用户全局风格偏好以及当前工程特定规约的高度动态渲染系统。本章将解构 Zed 是如何用 Handlebars 编译期模板和 9 类工程规则文件,搭建起这套精密、自适应且具备层级优先级的上下文装配体系的。
一、开场:静态提示词为什么无法胜任端侧桌面?
很多初涉大模型应用开发的工程师习惯于使用简单的字符串模板(如 Python 的 f-string):
python
system_prompt = f"You are an assistant. Current date is {date}..."
但在真正的桌面开发环境中,这种静态拼接方案会立刻遭遇以下动态维度的排列组合爆炸:
- 工具可用性带来的行为分裂:
- 如果当前 Profile 开启了 grep,提示词应该指导模型“搜索符号时优先使用 grep,逐步缩小范围”;但如果 Profile 关闭了 grep,这段指导就会误导模型去调用一个根本不存在的工具,直接导致报错;
- 如果开启了 spawn_agent,需要系统性注入子智能体任务编排范式;如果未开启,这段说明纯属浪费 Token;
- 沙箱与跨平台指令动态分支:
- 在 Linux 上,提示词需要告诉模型 /tmp 目录是可写的(基于 tmpfs);
- 在 Windows 上,需要警告模型终端命令正在 WSL 虚拟机内部运行,路径必须通过 /mnt/c/... 访问,且禁止单域名网络放行;
- 如果沙箱由于环境缺失不可用,必须彻底抹除沙箱条款,告诫模型命令在宿主裸跑;
- 多层规约的优先级冲突:
- 开发者个人的全局习惯(如“永远用中文回复”、“输出不要带道歉陈词”);
- 团队工程的特定要求(如“本项目遵循 Rust 2024 Edition”、“禁止修改 generated.rs”)。
Zed 在 crates/agent/src/templates.rs 与 crates/prompt_store 中,交出了一份教科书般的工业级上下文装配方案。
二、编译期模板引擎:templates.rs 与 Handlebars
Zed 并没有在运行时去动态拼装脆弱的字符串,而是采用了成熟的 Handlebars 模板引擎,并通过编译期嵌入机制(util::fs_embed!)实现了极致的执行效率与开发体验:
rust
// crates/agent/src/templates.rs:1-35
util::fs_embed! {
struct Assets,
crate_relative = "src/templates",
root_relative = "crates/agent/src/templates",
include = ["*.hbs"],
}
pub struct Templates(Handlebars<'static>);
impl Templates {
pub fn new() -> Arc<Self> {
let mut handlebars = Handlebars::new();
// 开启严格模式:任何未定义变量或解析错误直接报错,禁止默默吞没异常
handlebars.set_strict_mode(true);
// 注册通用列表包含判断辅助函数
handlebars.register_helper("contains", Box::new(contains));
handlebars.register_embed_templates::<Assets>().unwrap();
Arc::new(Self(handlebars))
}
}
【来源:crates/agent/src/templates.rs:1-35】
架构考量:
- strict_mode(true) 强类型防御:如果模板中引用的某个字段在 Rust 结构体中拼写错误,或者某个上下文由于重构丢失,系统在单元测试中直接抛出 RenderError,杜绝半截破损的提示词流入线上;
- 发布与开发的双轨嵌入:在发布包中,*.hbs 模板被直接作为静态二进制字节嵌入 Zed 可执行文件中,零 I/O 开销;在开发调试阶段,则实时映射磁盘路径,开发者修改 .hbs 模板后无需重新编译即可即时验证。
三、系统提示词装配全景:system_prompt.hbs 解剖
在 crates/agent/src/templates/system_prompt.hbs(279 行)中,Zed 沉淀了业界顶级的智能体行为规范。我们可以将其清晰划分为八大功能板块:

系统提示词不是写死的文本:工作区信息、当前启用的工具集、个人全局 AGENTS.md、工程内规则文件、沙箱运行特征五路输入,经 279 行 Handlebars 模板的六个分段渲染,才组装成发给模型的第 0 条消息。
3.1 核心板块精粹赏析
板块 1:沟通与响应格式(Communication & Formatting)
- 透明度优先于逢迎:
"Be accurate and truthful. Prioritize technical correctness over affirming the user's assumptions. If something seems wrong or risky, say so respectfully and explain the reasoning. Do not over-apologize when results are unexpected."
- 结构化图表渲染:
要求模型直接使用 Mermaid 渲染流程图,并特别指明:“Mermaid diagrams are automatically themed to match the user's editor theme. Do NOT include inline HTML elements in mermaid diagrams.”
板块 2:工具使用纪律(Tool Use)
- 杜绝猜测:
"Before acting, gather enough context to avoid guessing. Do not use placeholders, invented paths, or assumed command arguments in tool calls."
- 最大化并行:
"You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel."
- 禁止废话回读(No-Echo Rule):
"Do not waste tokens by re-reading files after calling write_file, edit_file, or similar. The tool call will fail if it didn't work."
板块 3:野心与精度的平衡(Ambition vs. Precision)
针对 Greenfield(从零新建)与 Brownfield(既有项目重构)场景作出了极具智慧的指导:
- 从零新建时展现野心:“For tasks with no prior context (starting something brand new), feel free to be ambitious and demonstrate creativity.”
- 在既有代码库中实施外科手术:“In an existing codebase, do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (e.g. changing filenames or variables unnecessarily).”
板块 4:诊断修复的“试不过三”原则
"Fixing Diagnostics: Make 1-2 focused attempts at fixing diagnostics you are likely able to resolve, then defer to the user with a clear explanation of what remains. Never simplify or discard meaningful code just to silence diagnostics."
彻底避免了智能体在编译报错面前反复挣扎、甚至为了消除告警而偷偷删掉用户有用业务逻辑的愚蠢行为。
四、多层规则体系与覆写机制:Personal vs Project
在现实软件开发中,开发者既有个人通用的工作习惯,每个具体的开源或企业项目又有着严苛的代码规范。
4.1 自动识别的 9 类规则文件
Zed 的 prompt_store 模块极具包容性。它不仅支持 Zed 自己的格式,还无缝兼容了整个行业现存的各类主流规范:
rust
// crates/prompt_store/src/prompts.rs:22-33
pub const RULES_FILE_NAMES: &[&str] = &[
".rules",
".cursorrules",
".windsurfrules",
".clinerules",
".github/copilot-instructions.md",
"AGENT.md",
"AGENTS.md",
"CLAUDE.md",
"GEMINI.md",
];
【来源:crates/prompt_store/src/prompts.rs:22-33】
无论开发者之前是从 Cursor、Windsurf、Cline 还是 Claude Code 迁移过来,无需重构任何文件,Zed 会自动探测并提取工程根目录下的规则文本。
4.2 层叠覆盖顺序:个人在先,工程在后
在 crates/agent/src/templates.rs 的单元测试中,存在一条非常严密的单向断言:
rust
// crates/agent/src/templates.rs:160-175
#[test]
fn test_system_prompt_renders_user_agents_md_before_project_rules() {
// ... 构建包含个人 AGENTS.md 和项目级 AGENTS.md 的测试数据 ...
let rendered = template.render(&templates).unwrap();
let personal_idx = rendered.find("### Personal `AGENTS.md`").unwrap();
let project_idx = rendered.find("### Project Rules").unwrap();
assert!(
personal_idx < project_idx,
"personal AGENTS.md should render before project rules so project rules can override it"
);
}
【来源:crates/agent/src/templates.rs:160-175】
为什么必须是“个人在先,项目在后”?
根据大模型注意力机制的基线规律:排在后面的提示词对排在前面的提示词具有更高的注意力和覆写权重。
- 如果用户个人全局配置了:“变量命名习惯使用 camelCase”;
- 但当前打开的 Linux 内核或 Rust 工程规则明确规定:“必须严格使用 snake_case”;
- 由于项目规则位于提示词靠后的位置,大模型会精准采用项目规则覆盖个人的全局偏好,确保团队协作的代码风格绝对纯净!
五、向技能系统的演进:rules_to_skills_migration.rs
在长期的工程实践中,Zed 团队敏锐地发现了传统规则文件的致命短板:规则膨胀危机(Rule Bloat)。
当团队把架构说明、部署指南、测试规范全部塞进 AGENTS.md 时,这个文件会迅速膨胀到上万 Token。大模型在处理一个简单的重构任务时,每次交互都要被迫重新阅读这上万 Token 的全量规则,既消耗巨额成本,又稀释了模型对具体任务的聚焦度。
为此,Zed 在 crates/prompt_store/src/rules_to_skills_migration.rs(1,037 行)中实现了一套自动化迁移机制:
- 静态规则精简:将 AGENTS.md 重新收敛为纯粹的行为准则与基本约束;
- 能力领域解耦:将庞大的特定任务知识(如“如何做端侧沙箱测试”、“如何解析图表”)自动引导迁移为独立的技能包(SKILL.md);
- 渐进式披露(Progressive Disclosure):通过下一章将要拆解的 agent_skills 模块,在系统提示词中只暴露微小的技能元数据,智能体在真正需要时再自主调用 skill 工具按需提取全文!
六、动手复核
你可以在本地源码检出中执行以下命令,验证本章引用的核心数据和模板断言:
bash
# 1. 验证 9 类规则文件名的定义清单
sed -n '22,35p' crates/prompt_store/src/prompts.rs
# 2. 查看 Handlebars 模板严格模式的配置代码
grep -n -C 5 "set_strict_mode" crates/agent/src/templates.rs
# 3. 查看系统提示词模板的真实行数与前 40 行
wc -l crates/agent/src/templates/system_prompt.hbs
head -n 40 crates/agent/src/templates/system_prompt.hbs
# 4. 检查个人规则位于项目规则之前的测试用例断言
sed -n '160,175p' crates/agent/src/templates.rs
# 5. 查看自动化规则向技能迁移模块的实现规模
wc -l crates/prompt_store/src/rules_to_skills_migration.rs
七、总结
Zed 的上下文工程为现代智能体树立了工业级标杆:
- 编译期严谨性:用强类型的 Handlebars 模板和静态测试杜绝破损提示词;
- 动态自适应能力:按需按平台按工具动态展开行为准则,绝不灌输无用信息;
- 清晰的优先级秩序:以“个人在先、项目在后”的精巧编排,完美兼顾个人习惯与团队公约;
- 迈向渐进式披露:以规则与技能的分流演进,化解长上下文与经济成本的矛盾。
在下一章中,我们将进一步探索智能体是如何向外延伸触角的 —— 扩展与委派:Skills、MCP 与子 Agent 协同。