发布时间:2026/8/30 18:05:47
Agent 文件处理中间件 1. 制作基础 Tool在开始文件处理中间件之前先给 Agent 增加两个简单的 Tool方便后续测试获取当前时间执行终端命令Tool 放在content/mytools/globle_tools.py中通过get_tools()统一返回。其中获取时间比较简单主要用于处理一些和当前时间有关的任务。终端命令则不一样。对于 Agent 来说终端本身就是一个很通用的操作入口。例如cat file.txt可以读取文件echo hello file.txt可以写入文件python test.py可以执行 Agent 临时生成的 Python 代码。所以理论上只要 Agent 能执行终端命令就可以完成很多原本需要单独开发 Tool 的事情。但终端命令也存在明显的问题。首先是安全性Agent 生成的命令不一定可靠例如删除文件、修改系统配置等操作都可能造成实际影响。其次是环境依赖不同操作系统、不同运行环境下同一条命令可能有不同的结果。最后是返回结果不固定Agent 还需要自己理解命令输出。因此这里没有把run_command当成主要的文件操作方式而是作为一个兜底能力。后续如果有专门的 Tool 能完成某项工作优先使用专用 Tool实在没有合适的工具时再考虑通过终端处理。2. 文件处理中间件2.1 为什么需要前面的文件后端已经能够处理 Agent 的文件操作但实际使用过程中还有两个问题。第一个问题是Agent 对当前目录并不一定清楚。比如 Agent 前面刚生成了一个文件下一步又需要读取它。如果模型不知道当前目录里有哪些文件就可能重新创建文件或者使用错误的路径。第二个问题是工具返回结果可能包含系统绝对路径。例如系统实际使用D:/agent_files/thread_xxx/data/test.txt但对于 Agent 来说更合适的形式应该是data/test.txtAgent 没必要知道D:/agent_files/thread_xxx/这一层具体对应服务器上的什么位置。所以这里准备做一个文件处理中间件主要处理两件事模型调用前在必要的时候告诉 Agent 当前目录结构Tool 执行结束后将返回结果中的系统绝对路径转换成相对路径。这样文件后端负责真正的文件操作中间件负责处理 Agent 与文件系统之间的一些衔接问题。3. 实现思路3.1 目录结构首先需要一个方法根据真实工作目录生成类似下面的结构project/ ├── src/ │ ├── main.py │ └── utils.py ├── data/ └── README.md这个方法放在utils/doc_utils/os_util.py里面。实现上就是使用os.listdir()递归遍历目录同时处理好目录层级和├──、└──这些符号。这里没有直接调用系统的tree命令而是自己实现。主要还是考虑到项目需要兼容不同运行环境而且这个方法本身并不复杂自己实现之后也更容易控制输出格式。3.2 不需要每次都重新获取目录目录结构虽然有用但也没必要每次调用模型都重新发送。例如调用模型 → 调用 Tool → Tool 返回 → 再次调用模型如果中间没有创建、删除或者修改文件那么目录结构其实没有变化。因此这里增加一个简单的判断当前目录最新文件修改时间 ↓ 是否晚于上一次记录的时间 ↓ 是 → 重新获取目录结构 否 → 什么都不做为了保存这个状态对AgentState做一个简单扩展class CustomState(AgentState): start_work_time: float file_update_time: float其中file_update_time用来记录已经知道的文件更新时间。Agent 开始执行时记录一次当前时间async def abefore_agent(self, state, runtime): current_time time.time() return { start_work_time: current_time, file_update_time: current_time }之后在abefore_model中检查当前目录。文件更新时间的获取同样放在os_util.py中。通过os.walk()遍历目录下的文件获取每个文件的mtime最后取最大值。4. 路径处理4.1 系统路径和 Agent 路径这里需要区分两个概念。系统路径是程序真正访问文件时使用的路径例如D:/agent_files/thread_123/data/test.txtAgent 路径则只需要data/test.txt因此项目中增加ROOT_PATH_SYSTEM用于表示系统上的真实工作根目录。Windows 下需要带盘符例如D:/agent_filesLinux 下则可以直接使用/agent_files再和当前线程 ID 拼接就可以得到当前 Agent 的实际工作目录。4.2 获取当前线程目录在content/utils/runtime_util.py中增加def get_root_thread_dir(): raw_path os.path.join( gc.ROOT_PATH_SYSTEM, get_thread_id() ) return os.path.normpath(raw_path)以后需要获取当前线程真实工作目录时直接调用这个方法即可。例如D:/agent_files/thread_123这样中间件不需要自己处理线程 ID 和系统根目录。4.3 将绝对路径转换为相对路径Tool 执行完成后如果返回D:\agent_files\thread_123\data\test.txt需要转换成data\test.txt因此在runtime_util.py中再增加一个def get_out_path(file_path): ...它主要做的事情就是获取当前线程目录 ↓ 判断返回结果是否包含该目录 ↓ 如果包含去掉线程目录部分 ↓ 得到 Agent 使用的相对路径这样路径处理逻辑集中在一个地方后面其他地方如果也需要做相同转换可以直接复用。5. 文件处理中间件前面的几个方法准备好之后就可以把它们组合到中间件中。中间件放在content/middles/file_manager_middle.py这里使用AgentMiddleware并实现三个生命周期方法abefore_agent abefore_model awrap_tool_call分别对应 Agent 开始执行、模型调用前、Tool 调用前后这几个阶段。5.1abefore_agentAgent 开始执行时记录两个时间start_work_time file_update_time目前start_work_time主要是为了记录本次任务的开始时间后续如果需要统计 Agent 工作时间也可以直接使用。file_update_time则用于后面的文件变化检测。5.2abefore_model模型调用之前先获取当前线程的真实工作目录。然后检查最新文件修改时间 file_update_time如果没有变化就直接继续调用模型。如果有变化则重新生成目录结构并把目录结构作为一条ToolMessage加入消息中。逻辑大致如下async def abefore_model(self, state, runtime): dir_path rt.get_root_thread_dir() if await self._check_if_new_file( dir_path, state[file_update_time] ): content get_directory_tree(dir_path) return { messages: [ ToolMessage( contentf当前目录结构:\n{content}, tool_call_idget_uuid(), namesummery_file_paths ) ], file_update_time: time.time() }这里有两个值得注意的地方。第一目录遍历本身是同步 I/O而 Agent 当前运行环境是异步的因此不能直接在异步流程里做大量同步 I/O。这里使用await asyncio.to_thread(...)将同步操作放到线程中执行。第二这条ToolMessage并不是 Agent 真正调用某个 Tool 得到的因此没有真实的tool_call_id。这里生成一个 UUID 作为标识即可。5.3awrap_tool_call另一个问题发生在 Tool 执行完成以后。这里通过awrap_tool_call包住实际的 Tool 调用async def awrap_tool_call(self, request, handler): tool_result await handler(request) if isinstance(tool_result, ToolMessage): tool_result.content rt.get_out_path( tool_result.content ) return tool_result执行顺序就是Agent 调用 Tool ↓ handler(request) ↓ Tool 真正执行 ↓ 得到 ToolMessage ↓ 处理其中的绝对路径 ↓ 返回 Agent这样就不需要在每个 Tool 中分别处理路径。如果后面再增加新的文件 Tool只要它正常返回结果中间件就可以统一处理。6. 接入 Agent最后在all_agent.py中注册中间件self.agent create_deep_agent( modelget_llm(), toolsself._get_tools(), middlewareself._get_middlewares(), backendmybackend.create_session_backend, system_promptprompt, )中间件列表def _get_middlewares(self): return [ file_manager_middle.FileMiddleware() ]至此文件管理相关的处理逻辑就从具体 Tool 中独立出来了。7. 最终目录本次主要新增和修改以下文件├── base │ └── configs.py │ # 增加 ROOT_PATH_SYSTEM │ ├── content │ ├── all_agent.py │ │ # 注册文件处理中间件 │ │ │ ├── middles │ │ └── file_manager_middle.py │ │ # 文件处理中间件 │ │ │ ├── mytools │ │ └── globle_tools.py │ │ # 基础 Tool │ │ │ └── utils │ └── runtime_util.py │ # 工作目录、路径转换 │ └── utils ├── doc_utils │ └── os_util.py │ # 目录遍历、文件更新时间 │ └── general_utils └── globle_util.py # 系统判断、UUID等通用方法8. 小结这次主要做的其实不是一个新的文件 Tool而是把文件系统相关的公共处理逻辑放到了 Agent Middleware 中。最终处理流程Agent 开始 ↓ 记录文件状态 ↓ 模型调用前检查文件变化 ↓ 有变化 → 更新目录结构 ↓ Tool 执行 ↓ Tool 返回结果 ↓ 绝对路径转换为相对路径 ↓ 返回 Agent这样处理之后Agent 可以在文件发生变化后重新获得目录结构没有文件变化时不会重复发送目录信息Agent 看到的是相对路径不需要知道服务器上的真实目录文件路径处理不需要分散到每一个 Tool 中文件相关逻辑与具体业务 Tool 解耦。这也是这次使用 Middleware 比直接修改 Tool 更合适的地方文件变化检测和路径处理本身并不属于某一个具体 Tool而是 Agent 执行过程中的公共逻辑。

相关新闻

2026/8/30 18:00:47

用 TUI 巡检 Snowflake Tasks:从状态查询到终端工具实现思路

如果你负责维护一个用 Snowflake Tasks 编排的数据平台,大概率经历过这种场景:凌晨被告警叫醒,某条任务链路失败了。你打开 Snowflake Web 控制台,先进入 Tasks 页面,一层层展开任务依赖,再点进运行历史&am…

2026/8/30 18:00:47

零基础学Python:用猜数字小游戏点燃编程兴趣与反馈闭环

如果有一件事能让零基础的人对 Python 的兴趣瞬间飙到一个夸张的数字,那通常不是一本语法书,而是一个能当场运行、现场反馈的小游戏。我第一次写出完整可玩的猜数字程序时,心里冒出来的其实不是“我会编程了”,而是“屏幕上的数字…

2026/8/30 18:00:47

方向盘玩恐怖Mod是馊主意?输入映射与力反馈冲突全解析

好几次在折腾游戏外设时,我都看到有人兴致勃勃地把方向盘接到恐怖游戏 Mod 环境里,接着没到十分钟就开始骂骂咧咧地拔线。表面上看这只是“设备选错”的乌龙,但背后其实牵扯到输入映射、力反馈逻辑、视角控制、Mod 兼容性等一系列完全可以拆开…

2026/8/30 18:15:48

VB6控件ReSize.ocx与imgctls.ocx注册打包及80040154报错全解析

简介:在Windows软件开发中,ActiveX控件(OCX)是实现界面增强功能的关键组件,尤其对VB6工程而言,控件注册与分发是项目落地的核心环节。理解OCX控件的运作原理,掌握正确的注册方式,能有…

2026/8/30 18:15:48

软件测试简历优化:在线评测逻辑与五大短板修复指南

每年到了求职季,软件测试岗位的竞争强度都在上升。很多人投出几十份甚至上百份简历,收到的面试邀请却寥寥无几。第一反应往往是“是不是岗位太少”“是不是学历不够”“是不是现在行情不好”。但实际上,在很多情况下,问题出在简历…

2026/8/30 18:15:48

Python 350道练习题刷题全攻略:从基础语法到算法实践

很多刚开始学 Python 的朋友都有过这样的体验:视频课跟着老师敲代码,每一步都能运行通过,感觉自己已经学会了;可一旦关掉视频,面对一个空白的编辑器界面,连“输出 1 到 100 的所有偶数”都要想半天。这并不…

2026/8/30 18:15:48

AI项目命名指南:从60年代科幻词根到自动化可用性筛选

给AI项目命名是一件看起来简单、实际很耗时的事。团队在立项时往往先想出一个自认为有科技感的名字,填写仓库名的时候才发现对应的GitHub组织、PyPI包、npm包、域名甚至商标都已经被人占用。另一个常见问题是,新造词为了“独特”而过度变形,导…

2026/8/30 18:10:48

Python入门实战:华氏温度转摄氏温度,掌握输入输出与类型转换

如果你想给Python入门找一个足够简单又能练到关键技巧的实战题目,华氏温度转摄氏温度是非常合适的选择。这个题目看着只有一行公式,但它能把环境安装、代码运行、输入输出、类型转换、格式化显示全部串起来。完成这个小程序之后,你不只是学会…

2026/8/30 0:03:35

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/8/30 0:03:35

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/8/30 0:03:35

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/8/30 0:03:35

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/8/30 0:03:35

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/8/30 0:03:35

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/8/28 16:16:48

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/28 16:16:50

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/28 11:06:45

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…