使用统一 diff（`@@` 块、`-`/`+`/空格行）对单个文件做精确编辑：追加、插入、替换、删除都可以在一次调用里完成。
硬性规则：

1) 补丁必须被 `*** Begin Patch` 与 `*** End Patch` 包裹。
2) 每个修改块必须以 `@@ [id:数字]` 开头。
3) 块内每一行只能是三类之一：
   - 上下文行：以空格开头（` ␠`），表示“文件里必须原样存在”的锚点；
   - 删除行：以 `-` 开头，表示要从文件中移除的原文；
   - 新增行：以 `+` 开头，表示要写入的新内容。
4) 任何“想新增/想删除/想替换”的内容都必须逐行写 `+` 或 `-`；如果你把多行新内容直接贴上去却不加 `+`，它会被当成上下文锚点去匹配原文件，极易导致“未找到匹配的原文”。
5) 重要语义：一个块里如果完全没有上下文行（空格开头）也没有删除行（`-`），那么它会被视为“仅追加（append-only）”，也就是把所有 `+` 行追加到文件末尾——这对“给空文件写正文”很合适，但对“插入到中间”是错误的。

正面案例（至少 5 个，且都包含多行原文/多处修改）

1) 给空文件写完整正文（追加到末尾；空文件=正确）
目标：新建 README.md 后一次性写入标题、安装、用法、FAQ（多段落、多行）。
要点：没有上下文/删除行 → 追加模式；空文件时最常用。

*** Begin Patch
@@ [id:1]
+# 项目名称
+
+一个简短说明：这个项目用于……
+
+## 安装
+
+```bash
+pip install -r requirements.txt
+```
+
+## 快速开始
+
+```bash
+python main.py
+```
+
+## 常见问题
+
+- Q: 为什么会报 xxx？
+  A: 先检查 yyy，再确认 zzz。
+
*** End Patch

2) “不删除，直接插入内容”到函数内部（必须用上下文锚定插入位置）
目标：在 def build_prompt(...): 里插入日志与参数归一化，但不改动其它行。
要点：插入发生在“两个上下文行之间”，上下文必须精确（包含缩进）。

*** Begin Patch
@@ [id:1]
 def build_prompt(user_text: str, system_text: str, tags: list):
     prompt_parts = []
+    # 参数归一化：去掉首尾空白，避免模型误判
+    user_text = (user_text or "").strip()
+    system_text = (system_text or "").strip()
+
+    logger.debug("build_prompt: tags=%s, user_len=%d", tags, len(user_text))
     prompt_parts.append(system_text)
     prompt_parts.append(user_text)
     if tags:
         prompt_parts.append("TAGS: " + ",".join(tags))
*** End Patch

3) 复杂替换：整段函数重构（多行 old/new + 保留稳定上下文）
目标：把旧的 apply_patch()（弱校验）替换成新实现（多分支、异常信息更清晰）。
要点：替换不是“改一行”，而是“删一段、加一段”，并用函数签名/相邻代码作锚点。

*** Begin Patch
@@ [id:1]
 class FilePatcher:
     def __init__(self, root: Path):
         self.root = root

     def apply_patch(self, path: str, patch_text: str) -> dict:
-        # old: naive replace
-        content = (self.root / path).read_text(encoding="utf-8")
-        content = content.replace("foo", "bar")
-        (self.root / path).write_text(content, encoding="utf-8")
-        return {"success": True}
+        full_path = (self.root / path).resolve()
+        if self.root not in full_path.parents and full_path != self.root:
+            return {"success": False, "error": "非法路径：越界访问"}
+
+        if "*** Begin Patch" not in patch_text or "*** End Patch" not in patch_text:
+            return {"success": False, "error": "补丁格式错误：缺少 Begin/End 标记"}
+
+        try:
+            original = full_path.read_text(encoding="utf-8")
+        except Exception as e:
+            return {"success": False, "error": f"读取失败: {e}"}
+
+        # 这里省略：解析 blocks、逐块应用、失败回滚等
+        updated = original
+        try:
+            full_path.write_text(updated, encoding="utf-8")
+        except Exception as e:
+            return {"success": False, "error": f"写入失败: {e}"}
+
+        return {"success": True, "message": "已应用补丁"}
*** End Patch

4) 复杂多块：同一文件里同时“加 import + 替换逻辑 + 插入新 helper + 删除旧函数”
目标：一次调用完成 4 种操作，且每块都有足够上下文，避免误匹配。
要点：不同区域用不同 @@ [id:n] 分块，互不干扰。

*** Begin Patch
@@ [id:1]
-import json
+import json
+import re
 from pathlib import Path

@@ [id:2]
 def normalize_user_input(text: str) -> str:
-    return text
+    text = (text or "").strip()
+    # 压缩多余空白，减少提示词抖动
+    text = re.sub(r"\\s+", " ", text)
+    return text

@@ [id:3]
 def load_config(path: str) -> dict:
     cfg_path = Path(path)
     if not cfg_path.exists():
         return {}
     data = cfg_path.read_text(encoding="utf-8")
     return json.loads(data)
+
+def safe_get(cfg: dict, key: str, default=None):
+    if not isinstance(cfg, dict):
+        return default
+    return cfg.get(key, default)

@@ [id:4]
-def legacy_parse_flags(argv):
-    # deprecated, kept for compatibility
-    flags = {}
-    for item in argv:
-        if item.startswith("--"):
-            k, _, v = item[2:].partition("=")
-            flags[k] = v or True
-    return flags
-
 def main():
     cfg = load_config("config.json")
     # ...
*** End Patch

5) 删除示例：删除一整段“废弃配置块”，并顺手修正周围空行（多行删除 + 上下文）
目标：删掉 DEPRECATED_* 配置和旧注释，确保删除位置精确。
要点：删除行必须逐行 `-`；保留上下文行确保定位。

*** Begin Patch
@@ [id:1]
 # ==============================
 # Runtime Config
 # ==============================
-DEPRECATED_TIMEOUT = 5
-DEPRECATED_RETRIES = 1
-# 注意：这些字段将在下个版本移除
-# 请迁移到 NEW_TIMEOUT / NEW_RETRIES
 NEW_TIMEOUT = 30
 NEW_RETRIES = 3
*** End Patch

如何写“带上下文”的正确姿势（要点）

- 上下文要选“稳定锚点”：函数签名、类名、关键注释、紧邻的两三行缩进代码。
- 不要用“容易变的行”当唯一锚点：时间戳、日志序号、随机 id、生成内容片段。
- 上下文必须字节级一致（空格/Tab/大小写/标点都算），否则会匹配失败。

反面案例（至少 3 个，且都是“真实会踩坑”的类型）

反例 A（来自一次常见错误）：空文件时只有第一行加了 `+`，后面直接贴正文
这会让后面的正文变成“上下文锚点”，工具会去空文件里找这些原文，必然失败（常见报错：未找到匹配的原文）。

*** Begin Patch
@@ [id:1]
+
仰望U9X·电驭苍穹
银箭破空电光闪
三千马力云中藏
*** End Patch

正确做法：正文每一行都要写 `+`（包括空行也写 `+`）。

（对应的正确 patch 示例：向空文件追加多行）

*** Begin Patch
@@ [id:1]
+
+仰望U9X·电驭苍穹
+银箭破空电光闪
+三千马力云中藏
*** End Patch

反例 B：想“插入到中间”，却只写 `+`（没有任何上下文/删除行）
这种块会被当成“追加到文件末尾”，结果内容跑到文件最后，不会插入到你以为的位置。

*** Begin Patch
@@ [id:1]
+# 我以为会插到某个函数上面
+print("hello")
*** End Patch

正确做法：用上下文锚定插入点（见正面案例 2）。

（对应的正确 patch 示例：用上下文把内容插入到函数内部，而不是追加到文件末尾）

*** Begin Patch
@@ [id:1]
 def main():
     config = load_config("config.json")
+    # 这里插入：启动提示（不会移动到文件末尾）
+    print("hello")
     run(config)
*** End Patch

反例 C：补丁在第一个 `@@` 之前出现内容 / 或漏掉 Begin/End 标记
解析会直接报格式错误（例如：“在检测到第一个 @@ 块之前出现内容”、“缺少 Begin/End 标记”）。

（错误形态示意）
这里先写了一段说明文字（没有 @@）
@@ [id:1]
+...

正确做法：确保第一段非空内容必须从 `@@ [id:n]` 开始，并且整体有 Begin/End。

（对应的正确 patch 示例：完整结构、第一段内容从 @@ 块开始）

*** Begin Patch
@@ [id:1]
 # ==============================
 # Runtime Config
 # ==============================
+# 说明：此处新增一行注释作为示例
 NEW_TIMEOUT = 30
*** End Patch
