前面我们介绍了三种基于本地执行环境的CodeAct解决方案,包括LangChain的PythonREPL类,以及MAF的HyperlightCodeActProvider提供的Hyperlight Sandbox,和利用LocalCodeActProvider提供了本地代码解释器。其实LLM生成的代码没有必要一定需要回传给Agent来执行,LLM提供商完全可以在云端构建一个完全的Sandbox来执行生成的代码。MAF的HostedCodeInterpreterTool就是为了解决这个问题而设计的。
1. 让LLM托管端执行生成的代码
HostedCodeInterpreterTool这个工具用于LLM服务商(如OpenAI、Azure AI)在云端沙箱中运行代码的能力。作为一个标记类的工具,其本身不包含任何代码解释和执行的逻辑,其本质是一个向AI服务的示意信号。当我们在Agent中注册此工具时,即代表授权LLM在处理当前任务时,可以自由编写并自主运行所需的代码(通常为Python),以解决复杂计算或数据分析问题。如下面的代码所示,HostedCodeInterpreterTool将工具命名为code_interpreter。
在如下的演示程序中,我们针对指定的Microsoft Foundry项目创建了一个AIProjectClient实例,并利用它创建了一个托管服务Agent。在创建Agent时,我们将HostedCodeInterpreterTool作为工具注册到Agent中。然后我们调用Agent的RunAsync方法来执行一个数据分析任务。
usingAzure.AI.Projects;usingAzure.Identity;usingDotNetEnv;usingMicrosoft.Extensions.AI;Env.Load();varprojectUrl=Environment.GetEnvironmentVariable("PROJECT_URL")!;varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varmodel=Environment.GetEnvironmentVariable("MODEL")!;varinstructions=""" 你是一个资深的数据分析师。请通过编写和运行Python代码来解决用户的问题。 如果遇到数据缺失,请先编写代码进行合理的清洗(例如用均值填充)。。""";varagent=newAIProjectClient(newUri(projectUrl),newAzureCliCredential()).AsAIAgent(model:model,instructions:instructions,tools:[newHostedCodeInterpreterTool()]);varcomplex_query=(""" 如下这个CSV格式的表格存储了2025年上半年PC和Phone的月度销售数据。 请帮我完成以下任务:-1.检查数据,如果某月的销售数据有缺失,请用该列的平均值填充;-2.分别计算PC和Phone的季度销售额和半年总销售额; ```csvMonth,PC,Phone1,20000.0,12000.02,25000.0,15000.03,23000.0,4,27000.0,22000.05,,19000.06,32000.0,26000.0```""");varresponse=awaitagent.RunAsync(complex_query);Console.WriteLine(response);具体来说,我们将一个不完整CSV格式的表格作为输入数据传递给HostedCodeInterpreterTool,并要求Agent帮我们完成以下任务:
- 检查数据,如果某月的销售数据有缺失,请用该列的平均值填充;
- 分别计算PC和Phone的季度销售额和半年总销售额。
从如下的输出结果可以看出,LLM在云端沙箱中成功运行了Python代码,并完成了数据清洗和统计计算的任务。
已完成数据检查、缺失值填充以及季度和半年销售额统计。 缺失值处理结果: - Phone 第3月缺失,用 Phone 列平均值 18800.0 填充 - PC 第5月缺失,用 PC 列平均值 25400.0 填充 清洗后的数据: | Month | PC | Phone | |---|---:|---:| | 1 | 20000.0 | 12000.0 | | 2 | 25000.0 | 15000.0 | | 3 | 23000.0 | 18800.0 | | 4 | 27000.0 | 22000.0 | | 5 | 25400.0 | 19000.0 | | 6 | 32000.0 | 26000.0 | 销售汇总结果: | 产品 | Q1 | Q2 | Half Year Total | |---|---:|---:|---:| | PC | 68000.0 | 84400.0 | 152400.0 | | Phone | 45800.0 | 67000.0 | 112800.0 |2. HostedCodeInterpreterTool
和其他以Hosted前缀命名的工具(HostedWebSearchTool、HostedFileSearchTool、HostedMcpServerTool和HostedToolSearchTool等)一样,由于不需要在本地执行,HostedCodeInterpreterTool仅仅是一个简单的标记而已,这个标记旨在告诉LLM托管服务:接下来的任务可以采用CodeAct模式来完成,并且直接利用托管方提供的代码解释器执行LLM生成的Python代码。HostedCodeInterpreterTool提供的标记基本上就体现在Name属性返回的工具名称code_interpreter上。
publicclassHostedCodeInterpreterTool:AITool{publicoverridestringName=>"code_interpreter";publicoverrideIReadOnlyDictionary<string,object?>AdditionalProperties{get;}publicIList<AIContent>?Inputs{get;set;}publicHostedCodeInterpreterTool();publicHostedCodeInterpreterTool(IReadOnlyDictionary<string,object?>?additionalProperties);}除了在初始化时利用参数additionalProperties来设置附加属性外,我们还可以通过Inputs属性来指定输入内容。我们可以利用它以AIContent列表的形式为代码解析器提供输入数据,这是该工具最关键的属性。代码解释器往往需要读取文件(例如让AI分析一个Excel表格或CSV数据)。支持的AIContent类型包括:
- HostedFileContent: 指向已经上传到云端服务商那里的文件ID);
- DataContent:直接传递二进制数据(并非所AI平台都支持直接传二进制流,不支持的会被
IChatClient自动忽略)。
3. 利用Inputs提供数据
前面演示的基于数据分析的例子需要提供一个.csv格式的表格来表示处理的数据,我们直接将它内嵌在描述任务的提示词中。很明显,这肯定不是推荐的编程方式,一般来说我们会将文件上传到云端并得到一个唯一标识此文件的文件标识,然后基于这个标识创建一个HostedFileContent作为HostedCodeInterpreterTool的输入。所以下面的编程方式才是我们推荐的做法:
usingAzure.AI.Projects;usingAzure.Identity;usingDotNetEnv;usingMicrosoft.Extensions.AI;usingOpenAI.Files;usingSystem.Text;Env.Load();varprojectUrl=Environment.GetEnvironmentVariable("PROJECT_URL")!;varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varmodel=Environment.GetEnvironmentVariable("MODEL")!;varprojectClient=newAIProjectClient(newUri(projectUrl),newAzureCliCredential());varopenAIClient=projectClient.GetProjectOpenAIClient();varfileClient=openAIClient.GetOpenAIFileClient();vardata=""" Month,PC,Phone1,20000.0,12000.02,25000.0,15000.03,23000.0,4,27000.0,22000.05,,19000.06,32000.0,26000.0""";varuploadResult=awaitfileClient.UploadFileAsync(BinaryData.FromBytes(Encoding.UTF8.GetBytes(data)),"data.csv",FileUploadPurpose.Assistants);varfileId=uploadResult.Value.Id;varfileContent=newHostedFileContent(fileId);varinstructions=""" 你是一个资深的数据分析师。请通过编写和运行Python代码来解决用户的问题。 如果遇到数据缺失,请先编写代码进行合理的清洗(例如用均值填充)。。""";varagent=projectClient.AsAIAgent(model:model,instructions:instructions,tools:[newHostedCodeInterpreterTool{Inputs=[fileContent]}]);varcomplex_query=(""" 这个.csv文件存储了2025年上半年PC和Phone的月度销售数据。 请帮我完成以下任务:-1.检查数据,如果某月的销售数据有缺失,请用该列的平均值填充;-2.分别计算PC和Phone的季度销售额和半年总销售额;""");varresponse=awaitagent.RunAsync(complex_query);Console.WriteLine(response);如上面的代码片段所示,我们根据指定的Microsoft Foundry项目的URL创建了一个AIProjectClient对象,并利用它提供的OpenAIFileClient上传了承载分析数据的.csv文件。在得到对于OpenAIFile的ID之后,我们创建了对应的HostedFileContent,并将它添加到HostedCodeInterpreterTool的输入列表中。运行程序一样可以得到我们希望的结果:
已完成数据检查、缺失值填充和销售汇总计算。 缺失值处理: - Phone 第3月缺失,用 Phone 列平均值 18800 填充; - PC 第5月缺失,用 PC 列平均值 25400 填充。 季度与半年销售额结果: - PC - 第一季度(Q1):68000 - 第二季度(Q2):84400 - 上半年合计:152400 - Phone - 第一季度(Q1):45800 - 第二季度(Q2):67000 - 上半年合计:112800