[MAF预定义的AIContextProvider-07]FileAccessProvider——为Agent提供文件读写能力
作为LangChain Harness框架的Deep Agents利用BackendProtocol协议定义了一个文件系统,并利用FileSystemMiddleware注册的工具提供了操作文件系统的能力。MAF也提供了类似的能力,它利用抽象类AgentFileStore定义了一个抽象的文件系统,并利用FileAccessProvider这个AIContextProvider为Agent提供了文件读写能力。FileAccessProvider提供的文件系统不仅可以被Agent直接使用,它同时也是其他一些依赖持久化能力组件的基础构建,比如基于文件系统的记忆组件。
1. 以自然语言的方式操作文件系统
借助于FileAccessProvider提供的工具,使得Agent可以采用自然语言的方式实现文件的读写和执行一些基本的目录操作,如下的实例演示了这一点。如代码片段所示,我们在调用AsAIAgent方法时提供了一个ChatClientAgentOptions对象,在这个对象中我们注册了FileAccessProvider这个AIContextProvider。创建FileAccessProvider对象时需要传入一个AgentFileStore对象,我们使用的时一个InMemoryAgentFileStore对象,它在内存中模拟了一个文件系统。
usingdotenv.net;usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingOpenAI;usingSystem.ClientModel;DotEnv.Load();varmodel=Environment.GetEnvironmentVariable("MODEL")!;varapiKey=Environment.GetEnvironmentVariable("API_KEY")!;varendpoint=Environment.GetEnvironmentVariable("OPENAI_URL")!;varagent=newOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{Endpoint=newUri(endpoint)}).GetChatClient(model).AsIChatClient().AsAIAgent(options:newChatClientAgentOptions{AIContextProviders=[newFileAccessProvider(newInMemoryAgentFileStore())],});varsession=awaitagent.CreateSessionAsync();while(true){Console.Write("\n请输入命令:");varcommand=Console.ReadLine();if(string.IsNullOrEmpty(command))break;varresponse=awaitagent.RunAsync(command,session);Console.WriteLine(response);}然后我们开启了一个循环,在每次循环中我们都从控制台读取用户输入的命令,并将这个命令发送给Agent来执行。如下所示的Agent针对我们输入命令的响应结果。
请输入命令:写入文本内容"Hello world!"到foo.txt 已成功将文本内容 “Hello world!” 写入到 `foo.txt`。 请输入命令:写入随机文本到bar.txt 已成功将随机文本写入到 `bar.txt`。 请输入命令:读取文件foo.txt的内容 `foo.txt` 的内容如下: ``` Hello world! ``` 请输入命令:读取文件bar.txt的内容 `bar.txt` 的内容如下: ``` Zx7qLm2pR9tVb4nK8wXc1dF6hJ0sY3uA Random sequence: 48291-ABXZ-77qpL Lorem ipsum fragment: velorix tanem sulvar quentis arvolex. Timestamp-like string: 2026-06-02T14:37:52Z ``` 请输入命令:列出当前目录下所有文件 当前目录下的文件如下: - `bar.txt` - `foo.txt` 请输入命令:删除文件bar.txt 已成功删除文件 `bar.txt`。 请输入命令:列出当前目录下所有文件 当前目录下的文件如下: - `foo.txt`2. 由AgentFileStore定义的抽象文件系统
AgentFileStore通过提供7个操作文件和目录的方法定义了一个抽象的文件系统,这些方法包括:写文件、读文件、删除文件、列出目录下的文件、检查文件是否存在、搜索文件以及创建目录。通过实现AgentFileStore,开发者可以将不同的存储系统(如本地文件系统、云存储服务等)适配到FileAccessProvider中,从而为Agent提供持久化的文件读写能力。
publicabstractclassAgentFileStore{publicabstractTaskWriteFileAsync(stringpath,stringcontent,CancellationTokencancellationToken=default);publicabstractTask<string?>ReadFileAsync(stringpath,CancellationTokencancellationToken=default);publicabstractTask<bool>DeleteFileAsync(stringpath,CancellationTokencancellationToken=default);publicabstractTask<IReadOnlyList<string>>ListFilesAsync(stringdirectory,CancellationTokencancellationToken=default);publicabstractTask<bool>FileExistsAsync(stringpath,CancellationTokencancellationToken=default);publicabstractTask<IReadOnlyList<FileSearchResult>>SearchFilesAsync(stringdirectory,stringregexPattern,string?filePattern=null,CancellationTokencancellationToken=default);publicabstractTaskCreateDirectoryAsync(stringpath,CancellationTokencancellationToken=default);}七个方法说明如下:
WriteFileAsync:将指定内容写入到指定路径的文件中。ReadFileAsync:读取指定路径的文件内容。DeleteFileAsync:删除指定路径的文件。ListFilesAsync:列出指定目录下的所有文件。FileExistsAsync:检查指定路径的文件是否存在。SearchFilesAsync:在指定目录下根据正则表达式搜索文件。CreateDirectoryAsync:创建指定路径的目录。
2.1 InMemoryAgentFileStore
上面演示实例使用的InMemoryAgentFileStore是AgentFileStore的一个内存实现版本,它使用一个字典(ConcurrentDictionary<string, string>)来模拟文件系统中的文件和目录结构。虽然它不提供持久化的存储能力,但它可以用于测试和演示目的。
publicsealedclassInMemoryAgentFileStore:AgentFileStore{publicoverrideTaskWriteFileAsync(stringpath,stringcontent,CancellationTokencancellationToken=default);publicoverrideTask<string?>ReadFileAsync(stringpath,CancellationTokencancellationToken=default);publicoverrideTask<bool>DeleteFileAsync(stringpath,CancellationTokencancellationToken=default);publicoverrideTask<IReadOnlyList<string>>ListFilesAsync(stringdirectory,CancellationTokencancellationToken=default);publicoverrideTask<bool>FileExistsAsync(stringpath,CancellationTokencancellationToken=default);publicoverrideTask<IReadOnlyList<FileSearchResult>>SearchFilesAsync(stringdirectory,stringregexPattern,string?filePattern=null,CancellationTokencancellationToken=default);publicoverrideTaskCreateDirectoryAsync(stringpath,CancellationTokencancellationToken=default);}2.2 FileSystemAgentFileStore
FileSystemAgentFileStore是AgentFileStore的另一个实现版本,它使用本地文件系统来存储文件和目录。通过构造函数指定的根目录,FileSystemAgentFileStore将所有的文件操作限制在这个根目录及其子目录下,从而提供了一定程度的安全性。
publicsealedclassFileSystemAgentFileStore:AgentFileStore{publicFileSystemAgentFileStore(stringrootDirectory);publicoverrideTaskWriteFileAsync(stringpath,stringcontent,CancellationTokencancellationToken=default);publicoverrideTask<string?>ReadFileAsync(stringpath,CancellationTokencancellationToken=default);publicoverrideTask<bool>DeleteFileAsync(stringpath,CancellationTokencancellationToken=default);publicoverrideTask<IReadOnlyList<string>>ListFilesAsync(stringdirectory,CancellationTokencancellationToken=default);publicoverrideTask<bool>FileExistsAsync(stringpath,CancellationTokencancellationToken=default);publicoverrideTask<IReadOnlyList<FileSearchResult>>SearchFilesAsync(stringdirectory,stringregexPattern,string?filePattern=null,CancellationTokencancellationToken=default);publicoverrideTaskCreateDirectoryAsync(stringpath,CancellationTokencancellationToken=default);}3. FileAccessProvider
FileAccessProvider的实现非常简单。我们构建该对象时会提供一个AgentFileStore对象和作为配置选项的FileAccessProviderOptions对象(可选)。在重写的ProvideAIContextAsync方法中,FileAccessProvider会创建用于操作AgentFileStore对象的一系列工具和系统指令,并注册到返回的AIContext对象中。
publicsealedclassFileAccessProvider:AIContextProvider{publicFileAccessProvider(AgentFileStorefileStore,FileAccessProviderOptions?options=null);protectedoverrideValueTask<AIContext>ProvideAIContextAsync(InvokingContextcontext,CancellationTokencancellationToken=default);}publicsealedclassFileAccessProviderOptions{publicstring?Instructions{get;set;}}FileAccessProviderOptions只提供用来作为系统指令的Instructions属性。如果没有提供这个属性,FileAccessProvider会使用一个默认的系统指令,内容如下:
## File Access You have access to a shared file storage area via the `FileAccess_*` tools for reading, writing, and managing files. These files persist beyond the current session and may be shared across sessions or agents. Use these tools to read input data provided by the user, write output artifacts, and manage any files the user has asked you to work with. - Never delete or overwrite existing files unless the user has explicitly asked you to do so.4. 查看注册的工具
我们可以通过一个自定义的AIContextProvider来查看FileAccessProvider注册到AIContext中的工具。如下所示的ToolTrackingProvider在ProvideAIContextAsync方法中会遍历当前上下文中的工具列表,并将其中的工具信息打印到控制台上。
classToolTrackingProvider:AIContextProvider{protectedoverrideValueTask<AIContext>ProvideAIContextAsync(InvokingContextcontext,CancellationTokencancellationToken=default){varindex=1;foreach(vartoolincontext.AIContext.Tools!){if(toolisAIFunctionfunction){Console.WriteLine($"""{newstring('-',50)}Tool{index++}{newstring('-',50)}Name:{tool.Name}Description:{tool.Description}JsonSchema:{JsonSerializer.Serialize(function.JsonSchema,newJsonSerializerOptions{WriteIndented=true})}""");}}returnbase.ProvideAIContextAsync(context,cancellationToken);}}我们采用如下的形式将ToolTrackingProvider和FileAccessProvider一起注册到Agent中,运行Agent之后我们就可以在控制台上看到FileAccessProvider注册的工具信息了。
usingdotenv.net;usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingOpenAI;usingSystem.ClientModel;usingSystem.Text.Json;DotEnv.Load();varmodel=Environment.GetEnvironmentVariable("MODEL")!;varapiKey=Environment.GetEnvironmentVariable("API_KEY")!;varendpoint=Environment.GetEnvironmentVariable("OPENAI_URL")!;varagent=newOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{Endpoint=newUri(endpoint)}).GetChatClient(model).AsIChatClient().AsAIAgent(options:newChatClientAgentOptions{AIContextProviders=[newFileAccessProvider(newInMemoryAgentFileStore()),newToolTrackingProvider()],});awaitagent.RunAsync();输出:
-------------------------------------------------- Tool 1 -------------------------------------------------- Name: FileAccess_SaveFile Description: Save a file with the given name and content. By default, does not overwrite an existing file unless overwrite is set to true. JsonSchema: { "type": "object", "properties": { "fileName": { "type": "string" }, "content": { "type": "string" }, "overwrite": { "type": "boolean", "default": false } }, "required": [ "fileName", "content" ] } -------------------------------------------------- Tool 2 -------------------------------------------------- Name: FileAccess_ReadFile Description: Read the content of a file by name. Returns the file content or a message indicating the file was not found. JsonSchema: { "type": "object", "properties": { "fileName": { "type": "string" } }, "required": [ "fileName" ] } -------------------------------------------------- Tool 3 -------------------------------------------------- Name: FileAccess_DeleteFile Description: Delete a file by name. JsonSchema: { "type": "object", "properties": { "fileName": { "type": "string" } }, "required": [ "fileName" ] } -------------------------------------------------- Tool 4 -------------------------------------------------- Name: FileAccess_ListFiles Description: List all file names. JsonSchema: { "type": "object", "properties": {} } -------------------------------------------------- Tool 5 -------------------------------------------------- Name: FileAccess_SearchFiles Description: Search file contents using a regular expression pattern (case-insensitive). Optionally filter which files to search using a glob pattern (e.g., "*.md", "research*"). Returns matching file names, snippets, and matching lines with line numbers. JsonSchema: { "type": "object", "properties": { "regexPattern": { "type": "string" }, "filePattern": { "type": [ "string", "null" ], "default": null } }, "required": [ "regexPattern" ] }从输出可以看出,FileAccessProvider为Agent注册了5个工具,它们分别是:
FileAccess_SaveFile:将指定内容保存到指定名称的文件中。默认情况下,如果文件已存在则不覆盖,除非overwrite参数设置为true。FileAccess_ReadFile:通过文件名读取文件内容。返回文件内容或者指示文件未找到的消息。FileAccess_DeleteFile:通过文件名删除文件。FileAccess_ListFiles:列出所有文件名。FileAccess_SearchFiles:使用正则表达式模式(不区分大小写)搜索文件内容。可选地使用glob模式(例如,“.md”,“research”)过滤要搜索的文件。返回匹配的文件名、片段以及带有行号的匹配行。
和AgentFileStore定义的7个抽象方法相比,FileAccessProvider注册的工具覆盖了其中的5个方法,少了用于创建目录和检查文件是否存在的工具。
