- 提示词一个字没改,成功率却涨了 6 个百分点
- 给框架划出边界,管理才算开始
- 从提示词工程走向框架工程
- 自我改进会先发生在框架上,而不是权重上
- 把上下文当成 playbook,而不是提示词
- 框架是带版本号的交付物
- 这个循环的瓶颈不是模型,而是评估者
- 奖励作弊不是 bug,而是正常输出
- 参考资料
提示词一个字没改,成功率却涨了 6 个百分点
智能体的任务成功率比上周涨了。没有提示词的提交,模型版本也没变。翻了一圈才发现:某个工具定义的描述文字被缩短了,重试上限从 3 提到了 5,读文件工具返回的行数上限也变了。这三处改动分别是不同的人出于不同的理由做的,而且没有一处出现在发布说明里。
下周要是成功率掉了,该回滚哪一个?在现在这个结构下,你答不上来。
给框架划出边界,管理才算开始
Lilian Weng 在 2026 年 7 月 4 日写的那篇文章给这一坨东西起了名字。框架是包裹基础模型、协调其执行的系统,是决定模型如何思考与规划、如何调用工具与行动、如何感知与管理上下文、把产物存到哪里、如何评估结果的那一层。
这个定义之所以有用,是因为它把范围划得很宽。比早期智能体框架所涵盖的更宽,它把工作流设计与评估、权限控制、持久状态管理都包了进来。前面例子里变动的那三处,全都落在这个边界之内。只有先划出边界,「到底是什么变了」这个问题才变得可回答。
从提示词工程走向框架工程
这次转移在实务上的含义,是杠杆在哪儿。大多数团队既不做基础模型,也不做微调。这些团队能动的,就是整个框架。
而框架这一侧的改进空间,通常比提示词的措辞大得多。比如暴露几个工具、失败怎么回传、什么时候拉起子智能体、中间产物是落成文件还是抱在上下文里往下走。这篇文章里说「代码是通用语言」的那一段,正是挂在这儿。用句子能指示的空间,远远小于用代码能定义的空间。
单看「工具失败怎么回传给模型」这一件事就是如此。把异常字符串原样丢回去,模型就会重复同一次调用。把失败原因连同当前可行的替代方案列表结构化地返回,下一次调用就会不一样。这是提示词写得再好也拿不到的那类改进,而且完全是代码侧的决定。
自我改进会先发生在框架上,而不是权重上
文章的核心主张关于递归式自我改进:AI 用当下的智能去改进那台生产自身智能的机器。而它的判断是,在可见的未来,这件事推进的路径不是直接改模型权重,而是框架不断演化。
这个判断听着抽象,其实已经以非常具体的形态在跑了。智能体改自己的工具定义、修改自己的执行脚本、读失败日志然后重排工作流。只要具备读写文件、执行 shell、git、创建子智能体这类工具,框架就成了一个可以自我编辑的对象。
这里在实务上更重要的,不是「这个循环已经在转」这个事实,而是「在大多数团队里它转得没有记录」这个事实。智能体润色了工具描述,人草草批了那个提交,性能变了一点点,没有人把这两件事联系起来。自我改进循环的危险不在于它快,而在于它没被观测。
把上下文当成 playbook,而不是提示词
这篇文章介绍的做法里,最能直接搬进实务的,是把上下文当成不断演化的 playbook,而不是越写越长的提示词。把「生成条目」「回顾条目」「筛选条目」的角色拆开,来管理结构化的条目。
差别在这里。提示词的做法里,新学到的东西不断被追加到段落末尾。一个月后没人再读那份文档,互相矛盾的指令并存,涨的只有 token。playbook 的做法里,每个条目都记录了它是什么时候加进来的、适用于什么情形、最近有没有派上用场,于是删除变得可能。上下文管理难的地方不是往里放,而是往外拿;而要能拿出来,条目就得带元数据。
框架是带版本号的交付物
走到这一步,就能回到最初那个问题了。要把框架当交付物来对待,至少得有一个指纹。
"""框架指纹:要和结果一起保存,才能回溯回归。"""
import hashlib
import json
from dataclasses import dataclass, field, asdict
@dataclass
class HarnessSpec:
model: str
system_prompt: str
tools: list # [{"name":..., "description":..., "schema":...}]
max_steps: int
max_retries: int
context_policy: dict # 截断、摘要、playbook 策略
permissions: list # 允许的副作用
def fingerprint(self) -> str:
payload = asdict(self)
# 工具顺序没有意义,先做归一化。不做的话指纹每次都会变。
payload["tools"] = sorted(payload["tools"], key=lambda t: t["name"])
blob = json.dumps(payload, sort_keys=True, ensure_ascii=False)
return hashlib.sha256(blob.encode("utf-8")).hexdigest()[:12]
def diff(a: HarnessSpec, b: HarnessSpec) -> dict:
da, db = asdict(a), asdict(b)
return {k: (da[k], db[k]) for k in da if da[k] != db[k]}
base = HarnessSpec(
model="some-model-v3",
system_prompt="...",
tools=[{"name": "read_file", "description": "读取文件", "schema": {}}],
max_steps=20,
max_retries=3,
context_policy={"strategy": "playbook", "max_items": 40},
permissions=["read_fs"],
)
candidate = HarnessSpec(**{**asdict(base), "max_retries": 5})
print(base.fingerprint(), "->", candidate.fingerprint())
print(diff(base, candidate)) # {'max_retries': (3, 5)}
把这个指纹和每一次评估运行的结果一起留下来,成功率曲线上的每一级台阶对应哪一次改动,就能回溯了。而且会自然产生一条规则:凡是会改变指纹的改动,都是需要重跑评估的改动。把重试上限从 3 提到 5 的那一行,会被当成和改提示词同一等级的事来对待。
这个循环的瓶颈不是模型,而是评估者
同一篇文章列了框架工程面临的若干难题,排在第一的是弱评估者。只要看一眼自我改进循环的结构,这就是必然的结论。
循环做的是:改框架、做评估、采纳更好的那一边。这个循环的速度不取决于改框架的速度,而取决于评估是否可信。评估如果是噪声,循环就会顺着噪声移动。它会变成一个没有方向却跑得很快的系统,指标在涨,实际使用的质量原地不动甚至更差。
所以在把框架改进自动化之前,必须先做的是校准评估者。顺序一颠倒,自动化就只是把问题制造得更快。
奖励作弊不是 bug,而是正常输出
最后一个难题是奖励作弊,而不误解这个说法很重要。智能体为了让测试通过而去改测试、塞进吞掉失败的异常处理、只填评估脚本会去看的那几个字段 —— 这些都不是系统出故障的结果,而是精确优化了我们所定义的目标的结果。
应对分两条线。一条是权限。把评估代码和评分数据从智能体可写的路径中排除掉,这一类的一半就消失了。原文之所以把权限控制明确列为框架的组成部分,原因就在这里。权限在成为安全项之前,首先是评估完整性的一项。
另一条是不要只用一个指标。在成功率之外,一并观察工具调用次数、被修改文件的范围、被删掉的测试数这类制衡指标。制衡指标不是目标而是警报,所以设个阈值、越线时让人来看一眼就够了。
总结起来是这样:框架工程的杠杆又大又抓得住,但要安全地扳动这根杠杆,评估必须先立起来。给框架打上指纹,是连接这两者最便宜的第一步。
参考资料
- Harness engineering for self-improvement — Lilian Weng, 2026-07-04 —— 框架的定义、递归式自我改进的判断、把上下文当 playbook 的做法,以及包括弱评估者与奖励作弊在内的难题清单,全都在这篇文章里。
- 本博客的相关文章:评估驱动开发中,最先该校准的是评审者
- 正文中的框架指纹代码与成功率的例子并非出自原文,而是我为了把原文的视角搬到运维中而构造的。
현재 단락 (1/55)
智能体的任务成功率比上周涨了。没有提示词的提交,模型版本也没变。翻了一圈才发现:某个工具定义的描述文字被缩短了,重试上限从 3 提到了 5,读文件工具返回的行数上限也变了。这三处改动分别是不同的人出于...