news 2026/4/30 14:34:37

第5篇:Vibe Coding时代:LangGraph 测试闭环实战,让 Agent 自动生成代码、运行测试并修复失败

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第5篇:Vibe Coding时代:LangGraph 测试闭环实战,让 Agent 自动生成代码、运行测试并修复失败

第5篇:Vibe Coding时代:LangGraph 测试闭环实战,让 Agent 自动生成代码、运行测试并修复失败


一、问题场景:Agent 写完代码后,没人知道它到底能不能跑

很多 AI Coding Demo 到“生成代码”就结束了。

但是做过真实开发都知道:

代码生成出来,只是第一步;能不能跑,测试说了算。

我之前做过一个自动生成接口的 Agent。

模型输出看起来很完整:

@app.post("/login")deflogin(...):...

但实际运行发现:

  • 依赖没写全
  • import 路径错误
  • Pydantic 版本用法混乱
  • 测试用例跑不通
  • 生成了不存在的函数
  • 异常返回格式不一致

如果没有测试闭环,这些问题都要人工发现。

所以本文要实现:

生成代码 → 写入文件 → 生成测试 → 执行 pytest → 失败后修复 → 再测试

这才更接近真实 Vibe Coding。


二、流程设计

用户需求 ↓ 生成项目文件 ↓ 生成测试文件 ↓ 写入 workspace ↓ 执行 pytest ↓ 测试是否通过? ├── 通过:输出结果 └── 失败:把错误信息传回代码生成节点

核心点:

测试错误信息必须进入 State,并传回修复节点。

否则模型不知道怎么修。


三、项目结构

vibe-agent-test-loop/ ├── app.py ├── graph.py ├── state.py ├── chains.py ├── tools.py ├── workspace/ └── requirements.txt

四、依赖安装

langchain langchain-openai langgraph python-dotenv pytest fastapi uvicorn httpx

安装:

pipinstall-rrequirements.txt

五、定义工具

创建tools.py

importsubprocessfrompathlibimportPath BASE_DIR=Path(__file__).parent.resolve()WORKSPACE=BASE_DIR/"workspace"WORKSPACE.mkdir(exist_ok=True)defsafe_path(path:str)->Path:target=(WORKSPACE/path).resolve()ifnotstr(target).startswith(str(WORKSPACE)):raiseValueError("非法路径")returntargetdefwrite_file(path:str,content:str)->str:target=safe_path(path)target.parent.mkdir(parents=True,exist_ok=True)target.write_text(content,encoding="utf-8")returnstr(target)defrun_pytest()->str:result=subprocess.run(["pytest","-q"],cwd=str(WORKSPACE),capture_output=True,text=True,timeout=30,)return(f"returncode={result.returncode}\n\n"f"stdout:\n{result.stdout}\n\n"f"stderr:\n{result.stderr}")

注意:

  • cwd限制在 workspace
  • timeout防止测试卡死
  • stdout/stderr 都要保存

六、定义 State

创建state.py

fromtypingimportTypedDict,ListclassFileItem(TypedDict):path:strcontent:strclassTestLoopState(TypedDict):requirement:strfiles:List[FileItem]test_result:strretry_count:interrors:List[str]final_answer:str

七、生成代码和测试

创建chains.py

importjsonfromlangchain_openaiimportChatOpenAIfromlangchain_core.promptsimportChatPromptTemplate llm=ChatOpenAI(model="gpt-4o-mini",temperature=0.1)defgenerate_project_files(requirement:str,test_result:str="")->list[dict]:prompt=ChatPromptTemplate.from_messages([("system","你是一名资深 Python 工程师。""请生成可运行项目文件和 pytest 测试文件。""必须输出 JSON 数组,不要输出 Markdown。"),("user",""" 用户需求: {requirement} 上一次测试结果: {test_result} 请输出 JSON 数组: [ {{ "path": "main.py", "content": "代码内容" }}, {{ "path": "test_main.py", "content": "测试内容" }} ] 要求: 1. 代码必须可运行 2. 测试必须能用 pytest 执行 3. 如果有上一次测试错误,请针对错误修复 """)])chain=prompt|llm response=chain.invoke({"requirement":requirement,"test_result":test_result,})returnjson.loads(response.content)

八、构建 LangGraph

创建graph.py

fromlanggraph.graphimportStateGraph,ENDfromstateimportTestLoopStatefromchainsimportgenerate_project_filesfromtoolsimportwrite_file,run_pytest MAX_RETRY=2defgenerate_node(state:TestLoopState)->TestLoopState:try:files=generate_project_files(requirement=state["requirement"],test_result=state["test_result"],)state["files"]=filesexceptExceptionase:state["errors"].append(f"生成失败:{str(e)}")returnstatedefwrite_node(state:TestLoopState)->TestLoopState:forfileinstate["files"]:try:write_file(file["path"],file["content"])exceptExceptionase:state["errors"].append(f"写入失败:{file.get('path')}{str(e)}")returnstatedeftest_node(state:TestLoopState)->TestLoopState:try:state["test_result"]=run_pytest()exceptExceptionase:state["test_result"]=f"测试执行异常:{str(e)}"state["errors"].append(state["test_result"])returnstatedefshould_retry(state:TestLoopState)->str:if"returncode=0"instate["test_result"]:return"finish"ifstate["retry_count"]>=MAX_RETRY:return"finish"state["retry_count"]+=1return"retry"deffinal_node(state:TestLoopState)->TestLoopState:state["final_answer"]=("## 测试结果\n\n"f"{state['test_result']}\n\n""## 重试次数\n\n"f"{state['retry_count']}\n\n""## 错误信息\n\n"f"{state['errors']}")returnstatedefbuild_graph():graph=StateGraph(TestLoopState)graph.add_node("generate",generate_node)graph.add_node("write",write_node)graph.add_node("test",test_node)graph.add_node("final",final_node)graph.set_entry_point("generate")graph.add_edge("generate","write")graph.add_edge("write","test")graph.add_conditional_edges("test",should_retry,{"retry":"generate","finish":"final",})graph.add_edge("final",END)returngraph.compile()

九、运行入口

创建app.py

fromgraphimportbuild_graphdefmain():app=build_graph()state={"requirement":"生成一个 FastAPI Hello World 接口,GET / 返回 {'message': 'hello'}","files":[],"test_result":"","retry_count":0,"errors":[],"final_answer":"",}result=app.invoke(state)print(result["final_answer"])if__name__=="__main__":main()

运行:

python app.py

十、验证结果

理想情况下输出:

returncode=0 stdout: . [100%] 1 passed in 0.42s

如果第一次失败,可能类似:

ModuleNotFoundError: No module named 'main'

这个错误会传回generate_node,模型会基于错误重新生成代码。


十一、踩坑记录:不要只让模型“自我审查”

很多人会写:

请检查你生成的代码是否有问题

模型通常会回答:

代码整体没有明显问题。

但实际运行可能直接报错。

所以工程上更可靠的闭环是:

模型审查 + 真实测试执行

模型审查发现风格问题,测试执行发现运行问题。

两者不能互相替代。


十二、踩坑记录:测试命令必须设置 timeout

错误写法:

subprocess.run(["pytest"])

如果测试卡住,整个 Agent 会一直挂着。

正确写法:

subprocess.run(["pytest","-q"],timeout=30,capture_output=True,text=True)

所有外部命令都应该设置超时。


十三、踩坑记录:测试失败信息必须完整传回模型

不要只传:

测试失败

这没用。

要传:

returncode stdout stderr 完整 traceback

模型修复代码时,非常依赖错误细节。


十四、适合收藏:测试闭环步骤

1. 生成业务代码 2. 生成测试代码 3. 写入 workspace 4. 执行 pytest 5. 捕获 returncode/stdout/stderr 6. 判断是否通过 7. 失败时把错误传回生成节点 8. 限制最大重试次数 9. 通过后输出最终结果 10. 失败后保留最后一次错误

十五、避坑清单

坑点表现解决方案
只生成代码不测试不知道能不能跑加 pytest 节点
只传“失败”模型无法修复传完整 stdout/stderr
没有 timeout流程卡死subprocess 加 timeout
无限重试成本失控设置 MAX_RETRY
工作目录错误找不到文件cwd 指向 workspace
测试文件缺依赖pytest 失败生成 requirements 或固定依赖

十六、总结

这一篇我们让 Coding Agent 从“生成代码”升级成了“生成 + 测试 + 修复”的闭环。

这是 Vibe Coding 进入工程化的关键一步。

我的经验是:

没有测试闭环的 AI Coding,只能叫代码建议;有测试闭环,才开始接近自动开发。

后续还可以继续扩展:

  • 执行 ruff 检查
  • 执行 mypy 类型检查
  • 执行安全扫描
  • 生成覆盖率报告
  • 对失败用例做归因分析

Agent 不应该只会写代码,它还应该知道代码是否真的能工作。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/30 14:33:23

对比直连与聚合接入在模型切换成本上的实际差异

模型切换效率对比:直连与聚合接入的实际开发体验 1. 多模型开发场景中的常见需求 在开发基于大语言模型的应用时,经常需要测试不同模型的输出效果。典型场景包括评估新模型性能、对比不同供应商的生成质量、或者针对特定任务寻找最佳模型。传统方式需要…

作者头像 李华
网站建设 2026/4/30 14:32:53

音乐API终极指南:如何快速获取全网音乐播放地址

音乐API终极指南:如何快速获取全网音乐播放地址 【免费下载链接】music-api Music API 项目地址: https://gitcode.com/gh_mirrors/mu/music-api 在数字音乐时代,你是否曾为不同音乐平台的接口差异而烦恼?music-api项目为你提供了一套…

作者头像 李华
网站建设 2026/4/30 14:32:15

3个技巧让Mac风扇控制更智能:smcFanControl完全指南

3个技巧让Mac风扇控制更智能:smcFanControl完全指南 【免费下载链接】smcFanControl Control the fans of every Intel Mac to make it run cooler 项目地址: https://gitcode.com/gh_mirrors/smc/smcFanControl smcFanControl是一款专为Intel Mac设计的开源…

作者头像 李华
网站建设 2026/4/30 14:29:27

MacOS平台虚拟机搭建开发环境新方法使用OrbStack‌

过去很长一段时间都是使用Parallels Desktop,然后在里面构建Linux所需的软件环境来进行开发 OrbStack‌ OrbStack 是一款专为‌macOS 系统‌设计的轻量级容器与虚拟机管理工具,可作为 Docker Desktop 的高效替代品,支持快速运行 Docker 容器…

作者头像 李华
网站建设 2026/4/30 14:28:28

TPFanCtrl2:为ThinkPad用户打造个性化散热体验的完整指南

TPFanCtrl2:为ThinkPad用户打造个性化散热体验的完整指南 【免费下载链接】TPFanCtrl2 ThinkPad Fan Control 2 (Dual Fan) for Windows 10 and 11 项目地址: https://gitcode.com/gh_mirrors/tp/TPFanCtrl2 你是否曾为ThinkPad笔记本在重负载下的风扇噪音而…

作者头像 李华
网站建设 2026/4/30 14:24:12

LangChain实现简易版-----PDF 文档问答机器人

文档加载器 文本分割器 PromptTemplate LLM原理(极简版,不学向量也能懂)加载 PDF 全部文本分割成多个语义完整文本块用户提问 → 简单匹配最相关的文本块把「相关文档片段 用户问题」塞进提示词强制 LLM 只能看给的文档片段回答&#xff…

作者头像 李华