ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

在 .Net AgentFramework 中为 AI 智能体添加 Python 脚本执行能力:TaoToken 统一 Key 接入与 openClaw 技能对接预演

在 .Net AgentFramework 中为 AI 智能体添加 Python 脚本执行能力:TaoToken 统一 Key 接入与 openClaw 技能对接预演

1. 为什么要在 .Net AgentFramework 里给智能体加 Python 执行能力

在 .Net AgentFramework 里做 AI 智能体,最开始的形态通常只是「对话 + 调用几个 C# 方法」。一旦业务稍微复杂一点,你就会发现纯 C# 工具集不够用:数据清洗想用 pandas、图表想用 matplotlib、临时算法想用 numpy,甚至运维脚本本身就是 Python 写的。这时候如果每个需求都翻译成 C# 再编译一遍,迭代速度会被拖垮。

给智能体加 Python 脚本执行能力,本质上是把「Python 解释器」当成一个通用工具暴露给模型。模型不再需要理解你的 C# 业务代码,它只需要知道:有一个叫RunPythonPy的工具,传入脚本路径和参数,就能拿到标准输出。这样智能体的能力边界从「你预先写好的方法」扩展到「整个 Python 生态」。

这个场景适合三类人:一是已经在用 .Net AgentFramework 搭智能体、想快速扩展工具集的开发者;二是手里有一堆 Python 脚本资产、想让 AI 自动编排调用的团队;三是准备对接 openClaw 技能体系、需要统一脚本执行入口的工程同学。openClaw 的技能目录约定里,scripts文件夹放的就是可执行脚本,Python 脚本用RunPythonPy跑、其他脚本用 shell 跑,这套约定和 AgentFramework 的工具注册天然契合。

我试过把 Python 执行能力接进 AgentFramework 之后,最直观的变化是:以前要写一个「读取 CSV 并统计缺失值」的工具方法,现在只需要在技能目录里放一个check_csv.py,模型自己会加载技能、读取指令、调用脚本、把结果回传。整个过程不需要重新编译 .Net 项目。

不过这里有个容易被忽略的点:模型调用凭据的管理。当智能体开始频繁调用脚本、每轮对话都要请求模型时,Key 散落在配置文件里会很难维护。后面会讲怎么用 TaoToken 的统一 Key/API 通道把这块收口,让脚本执行和模型调用各管各的。

2. TaoToken 前置准备:统一 Key 与 API 通道配置

在动手写工具之前,先把模型调用的凭据通道理顺。AgentFramework 的智能体每轮推理都要访问模型,如果 Key 硬编码在appsettings.json里,换环境、换模型、多人协作时都会出问题。TaoToken 提供的是统一 Key 和 API 通道,把「用哪个模型、走哪个端点」这件事从业务代码里抽出来。

先注册并拿到 Key。打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,完成账号注册后进入控制台。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,在 API Keys 页面创建一个新 Key。创建时建议按用途命名,比如agentframework-dev,方便后面区分开发和生产。

拿到 Key 之后,API 端点统一用 https://taotoken.net/api ,注意这个地址不带任何查询参数。模型 ID 按你实际要用的填,比如claude-sonnet-4-5或gpt-4o这类,具体以控制台模型列表为准。这三件套——Base URL、Key、Model ID——是后面所有配置的基础,缺一不可。

如果你用的是 Claude Code 这类编码工具做辅助开发,可以在 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 看到接入说明;如果只是想先在网页里验证模型通不通,用模型对话页面 https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=modelchat&utm_campaign=rewrite 发一条消息即可。长期跑编码 Agent 的话,Coding Plan 页面 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=codingplan&utm_campaign=rewrite 有套餐说明。

这里要强调一个原则:TaoToken 是模型调用的凭据通道,不是脚本执行环境。Python 脚本跑在你自己的机器或容器里,TaoToken 只负责模型请求的鉴权和路由。两者职责分离,排查问题时才不会互相干扰。

配置建议放在环境变量里,而不是提交到 Git。Windows 下用系统环境变量,Linux/macOS 下写进 shell profile。AgentFramework 读取时用Environment.GetEnvironmentVariable,这样本地开发和 CI 可以用不同的 Key。

3. 可复制配置:AgentFramework 工具定义与 Python 环境

这一节给出可以直接粘贴的代码。先建工具类,命名空间按你自己的项目改,我这里用kevin.AI.AgentFramework.Tools作为示例。

using System.ComponentModel; using System.Diagnostics; namespace kevin.AI.AgentFramework.Tools { public class PythonTools { [Description("执行Python脚本。通过System.Diagnostics.Process类来启动一个新的进程,并运行Python.py的脚本。这种方法适用于Windows和Linux系统。")] public static string RunPythonPy( [Description("需要执行的python脚本路径。例如:'Skills\\python-skills\\hello-python\\scripts\\hello-python.py'")] string scriptPath, [Description("需要传入python脚本的参数。例如:['你好','word']")] List<string> args = default) { try { string output = ""; scriptPath = AppContext.BaseDirectory + scriptPath.Replace(@"/", @"\"); Console.WriteLine($"正在执行Py脚本 {scriptPath}"); ProcessStartInfo start = new ProcessStartInfo(); start.FileName = @"python"; start.Arguments = $"{scriptPath}"; if (args != default) { foreach (var item in args) { start.Arguments += $" {item} \" "; } } start.UseShellExecute = false; start.RedirectStandardOutput = true; start.RedirectStandardError = true; using (Process process = Process.Start(start)) { output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); process.WaitForExit(); if (!string.IsNullOrEmpty(error)) { return $"执行失败: {error}"; } } if (string.IsNullOrWhiteSpace(output)) { output = "Python脚本执行完成,但没有输出结果。"; } return output; } catch (Exception ex) { return $"执行失败: {ex.Message}"; } } } }

这段代码的关键点在于UseShellExecute = false配合RedirectStandardOutput,这样才能在 .Net 进程里捕获 Python 的输出。start.FileName写python依赖系统 PATH,如果机器上有多个 Python 版本,建议改成绝对路径,比如C:\Python311\python.exe或/usr/bin/python3。

接下来是技能注册。AgentFramework 用FileAgentSkillsProvider从文件系统加载技能,每个技能文件夹命名成技能名-skills,里面放instruction.txt、resources和scripts。

#pragma warning disable MAAI001 var skillsProvider = new FileAgentSkillsProvider( skillPaths: [ Path.Combine(AppContext.BaseDirectory + "/Skills", "expense-report-skills"), Path.Combine(AppContext.BaseDirectory + "/Skills", "system-ops-skills"), Path.Combine(AppContext.BaseDirectory + "/Skills", "hello-python-skills") ], options: new FileAgentSkillsProviderOptions { SkillsInstructionPrompt = """ 你可以使用以下技能获取领域知识和操作指引。 所有文件目录都在服务器的/Skills文件夹下,技能文件夹命名为 技能名称-skills,技能文件夹内包含技能指令文件instruction.txt、参考资料文件夹resources和可执行脚本文件夹scripts。 脚本文件夹scripts如何包含python脚本,则使用RunPythonPy来执行或者RunPythonCode来执行,否则使用RunShell来执行。 每个技能提供专业指令、参考文档和可执行脚本,它们如下: {0} 使用 `hello-python-skills` 这个技能 1.当用户任务匹配技能描述时,使用 `load_skill` 加载该技能的完整指令 2.技能指令中会标明可用脚本及其执行命令 3.用于测试python环境运行的技能,包含一个简单的python脚本 脚本文件名:hello-python.py, 可以随意传入参数, 输出"你所有的参数和Hello,Python"返回结果为"你所有的参数和Hello,Python"。 4. 需要时使用 `read_skill_resource` 读取参考资料。 """ }); #pragma warning restore MAAI001 chatClientAgentOptions.AIContextProviders = [skillsProvider]; Console.WriteLine("Skills 已从文件系统加载");

SkillsInstructionPrompt里的{0}会被技能列表替换,所以不要漏掉。#pragma warning disable MAAI001是因为这个类型还在评估阶段,编译器会提示,取消警告即可。

Python 环境这边,确认python --version能正常输出。如果脚本用到第三方库,提前pip install好,因为RunPythonPy不会自动装依赖。脚本路径统一放在Skills/技能名-skills/scripts/下,和 openClaw 的目录约定保持一致,后面接 openClaw 技能时不用改路径。

4. 验证请求:一次端到端跑通 Python 脚本

配置写完了,得实际跑一次才算数。先建一个最小技能目录:

Skills/ hello-python-skills/ instruction.txt scripts/ hello-python.py

hello-python.py内容:

import sys def main(): args = sys.argv[1:] result = "你所有的参数和Hello,Python" print(result) if args: print("参数列表:", args) if __name__ == "__main__": main()

instruction.txt里写清楚这个技能干什么、脚本怎么调:

技能名称:hello-python 描述:测试 Python 环境是否可用的最小技能 可用脚本:scripts/hello-python.py 执行方式:RunPythonPy,传入脚本路径和任意参数

然后在 AgentFramework 里发一条请求,让智能体执行这个脚本。模型会先load_skill加载指令,再调用RunPythonPy,传入Skills/hello-python-skills/scripts/hello-python.py和参数["test", "123"]。

预期返回:

你所有的参数和Hello,Python 参数列表: ['test', '123']

如果返回的是这个,说明整条链路通了:技能加载 → 模型决策 → 工具调用 → 进程启动 → 输出捕获 → 结果回传。这时候你可以把hello-python.py换成真实的业务脚本,比如数据清洗、报表生成,模型会自动按同样的流程调用。

验证模型调用通道是否正常,可以在模型对话页面 https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=modelchat&utm_campaign=rewrite 发一条测试消息,确认 Key 和端点配置无误。如果 AgentFramework 里模型请求报鉴权错误,先在这里排除是 Key 的问题还是代码的问题。

端到端跑通之后,建议把这次调用的日志留下来,包括脚本路径、参数、返回内容。后面接 openClaw 技能时,这些日志就是对照基准。

5. 常见报错排查:401、local proxy failed 与 reading choices

实际接入时踩的坑基本集中在几类报错上,逐个说。

401 Unauthorized:模型请求被拒。先检查 Key 是否复制完整,有没有多余空格。再确认 Base URL 是不是 https://taotoken.net/api ,注意不要带尾部斜杠或查询参数。如果 Key 是在控制台新建的,确认没有误删。环境变量读取失败也会导致 Key 为空,打印一下Environment.GetEnvironmentVariable("TAOTOKEN_API_KEY")看是不是 null。

local proxy failed:这类报错通常出现在本地网络层,不是 TaoToken 服务端的问题。检查本机是否能正常访问外网、DNS 解析是否正常。如果是公司网络,确认没有拦截 API 请求。这个报错和脚本执行无关,别去改 Python 代码。

reading choices 相关报错:一般是模型返回体解析失败。常见原因是 Model ID 填错了,比如把claude-sonnet-4-5写成了别的名字。去控制台模型列表核对一遍。另外确认请求的max_tokens等参数没有超出模型限制。

OAuth 相关报错:如果你用的是 Claude Code 这类工具做辅助,OAuth 流程没走完会报这个。按 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 的说明重新走一遍授权。注意 OAuth 和 API Key 是两套机制,别混用。

Python 脚本执行失败:先看RunPythonPy返回的 error 内容。常见的是python不在 PATH、脚本路径拼错、脚本里有语法错误。路径拼接用的是AppContext.BaseDirectory + scriptPath,如果scriptPath开头带了斜杠,拼出来会多一层,检查一下。

脚本没有输出:RunPythonPy在输出为空时返回「执行完成但没有输出结果」。检查脚本里有没有print,以及print的内容有没有被缓冲。Python 默认行缓冲,脚本结束时才 flush,一般没问题,但如果脚本卡住不退出,WaitForExit会一直等。

排查顺序建议:先确认模型通道(用模型对话页面测),再确认工具注册(看 Skills 加载日志),最后确认脚本本身(命令行直接跑一遍)。三层分开排查,比一上来就改代码高效得多。

6. 对接 openClaw 技能与统一 Key 的后续动作

Python 执行能力跑通之后,对接 openClaw 技能就是水到渠成的事。openClaw 的技能目录约定和 AgentFramework 的FileAgentSkillsProvider基本一致:技能文件夹、instruction.txt、resources、scripts。你只需要把 openClaw 的技能目录挂到skillPaths里,模型就能自动发现并加载。

脚本执行的分流逻辑已经在SkillsInstructionPrompt里写清楚了:scripts里有 Python 脚本就用RunPythonPy,否则用RunShell。这样 openClaw 技能里不管是 Python 还是 shell 脚本,都能被正确调用。

模型调用凭据这块,继续用 TaoToken 统一管理。API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=apikeys&utm_campaign=rewrite 可以按环境创建多个 Key,开发、测试、生产各一个,出问题能快速定位是哪个环境的请求。接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 里有参数说明和示例,配置时对照着看。

长期跑编码 Agent 或需要频繁调用模型的场景,Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=codingplan&utm_campaign=rewrite 比按量计费更划算。如果只是偶尔验证,用模型对话页面就够了。

最后提醒一点:脚本执行环境的安全边界要自己把控。RunPythonPy启动的是本机 Python 进程,脚本能访问文件系统和网络。生产环境建议把脚本执行放到容器或沙箱里,限制可访问的目录和网络范围。AgentFramework 负责编排,安全隔离得靠部署层解决。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进