首页 / 文章 / 实用笔记:基于智能体的循环工程

实用笔记:基于智能体的循环工程

《实用笔记:基于智能体的循环工程》操作指南:为采用该模式的团队提供的契约、校验机制以及可直接插入的代码模块。

2945 词

可将此内容视为《基于智能体的循环工程》中理念面向操作员的优化版本:清晰的阶段划分、有序的代码模块,以及能在交接过程中保留的恢复说明。 将“概览”阶段视为可度量的界面使用效果最佳。在扩大范围之前,先记录一份理想的执行日志、一个故障案例以及回滚说明。 同时记录正常流程与恢复流程。重试机制、人工审核环节以及死信处理都是产品本身的组成部分,而非后续需要补充的内容。

目录

在目录阶段,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。相比庞大的脚本,更应采用小型且可测试的单元。当某个步骤失败时,故障原因应能指向单一责任主体,而非复杂的流程链。对于涉及资金支出或修改生产数据的操作,必须经过人工审批。编译时的逻辑连接并不等同于业务功能的完整性。

1. 智能循环的结构

在“1. 结构分析”阶段,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 对于涉及资金支出或修改生产数据的操作,必须经过人工审批。编译时的连接方式并不等同于业务上的完整性。

2. 何时使用循环工程

在“2. 使用时机”阶段,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 在功能结果旁记录执行时间以及令牌或查询成本。提前显示成本可避免在流程从演示环境转向共享环境时出现意外费用。 对于会产生费用或修改生产数据的操作,必须经过人工审批。编译时的配置并不等同于业务功能的完整性。 在“2. 使用时机”阶段,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 需同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误处理都是产品不可或缺的部分,而非后续需要补充的内容。

3. 常见的循环类型

在研究这三种常见循环类型时,首先列出相关约定:所需输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 建议使用小型、可测试的单元,而非庞大的脚本。当某个步骤失败时,故障应指向单一责任点,而非复杂的流程链。 在成本较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次调用相同的大型语言模型。

   +-----------+      +-----------+
-->| Generate  |----->|  Verify   |----- pass -----> [ done ]
   +-----------+      +-----+-----+
        ^                   |
        +------- fail ------+
   +-----------+      +-----------+
-->| Generate  |----->|  Score    |--- good enough --> [ done ]
   +-----------+      +-----+-----+
        ^                   |
        +-- improve --------+
            (use the score)
   +-----------+      +-----------+
-->|   Plan    |----->|  Execute  |-- all steps done --> [ done ]
   +-----------+      +-----+-----+
        ^                   |
        +-- replan ---------+
            (hit a surprise)
   +-----------+     +-----------+     +-----------+
-->|   Wait    |---->|   Check   |---->|    Act    |---+
   | (timer /  |     +-----------+     +-----------+   |
   |  trigger) |                                       |
   +-----------+ <-------------------------------------+
        (no fixed end — keeps watching over time)

4. 如何构建循环

在完成“4个构建方法”阶段时,首先写下相关契约:所需的输入参数、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 将这一阶段视为输入与验证后输出之间的契约。为相关成果命名,明确成功判定标准,杜绝无声的半完成状态。 在成本较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次调用相同的大型语言模型。

                    +------------------+
  START ----------> |     Research     | <-------------+
                    | (draft / revise) |               |
                    +--------+---------+               |
                             |                         |
                             v                         | needs work
                    +------------------+               | (+ feedback)
                    |      Verify      |               |
                    |  (check claims)  |               |
                    +--------+---------+               |
                             |                         |
                             v                         |
                       +-----------+   needs work      |
                       |  Decide   |-------------------+
                       | (router)  |
                       +-----+-----+
                             | verified / out of tries
                             v
                          [ END ]
pip install langgraph==1.2.6 langchain-openai==1.3.3 pydantic==2.13.4
export OPENAI_API_KEY="your-key-here"
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field

# A model client on OpenAI's Responses API, with the built-in web-search tool
# bound on — so the model can search the web itself, no extra package needed.
# "gpt-5" is a reasoning model; swap it for any current model you have access to.
llm = ChatOpenAI(model="gpt-5", use_responses_api=True)
searcher = llm.bind_tools([{"type": "web_search"}])

MAX_ITERATIONS = 3         # a stop rule, decided up front

# STATE — the shared memory passed between every node
class ResearchState(TypedDict):
    question: str          # what we're answering
    draft: str             # the current best answer
    verdict: str           # "verified" or "needs_work"
    feedback: str          # what the verifier said to fix
    iterations: int        # how many times we've looped

# The verifier returns a typed result, so the router gets a clean
# "verified" / "needs_work" to branch on instead of parsing prose.
class Verdict(BaseModel):
    status: str = Field(description='"verified" or "needs_work"')
    feedback: str = Field(description="claims lacking support, if any")

# NODE 1 — the maker: search the web, then draft (or revise) the answer.
def research(state: ResearchState) -> dict:
    prompt = "Search the web, then answer the question. Back every claim with a source.\n"
    if state.get("feedback"):
        prompt += f"A reviewer flagged these gaps — fix them:\n{state['feedback']}\n"
    prompt += f"\nQuestion: {state['question']}"
    draft = searcher.invoke(prompt).text
    return {"draft": draft, "iterations": state["iterations"] + 1}

# NODE 2 — the checker: search for evidence, then critique the draft.
def verify(state: ResearchState) -> dict:
    evidence = searcher.invoke(
        f"Search the web for evidence to fact-check claims about: {state['question']}"
    ).text
    checker = llm.with_structured_output(Verdict)
    result = checker.invoke(
        "You are a fact-checker. Using the evidence below, reply 'verified' "
        "only if every claim in the answer is supported; otherwise 'needs_work' "
        "and list the unsupported claims as feedback.\n\n"
        f"Evidence:\n{evidence}\n\nAnswer:\n{state['draft']}"
    )
    return {"verdict": result.status, "feedback": result.feedback}

# ROUTER — the heart of the loop. Reads the verdict, picks the next step.
def decide(state: ResearchState) -> Literal["research", "__end__"]:
    if state["verdict"] == "verified":
        return "__end__"                      # success: goal met
    if state["iterations"] >= MAX_ITERATIONS:
        return "__end__"                      # surrender: out of tries
    return "research"                         # loop back and fix the gaps

# WIRE IT UP
graph = StateGraph(ResearchState)
graph.add_node("research", research)
graph.add_node("verify", verify)

graph.add_edge(START, "research")            # trigger
graph.add_edge("research", "verify")         # always verify a fresh draft
graph.add_conditional_edges("verify", decide, {
    "research": "research",                   # the backward arrow = the loop
    "__end__": END,
})

agent = graph.compile()

result = agent.invoke({
    "question": "What were the main causes of the 2008 financial crisis?",
    "draft": "", "verdict": "", "feedback": "", "iterations": 0,
})
print(result["draft"])

5. 失败模式与防护措施

在完成“5种故障模式防护机制”这一阶段时,首先需明确相关规范:所需输入、成功信号以及部分故障时的处理方式。这份清单能确保后续的代码修改始终符合既定要求。 在记录功能结果的同时,还需标注执行时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境过渡到共享环境时出现意外费用。 在耗时较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次对同一次大型语言模型调用收费。 在完成“5种故障模式防护机制”这一阶段时,首先需明确相关规范:所需输入、成功信号以及部分故障时的处理方式。这份清单能确保后续的代码修改始终符合既定要求。 需同时记录正常流程与故障恢复流程。重试机制、人工审核环节以及死信处理都是产品功能的一部分,而非后续需要补充的内容。

6. 何时不应使用循环工程

“6个不应进行分阶段处理的场景”这一概念若被视为可度量的标准则最为有效。在扩大范围之前,先记录一个成功的案例、一个失败案例以及回滚说明。 相较于庞大的脚本,应优先选择小型且可测试的单元。当某个步骤失败时,故障应能指向单一的责任主体,而非复杂的流程链。 保持图表状态简洁且具有类型定义。嵌套的数据块会掩盖哪个节点修改了哪个字段的信息,还会在流程中断后导致无法继续执行。

结论

将“结论”阶段视为可度量的对象能发挥最佳作用。在扩大范围之前,先记录一份优秀的成果文本、一个失败案例以及回滚说明。 把这一阶段视为输入与已验证输出之间的契约。为相关成果命名,明确成功标准,绝不允许默默地仅完成部分工作。 保持图表状态简洁且类型明确。嵌套的数据块会掩盖哪个节点修改了哪个字段,还会在中断后导致无法继续处理。

参考资料

将“参考阶段”视为可度量的对象来处理时,其效果最佳。在扩大范围之前,需记录一份理想的操作流程、一个故障案例以及回滚说明。 在功能结果旁同时记录处理时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境过渡到共享环境时出现意外费用。 保持图表状态简洁且类型明确。嵌套的数据块会掩盖哪个节点修改了哪个字段的信息,还会在流程中断后导致无法继续执行。 将“参考阶段”视为可度量的对象来处理时,其效果最佳。在扩大范围之前,需记录一份理想的操作流程、一个故障案例以及回滚说明。 需同时记录正常流程与恢复流程。重试机制、人工审核环节以及死信处理都是产品本身的组成部分,而非后续需要补充的功能。

操作检查清单

在处理操作检查清单阶段时,首先写下合同细节:所需输入、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。

将配置信息与应用程序代码分开。环境文件、密钥存储和功能开关应集中存放于一个位置,以便操作人员无需查看整个系统结构即可进行审计。

在成本较高的步骤之后设置检查点。当操作人员重新尝试后续节点时,恢复流程不应再次计费相同的大型语言模型调用费用。

锁定依赖项的版本,并记录用于运行演示的镜像摘要。可重复性比经验知识更为重要。

同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及死信处理都是产品的一部分,而非后续需要补充的内容。

在成本较高的步骤之后设置检查点。当操作员重新尝试后续节点时,续订服务不应再次对同一次大型语言模型调用收费。

在升级整个系统之前,需冻结各版本,为关键路径记录标准文本转录,并明确回滚步骤。共享环境需要设置速率限制、租户验证机制,以及负责密钥轮换的明确责任人。与其追求花哨的一次性演示,不如注重扎实的可靠性。

关于5e9b984e8d8a的批处理说明:请将提供商密钥存放在仓库之外,设定每会话的令牌上限,并将文本转录与评估相关文件放在一起,以便后续更换模型时仍能保持数据可比性。

在将加固阶段视为可测量的表面时,第0阶段的处理效果最佳。在扩大范围之前,需记录一份理想的测试用例、一个故障案例以及回滚说明。 应将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,绝不允许默许不完整的处理结果。

加固细节0/884:需测量该阶段的执行时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非主观判断来决定是否保留该变更。

在强化措施的第一阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能标志应集中存放于一个位置,这样操作人员无需查看整个系统结构即可进行审计。

强化措施细节 1/884:针对此项措施,需统计执行时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非主观经验来决定是否保留该变更。

在处理强化措施的第2阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合要求。 相比冗长的脚本,更应采用小型且可测试的单元。当某个步骤失败时,故障应能指向单一的责任模块,而非复杂的流程链。

强化措施细节2/884:需测量该步骤的运行时间、错误类型以及代币消耗情况,然后依据固定的评估标准而非主观感受来决定是否保留该修改。

将强化措施的第3阶段视为可度量的对象来处理效果最佳。在扩大范围之前,先记录一份理想的运行示例、一个失败案例以及回滚说明。 在功能结果旁同时记录时间消耗及代币或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外支出。

强化措施细节3/884:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个别案例来决定是否保留该变更。

对于强化措施的第4阶段,在修改代码之前需明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新执行该步骤,而无需猜测隐藏状态。同时需将正常流程与故障恢复流程一并记录下来。重试机制、人工审核环节以及错误处理方式都是产品本身的组成部分,而非后续需要补充的内容。

强化措施细节4/884:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个别案例来决定是否保留该变更。

在处理强化措施的第5阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合约定。 将这一阶段视为输入与验证后输出之间的契约。为相关产物命名,明确成功判定标准,杜绝默许部分完成的情况。

强化措施细节5/884:需测量该步骤的耗时、错误类型以及令牌消耗情况,然后依据固定的评估标准而非个人经验来决定是否保留该变更。

将强化措施的第6阶段视为可量化的对象来处理效果最佳。在扩大范围之前,先记录一份标准操作示例、一个失败案例以及回滚说明。 应将配置信息与应用程序代码分开。环境文件、密钥存储和功能开关应集中存放于一处,以便操作人员无需查看全部代码结构即可进行审计。

强化措施细节 6/884:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在强化措施的第7阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。相比复杂的脚本,更应采用小型且可测试的单元。当某一步骤失败时,故障原因应能指向单一责任方,而非混乱的整个流程。

强化措施细节 7/884:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在处理强化建议的第8阶段时,首先写下相关约定:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合初始要求。

在功能结果旁记录执行时间以及令牌或查询成本。提前了解这些成本信息,可避免在系统从演示环境过渡到共享环境时出现意外费用。

强化建议的第8/884条要求:测量该建议对应的执行时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非个人经验来决定是否保留相关修改。

将强化建议的第9阶段视为可度量的工作面来处理效果最佳。在扩大范围之前,先记录一个理想运行案例、一个失败案例以及回滚说明。

应同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及错误处理方式都是产品本身的组成部分,而非后续需要补充的内容。

强化措施细节 9/884:记录该任务的执行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在强化措施的第10阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。应将此阶段视为输入参数与验证后输出结果之间的契约,为相关成果命名、定义成功检测标准,并拒绝默许部分完成的情况。

强化措施细节 10/884:记录该任务的执行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在处理强化措施的第11阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合要求。 应将配置信息与应用程序代码分开。环境文件、密钥存储以及功能开关应集中存放于一个位置,这样操作人员无需查看整个系统结构即可进行审计。

强化措施细节11/884:需测量该措施的执行时间、错误类型以及令牌消耗情况,然后根据固定的评估标准而非个人经验来决定是否保留该修改。