循环、图与骨架工程
第 13 章经营的是模型"看到什么"——窗口里装什么、裁掉什么、留下什么。这一章换个视角:模型之外的所有工程结构。同一个模型,装进不同的骨架,表现可以天差地别;循环怎么跑怎么停、复杂流程怎么编排、整套骨架怎么分层搭起来—…
第 13 章经营的是模型"看到什么"——窗口里装什么、裁掉什么、留下什么。这一章换个视角:模型之外的所有工程结构。同一个模型,装进不同的骨架,表现可以天差地别;循环怎么跑怎么停、复杂流程怎么编排、整套骨架怎么分层搭起来——这些模型"看不见"的工程决策,才是可靠性的真正来源。本章位于"第五章 怎么做得可靠"的核心位置,分三部分展开:先讲最具体的循环工程(让循环该停时停、偏航时正、失控时刹),再讲图工程(复杂流程的显式编排),最后用骨架工程(Harness)收官——把前两部分所做的一切升华成体系化的总纲。
1. 循环工程:让循环安全地跑
Agent 的本质是循环(第 8 章),而循环的本质是风险——没有循环,错误止于一次调用;有了循环,一个错误会被放大成整个任务的失败。第 8 章给了四道闸门做应急处理,这一部分把它扩展成系统的循环工程学:怎么让循环该停时停、偏航时正、失控时刹。
1.1 循环的三种死法
先病理分析。Agent 循环的失败模式归为三类(第 8 章见过前两类):
死法一:打转(oscillation)
search[天气] → 结果不满意 → search[天气] → …… ← 第 8 章的重复检测
死法二:发散(drift)
任务:写周报 → 中途开始"优化模板" → 又开始"调研工具" → 忘了初衷
每步都"合理",整体离题万里——目标漂移
死法三:滚雪球(cascade)
轮次↑ → 上下文↑ → 注意力稀释 → 判断质量↓ → 更多无效调用 → 轮次↑
正反馈循环,越跑越糟
死法一有现成解药(重复检测)。死法二和三更隐蔽:每一步单看都没毛病,是宏观行为坏了——这就是循环工程要处理的核心难题:微观合理性与宏观失控的矛盾。
1.2 终止工程:什么时候该停
终止不止"达到上限就砍"(第 8 章的粗暴版本)。完整的终止设计分三层:
成功终止
模型不再调用工具、给出最终答案——这是自然出口。但自然出口 ≠ 正确出口:模型可能在证据不足时提前"自信作答"(第 9 章见过:搜一次就作答)。对策是在系统提示词里定义完成标准("必须交叉验证两个来源才能回答"),而不是任由模型自己感觉"差不多了"。
资源终止(硬止损)
第 8 章的四道闸门完整版。这里补一个关键的工程细节——各级闸门的关系应该是嵌套的软硬结合:
# 软闸门:先警告,给模型自纠的机会
if self.tokens_used > self.budget * 0.7:
if not self._warned:
self.messages.append({"role": "user",
"content": "提示:token 预算已使用 70%。请尽快总结当前成果并收尾。"})
self._warned = True
# 硬闸门:无情切断
if self.tokens_used > self.budget:
return self._partial_result() # 带着部分成果退出,而不是空手
_partial_result 值得展开:硬闸门触发时,让模型基于已有信息输出一个"目前最佳答案",比直接抛"任务失败"有价值得多——已消耗的成本换点残值回来:
def _partial_result(self) -> str:
resp = client.chat.completions.create(
model=self.model,
messages=self.messages + [{
"role": "user",
"content": "预算已用尽。请基于已收集到的信息,"
"给出当前最佳的不完整答案,并注明局限。",
}],
)
return resp.choices[0].message.content
语义终止(质量止损)
资源闸门防的是"跑太久",语义闸门防的是"跑着跑着没意义":
def _goal_check(self, original_task: str) -> bool:
"""每 N 轮做一次目标对齐检查"""
resp = client.chat.completions.create(
model=self.model, temperature=0,
messages=[
{"role": "system",
"content": "判断当前进度是否仍在服务原始任务。"
"只输出 ALIGNED 或 DRIFTED。"},
{"role": "user",
"content": f"原始任务:{original_task}\n\n"
f"最近的行动:{self.recent_actions_summary()}"},
],
)
return resp.choices[0].message.content.strip() == "ALIGNED"
对准的是死法二(目标漂移):每 5 轮花一次廉价调用检查"还在正道上吗"。发现 DRIFTED 时的处置不是杀掉重来,而是注入纠偏消息("你正在偏离任务,请回到:{original_task}")——下一节的纠偏机制。
1.3 纠偏工程:偏航时怎么正
终止是最后手段,纠偏是日常操作。核心思想:循环里要有"负反馈"——不是让模型一直往前跑,而是持续校准它。
三类纠偏信号(按介入强度):
# ① 结果型纠偏:工具返回了错误信息(第 7 章的既有模式)
# 模型看到 "参数校验失败:..." 通常下一轮自己修正
# ② 提示型纠偏:框架检测到模式问题,注入 user 消息
def _inject_correction(self, issue: str, guidance: str):
self.messages.append({
"role": "user",
"content": f"[系统提示] 检测到问题:{issue}。{guidance}",
})
# 用例:重复调用后 → "你已连续3次做相同调用,请更换策略"
# 目标漂移后 → "当前行动偏离了原始任务,请回到:{task}"
# ③ 结构型纠偏:重置部分状态(最重)
def _structural_reset(self):
"""保留任务和关键结论,丢弃失败过程"""
self.messages = [
self.messages[0], # system
{"role": "user", "content": self.original_task},
{"role": "assistant",
"content": f"已完成部分:{self.achieved_summary}。"
f"失败尝试:{self.failed_summary}(避免重复)。"},
]
③ 是第 12 章"干净上下文"思想在单 Agent 内的应用:与其在污染的上下文里挣扎,不如带着摘要重开。"重启"不是失败,是循环工程的正常工具。
1.4 循环形状的设计:不是所有循环都该一样
第 8 章的循环是"自由循环"(模型全权决定下一步)。实际上不同任务适合不同形状:
| 形状 | 结构 | 适合 | 风险 |
|---|---|---|---|
| 自由循环(ReAct 式) | 模型每轮自选动作 | 探索型任务(调研) | 死法一二三 |
| 阶段循环 | 固定阶段(分析→执行→验证),阶段内自由 | 流程明确的复杂任务 | 阶段间信息损耗 |
| 双层循环 | 外层规划、内层执行(Plan-Execute) | 长任务 | 计划赶不上变化 |
阶段循环的实现骨架(第二部分图工程的雏形):
PHASES = ["analyze", "execute", "verify"]
def run_phased(self, task: str):
context = {"task": task, "findings": []}
for phase in PHASES:
phase_prompt = self.phase_prompts[phase].format(**context)
self.messages.append({"role": "user", "content": phase_prompt})
# 阶段内跑第 8 章的标准循环(限更小轮次)
result = self._bounded_loop(max_rounds=3)
context["findings"].append(result)
# 阶段间质量控制:verify 不过可以折返
if phase == "verify" and self._failed(result):
return self.run_phased(task) # 或定向折返 execute
return context["findings"][-1]
自由度是资源,不是越多越好:确定性强的部分用结构锁定,探索性的部分留给模型(第三部分原则四的又一次应用)。verify 阶段的存在本身是重要的循环设计——Agent 的循环里要有"自我验证"的环节,让"完成"是验证过的判断而非模型的自我感觉。
1.5 失控保险丝:最后的防线
汇总成一张保险丝配置表(生产前自查):
| 保险丝 | 阈值 | 动作 |
|---|---|---|
| 轮次上限 | 任务复杂度 + 2(如 8~10) | 软警告 → 硬止损+部分结果 |
| token 预算 | 70% 警告 / 100% 止损 | 同上 |
| 重复检测 | 连续 3 次相同调用 | 注入纠偏 → 重置状态 |
| 目标漂移 | 每 5 轮检查 | 注入纠偏 → 终止 |
| 副作用频率 | 单轮写操作 > N 次 | 熔断(第 15 章 fail-closed) |
| 壁钟时间 | 任务级超时(如 10 分钟) | checkpoint + 终止 |
最后一条"壁钟时间"单独强调:它是唯一不属于模型维度的保险丝。LLM 推理的延迟波动大(第 4 章:prefill 随输入长度变化),没有任务级超时的 Agent,一次 API 卡顿就能挂住你的整条流水线。框架层的 timeout 必须存在,哪怕设得很宽松。
第一部分小结
- 三种死法:打转(有解药)、发散(目标漂移)、滚雪球(质量正反馈恶化)——后两个是微观合理宏观失控
- 终止三层:成功终止(要定义完成标准)、资源终止(软硬闸门+部分结果)、语义终止(目标对齐检查)
- 纠偏三层:结果型(工具错误自纠)→ 提示型(注入系统消息)→ 结构型(带摘要重启)
- 循环形状按任务选:自由/阶段/双层——自由度是资源,确定性部分用结构锁定
- 保险丝六条:轮次/预算/重复/漂移/副作用/壁钟时间——最后一条与模型无关但必须有
循环解决了"步骤间的动力",但当整个任务有复杂的阶段依赖和分支走向时,需要把循环进一步结构化——状态图。
2. 图工程:把流程变成代码里的一等公民
自由循环(第 8 章)像即兴爵士,模型随手发挥;阶段循环(第一部分)像固定曲目单;而当任务有复杂的状态依赖、条件分支、并行汇合——你需要的是一张显式的图。这一部分讲图工程(Graph Engineering):把工作流从"模型的即兴发挥"变成"代码里的一等公民",以及什么时候该做(和不该做)这个转变。
2.1 从代码顺序到图
先看熟悉的代码形态(第一部分的阶段循环):
result = analyze(task)
result = execute(result)
if not verified(result):
result = execute(result) # 折返重试
return report(result)
它隐含了一张图,但图埋在控制流里——想改流程(比如 verify 失败要回到 analyze 而不是 execute),得改代码结构。图工程的主张:把流程本身升为显式数据结构:
┌──────────┐
│ analyze │
└────┬─────┘
▼
┌──────────┐
┌───▶│ execute │
│ └────┬─────┘
│ ▼
│ ┌──────────┐ fail
└──│ verify │────────┐
└────┬─────┘ ▼
│ pass ┌────────┐
▼ │ retry │──┐
┌────────┐ └────────┘ │(计数)
│ report │ ……
└────────┘
显式化的收益:
| 维度 | 代码控制流 | 显式图 |
|---|---|---|
| 看懂流程 | 读代码+脑内模拟 | 看图 |
| 改流程 | 改代码结构 | 改边/节点配置 |
| 并行分支 | 手写线程/异步 | 声明式 |
| 状态追溯 | 散落各处 | 图执行引擎统一记录 |
| 人机协作 | 难 | 图可以直接给产品/客户看 |
LangGraph、Dify、n8n 这些"工作流/编排"产品,本质都是在做同一件事:图结构的 Agent 编排。
2.2 图的三个基本要素
节点(Node):做一件事的单位
节点是最小的执行单元,内容可以是任何东西:
from dataclasses import dataclass, field
@dataclass
class Node:
name: str
execute: callable # 执行函数:state → state
kind: str = "agent" # agent / tool / human / logic
关键认知:节点不等于 Agent。一个节点可以是一次 LLM 调用(轻)、一个完整的第 8 章 Agent(重)、一段纯代码(判定逻辑)、甚至一次人工介入(第 15 章的确认门)。图是编排层,节点内容自选粒度——这正是第三部分"复杂度搬家"的应用:把流程逻辑从模型搬到图结构,把每个节点内的自由留给模型。
状态(State):贯穿全局的记事本
图执行时,所有节点共享一份状态:
from typing import TypedDict
class WorkflowState(TypedDict):
task: str # 原始任务
findings: list[str] # 各节点产出的累积
attempt_count: int # 重试计数
verified: bool # 验证结论
current_node: str # 执行位置
状态的收敛性设计很重要:图里流动的是"结论"而非"过程"。节点内部(比如一个子 Agent)可以跑得轰轰烈烈,但对外只写关键结论进 state——第 13 章上下文管理的图级版本:每个节点只消费和产出必要信息。
边(Edge):转移规则
@dataclass
class Edge:
source: str
target: str
condition: callable = None # 条件边:state → bool
边的两种形态:直边(无条件转移)和条件边(路由函数决定去向)。条件边是图的智慧所在——verify 之后去 report 还是回 execute,由 condition(state) 的代码逻辑决定,确定性路由留在代码,不确定性留给节点内的模型。
2.3 实现一个最小的图引擎
一个能跑的迷你引擎(麻雀虽小,五脏俱全——节点/边/状态/条件路由/循环):
from typing import Callable
class Graph:
def __init__(self):
self.nodes: dict[str, Callable] = {}
self.edges: list[Edge] = []
def add_node(self, name: str, fn: Callable):
self.nodes[name] = fn
def add_edge(self, source: str, target: str,
condition: Callable | None = None):
self.edges.append(Edge(source, target, condition))
def run(self, initial_state: dict, start: str,
max_steps: int = 20) -> dict:
state = initial_state
current = start
for step in range(max_steps): # 第一部分的保险丝
state["current_node"] = current
state = self.nodes[current](state) # 执行节点
# 找下一个节点:优先匹配条件边
next_node = None
for e in self.edges:
if e.source != current:
continue
if e.condition is None or e.condition(state):
next_node = e.target
break
if next_node is None: # 没有出边 = 自然终点
return state
current = next_node
raise RuntimeError("图执行超过步数上限(疑似环死循环)")
用它搭第一部分那个"分析→执行→验证"流程的完整版:
g = Graph()
def analyze(state):
state["findings"].append(f"分析结果: {state['task'][:20]}...")
return state
def execute(state):
state["findings"].append("执行结果: ...")
return state
def verify(state):
state["verified"] = len(state["findings"]) >= 2 # 演示用判断
return state
def report(state):
state["final"] = "\n".join(state["findings"])
return state
g.add_node("analyze", analyze)
g.add_node("execute", execute)
g.add_node("verify", verify)
g.add_node("report", report)
g.add_edge("analyze", "execute")
g.add_edge("execute", "verify")
g.add_edge("verify", "report", condition=lambda s: s["verified"])
g.add_edge("verify", "execute",
condition=lambda s: not s["verified"] and s["attempt_count"] < 3)
result = g.run({"task": "写周报", "findings": [],
"attempt_count": 0}, start="analyze")
print(result["final"])
对照第一部分的阶段循环代码:流程逻辑从 if/for 里浮到了边的声明里。verify→execute 的折返重试从"递归调用"变成了"一条带条件的边"。改流程 = 改图,不碰节点实现。
2.4 图上的高级模式
引擎之上,三个常用的图模式:
并行扇出/扇入(fan-out / fan-in)
┌→ research_A ─┐
analyze ┤ ├→ synthesize
└→ research_B ─┘
research_A 和 B 无依赖可并行跑,synthesize 等齐了再动(第 12 章子代理的图化表达)。实现上扇出节点返回多个后继、扇入节点做 barrier 计数——生产引擎(LangGraph 的 Send API 等)都内置了这个模式。
人工门(human gate)
draft → [human_review] → publish
│ reject
▼
revise → draft
把第 15 章的 human-in-the-loop 做成一个节点:执行时暂停图、通知人、等人回复、带着决定继续。图的持久化状态让"暂停等几天"成为可能(第三部分 checkpoint 的图级版)——审批流这种天然跨天的工作流,只有图结构能优雅承接。
动态图(边由模型决定)
固定图之外,还可以让模型在运行时选择下一条边(路由节点:模型看 state 决定去向)——这其实就是把第 8 章的"模型自选下一步"压缩成单个节点的内部逻辑。固定图和自由循环不是对立的,是同一光谱的两端:
纯代码流程 ── 固定图 ── 混合图(部分边动态)── 路由循环 ── 纯自由循环
(n8n 工作流) (审批流) (客服分流+处理) (第8章ReAct)
2.5 什么时候不该上图
图工程最大的陷阱是过度工程。不该上图的信号:
- 流程只有三步且不会变:if-else 写完五分钟的事,上图是自找复杂度
- 探索性主导的任务:调研类任务下一步做什么取决于上一步发现什么,预定义的图反而限制模型发挥——该用自由循环(第 8 章)
- 流程还在剧烈变化:图结构适合"已知的确定性",摸索期用自由循环收集行为模式,稳定后再固化成图(和第 12 章"Skill 是 MCP 的孵化器"同一思想:自由循环是图的孵化器)
- 团队没有图运维能力:图引擎是个新依赖,调试、监控、版本管理都要学——工具链的账要算
一个可用的决策标准:当你在自由循环里反复写"如果又发生 X 就……"的补丁时,就到了该上图的时候——那说明流程的结构已经从实践中浮现出来了,值得显式固化。
第二部分小结
- 显式图的收益:流程可视、改流程不改代码、声明式并行、状态统一追溯
- 三要素:节点(任意粒度:LLM 调用/完整 Agent/纯代码/人工门)、状态(流动结论不流过程)、边(条件路由,确定性归代码)
- 迷你引擎 60 行:节点执行 + 条件边路由 + 步数保险丝
- 高级模式:扇出扇入(并行)、人工门(跨天暂停)、动态边(模型路由)——固定与自由是光谱不是对立
- 不该上图的四个信号;自由循环是图的孵化器
循环让系统动起来,图让复杂流程有了形状——但它们都只是骨架的一部分。第三部分收官:把模型之外的一切工程结构收进一个体系,看骨架如何决定同一个模型的表现上限。
3. 骨架工程:模型之外的体系(收官)
同一个模型,放进不同的工程骨架,表现天差地别——这层骨架就叫 Harness(脚手架/马具)。第 8 章的 Agent 循环就是一个最小 Harness,本章前两部分做的循环控制与图编排,都是骨架的组成部分。这一部分收官升维:把模型之外的一切工程要素系统化——为什么骨架比模型更能决定成败,好的 Harness 长什么样。它是本章前两部分所做之事的理论升华与体系化总纲。
3.1 模型 × 骨架 = 表现
先看一个思想实验(综合前面各章的知识就能推出来):
同一个 qwen3:4b,装进不同的骨架:
| 骨架 | 表现 |
|---|---|
| 裸调用(一次问答) | 能聊天,复杂任务必挂 |
| + 工具 + 循环(第 8 章) | 能查证、能计算、能多步执行 |
| + 工具 + 循环 + 重试 + 校验(第 6/7 章防御) | 可靠度大幅上升 |
| + 记忆 + 权限 + 预算(第 13、15 章) | 可以托付真实工作 |
模型没变,表现天差地别。这个加法链条就是骨架工程(Harness Engineering)的内容——它不是新概念,是第 7 章到第 13 章所有工程决策的统称,也是本章前两部分(循环工程、图工程)的理论升华。
一个流传很广的判断(源自 Claude Code 等产品的实践观察):模型能力的下限由模型决定,上限由 Harness 决定。前沿团队花在骨架上的工程量,远超 prompt 本身。
3.2 Harness 的解剖图
把第 8 章的 Agent 类按职责重新分层:
┌─────────────────────────────────────────┐
│ Agent Harness │
│ │
│ ┌─────────┐ 模型接口层 │
│ │ 模型调用 │ 超时、重试、降级、备用模型 │
│ └─────────┘ │
│ ┌─────────┐ 工具执行层 │
│ │ 工具系统 │ 权限、沙箱、超时、结果截断 │ ← 第 7/11/15 章
│ └─────────┘ │
│ ┌─────────┐ 循环控制层 │
│ │ 主循环 │ 轮次、预算、卡死检测 │ ← 第 8 章
│ └─────────┘ │
│ ┌─────────┐ 上下文层 │
│ │ 上下文 │ 组装、裁剪、预算分配 │ ← 第 13 章
│ └─────────┘ │
│ ┌─────────┐ 反馈层 │
│ │ 校验重试 │ 输出校验、失败重试、自纠错 │ ← 第 6 章
│ └─────────┘ │
│ ┌─────────┐ 观测层 │
│ │ 事件审计 │ 轨迹、日志、熔断 │ ← 第 8/15 章
│ └─────────┘ │
└─────────────────────────────────────────┘
六层每层都独立可测、可换。分层的价值在此刻兑现:换模型只动接口层(第 5 章的"模型当配置")、加安全只动执行层、调上下文策略不碰循环。
3.3 三层最容易被低估的骨架能力
有些骨架组件的重要性常被低估,单独展开。
错误恢复:失败是常态
第 6 章的校验-重试是单次调用的恢复。任务级的恢复更粗粒度:
def run_with_recovery(self, task: str, max_retries: int = 2) -> str:
for attempt in range(max_retries + 1):
try:
result = self.run(task)
if not self._looks_failed(result): # 启发式检查结果质量
return result
failure_reason = "结果质量可疑"
except Exception as e:
failure_reason = str(e)
if attempt < max_retries:
# 带着教训重试:失败原因进入下一轮的系统提示词
self.messages.append({
"role": "user",
"content": f"上次尝试失败({failure_reason})。"
f"请换一种策略重新完成任务。",
})
self._cleanup_partial_work() # 回滚半成品副作用
return self._fallback_answer(task) # 优雅降级
两个关键设计:失败原因要进入重试的上下文(不带教训的重试是重复撞墙);有副作用要回滚(写了半个文件的任务重试,先清掉残留——否则下次运行环境已脏)。
中断与恢复:长任务的存档点
Agent 跑 20 分钟的任务,中途崩了怎么办?——checkpoint 机制:
def checkpoint(self, task_id: str):
"""把当前状态序列化——messages + 关键中间产物"""
state = {"messages": self.messages,
"round": self.current_round}
Path(f".checkpoints/{task_id}.json").write_text(
json.dumps(state, ensure_ascii=False), encoding="utf-8")
def resume(self, task_id: str) -> bool:
"""从最近的存档点恢复"""
p = Path(f".checkpoints/{task_id}.json")
if not p.exists():
return False
state = json.loads(p.read_text(encoding="utf-8"))
self.messages = state["messages"]
self.current_round = state["round"]
return True
每轮循环末尾存一次档。这是长任务生产化的分水岭——不能断点续跑的 Agent 只能处理玩具任务。
流式反馈:可感知的进展
第 5 章说过流式不省时间只省焦虑。对 Agent 加倍成立:多轮任务动辄几分钟,黑盒等待会杀死用户的信任。第 8 章的事件系统在这里再兑一次现——把 TOOL_CALL 事件实时推给用户("正在查询天气…""正在读取文件…")。工程含义:Harness 的观测层同时是 UX 层,一份数据两个消费者。
3.4 Harness 的设计原则
收拢成四条(全部来自前文的实践):
原则一:模型不可靠,骨架要可靠。所有"模型应该会做对"的地方都要问:它做错了,谁来兜底?——校验(第 6 章)、闸门(第 8 章)、确认(第 15 章)。骨架的存在意义就是把概率行为约束在安全轨道上。
原则二:每层可独立替换。模型会升级(接口层)、工具会增删(执行层)、策略会调整(上下文层)——耦合了任何两层的代码都会在未来某天让你重写整个系统。
原则三:可观测优先于聪明。一个平庸但全轨迹可见的 Agent,好过一个聪明但黑盒的 Agent——前者可调试可改进,后者出问题时你只能盯着结果发呆(第 15 章的根基)。
原则四:复杂度守恒,只是搬家。把决策从模型搬到代码(确定性增强),或从代码搬到模型(灵活性增强),复杂度没有消失只是换了地方。Harness 设计的艺术在于把确定性要求高的复杂度搬进代码,把探索性的复杂度留给模型。
3.5 实例:从第 8 章的 Agent 到完整 Harness 的差距
盘点第 8 章的 Agent 类距离生产 Harness 还缺什么(也是自查清单):
| 缺口 | 解法 | 状态 |
|---|---|---|
| 模型调用无重试/超时 | 接口层加 retry + timeout + 备用模型 | 本章 3.3 |
| 无 checkpoint | 每轮存档 | 本章 3.3 |
| 无流式反馈 | 事件转发到用户界面 | 本章 3.3 |
| 无成本核算 | 第 8 章有预算闸门,缺分项记账(模型/工具/记忆各花多少) | 第 15 章 |
| 无评测基线 | 改动无从验证好坏 | 第 15 章 |
| 并行能力 | 子代理(第 12 章)已在架构上就绪 | ✓ |
这个表也解释了骨架工程为什么能担纲本章收官:它是本章前两部分所做之事的理论升华与体系化总纲,也是通往第 15 章的地基——度量的对象不是模型,是整个 Harness。
3.6 收官:五个工程层次的全景
至此五个 Engineering 讲完,用一张全景图收束(也是第 13 章与本章的复习):
┌────────────────────────────────────────────────┐
│ Agent 系统 │
│ │
│ Prompt Eng. 怎么把一件事说清楚(13 章) │
│ ↓ 每条指令进入 │
│ Context Eng. 窗口里装什么(13 章) │
│ ↓ 每轮组装成 │
│ Harness Eng. 系统骨架怎么搭(本章) │
│ ↓ 骨架的运行时是 │
│ Loop Eng. 循环怎么跑怎么停(本章) │
│ ↓ 复杂流程结构化为 │
│ Graph Eng. 流程怎么编排(本章) │
└────────────────────────────────────────────────┘
五个层次从微观(一句话)到宏观(整个系统),每一层解决不同粒度的问题——它们不是竞争关系,是同一个人在不同抽象高度看同一个系统。
第三部分小结
- 模型能力下限由模型决定,上限由 Harness 决定——骨架工程量远超 prompt 本身
- 六层解剖:模型接口 / 工具执行 / 循环控制 / 上下文 / 校验重试 / 观测审计——每层独立可换
- 三个易低估的骨架能力:任务级恢复(带教训重试+副作用回滚)、checkpoint 续跑、流式反馈(观测层即 UX 层)
- 四原则:模型不可靠骨架可靠、每层可换、可观测优先、复杂度搬家艺术
- 第 8 章的 Agent + 本部分缺口清单 = 一个真实可用的 Harness 全貌
- 五个 Engineering 全景:说清楚 → 装对东西 → 搭好骨架 → 控制循环 → 编排流程
至此,三大工程的全貌齐了:循环负责"怎么跑、怎么停",图负责"复杂流程怎么编排",Harness 把它们连同上下文、工具、校验一起收进可替换、可观测、可托付的体系。只剩最后一件事:把它送上生产,并用数据证明它做得好。
下一篇:15 · 记忆、权限与评测