当前位置: 首页 > news >正文

第3篇:Vibe Coding时代:LangChain Tools 实战,给 LangGraph Agent 加上文件读写能力

第3篇:Vibe Coding时代:LangChain Tools 实战,给 LangGraph Agent 加上文件读写能力


一、问题场景:Agent 能生成代码,但不能落盘,还是半成品

上一篇我们解决了 State 设计问题。

但很快又遇到一个新的真实问题:

Agent 生成了代码,可是代码只存在字符串里,不能写入项目文件。

比如模型输出:

main.py auth.py requirements.txt

但这些内容只是聊天结果。

开发者还要手动复制到本地文件。

这就很尴尬。

Vibe Coding 的目标不是让模型“说代码”,而是让模型参与真实开发流程:

理解需求 → 生成代码 → 写入文件 → 执行测试 → 修复问题

所以本文要解决:

如何给 LangGraph Agent 增加文件读写工具,让它从“回答型助手”升级成“可操作型 Coding Agent”。


二、真实问题:工具调用如果不加约束,很容易误操作

一开始我直接让模型决定写文件路径:

你可以自由写入文件。

结果它生成过这种路径:

C:\Users\Admin\Desktop\project\main.py /home/app/prod/config.py ../../settings.py

这非常危险。

因为真实环境中,文件写入是高风险操作。

必须限制:

  • 只能写入工作目录
  • 不能写系统目录
  • 不能覆盖敏感文件
  • 文件名必须合法
  • 写入前最好记录日志
  • 高风险写入需要人工确认

本文先实现安全版基础能力。


三、项目结构

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

workspace/是 Agent 允许操作的目录。

所有文件读写都限制在这个目录下。


四、安装依赖

创建requirements.txt

langchain langchain-openai langgraph python-dotenv

安装:

pipinstall-rrequirements.txt

五、定义文件工具

创建tools.py

frompathlibimportPath BASE_DIR=Path(__file__).parent.resolve()WORKSPACE_DIR=BASE_DIR/"workspace"WORKSPACE_DIR.mkdir(exist_ok=True)defsafe_path(relative_path:str)->Path:target_path=(WORKSPACE_DIR/relative_path).resolve()ifnotstr(target_path).startswith(str(WORKSPACE_DIR)):raiseValueError("非法路径:禁止访问 workspace 之外的文件")returntarget_pathdefwrite_file(relative_path:str,content:str)->str:target_path=safe_path(relative_path)target_path.parent.mkdir(parents=True,exist_ok=True)target_path.write_text(content,encoding="utf-8")returnf"文件写入成功:{target_path}"defread_file(relative_path:str)->str:target_path=safe_path(relative_path)ifnottarget_path.exists():raiseFileNotFoundError(f"文件不存在:{relative_path}")returntarget_path.read_text(encoding="utf-8")deflist_files()->list[str]:files=[]forpathinWORKSPACE_DIR.rglob("*"):ifpath.is_file():files.append(str(path.relative_to(WORKSPACE_DIR)))returnfiles

六、关键安全点解释

1. 为什么要用 safe_path?

核心代码:

target_path=(WORKSPACE_DIR/relative_path).resolve()

然后判断:

ifnotstr(target_path).startswith(str(WORKSPACE_DIR)):raiseValueError("非法路径")

这是为了防止路径穿越攻击。

比如用户输入:

../../.env

如果不做限制,就可能读取项目敏感配置。


2. 为什么只允许 workspace?

因为 Agent 写文件不可完全信任。

即使模型本身没有恶意,也可能因为 Prompt 理解错误写错路径。

工程上应该默认:

模型输出不可信,工具执行必须加边界。


七、定义 State

创建state.py

fromtypingimportTypedDict,ListclassFileArtifact(TypedDict):path:strcontent:strclassToolState(TypedDict):requirement:strfiles_to_write:List[FileArtifact]written_files:List[str]errors:List[str]final_answer:str

八、让模型生成文件列表

创建chains.py

importjsonfromlangchain_openaiimportChatOpenAIfromlangchain_core.promptsimportChatPromptTemplate llm=ChatOpenAI(model="gpt-4o-mini",temperature=0.1)defgenerate_files(requirement:str)->list[dict]:prompt=ChatPromptTemplate.from_messages([("system","你是一名资深 Python 工程师。""请根据用户需求生成项目文件列表。""必须输出 JSON 数组,不要输出 Markdown。"),("user",""" 用户需求: {requirement} 请输出格式: [ {{ "path": "main.py", "content": "文件内容" }}, {{ "path": "requirements.txt", "content": "文件内容" }} ] """)])chain=prompt|llm response=chain.invoke({"requirement":requirement})returnjson.loads(response.content)

这里要注意:

文件工具最好消费结构化数据,不要直接解析 Markdown 代码块。

很多人会让模型输出:

```python ...
然后再自己切代码块。 这种方式很不稳定。 --- ## 九、构建 LangGraph 创建 `graph.py`: ```python from langgraph.graph import StateGraph, END from state import ToolState from chains import generate_files from tools import write_file def generate_files_node(state: ToolState) -> ToolState: try: files = generate_files(state["requirement"]) state["files_to_write"] = files except Exception as e: state["errors"].append(f"生成文件失败:{str(e)}") return state def write_files_node(state: ToolState) -> ToolState: for item in state["files_to_write"]: try: result = write_file(item["path"], item["content"]) state["written_files"].append(result) except Exception as e: state["errors"].append(f"写入 {item.get('path')} 失败:{str(e)}") return state def final_node(state: ToolState) -> ToolState: state["final_answer"] = ( "文件生成完成。\n\n" f"成功写入:\n{chr(10).join(state['written_files'])}\n\n" f"错误信息:\n{chr(10).join(state['errors'])}" ) return state def build_graph(): graph = StateGraph(ToolState) graph.add_node("generate_files", generate_files_node) graph.add_node("write_files", write_files_node) graph.add_node("final", final_node) graph.set_entry_point("generate_files") graph.add_edge("generate_files", "write_files") graph.add_edge("write_files", "final") graph.add_edge("final", END) return graph.compile()

十、运行入口

创建app.py

fromgraphimportbuild_graphdefmain():app=build_graph()init_state={"requirement":"生成一个 FastAPI Hello World 项目,包含 main.py 和 requirements.txt","files_to_write":[],"written_files":[],"errors":[],"final_answer":"",}result=app.invoke(init_state)print(result["final_answer"])if__name__=="__main__":main()

运行:

python app.py

十一、验证结果

查看目录:

lsworkspace

你应该能看到:

main.py requirements.txt

查看内容:

catworkspace/main.py

可能类似:

fromfastapiimportFastAPI app=FastAPI()@app.get("/")defhello():return{"message":"Hello World"}

运行项目:

cdworkspace pipinstall-rrequirements.txt uvicorn main:app--reload

访问:

http://127.0.0.1:8000

返回:

{"message":"Hello World"}

十二、踩坑记录:不要让模型直接决定绝对路径

错误提示词:

请把文件写入用户项目目录

模型可能会生成:

/Users/admin/project/main.py C:\project\main.py ../../main.py

正确做法:

你只能输出相对于 workspace 的路径,例如 main.py、app/main.py。 禁止输出绝对路径。 禁止输出包含 .. 的路径。

并且工具层还要再次校验。

不要只相信 Prompt。


十三、踩坑记录:写文件前要考虑覆盖问题

当前write_file会直接覆盖同名文件。

生产环境建议改成:

defwrite_file(relative_path:str,content:str,overwrite:bool=False)->str:target_path=safe_path(relative_path)iftarget_path.exists()andnotoverwrite:raiseFileExistsError(f"文件已存在,禁止覆盖:{relative_path}")target_path.write_text(content,encoding="utf-8")returnf"文件写入成功:{target_path}"

这样可以避免 Agent 误覆盖已有文件。


十四、适合收藏:工具接入 checklist

1. 工具是否有明确输入参数? 2. 工具是否限制操作范围? 3. 工具是否做路径校验? 4. 工具是否有异常处理? 5. 工具执行结果是否写回 State? 6. 高风险工具是否需要人工确认? 7. 是否记录了工具调用日志? 8. 是否限制文件覆盖? 9. 是否能重复执行? 10. 是否方便单元测试?

十五、避坑清单

坑点表现解决方案
模型生成绝对路径写入危险目录只允许相对路径
路径穿越读取.env等敏感文件使用resolve + startswith校验
直接覆盖文件原代码丢失默认禁止覆盖
解析 Markdown 代码块文件拆分失败让模型输出 JSON
工具异常中断流程Agent 直接崩溃异常写入errors
工具结果没入 State后续节点无法使用所有结果写回状态

十六、总结

这一篇我们给 LangGraph Coding Agent 加上了文件读写能力。

核心经验是:

工具能力越强,边界越要清晰。

Agent 能写文件之后,就从“回答型助手”变成了“操作型助手”。

但同时也带来风险。

生产环境中,一定要做到:

  • 限制目录
  • 校验路径
  • 控制覆盖
  • 记录日志
  • 异常可恢复
  • 高风险操作人工确认

Vibe Coding 的工程化关键,不是让模型“想干什么就干什么”,而是让模型在安全边界内完成任务。


http://www.cnnetsun.cn/news/2161121.html

相关文章:

  • 第4篇:Vibe Coding时代:LangChain RAG + LangGraph 实战,让 Coding Agent 读懂项目文档再写代码
  • 3分钟掌握:Windows电脑直接安装安卓应用的终极方案
  • 互联网大厂 Java 求职面试:从 Spring Boot 到微服务的技术问答
  • Codex CLI教程(特殊篇) | PM Skills 全量解析剖析
  • 如何在Apple Silicon Mac上获得主机级游戏体验:PlayCover按键映射终极指南
  • Postman测试EasyExcel导入功能:从本地文件路径到HTTP上传的完整避坑指南
  • 轻松掌握vue3-element-admin字体设置:从基础调整到深度定制全攻略
  • Android 开发问题:WRITE_EXTERNAL_STORAGE is deprecated (and is not granted) when targeting Android 13+.
  • VMware macOS解锁终极指南:5分钟搞定苹果系统虚拟机
  • 终极FF14副本动画跳过指南:3分钟告别冗长等待的ACT插件完整教程
  • 锐评 Kimi K2.6 vs Claude Opus 4.7:别卷了,大家都在抢 Agent 这张票
  • ROFL-Player终极指南:3个简单步骤掌握英雄联盟回放分析
  • 为Jellyfin媒体库注入Bangumi动漫元数据:构建智能中文番剧管理系统
  • 3分钟学会AI视频去水印:让您的视频内容焕然一新
  • 告别网盘限速烦恼!八大主流网盘直链下载助手终极指南
  • 为什么职场精英镀金,都盯上这所瑞士商学院
  • 2026年企业网盘推荐,从场景功能出发,打造高效协作的数字化解决方案
  • 快检C3:60分钟锁定补体级联“风暴眼”,精准狙击肾病/自免疾病
  • 体验Taotoken多模型聚合路由带来的高可用性与低延迟
  • Windows平台APK安装革命:告别模拟器的智能安卓应用部署方案
  • OBS实时字幕插件完整配置指南:5步实现专业直播体验
  • 3分钟破解视频水印难题:开源工具的智能修复方案
  • Translumo终极指南:如何用免费实时屏幕翻译工具打破语言障碍
  • UDS网络层时间参数N_As/N_Br/STmin详解:如何优化多帧传输效率与稳定性
  • 从豆瓣评分到淘宝推荐:深入聊聊皮尔森相关系数的优势、坑与替代方案
  • ROS2 交互式调试工具:告别繁琐的命令行操作
  • R语言如何量化大模型偏见?3个被顶会反复验证的统计检验(KS/Wilcoxon/Cochran-Armitage)源码逐行解析
  • 实测GPT-5.5两天高频使用:能力跃升干货总结,附省心中转推荐
  • 从 GCC 到 JVM:编译期 vs 运行时,一次彻底讲透(体系篇)
  • 落地灯哪种好用又实惠?全网公认排行榜,性价比之王