agent-Specialization/doc/write_file_diff_description.txt
2025-12-14 04:22:00 +08:00

238 lines
8.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

使用统一 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