代码是AI写的用的CC接入DS-v4-pro代码在前文基础上更新功能包括Agent框架文件工具联网搜索本篇文章仅作为个人学习笔记记录文件工具完整代码如下 文件工具 Agent —— 让 AI 能读写你的文件 基于 04-agent-framework.py 的框架新增两个文件工具。 展示框架的扩展能力想加工具写函数 → add_tool → 搞定。 import sys import os sys.stdout.reconfigure(encodingutf-8) # 直接复用框架 from importlib.util import spec_from_file_location, module_from_spec spec spec_from_file_location(framework, os.path.join(os.path.dirname(__file__), 04-agent-framework.py)) framework module_from_spec(spec) spec.loader.exec_module(framework) Agent framework.Agent TOOL_REGISTRY framework.TOOL_REGISTRY.copy() # 继承基础工具 # # 新增工具1读文件 # def read_file(path: str) - str: 读取指定路径的文件内容 if not os.path.exists(path): return f文件不存在{path} try: with open(path, r, encodingutf-8) as f: content f.read() # 限制返回长度避免 token 爆炸 if len(content) 3000: content content[:3000] \n...(内容已截断) return content except Exception as e: return f读取失败{e} # # 新增工具2写文件 # def write_file(path: str, content: str) - str: 写入内容到文件。会自动创建不存在的目录。 try: dir_path os.path.dirname(path) if dir_path and not os.path.exists(dir_path): os.makedirs(dir_path) with open(path, w, encodingutf-8) as f: f.write(content) return f文件已写入{path}{len(content)} 个字符 except Exception as e: return f写入失败{e} # # 注册新工具 # TOOL_REGISTRY.update({ read_file: { func: read_file, description: 读取电脑上的文件内容。当需要查看某个文件时使用。, parameters: { type: object, properties: { path: {type: string, description: 文件的完整路径}, }, required: [path], }, }, write_file: { func: write_file, description: 将内容写入文件。用户要求保存、记录、导出时使用。, parameters: { type: object, properties: { path: {type: string, description: 要写入的文件路径}, content: {type: string, description: 要写入的内容}, }, required: [path, content], }, }, }) # # 启动 # if __name__ __main__: # 指定一个工作目录给 Agent避免它乱翻 work_dir os.path.join(os.path.dirname(__file__), agent_workspace) os.makedirs(work_dir, exist_okTrue) agent Agent(system_promptf你是一个能用工具的 AI 助手可以用中文回答问题。 你可以 - 运行 Python 代码做计算 - 查看当前时间 - 读写电脑上的文件 文件操作的默认目录是{work_dir} 用户说记下来时你就用 write_file 保存到那个目录。 用户说看一下时你就用 read_file 读取。) for name, info in TOOL_REGISTRY.items(): agent.add_tool(name, info[func], info[description], info[parameters]) print( * 50) print(文件 Agent —— 我能帮你读写文件了) print(f工作目录{work_dir}) print(试试) print( 帮我写一首诗保存到 poem.txt) print( 帮我记一下明天下午3点开会) print( 看看 poem.txt 里写了什么) print(输入 quit 退出clear 清空记忆) print( * 50) while True: user_input input(\n你: ) if user_input.lower() quit: print(再见) break if user_input.lower() clear: agent.clear_memory() print((记忆已清空)) continue reply agent.chat(user_input) print(fAI: {reply})一、动态加载普通import动态加载当前代码文件必须在sys.path列出的目录中如当前目录、PYTHONPATH可以从任意绝对或相对路径加载不受sys.path限制模块名必须与文件名相同除去.py可以任意指定模块名如framework不与文件名绑定导入时机在代码编写时就确定了可以在运行时决定加载哪个文件比如根据配置示例import 04_agent_framework文件名不能以数字开头不合法可以加载以数字开头的文件名如04-agent-framework.py普通import做不到使用普通import复用其他.py文件只需要直接import文件名不带.py后缀即可1.从importlib.util导入两个辅助函数spec_from_file_location创建一个“模块规范”ModuleSpec描述了模块的元数据。module_from_spec根据模块规范创建一个空的模块对象。# 直接复用框架 from importlib.util import spec_from_file_location, module_from_spec2.spec spec_from_file_location(framework, os.path.join(os.path.dirname(__file__), 04-agent-framework.py))spec_from_file_location的第一个参数framework是给这个模块起的名字可以任意不一定和文件名相同。第二个参数是文件的完整路径通过os.path.dirname(__file__)获取当前脚本所在的目录__file__当前脚本文件的路径然后拼接上04-agent-framework.py。这个函数返回一个ModuleSpec对象里面记录了“如何加载这个文件作为一个模块”。framework module_from_spec(spec)根据上面创建的规范创建一个空的模块对象spec.loader是模块对应的加载器.exec_module(framework)是真正执行04-agent-framework.py文件中的代码并把执行结果填充到framework这个模块对象中spec spec_from_file_location(framework, os.path.join(os.path.dirname(__file__), 04-agent-framework.py)) framework module_from_spec(spec) spec.loader.exec_module(framework)3.调用上面代码导入的framework模块framework.Agent获取框架中的类 .copy()方法复制字典避免修改原注册表Agent framework.Agent TOOL_REGISTRY framework.TOOL_REGISTRY.copy() # 继承基础工具二、文件读取def read_file(path: str) - str: 读取指定路径的文件内容 if not os.path.exists(path): # 1. 检查文件是否存在 return f文件不存在{path} try: with open(path, r, encodingutf-8) as f: # 2. 打开文件 content f.read() # 3. 读取内容 # 4. 限制返回长度避免 token 爆炸 if len(content) 3000: content content[:3000] \n...(内容已截断) return content except Exception as e: # 5. 异常处理 return f读取失败{e}1.with open()是上下文管理器自动关闭文件as f将打开的文件对象赋值给变量fwith 表达式 [as 变量]:调用该对象的_enter_()方法其返回值如果有赋值给as后面的变量。无论块内是否发生异常都会在退出时调用上下文管理器的_exit_()方法执行清理工作。如果_exit_返回True则异常被压制不再向外抛出否则异常会继续传播。def read_file(path: str) - str: 读取指定路径的文件内容 if not os.path.exists(path): # 1. 检查文件是否存在 return f文件不存在{path} try: with open(path, r, encodingutf-8) as f: # 2. 打开文件 content f.read() # 3. 读取内容 # 4. 限制返回长度避免 token 爆炸 if len(content) 3000: content content[:3000] \n...(内容已截断) return content except Exception as e: # 5. 异常处理 return f读取失败{e}2.f.read()一次性读取文件的全部内容返回一个字符串。content f.read()三、文件写入工具1.os.makedirs()递归创建多级目录os.makedirs(path, exist_okTrue)递归创建所有缺失目录同时在路径已存在的时候不会报错def write_file(path: str, content: str) - str: 写入内容到文件。会自动创建不存在的目录。 try: dir_path os.path.dirname(path) # 1. 获取目录路径 # 2. 如果目录不存在则创建 if dir_path and not os.path.exists(dir_path): os.makedirs(dir_path) # 递归创建目录 # 3. 写入文件 with open(path, w, encodingutf-8) as f: f.write(content) # 写入内容 return f文件已写入{path}{len(content)} 个字符 except Exception as e: return f写入失败{e}2.if dir_path and not os.path.exists(dir_path):中dir_path首先判断你给出的路径名称是不是空的然后and not os.path.exists(dir_path):判断路径是不是已经存在了if dir_path and not os.path.exists(dir_path):四、工具注册TOOL_REGISTRY.update({ read_file: { func: read_file, description: 读取电脑上的文件内容。当需要查看某个文件时使用。, parameters: { type: object, properties: { path: { type: string, description: 文件的完整路径 }, }, required: [path], # 必需参数 }, }, write_file: {...} # 类似结构 })五、主程序配置1.创建工作目录work_dir os.path.join(os.path.dirname(__file__), agent_workspace) os.makedirs(work_dir, exist_okTrue)2.name和info是键值对info也是字典这个循环可以使主程序自动加载工具for name, info in TOOL_REGISTRY.items(): agent.add_tool(name, info[func], info[description], info[parameters])