LangGraph 实战:构建“自我修正”的代码生成 Agent
两年前我第一次在项目里塞了一个“一键生成代码”的功能,当时想的很简单:把需求丢给大模型,拿到代码就跑。结果上线第一周就发现,生成十段代码里能直接跑通的不到三成,剩下七成全是“看起来对、一执行就崩”。后来我把执行反馈重新喂回模型,让它针对报错信息做第二轮补丁,成功率明显上来了。这就是“自我修正”的雏形:不是让模型一次性写对,而是在执行结果面前不断承认错误、重新生成。这篇文章就用 LangGraph 把这条闭环完整落地,适合已经在用 LangChain 但还没理清 Agent 状态管理、或者想从“单次调用”升级到“带反馈循环”的开发者。你需要的不是更多魔法,而是一个能把“执行反馈”和“重新生成”串起来的图结构,以及一套避免死循环、控制成本的方法。
图是什么、为什么单次调用永远不够,这是核心问题。下面我先把整体循环拆给你看,再逐个节点落到代码上。
1. 内容整体设计与思路拆解
1.1 从“单次生成”到“循环修正”的本质转变
很多团队做代码生成 Agent 时,习惯性做成“输入需求 → 返回代码 → 结束”。这种结构在 Demo 里效果很好,一旦碰上真实仓库、真实依赖、真实系统环境,立刻就露怯。因为大模型生成代码本质上是一个“基于概率的采样过程”,它对 API 名称、库的调用方式、类型签名理解得越好,成功概率越高,但永远存在一个非零的出错率,尤其在多文件项目里,模型很容易忘记你在某个工具类里定义过什么方法。
自我修正 Agent 的思路是完全反过来:允许模型出错,把“运行测试”当作另一个节点放进流程里,让程序先跑一遍,把报错信息或测试失败结果作为上下文喂给模型,让它带着“具体失败原因”重新生成。这就像你写代码时边跑边改,而不是憋一个大版本再一次性提交。LangGraph 的价值恰恰在于它给了你一个“显式的状态机”:每个节点输出一个状态,状态在节点之间流动,条件边决定下一步是“修”还是“停”。
用生活类比解释一下:你找一个人工智能助手帮你装家具,单次生成类似于“助手指着说明书口述一遍步骤”就完事,螺丝拧歪了它看不见;自我修正则类似“助手在旁边看你组装,听到‘咔哒’一声没到位,就拆掉重装那一步”。抓手是执行结果,不是模型自己的信心。
1.2 为什么选 LangGraph 而不是裸写 LangChain 循环
裸写 LangChain 也可以实现类似的循环:你可以在 Python 里写一个while循环,把上一次的报错拼进 prompt,再把新代码喂给测试函数。但这么做的代价是,状态管理、重试上限、中途打断、分支跳转全得自己维护。LangGraph 把这些变成图结构里的一等公民,你可以直接在节点之间加条件边,让“失败”走修复分支、“成功”走结束分支,代码的可读性和可控性完全不一样。
还有一层原因:真实项目中你需要可视化。LangGraph 自带图结构展示,调试的时候你能肉眼看到每次运行走到哪个节点、状态传递了什么数据。裸写的循环一旦报错,你想知道“到底是哪一轮、哪次调用的上下文出了问题”,那真是全靠猜。LangGraph 把整个执行过程数据化了,每个节点可以记录完整的输入输出,排查问题的时候直接翻状态记录,效率高得多。
不过我的建议是:不要把这块跟 LangChain 撕裂来看。LangGraph 是编排框架,LangChain 是模型调用和工具封装的基础库,它们搭在一起才顺。
2. 核心细节解析与实操要点
2.1 完整图结构与状态定义
在动手写代码前,先把图结构在脑子里画清楚。我建议你的代码生成 Agent 至少包含四个节点:需求理解、代码生成、执行验证、错误分析。其中“代码生成”会被重复调用,“错误分析”负责给模型提供清晰的修正依据。
在 LangGraph 里,节点之间共享的数据用一个State对象表达。代码里我会定义成这样:
from typing import TypedDict, List, Optional from langgraph.graph import StateGraph, END class CodeAgentState(TypedDict): task_description: str # 用户输入的需求描述 code_history: List[str] # 历史生成的代码(保留最近几轮) last_error: Optional[str] # 最后一次执行失败的报错信息 generated_code: Optional[str] # 当前轮的代码 test_result: Optional[str] # 测试输出或成功标记 attempt_count: int # 当前尝试次数 max_attempts: int # 最大尝试次数这里有个关键点:code_history不是存全部历史代码,而是只保留最近两到三轮。原因很实际,模型上下文长度是有限的,你把十轮失败代码全部拼接进去,不仅浪费 token 还容易干扰模型注意力,它可能会从旧代码里去抄已经被否决的错误写法。我的实践经验是,保留当前轮和上一轮就足够。
attempt_count和max_attempts是防止死循环的保险丝。模型修正代码时经常出现一种情况:第一次报错“缺少 import”,第二次补上后又报新的错,第三次又冒出另一个问题,第四次它反而把原来的正确代码改错了。如果没有上限,这个循环会一直烧钱烧下去。设置一个max_attempts(我一般设 3,最多 5),达到上限后直接走“放弃”分支,把当前状态交还给用户。
2.2 每个节点的“为什么这样设计”
需求理解节点:这个节点的主要价值不是提高生成正确率,而是“对齐需求边界”。大模型对含糊需求非常敏感,你写“生成一个计算器”,它可能生成一整个 GUI 程序;你写“生成一个函数计算两个数的和”,它就老实很多。我在这个节点里用一个很短的 prompt 强制模型输出结构化的“需求理解摘要”,包括输入、输出、依赖限制,这个摘要会作为后续生成代码的固定前缀。
这个步骤最大的好处是给“多轮修正”提供了稳定锚点。没有这个节点的话,第二轮生成的代码很可能会漂移:模型为了修正报错,可能改变函数签名,结果第一轮调用的代码也跟着失效。有了需求理解摘要,你在生成节点里明确告诉模型“不管你怎么修,都必须保持对外接口不变”,修正就变成了局部补丁,而不是推倒重写。
代码生成节点:这是最常规的一环,本质是一个带系统提示词的 LLM 调用。但有一层细节容易被忽视:你的 prompt 里必须把上一次的错误信息放进去,而且要放在一个非常醒目的位置。我会用一个固定的区块标题,比如“下面是执行失败信息,请针对性修正”,让模型清楚区分“任务需求”和“执行反馈”。
一些模型在长上下文中容易忽略埋在中间的报错信息,你需要把报错信息重写到生成节点 prompt 的末尾,而不是简单拼接一个全局上下文。这看起来是个小改动,但对修正效果的影响非常大。
执行验证节点:这个节点是所有“自动化”的基础,也是风险最集中的地方。不要用subprocess.run直接裸跑模型生成的代码,尤其是当你的 Agent 部署为公网服务时,一个恶意生成的代码片段可以执行任意系统命令。我这里的做法永远是:先在隔离环境里运行。
最轻量的方案是用 Docker 容器:每次要验证代码时,启动一个临时容器,把用户代码和测试文件挂载进去,执行pytest或者直接运行脚本,拿到 stdout 和 stderr 作为输出。如果是在本地环境做 Demo,不考虑安全隔离,那至少也要用subprocess.run(..., timeout=10)加上超时控制,避免生成代码陷入无限死循环。
这个节点还承担一个隐藏职责:格式化和截断输出。模型生成的代码如果包含print大量调试信息,测试输出会非常长,直接塞回 prompt 既浪费 token 又干扰模型。我的做法是只保留最后 2000 字符的 stderr,以及测试失败断言的摘要部分。
错误分析节点:这个节点负责把原始报错信息裁剪成“模型友好”的格式。以 Python 为例,完整 traceback 里往往有大量框架内部调用栈,模型不需要看那些,需要的是准确的出错文件和行号。我会用正则在服务端提取关键行:File "xxx.py", line N,加上异常的最终消息。
这个节点还有一个容易被忽略的功能:判断错误类型。如果错误属于SyntaxError(语法错误),那直接抛回给模型重新生成整个代码块即可;如果错误属于AssertionError(测试断言失败),那么模型需要分析的是“逻辑为什么不正确”,要给它更多的上下文(比如测试用例期望值和实际值)。两者对应的修正策略不同,最好在错误分析节点就做好分流。
2.3 工具选型解析
做这类 Agent 最少需要三块能力:LLM 调用、代码执行沙箱、测试输出捕获。LLM 调用我实测下来最顺手的是langchain-openai封装,换不同模型厂商时只改model和base_url;如果你想完全绕开 LangChain,直接用openaiSDK 也没问题,LangGraph 节点本来就可以是任意 Python 函数,不一定非要用 LangChain 的抽象。
代码执行沙箱我建议按部署环境分两档:本地调试用subprocess加timeout,生产环境务必上 Docker 或容器服务。如果团队资源紧张,前期可以先写死一个 Python 3.11 的基础镜像,里面预装 pytest、requests 这类常用库,等需求多了再扩展。
测试输出捕获要重视“不可见的异常”这一层。模型生成的代码有时不是报错,而是逻辑正确但结果不对,这种情况只有通过单元测试能发现。我的建议是在test_code里直接生成一个临时test_{uuid}.py,里面加载被测试代码并执行几个断言用例,然后把 pytest 的结果文本作为验证输出。这样循环反馈的不只是“程序崩没崩”,而是“程序对不对”。
3. 实操过程与核心环节实现
3.1 从零开始搭建 LangGraph 循环
先安装依赖,这个项目的核心包就是langgraph和langchain-openai,测试环境还需要pytest。我一般固定在一个虚拟环境里操作,避免全局包污染。
pip install langgraph langchain-openai pytest紧接着定义上面提到的 State 和节点函数。以“代码生成节点”为例,它接收state作为唯一入参,返回一个字典用于更新状态,这是 LangGraph 的约定:
from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-4o", temperature=0.2, ) def generate_code_node(state: CodeAgentState) -> dict: prompt = build_generation_prompt(state) response = llm.invoke(prompt) new_code = extract_code_from_output(response.content) return { "generated_code": new_code, "code_history": state["code_history"] + [new_code], }build_generation_prompt是核心封装函数,它的内部逻辑可以这样写:
def build_generation_prompt(state: CodeAgentState) -> str: task = state["task_description"] history = state["code_history"] last_error = state["last_error"] attempt_count = state["attempt_count"] base_prompt = f""" 你是代码生成助手。请根据下面的任务描述生成完整可运行的代码。 任务:{task} 要求: - 代码必须包含必要的 import - 函数名和对外接口必须保持稳定,不可随意变更 - 输出仅包含代码块,不要附带解释 """ if history: base_prompt += "\n\n历史生成记录(最近两轮):\n" for idx, code in enumerate(history[-2:], 1): base_prompt += f"--- 第 {idx} 轮代码 ---\n{code}\n" if last_error: base_prompt += f""" 【重要】上次执行失败,报错信息如下: {last_error} 请仔细分析错误原因,输出修正后的完整代码。 如果上一轮的代码基本正确,只做局部修改,不要重写全部逻辑。 """ else: base_prompt += "\n这是第一轮生成,请直接输出最终代码。" return base_prompt这一步的关键点是:需求理解摘要可以再加进去,通常我把它放在系统提示词的最前面,告诉模型“当前需求边界”。
3.2 条件边与循环中断
有了节点之后,图结构需要连起来,条件边是 LangGraph 最强大的机制。执行验证完成后,你要根据测试结果决定走哪条分支。在StateGraph里,条件边是一个返回“分支名称”的函数:
def route_after_verification(state: CodeAgentState) -> str: if state["test_result"] == "PASS": return "end" if state["attempt_count"] >= state["max_attempts"]: return "give_up" # 根据错误类型分流:语法错误走快速修复,断言之类走完整分析 error = state["last_error"] or "" if "SyntaxError" in error or "ModuleNotFoundError" in error: return "generate" # 快速修复:直接回到生成代码节点 return "analyze" # 需要更详细分析,先走错误分析节点 graph = StateGraph(CodeAgentState) graph.add_node("generate", generate_code_node) graph.add_node("verify", verify_code_node) graph.add_node("analyze", analyze_error_node) graph.set_entry_point("generate") graph.add_edge("generate", "verify") graph.add_conditional_edges( "verify", route_after_verification, { "generate": "generate", "analyze": "analyze", "end": END, "give_up": END, }, ) graph.add_edge("analyze", "generate")这里有个我踩过的坑:条件边的返回值必须和add_conditional_edges第三个参数里传的 mapping 完全一致,不能返回未注册的分支名。第一次写的时候我在route_after_verification里返回了"success",结果 mapping 里写的是"end",运行报错让我排查好久。LangGraph 查这种错误比较隐晦,它只会告诉你“invalid branch”,不会指出具体错在哪里。
give_up分支的处理也很有讲究。你不应该直接丢一个空响应,而是把last_error和code_history拼成一条回执,告诉用户“已经尝试了 N 次,最新错误是什么”。这样即使用户拿到的是失败结果,他也能手动介入。
3.3 执行验证节点的完整代码
执行验证节点是整个 Agent 的“照妖镜”,写得是否健壮直接决定循环能不能闭环。先看基础版本:
import subprocess import tempfile import uuid import os def verify_code_node(state: CodeAgentState) -> dict: code = state["generated_code"] if not code: return {"test_result": "FAIL", "last_error": "No code generated."} with tempfile.TemporaryDirectory() as tmp_dir: main_file = os.path.join(tmp_dir, "solution.py") test_file = os.path.join(tmp_dir, f"test_{uuid.uuid4().hex}.py") with open(main_file, "w", encoding="utf-8") as f: f.write(code) # 基础测试模板:可以动态注入测试用例 tests = state.get("test_cases", "assert add(1, 2) == 3") with open(test_file, "w", encoding="utf-8") as f: f.write(f"import solution\n{tests}\n") try: proc = subprocess.run( ["python", "-m", "pytest", test_file, "-x", "--tb=short"], capture_output=True, text=True, timeout=10, cwd=tmp_dir, ) output = proc.stdout + proc.stderr if proc.returncode == 0: return {"test_result": "PASS", "last_error": None} else: error_snippet = extract_essential_error(output) return { "test_result": "FAIL", "last_error": error_snippet, "attempt_count": state["attempt_count"] + 1, } except subprocess.TimeoutExpired: return { "test_result": "FAIL", "last_error": "Execution timed out. Possible infinite loop.", "attempt_count": state["attempt_count"] + 1, }这段代码不是银弹,有几个注意点:
TemporaryDirectory默认在/tmp下创建,权限相对安全,但不能用来对抗恶意代码。生产环境还是放 Docker。-x参数让 pytest 遇到第一个失败立即停止,不要继续跑全部用例,节省时间。--tb=short让 traceback 尽量短,为下文提取关键信息做铺垫。- 如果模型生成的是一个需要 stdin 交互的程序,上述方式会卡在
subprocess.run上,timeout=10会救你。 - 每个测试循环都在全新临时目录里跑,避免上一轮残留文件影响结果。
extract_essential_error是提取错误摘要的小工具,我的实现逻辑很简单:找到第一行E开头的断言错误,或者Error关键字附近的内容,截取 300 字符左右。目的不是完整展示 traceback,是让模型能定位到关键问题。
3.4 把“错误分析”和“快速修复”做出差异
很多人做自我修正 Agent,失败后就只是把错误信息拼接进 prompt 再跑一次。我建议你把错误分析做成独立节点,这会在修正质量上拉开明显差距。
analyze_error_node做的事情很聚焦:把 raw error 分类,产出“修正策略建议”。例如:
ModuleNotFoundError: No module named 'langchain'→ 提示缺少依赖,建议代码里添加 pip install 语句,或者改用已有依赖的库。AttributeError: 'int' object has no attribute 'length'→ 提示类型错误,可能是把长度属性名写错了,或者变量类型与预期不符。TimeoutExpired→ 提示可能存在无限循环,建议为代码添加最大迭代次数。AssertionError: assert solution.add(1, 2) == 4→ 提示逻辑错误,需要重新检查业务逻辑。
这个分类结果最终通过 prompt 传给生成节点,生成节点在修正时就有了明确方向,不是无头苍蝇似地重写代码。
另外,你可以在错误分析节点里做一步“代码 diff 定位”,把上一轮代码和当前轮代码做个简单文本比对,找出改动范围。模型往往在修改一行代码时把整个函数体都改了,导致新错误,而 diff 定位能帮助你在 prompt 里添加一句“请确保只改动指定函数,不要影响其他函数”。这个操作在纯代码生成的场景下非常见效。
4. 常见问题与排查技巧实录
4.1 模型“反复横跳”,同一个问题修了三次还在无限循环
这在自我修正 Agent 里是最常见的问题,症状是:第一轮模型把代码从 A 改成 B,第二轮又把 B 改回 A,然后一直左右横跳。原因通常是模型的上下文里没有明确的“正确方向”锚点,每次报错后它只看到局部错误,重新提出一个假设。
实操解法有三个,我按优先级排列:
- 在 prompt 里显式声明“不要回退到上一轮代码”,或者“只能基于上一版代码做最小修改,不允许改写与报错无关的部分”。
- 提高生成温度或者降低一点,让模型对不确定性的探索收敛更快。实测下来温度从 0.2 调到 0.1 能减少不少横跳。
- 限制历史代码回顾轮数。有些模型看到历史代码多了,会自动参考历史里的错误方案,所以 code_history 只放最近两轮是最稳的。
如果三种都试了还是横跳,那就接受现实:这个任务超出了模型单轮修正能力。你要做的不是无限循环,而是把max_attempts设小一点,尽早交给用户。
4.2 执行环境报错与生成代码错配:模型生成的不是 Python
常见翻车场景:你告诉模型“生成 Python 代码”,但它输出了一段伪代码或者自然语言夹杂代码。我处理这个问题的办法是在extract_code_from_output里做严格解析:只提取 ```python 代码块内的内容,如果没有代码块,就搜索函数定义关键字def。如果两者都没有,直接判定生成失败,把这个输出本身当作错误信息传回模型,要求它“只输出代码,不要附带解释”。
更隐蔽的是模型生成了一小段可运行的 Python,但它依赖了一个你的沙箱环境里根本没有的库。这时候执行验证节点会报ModuleNotFoundError,修复的思路不是让模型自动安装依赖,而是提醒它“当前环境可用依赖列表”,把这个列表直接注入到生成节点的系统 prompt 里。这样修出来的代码不会为了解决一个依赖问题又引入新依赖。
4.3 并行执行测试导致资源耗尽
如果你部署了这个 Agent 并允许并发请求,每个请求都起一个 subprocess 跑 pytest,很短时间内就能把机器的 CPU 和内存打满。我踩过的坑是:一次压测里同时来了十几个请求,每个请求都循环修正 3 次,一下子起了几十个 Python 解释器,机器直接假死。
解法是加执行层并发控制。最简单的是信号量:用 Python 的threading.Semaphore包装verify_code_node,限制同时验证的请求数。更工程化的做法是引入任务队列(如 Redis 队列或 Celery),把执行验证节点从同步调用改成异步消费,但那样会牺牲 LangGraph 节点设计的简洁性。
4.4 模型生成的代码“能跑但不对”,测试用例怎么设计
自我修正的核心是执行反馈必须有“对错标准”。如果只靠运行不报错来判断成功,很多错误代码会被当作正确代码输出。所以测试用例的设计质量,直接决定了 Agent 的最终质量。
我建议在需求理解节点就顺便让模型生成测试用例,而不是由人手工写。做法是把“生成代码”和“生成测试”拆成两个独立节点:先让模型根据需求生成一组单元测试断言,再生成满足这些断言的代码。测试用例先于代码被执行,模型在生成代码时就有了“目标函数行为”的概念,准确率会明显提升。
不过这里要注意:不能完全相信模型生成的测试,因为它可能写出跟代码一样有偏见的测试。一个可行的折中是,让用户或项目维护者在任务描述里附上 2~3 个必须通过的验收用例,Agent 生成的测试作为补充,不替代人工验收。
4.5 LangGraph 状态更新的坑:返回体里没有的键会被覆盖吗
我在实践早期踩过一个隐藏 bug:某个节点返回的字典里只包含部分键,我误以为其他键不会被修改,结果 LangGraph 默认行为是“返回的键覆盖,没返回的键保持不变”。这个设计是对的,但我当时在多个节点里重复给attempt_count赋值,导致计数器混乱,循环提前终止。
排查方法是查看每次状态的快照。LangGraph 编译后的图对象可以接收一个checkpoint参数,加上它之后每次节点执行完都会把完整 state 存到内存或外部存储里,非常适合调试:
from langgraph.checkpoint.memory import MemorySaver memory = MemorySaver() app = graph.compile(checkpointer=memory)调用时传入一个thread_id,后续就可以查看该线程的状态历史,一步步核对哪个节点把attempt_count改了。
5. 上线部署与稳健性加固
5.1 从 Demo 到服务的工程改造点
跑通 Demo 只是第一步,做成服务要考虑的还很多。一是要把“需求理解、代码生成、执行验证”拆成可观测的独立模块,每个模块都要有日志和耗时指标,这样用户反馈某个需求生成失败时,你能快速定位是模型理解偏了、代码生成挂了,还是测试执行环节出故障。
二是要控制并发和资源。这个 Agent 的每个请求都可能产生多次 LLM 调用,耗时从几十秒到几分钟不等,如果你用同步 HTTP 服务来承接,连接池会被占满。我建议用任务队列(Celery 或 Redis Streams)接住所有请求,再通过 Worker 并发消费,把每个 Agent 运行实例封装成独立任务。
三是 prompt 和模型版本要固化。自我修正 Agent 特别吃 prompt 细节,如果你在测试阶段调试好了 prompt,上线时千万不要频繁调整系统提示词。每次改动 prompt 都可能影响模型的修正策略,需要回归验证。我在团队里要求所有 prompt 变更必须留档,并附带至少 20 个典型需求的测试结果对比。
5.2 增加人工审批节点:什么时候该停下来问人
自我修正不是越修正越好,恰恰相反,无限制的自动修正在某些场景是有危险的。比如模型生成的代码涉及文件删除、系统命令执行,或者依赖安装包来自第三方源,这种情况下你必须在图里加一个“人工审批”节点。
LangGraph 里加人工审批非常简单:在 condition 边之前插一个特殊节点,这个节点不调用任何模型,而是对外输出“等待人工确认”的信号,然后挂起整个图执行。等用户在 Web 界面点“允许”或“拒绝”后,再调用app.update_state把审批结果写回状态,图继续走下去。
我给代码生成 Agent 的建议是:前几轮修正可以全自动,达到max_attempts上限后不要直接放弃,而是进入人工审批分支,把最新代码和错误信息一起展示给用户,等用户决定是手动修改还是继续自动修正。这样既保留自动化效率,又保留人类兜底能力。
5.3 成本控制:一次生成任务烧掉多少 token
自我修正 Agent 的 token 消耗是单次生成的数倍,这一点必须在上线前算清楚。假设每个任务平均循环 3 次,每次生成的输入都包含历史代码和错误信息,输入 token 量会随循环次数加大。我用过一个很土但有效的优化:在错误分析节点里先做一次 LLM 摘要,把冗长的报错信息压缩成一行半行的“错误定位描述”,再拼接到生成 prompt 里,这样生成节点的输入 token 能降不少。
另一个优化是给每个节点设 token 上限。像代码生成节点的输出很容易被模型写成长篇大论,你需要用max_tokens限制它,让它专注输出代码主体。测试节点的输出是确定性的,可以不加限制。
5.4 用状态快照做最终决策留痕
当你的 Agent 在真实业务里跑了一段时间后,你可能需要复盘:哪些任务失败,失败在哪个环节。我的做法是让 LangGraph 的 MemorySaver 持久化到 SQLite 或 Postgres,每次任务结束都会保存完整的 state 快照,包括所有历史代码、错误信息、测试结果。有了这些数据,你可以系统性分析模型在不同任务类型上的短板,也可以拿真实失败样本去评测新模型或新 prompt 的效果。
这个留痕机制平时看不出价值,一旦你决定升级模型,或者修改 prompt 策略,它就成了最有说服力的回归数据集。没有状态快照,你做任何优化都只能靠感觉,这对工程化来说是不可接受的。
结尾
实话说,自我修正 Agent 做出来不难,难的是让它在真实场景里“修得有效、修得可控”。我自己的体会有三点:第一,执行验证节点比模型调用节点重要得多,它是整个闭环的裁判,裁判错了再好的选手也发挥不出来;第二,条件边和 max_attempts 不只是技术方案,更是业务规则的落地,你需要在“自动修”和“及时止损”之间找平衡;第三,LangGraph 的价值不只是状态管理,更是把 Agent 的每次决策都变成可追溯、可复盘的资产。
最后分享一个我在测试环境里会用的小技巧:把所有节点的 LLM 调用封装成带 mock 的版本,跑图的时候不走真实模型,而是从预存的代码片段库里按顺序返回预置结果。这样你可以在不花钱的情况下,把图的整个执行路径,包括条件边的每个分支,完整测一遍。等逻辑没问题了再换成真实模型,能省掉大量调试时间。希望这篇内容对你有用。