1. 为什么单程生成总是不达标:Loop Engineering要解决的那个核心麻烦
经常有朋友问我,为什么同一个模型、同样的知识库,别人写的输出就是又准又耐看,我这边一次生成的稿子却老是差口气。我的回答通常很直接:你拿大模型当一次性打印机用了。模型给你一次回答,你拿回去直接用,它错就错、浅就浅、乱就乱,你没有给它第二次机会。
Loop Engineering这个名字这两年才热起来,但它背后的思路一点都不新。你回想一下自己在公司里怎么带新人:你不可能逼着一个实习生一次交一份完美方案,正常流程是让他先出初稿,你审一遍挑出问题,打回去让他改,改完再看,直到达到标准才放行。这个"初稿—审阅—修改—再审阅"的闭环,就是Loop Engineering的原型。只不过现在我们把"实习生"换成了大语言模型,把"审阅的人"换成了一组精心设计的Prompt,把整个流程从人工盯梢变成了程序自动跑。
那为什么不直接写一个更长的Prompt让模型一步到位?因为语言模型的一次性生成能力是有硬上限的。它的注意力在长上下文里会衰减,它没有能力在生成的同时对自己的输出做真正的批判性审视,而且"一次成型"意味着所有逻辑决策、措辞选择、事实核查都在同一个瞬时上下文里同时发生。你让它在一次生成中既当写手又当编辑又当校对,结果往往是哪头都顾不好。Loop Engineering的核心思路恰好相反:把"生成"和"评估"拆成两个节点,让它们各自专注一件事,然后通过一个受控的反馈回路迭代逼近目标输出。这不是调Prompt的技巧,是一套小型工程系统——这也是它配得上Engineering这个词的原因。
这篇不是泛泛介绍概念,我会把反馈环路的每个零件拆开讲清楚,再带一个完整的、可以直接抄的项目——一个自动打磨营销文案的循环系统,从Prompt设计到Python代码一次跑通。适合想让LLM输出质量上一个台阶的开发者、提示工程师,以及正在做Agent和自动化内容管线的人。
2. 一条能跑的反馈环需要哪几个零件:不止是"让它改改"这么简单
很多人第一次听说Loop Engineering,以为就是在代码里写个for循环,把Prompt调两次。真这么干,你会得到一个很尴尬的结果:模型改了三轮,输出反而比第一轮更差。原因很简单,你只搭了"改"这个动作,没有搭"判断改得好不好"和"改完为什么能变好"这两个关键环节。一条结构完整的反馈回路,至少需要五个零件。
2.1 生成器:干粗活的那个模型节点
生成器是环路的主执行者,负责产出当前版本的输出。它必须明确知道"现在是第几轮改动、上一版被指出了哪些问题、本次要求改成什么样"。很多失败案例就是没把历史信息传给生成器,它每一轮都在凭空重写,自然在原地打转。
我在设计生成器的Prompt时,通常采用这样的信息结构:
- 当前草稿全文
- 修订需求列表(每条需求标清优先级)
- 历史修订记录(上一轮改了什么、为什么改,避免来回横跳)
生成器的temperature也要单独控制。初稿阶段可以稍微放开一点(0.7左右),修订阶段最好降到0.3以下——修订时你需要的是稳定的、按指令执行的输出,不需要太多创造性漂移。
2.2 评估器:给输出打分的裁判节点
评估器是整个环路质量的基石。它可以是另一个LLM(也就是常说的LLM-as-Judge),也可以是一组规则代码,更常见的是两者结合。
规则代码擅长检查硬性标准:字数范围、必含关键词、禁用词、JSON格式合法性、URL有效性。LLM擅长判断软性标准:逻辑是否连贯、语气是否一致、说服力如何、结构是否清晰。一个可靠的评估器应该把这两者都纳入,否则你很可能遇到"模型自评每轮都是9分,拿给真实用户看却完全不是那么回事"的尴尬。
我自己的经验是,评估器Prompt里必须有一份评分卡(Rubric)。评分卡不是泛泛写"请评估这段文字的质量",而是把质量拆成几个可判断的维度,每个维度给出具体的评分基准。比如文案类任务,我常用这四个维度:
| 维度 | 5分描述 | 3分描述 | 1分描述 |
|---|---|---|---|
| 清晰度 | 核心卖点无歧义,结构一眼可读 | 部分信息含糊,但整体可懂 | 读两遍不知道在说什么 |
| 说服力 | 有明确逻辑链,证据支撑充分 | 有些观点无支持 | 全篇断言,无展开 |
| 结构 | 有抓眼开头、步步递进、收束有力 | 顺序合理但不吸引 | 段落堆砌 |
| 合规性 | 无绝对化用语,无未证实承诺 | 基本合规但遗漏1处 | 存在明显风险表述 |
评分卡的价值在于把评估器从"凭感觉打分"变成"按证据打分",也让生成器收到反馈时知道具体哪里不行。
2.3 反馈管道:把"评价"变成"修改命令"
这是大多数人会忽略的一环。评估器输出的原始结果往往是很长一段评价文字,直接塞给生成器让它"自己看着办",它很容易被淹没在信息里。正确做法是让评估器输出结构化反馈,比如JSON格式:
{ "dimension_scores": { "清晰度": 3, "说服力": 4, "结构": 2, "合规性": 5 }, "top_issues": [ { "dimension": "结构", "quote": "从第二段开始的每段都在解释产品功能,缺少层次", "suggestion": "把功能拆成3个小标题,按'痛点-方案-收益'顺序重排" }, { "dimension": "清晰度", "quote": "第一段没有说明产品适用人群", "suggestion": "首段前两句话直接点出目标用户是谁" } ] }然后把这份JSON用json.dumps()转成紧凑文本,跟"请严格按照top_issues顺序逐条处理"的命令拼在一起喂给生成器。这个过程就是把裁判的口头评论翻译成执行者可执行的任务清单。
注意:一次反馈里问题的数量要克制。我通常只让评估器挑Top2-3个最关键问题,不要超过3个。给生成器一次性甩8条修改意见,它顾此失彼,经常改A坏了B。
2.4 控制器:决定"什么时候停"的循环大脑
控制器是Loop Engineering里最容易体现在代码上的零件——一个while循环或for循环,但关键设计在于停止条件。停止条件分为两类:
- 硬性停止:达到最大迭代次数(预算),强制结束
- 软性停止:这一轮所有维度都超过阈值,或者连续两轮评分都没有提升,提前结束
提前止损非常重要。现实中很多任务在第二轮就达到质量高原,第三轮只是徒增成本,甚至质量下坠。控制器要做的就是在分数出现"平台期"时果断掐断循环,保存历史最优版本。
2.5 记忆:让循环不犯同一个错误的账本
最后是记忆。每一轮迭代的草稿、评分、反馈意见、修改摘要都应该被保存下来。记忆有两个作用:一是给生成器做参考,让它知道哪条路已经试过了、效果不好;二是给控制器做判断依据,检测是否出现"振荡"——即模型在第2轮把第1轮的A问题修好但破坏了B,第3轮修好B又退回了A。一旦检测到振荡,最好的策略不是继续硬跑,而是从历史版本里挑选综合分最高的那个。
到目前为止,你已经看到了一个完整反馈环路的骨架。下面聊聊最关键的一个问题:哪些任务适合开环,哪些任务根本不该绕这个圈子。
3. 什么样的任务才值得开环绕圈:任务筛选、阈值设定与成本预算
Loop Engineering不是万金油。我在项目里见过最惨痛的教训,就是有人把数学计算题也塞进一个四轮循环里——模型每一轮都在用不同的错误方式重算同一道题,评估器还煞有介事地越打越高。这就说明任务选错了。
3.1 适合开环的任务有三个特征
第一,任务有明确的质量评判标准。也就是说你知道"好"长什么样,并且能把"好"拆成维度。一篇营销文案好不好,可以从清晰度、说服力、结构、合规性判断;一份技术方案好不好,可以从完整性、可行性、风险暴露程度判断。如果任务连你自己都说不清怎样算好,评估器更说不好,循环就是瞎绕。
第二,任务是一个"逐步逼近"的过程,而不是"一步计算"的过程。写作、策划、方案设计、代码重构、报告润色、话术优化,都属于逐步逼近类。而"3.7乘以8.2等于多少"、"这段代码的时间复杂度是多少"、"把这段文本从中文翻译成英文"这类任务,要么一次算完,要么翻译结果本身有标准答案,循环没有意义。
第三,改进方向是可逆且有连续梯度的。如果模型改完第2轮发现第1轮的某个表达其实更好,它有能力基于反馈改回去。任务空间里有"更好的方向"可探索,而不是非黑即白。比如合规性检查就是非黑即白的,违反就违反,循环改不出合规来,该做的是规则前置过滤。
3.2 几种常见的循环模式对比
Loop Engineering在工程上已经沉淀出好几种典型模式,我画了个表格供你选型:
| 模式 | 核心机制 | 适用场景 | 成本特点 |
|---|---|---|---|
| Self-Refine | 生成器先产出,评估器挑错,生成器修改 | 文案打磨、报告优化 | 每轮2次LLM调用,中等 |
| Reflexion | 不仅改当前输出,还记录"失败经验"供后续任务复用 | 多轮复杂推理、代码调试 | 需要持久化记忆,偏高 |
| ReAct工具循环 | 每轮决定调用什么工具,根据工具结果继续推理 | 需要查资料、算数、检索的Agent任务 | 调用次数不定,成本波动大 |
| Multi-Agent辩论 | 多个角色模型互相批评,汇总出最终答案 | 高难度决策、有争议的写作 | 调用次数多,成本最高 |
| 规则+LLM混合 | 规则程序做硬校验,LLM只优化软性质量 | 有严格格式或合规要求的批量生产 | 最低,规则零成本 |
入门阶段建议从Self-Refine练起。它结构最简单,却能让你把评估器、反馈管道、控制器这套逻辑彻底跑顺。等你观察到"改了三轮之后明显变好"的复现曲线,再往Reflexion和Multi-Agent方向扩展也不迟。
3.3 阈值、迭代次数和成本预算的具体设计
我常用的参数设计方法如下:
- 最大迭代次数:先定
max_iter = 4,然后拿20个真实任务跑一遍,画出每轮评分的分布曲线。如果一个任务平均在2.5轮内收敛,那max_iter定为4是安全的;如果第4轮还在显著提升,可以加到5,但超过5轮的业务性价比通常很低。 - 通过阈值:不要只设一个总分阈值。我推荐"所有维度单项≥3分且总分≥17分(以5维×5分制为例)"。单项阈值的存在是为了防止某维被其他维度拉平均。
- 提前终止:记录连续两轮的维度得分,如果打分无提升或总分下降,就触发终止,从记忆里把当前最优版本捞出返回。
成本方面,做一个粗略但有用的估算:一次循环的token消耗约等于1次初稿生成 + max_iter × (1次评估 + 1次修改生成)。假设初稿和修改都是2000 token输入、500 token输出,评估是600 token输入、200 token输出,那么一个4轮循环的token量大约是:
初稿: 2000 + 500 = 2500 每轮: (2000+600+500) + (500+200) = 3800 总计: 2500 + 4 × 3800 = 17700 token再乘以你用的模型单价,就能算出单任务的成本上限。当单任务成本超过任务本身价值的20%时,循环就得不偿失,应该考虑降低迭代上限或换更便宜的小模型做评估器。
4. 保姆级实战:搭一个文案自动打磨循环,从Prompt到Python代码一次跑通
理论说了半天,下面上一个完整的项目。这个项目的目标很直接:你输入一段粗糙的产品描述,系统自动帮你产出经过多轮打磨的营销文案终稿,每一轮都由AI裁判评分、挑刺、打回重写。我会直接给出可运行的Python代码和全套Prompt模板,照着抄就能跑。
4.1 项目目标和整体管线设计
输入示例(毛坯稿):
我们的电池充电很快,续航也不错,适合出差用。价格在同档位里比较便宜,而且支持快充协议。
输出目标:一段有卖点结构、有用户视角、有说服力的文案,并且清晰度、说服力、结构、合规性四个维度都超过阈值。
整体管线分四步:
- 初稿生成:把毛坯稿扩展成一篇结构完整的初稿
- 评估打分:用评估器按评分卡输出JSON反馈
- 迭代修改:把
top_issues喂给生成器,让它逐条修订 - 循环控制:直到所有维度达标或达到最大轮数,从历史中挑最优版本
4.2 定义评分卡和迭代参数
参数我建议放在配置区,方便调优:
MAX_ITER = 4 MIN_DIM_SCORE = 3 QUALIFY_THRESHOLD = 17 # 四维度满分20,17为达标线 JUDGE_MODEL = "gpt-4o-mini" # 评估用小模型,省钱 GENERATE_MODEL = "gpt-4o" # 生成用大模型,保质 TEMPERATURE_GENERATE = 0.3 TEMPERATURE_JUDGE = 0.0 # 评估器温度必须为0,保证打分稳定性一个关键心得:评估器用便宜的小模型往往就够了,生成器用贵的大模型。因为打分是一项"判断"任务,小模型遵循评分卡的能力并不比大模型差多少;而修订是"创造"任务,大模型的表达和指令遵循能力优势明显。这种组合能省下不少成本。
4.3 生成器Prompt模板
生成器Prompt分为初稿和修订两个版本。初稿版本负责把粗糙输入扩写成结构完整的草稿:
你是一名资深营销文案撰稿人。请把下面这段原始产品描述改写为一篇营销文案初稿。 要求: 1. 开头一句话抓住目标用户注意力 2. 中段按"痛点-方案-收益"结构展开 3. 结尾给出行动引导 4. 语气真诚,避免夸张和绝对化用语 5. 不要编造原始描述中没有的信息 原始描述: {raw_input}修订版本在初稿基础上增加了历史信息和修订指令:
你正在对一篇营销文案进行第 {round} 轮修订。 这是当前草稿: {current_draft} 这是上一轮的评分和评审意见: {feedback_history} 请严格按照下面的修改指令逐条处理,不要遗漏,也不要做额外的大幅改动: {top_issues} 要求: - 只修改与top_issues相关的内容 - 保持全文语气一致 - 不要引入新的绝对化用语和未证实承诺 - 返回修改后的完整文案注意修订Prompt里那句"不要做额外的大幅改动"。这是防漂移的关键,否则模型会借着修改机会把整篇稿子重写一遍,让你无法判断上一轮的修改究竟有没有效果。
4.4 评估器Prompt模板
评估器是循环的眼睛。我要求它输出严格的JSON,并用低温度保证稳定:
你是一名文案质量评审专家。请基于以下评分卡对文案进行评分。 评分维度: 1. 清晰度:核心卖点是否无歧义,读者能否快速理解产品价值 2. 说服力:是否有具体逻辑支撑观点,而不是空泛断言 3. 结构:开头、展开、结尾是否有层次,段落衔接是否自然 4. 合规性:是否有绝对化用语(如"最""第一""100%")或未证实承诺 评分标准: 5分 = 该维度表现优秀,无瑕疵 4分 = 表现良好,仅有轻微瑕疵 3分 = 达到合格线,存在可改进点 2分 = 明显不足 1分 = 严重缺陷 判定原则: - 只有出现具体证据才可打5分或4分 - 无法在文案中找到依据的高分,一律降级 - 合规性只要有1处违规,该维度直接给1分 文案内容: {article} 请严格按以下JSON格式输出,不要输出其他内容: {{ "dimension_scores": {{"清晰度": 0, "说服力": 0, "结构": 0, "合规性": 0}}, "top_issues": [ {{"dimension": "...", "quote": "原文引用问题片段", "suggestion": "具体修改建议"}} ], "overall_comment": "一句话总结当前质量水平" }}那个"只有出现具体证据才可打高分"的判定原则,是反打分膨胀的关键。如果你发现评估器每轮都给4-5分,多半是你漏了这条。
4.5 主循环控制器代码
下面是可以直接跑的控制器主体。这里我假设你用的是OpenAI SDK,但接口部分很容易替换成其他模型服务:
import json from openai import OpenAI client = OpenAI() def call_llm(system_prompt, user_prompt, model, temperature): resp = client.chat.completions.create( model=model, temperature=temperature, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ] ) return resp.choices[0].message.content def generate_initial_draft(raw_input): prompt = GENERATE_INITIAL_PROMPT.format(raw_input=raw_input) return call_llm( "你是一个专业文案撰稿人。", prompt, GENERATE_MODEL, TEMPERATURE_GENERATE ) def evaluate_article(article): prompt = JUDGE_PROMPT.format(article=article) result = call_llm( "你是一个严格的文案评审专家。", prompt, JUDGE_MODEL, TEMPERATURE_JUDGE ) # 容错解析:去掉可能的markdown代码围栏 result = result.strip() if result.startswith("```"): result = result.split("```")[1] if result.startswith("json"): result = result[4:] return json.loads(result) def refine_article(current_draft, feedback_history, top_issues, round_num): issues_text = json.dumps(top_issues, ensure_ascii=False, indent=2) plan_text = json.dumps(feedback_history, ensure_ascii=False, indent=2) prompt = GENERATE_REFINE_PROMPT.format( round=round_num, current_draft=current_draft, feedback_history=plan_text, top_issues=issues_text ) return call_llm( "你是一个专业文案撰稿人。", prompt, GENERATE_MODEL, TEMPERATURE_GENERATE ) def run_polish_loop(raw_input, max_iter=MAX_ITER): # 第0轮:生成初稿 draft = generate_initial_draft(raw_input) history = [{"round": 0, "draft": draft, "feedback": None}] best_version = {"round": 0, "draft": draft, "score": 0} for i in range(1, max_iter + 1): # 评估当前草稿 result = evaluate_article(draft) scores = result["dimension_scores"] sum_score = sum(scores.values()) min_score = min(scores.values()) # 记录本轮信息 history.append({ "round": i, "draft": draft, "feedback": result, "scores": scores, "sum_score": sum_score }) # 保存历史最高分 if sum_score > best_version["score"]: best_version = {"round": i, "draft": draft, "score": sum_score} print(f"[Round {i}] 总分={sum_score}, 最低维={min_score}") # 达标或平原期判断 if min_score >= MIN_DIM_SCORE and sum_score >= QUALIFY_THRESHOLD: print(f"[Round {i}] 达标,提前终止。") return draft, history if i >= 2: if sum_score <= history[-2]["sum_score"]: print(f"[Round {i}] 分数未提升,触发止损。") return best_version["draft"], history if i < max_iter: draft = refine_article(draft, history, result["top_issues"], i + 1) return best_version["draft"], history这段代码里有两个不太起眼但极其重要的设计,我单独说明:
一是**best_version的跟踪**。循环结束时不一定返回最后一版,而是返回历史最高分版本。原因前面提过:模型完全有可能在最后一轮改跑偏。提交最优版本,而不是最新版本,是Loop Engineering里最值得养成的习惯。
二是连续两轮分数未提升就停止。这个止损逻辑我省去了额外一次评估:第i轮评估结果本身就是"第i轮没有比第i-1轮高"的证据,所以不需要再调模型就能判断是否该停。成本上特别划算。
4.6 跑通后的结果形态
我用一个真实测试跑了一下上面的流程。毛坯稿是开头那段话,第一轮初稿总分只有12分,最低维度是"说服力"只有2分,评估器给出的意见是"卖点陈述停留在功能罗列,缺少用户场景和收益表达"。第二轮修改后总分升到16分,"结构"维度到了4分但"清晰度"还是3分。第三轮把开头改成直接面向差旅人群的痛点句之后,总分到18分,全部单项≥3,循环提前终止。
有意思的是第二轮修改时,生成器把"价格在同档位里比较便宜"改写成了"在同档位里提供更有竞争力的价格",这其实是一个合规性隐患的自我修正——虽然评估器没有直接点这一点,但生成器在重写时自动做了软化。这就是闭环带来的附带收益:模型在修改过程中会朝着更稳妥的方向自行调整。
5. 环路跑起来之后的四个大坑:评估器失真、反馈混淆、振荡不收敛、成本失控
到这里你已经能跑通一条循环了。但把循环从"能跑"变成"在真实业务里稳定可交付",还要过四道坎。我把踩坑记录直接列出来,这些经验花了我不少token才换来的。
5.1 评估器失真:LLM打分的三大恶习
LLM作为评估器有三个常见毛病。分数膨胀:默认倾向给高分,尤其是高分区间难以区分"良好"和"优秀"。对策就是我之前说的"没有具体证据不准给4分以上",并且可以给评估器喂一两个已标好分的参考样本做few-shot锚定。位置偏见:评估器倾向于认为文章中靠前的内容更重要,导致开头好的文章整体分虚高。对策是把文案打乱顺序评估后取均值,或者让评估器分段评分再汇总。自我偏好:如果评估器和生成器是同一个模型,它可能对与自己风格一致的输出偏心。对策是尽量让评估器用不同的、更小但更严格的模型,并强调"只依据评分卡判断"。
稳定性方面,我强烈建议你在上线前做一次一致性测试:拿10篇文案灌给评估器,每篇测5次,看打分方差。如果同一篇文案的打分波动超过1分,先别急着调生成器,把评估器调稳定了再说。
5.2 反馈混淆:一次给太多修改意见等于没给
生成器本质上仍是一个语言模型,让它一次性同时处理6条方向各异的修改意见,它的表现会明显退化。我在2.3节已经提了"只挑Top3",这里再补一个经验:这些top_issues必须按影响面排序,而不是按评估器输出的顺序。影响面最大的永远是"结构"层面的问题,因为它决定了整篇文章骨架,其次是"清晰度",最后才是措辞层面的小修小补。如果结构问题没解决,后面再怎么打磨措辞都是白费。所以在评估器Prompt里,我特意要求先给结构维度的问题,再给其他维度,这个排序会影响修改质量。
5.3 振荡不收敛:模型在两个版本之间来回横跳
振荡是循环系统最经典的失控模式。表现出来就是第二轮修好了A破坏了B,第三轮修好了B又把A退回了原样,第四轮和第三轮完全一样,分数原地踏步。我的对策分两步:
第一步是在生成器Prompt里加强历史约束。修订Prompt里的feedback_history不仅记录上一轮的评审意见,还应记录上一轮实际改了什么。我会在历史里插入一行"第2轮针对结构问题做了如下调整,请确认第3轮不要重新打乱这些结构"。这相当于给生成器一个"已冻结改动"的清单。
第二步是在控制器里做版本回退保护。如果第i轮的分数低于记忆中的best_version,不要让它覆盖最优版本;如果连续两轮分数不涨,直接返回最优版本停止。这套逻辑已经写进4.5的代码里了。
5.4 成本失控:小项目跑出大账单
循环系统是token吞金兽,尤其是像Multi-Agent辩论这种结构。控制成本有几个实用手段:
- 评估器降级:能用小模型就用小模型,评估任务对推理深度的要求通常低于生成任务
- 共享上下文压缩:迭代多轮后,历史信息会不断变长。不要把每一轮的完整草稿都塞进反馈历史,我通常只保留"上一轮草稿+所有轮的修改摘要",省上下文窗口的同时也省token
- 缓存评估结果:同样的草稿不会出现两次,但相似度极高的草稿可以预先做去重判断,跳过重复评估
- 抽样返工:如果批量生产100篇文案,先抽5篇跑完整循环确认评估器稳定,再全量跑。别一上来就全量压上去
我见过最极端的失控案例是有人给每个产品写了一篇3000字的评测,跑了8轮循环,最后一算单篇成本超过20元——而这篇评测的人工改写成本本来也就30元。循环省下的时间全被成本吃掉了,得不偿失。
最后再分享一条调试心得:给循环加日志和落盘。每一轮的草稿、评分、反馈意见、最终采用了哪一轮,都存到本地JSON文件里。这些数据是你调评分卡、调阈值的最重要依据,也是你向团队证明"这个循环确实在收敛"的底气。没有日志的循环,跑十次也说不清问题出在哪一环。
我个人最喜欢的结构仍然是"一大一小双模型"的2+1闭环:贵的大模型负责改,便宜的小模型负责评,控制器负责盯着分数曲线,超过阈值就放行,不达标就止损回滚。这套方案在文案、报告、方案设计这些内容生成场景里,质量稳定性和成本可控性都经过了实际检验。你把上面代码里的评分卡换一换,模型服务改一改,几乎可以直接平移到自己的业务里。