用 Instructor 实现 Self-Refine:让 LLM 通过自我反馈迭代改进输出的完整指南
【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor
在生成式 AI 应用中,单次调用大模型往往难以一步到位产出高质量结果。Self-Refine(自我精炼)是一种研究验证过的提示工程技术:让同一个 LLM 先生成初始输出,再对输出给出反馈,最后依据反馈改进输出,如此循环直到满足停止条件。本文基于当前仓库中 docs/prompting/self_criticism/self_refine.md 的完整方案,结合 Instructor 的结构化输出能力,讲解如何用 Pydantic 模型把"生成—反馈—改进"三阶段管线落地为可运行代码,并深入剖析其中的停止条件、历史记录与底层调用机制。读完本文,你将能够为一个任意生成任务搭建自己的自精炼循环,并通过结构化模型让反馈与改进过程全程可控、可审计。
Self-Refine 是什么:用一个 LLM 完成生成、反馈与改进
Self-Refine 的核心思想来自论文《Self-Refine: Iterative Refinement with Self-Feedback》:我们如何为 LLM 提供反馈,让它改进自己的回答?答案是——让模型自己干这件事。
它由三个步骤组成,且三个步骤都复用同一个 LLM:
- 生成初始输出(Generate):模型根据用户查询生成第一版答案;
- 生成反馈(Feedback):模型审视自己的输出,给出具体的改进意见;
- 改进输出(Refine):模型结合反馈重写输出,得到更优版本。
整个流程循环往复,直到满足停止条件(例如反馈方认为无需再改,或达到最大迭代次数)。其完整工作流如下:
从图中可以看到,反馈生成之后立即检查停止条件:若满足则直接输出最终结果;若不满足,则进入"改进"环节,改进后的输出又回到"生成反馈"节点,形成闭环。该技术被收录在当前仓库的 docs/prompting/index.md 的Self-Criticism(自我批评)分类下,与 Chain of Verification、Self-Verification、Self-Calibration 等共同构成"模型自我评估与纠错"的方法族,定位是"自动生成反馈并改进(Auto-generate feedback and improve)",典型适用场景是迭代式改进(Iterative improvement)。
为什么需要结构化:Self-Refine 与 Instructor 的结合点
Self-Refine 的难点不在于"多调用几次模型",而在于让反馈、改进结果可被程序解析、保存和循环使用。这正是 Instructor 的用武之地。
Instructor 的核心能力是把 Pydantic 模型转换为工具调用/JSON Schema,让 LLM 的输出严格符合我们定义的结构。在 instructor/init.py 中,from_provider被声明为懒加载导出(对应实现位于 instructor/v2/auto_client.py),它接受"provider/model-name"形式的字符串,自动路由到对应厂商的客户端,例如instructor.from_provider("openai/gpt-5-nano")。
每次client.create(...)调用都通过response_model参数绑定结构化输出。在 instructor/v2/core/client.py 中可以看到create方法的核心签名:response_model用于声明输出结构,max_retries默认为 3,负责在模型输出不符合结构或验证失败时自动重试。这意味着在 Self-Refine 的每一轮调用中,反馈列表、done标志、改进后的代码等字段都由 Schema 约束,模型"胡说"的概率被结构性降低,程序无需脆弱地做字符串解析。
设计数据模型:把"反馈"和"历史"变成一等公民
要实现一个健壮的自精炼循环,首先需要定义四个 Pydantic 模型,分别承载输出、反馈、单轮记录与完整历史:
import instructor from pydantic import BaseModel, Field from typing import Optional class Response(BaseModel): code: str class Feedback(BaseModel): feedback: list[str] = Field( description="A list of actions to take to improve the code." ) done: bool class Timestep(BaseModel): response: str feedback: Optional[list[str]] = Field(default_factory=list) refined_response: Optional[str] = Field(default="") class History(BaseModel): history: list[Timestep] = Field(default_factory=list) def add(self, code, feedback, refined_code): self.history.append( Timestep(response=code, feedback=feedback, refined_response=refined_code) )各模型的职责与设计要点如下:
| 模型 | 字段 | 作用 |
|---|---|---|
Response | code: str | 约束每次生成/改进的输出必须是一段代码字符串,防止模型输出解释性杂文 |
Feedback | feedback: list[str]、done: bool | 反馈以"改进动作列表"形式给出;done是模型自评"是否无需再改"的显式信号,构成停止条件的一环 |
Timestep | response、feedback、refined_response | 记录一轮迭代的快照:改进前的代码、反馈列表、改进后的代码 |
History | history: list[Timestep]+add() | 累积所有迭代记录,用于停止条件判断与事后审计 |
注意Feedback.feedback的字段描述"A list of actions to take to improve the code."—— 这段描述会被 Instructor 注入到 Schema 中,引导模型输出可执行的改进动作而非笼统评价。这正是 docs/prompting/index.md 中总结的实现套路:"把提示技术写进模型 docstring 或字段描述,再用补丁后的客户端 + 响应模型调用"。
搭建客户端:一行代码获得结构化客户端
client = instructor.from_provider("openai/gpt-5-nano")from_provider是当前仓库推荐的统一入口(见 instructor/init.py 的__all__与懒加载表)。它接受"openai/gpt-5-nano"这种"厂商/模型名"格式的字符串,底层通过 instructor/v2/auto_client.py 中的ALIAS_TO_PROVIDER映射表完成厂商路由,自动选择该厂商的推荐调用模式,返回一个同步的Instructor实例。若需要异步版本,传入async_client=True即可(参见 Chain of Verification 中的用法)。
核心循环三要素:反馈、改进与停止条件
整个 Self-Refine 管线由三个函数构成,它们是循环的心脏。
1. 生成反馈generate_feedback
def generate_feedback(response): return client.create( model="gpt-4o", response_model=Feedback, messages=[ { "role": "user", "content": f""" You are an expert Python coder. Provide feedback on this code. How can we make it (1) faster and (2) more readable? <code> {response.code} </code> If the code does not need to be improved, then indicate by setting "done" to True. """, } ], )要点解读:
- 提示词用
<code>标签包裹待评审代码,明确两个评审维度:更快(faster)与更易读(readable); - 最关键的一行是
If the code does not need to be improved, then indicate by setting "done" to True.——它把"是否停止"的决策权交给模型,而done字段由Feedback模型结构化约束,程序可以直接读取; - 注意这里使用了
gpt-4o作为执行模型,而客户端本身由gpt-5-nano创建——说明同一个客户端可以切换不同模型完成不同角色,读者可根据成本与效果自行调整。
2. 改进输出refine
def refine(response, feedback): return client.create( model="gpt-4o", response_model=Response, messages=[ { "role": "user", "content": f""" You are an expert Python coder. <response> {response.code} </response> <feedback> {feedback.feedback} </feedback> Refine your response. """, } ], )改进函数把上一轮的代码与反馈列表一起交给模型,要求其"Refine your response"。输出仍绑定Response模型,保证改进结果同样是干净的代码字符串,从而可以无缝进入下一轮反馈环节。
3. 停止条件stop_condition
def stop_condition(feedback, history): return feedback.done or len(history.history) >= 3停止条件由两部分组成,构成"双保险":
- 模型自评:
feedback.done为True,即模型认为代码已无需改进; - 最大迭代上限:
len(history.history) >= 3,即最多迭代 3 轮,防止模型陷入无限循环、也防止 API 成本失控。
把迭代上限写进停止条件是一个非常重要的工程实践——它把"理想情况"(模型自觉收敛)与"现实保障"(成本与延迟封顶)统一在了同一处判断逻辑里。
主循环:把三要素串成完整管线
在__main__中,先是初始生成,然后进入while True循环:
if __name__ == "__main__": response = client.create( model="gpt-4o", response_model=Response, messages=[ { "role": "user", "content": "Write Python code to calculate the fibonacci sequence.", } ], ) history = History() while True: feedback = generate_feedback(response) if stop_condition(feedback, history): break refined_response = refine(response, feedback) # Save to history history.add(response.code, feedback.feedback, refined_response.code) response = refined_response循环逻辑非常清晰:
- 对当前
response生成反馈; - 检查停止条件,满足即跳出;
- 否则用反馈改进出
refined_response; - 将"旧代码 + 反馈 + 新代码"存入
History,并把response更新为改进后的版本,进入下一轮。
这种"先存历史再覆盖当前"的顺序保证每一轮的原始输出都留有痕迹,最终可以通过history还原完整的演化链条。
运行结果分析:一次真实的三轮迭代
以"编写计算斐波那契数列的 Python 代码"为初始任务,运行上述程序,可以观察到一次完整的三轮自精炼过程(输出见 docs/prompting/self_criticism/self_refine.md):
第一轮初始输出:
def fibonacci(n): sequence = [0, 1] while len(sequence) < n: sequence.append(sequence[-1] + sequence[-2]) return sequence[:n]模型给出的反馈列表(共 4 条):
[ 'Use a generator to reduce memory consumption for large `n` values and improve speed.', 'Enhance readability by adding type hints for input and output.', "Add docstrings to explain the function's purpose and parameters.", "Avoid slicing the list at the end if it's not necessary; instead, ensure the loop condition is precise.", ]依据反馈改进后的代码:
def fibonacci(n: int) -> list[int]: """Generate a Fibonacci sequence of length n. Args: n (int): The length of the Fibonacci sequence to generate. Returns: list[int]: A list containing the Fibonacci sequence of length n. """ def fibonacci_generator(): a, b = 0, 1 for _ in range(n): yield a a, b = b, a + b return list(fibonacci_generator()) # Example usage: n = 10 print(fibonacci(n))可以看到改进版引入了生成器(降低大n的内存占用)、类型注解(n: int -> list[int])与 docstring(提升可读性),与反馈条目一一对应。
最终程序打印...process repeated 3 times...,且最后一轮输出进一步演化为不使用生成器的内存预分配版本:
def fibonacci(n: int) -> list[int]: """Generate a Fibonacci sequence of length n. Args: n (int): The length of the Fibonacci sequence to generate. Returns: list[int]: A list containing the Fibonacci sequence of length n. """ if n <= 0: return [] sequence = [0] * n if n > 1: sequence[1] = 1 for i in range(2, n): sequence[i] = sequence[i-1] + sequence[i-2] return sequence # Example usage: n = 10 print(fibonacci(n))值得注意的细节是:程序通过history.history[0]打印的是第一轮的快照,而response.code打印的是最终轮的结果——两者对比正好展示了"历史留存"与"当前最优"两种视角的分工。这也印证了History.add设计的价值:每一轮的演化都被完整记录,可供后续对比分析甚至回退。
把 Self-Refine 扩展到你自己的任务
Self-Refine 不限于代码生成。将Response.code替换为你任务所需的任意字段(如写作段落、SQL 查询、JSON 结构化数据),把generate_feedback中的评审维度(更快、更易读)换成任务相关的标准(更准确、更简洁、更符合事实),即可复用同一套管线。当前仓库的 Self-Verification(生成多个候选并用验证打分选择最优)与 Self-Calibration(让模型判断自身回答是否正确并输出置信度)提供了互补思路——前者适合"选最优",后者适合"估置信度",而 Self-Refine 适合"持续改进"。
在实际工程化时,还有几点值得结合 Instructor 特性加以利用:
- 重试兜底:
client.create的max_retries默认为 3(见 instructor/v2/core/client.py),当模型输出无法通过结构化校验时会自动重试,多轮循环中每轮调用都自带这一保障; - 异步并行:如需同时评估多个候选答案,可参考 Chain of Verification 中使用
async_client=True与asyncio.gather的做法,将反馈生成改为并发执行; - 成本控制:每次迭代至少两次模型调用(反馈 + 改进),因此
stop_condition中的迭代上限应结合预算设置——本方案中的 3 次上限即是一个保守而实用的默认值; - 记录审计:利用
History保留完整演化轨迹,无论是调试提示词还是向用户展示改进过程,都优于"只保留最终结果"的做法。
小结
Self-Refine 用"同一个模型既是作者也是批评者"的方式,把单次生成升级为可收敛的迭代改进过程。结合 Instructor 的结构化输出,反馈被约束为"动作列表 + 完成标志",改进结果被约束为"干净的代码字符串",历史轨迹被完整留存,停止条件由"模型自评 + 迭代上限"双重保障。这套模式非常适合代码生成、文本润色、SQL 编写等"初稿质量一般、但可依据反馈持续变好"的任务,是 Self-Criticism 技术族中落地成本最低、效果最直观的方法之一。
参考
- 本方案原始出处:docs/prompting/self_criticism/self_refine.md
- 相关技术族目录:docs/prompting/index.md(Self-Criticism 一节)
- 结构化客户端入口:instructor/v2/auto_client.py、instructor/init.py
create方法签名与max_retries:instructor/v2/core/client.py- 互补方法:Chain of Verification、Self-Verification、Self-Calibration
- 论文依据:Self-Refine: Iterative Refinement with Self-Feedback(arXiv:2303.17651);The Prompt Report: A Systematic Survey of Prompting Techniques(arXiv:2406.06608)
【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考