这是一个标准化的预制件模板仓库,用于为 AI 编码平台创建可复用的高质量代码模块。
预制件 (Prefab) 是一个可被 AI 直接调用的、经过标准化打包的 Python 代码模块。它解决了 AI 在处理复杂业务逻辑时能力不足的问题,通过社区贡献的方式为平台提供高质量、可复用的代码组件。
- ✅ 标准化结构: 统一的文件组织和配置规范
- 🤖 AI 友好: 明确的函数签名和元数据描述
- 🚀 自动化 CI/CD: 一键测试、打包、发布
- 📦 依赖管理: 自动打包运行时依赖
- 🔒 质量保证: 强制性的代码检查和测试
- 🔐 密钥管理: 完善的 secrets 支持
点击 GitHub 上的 "Use this template" 按钮,或者克隆此仓库:
git clone https://github.com/your-org/prefab-template.git my-prefab
cd my-prefab使用现代化的 uv 工具:
# 安装 uv(如果尚未安装)
# Windows: powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# macOS/Linux: curl -LsSf https://astral.sh/uv/install.sh | sh
# 同步依赖(自动创建虚拟环境)
uv sync --dev安装 pre-commit hooks 后,每次提交代码前会自动运行质量检查,避免提交有问题的代码:
# 安装 pre-commit hooks
uv run pre-commit install
# 🎉 现在每次 git commit 都会自动检查代码质量!自动检查项目:
- ✅ Flake8 代码风格(防止 F401 等常见错误)
- ✅ isort 导入排序
- ✅ Manifest 验证
- ✅ 单元测试
- ✅ 版本同步检查
- 编辑
src/main.py: 在这里编写你的核心业务逻辑 - 更新
prefab-manifest.json: 描述你的函数签名和元数据 - 编写测试: 在
tests/test_main.py中添加单元测试
# 运行测试
uv run pytest tests/ -v
# 代码风格检查
uv run flake8 src/ --max-line-length=120
# 验证 manifest 一致性
uv run python scripts/validate_manifest.py
# 一键运行所有验证
uv run python scripts/quick_start.py# 方式一: 使用版本升级脚本(推荐)
uv run python scripts/version_bump.py patch # 1.0.0 -> 1.0.1
# 或
uv run python scripts/version_bump.py minor # 1.0.0 -> 1.1.0
# 或
uv run python scripts/version_bump.py major # 1.0.0 -> 2.0.0
# 然后提交并推送
git add .
git commit -m "Bump version to x.x.x"
git tag vx.x.x
git push origin vx.x.x
# 方式二: 手动更新
# 1. 手动编辑 prefab-manifest.json 和 pyproject.toml 中的 version(必须保持一致)
# 2. git tag v1.0.0
# 3. git push origin v1.0.0🎉 GitHub Actions 将自动完成测试、打包(生成 .whl 格式)和发布!
prefab-template/
├── .github/
│ └── workflows/
│ └── build-and-release.yml # CI/CD 自动化流程
├── data/ # 数据文件目录
│ ├── inputs/ # 输入文件目录(开发/测试时使用)
│ └── outputs/ # 输出文件目录(开发/测试时使用)
├── src/
│ └── main.py # 预制件核心代码(必须)
├── tests/
│ └── test_main.py # 单元测试
├── scripts/
│ └── validate_manifest.py # Manifest 验证脚本
├── prefab-manifest.json # 预制件元数据(必须)
├── pyproject.toml # 项目配置和依赖
├── .gitignore # Git 忽略文件
├── LICENSE # 开源许可证
└── README.md # 项目文档
这是你的预制件的唯一入口文件。所有暴露给 AI 的函数都必须在此文件中定义。
示例函数:
def analyze_dataset(data: list, operation: str = "statistics") -> dict:
"""
分析数据集并返回统计结果
Args:
data: 数字列表
operation: 操作类型 ("statistics", "sum", "average")
Returns:
包含分析结果的字典
"""
try:
if not data:
return {
"success": False,
"error": "数据集不能为空",
"error_code": "EMPTY_DATA"
}
if operation == "statistics":
stats = calculate_statistics(data)
return {
"success": True,
"data": {
"operation": "statistics",
"statistics": stats
}
}
# ... 其他操作类型
except Exception as e:
return {
"success": False,
"error": str(e),
"error_code": "UNEXPECTED_ERROR"
}编码规范:
- ✅ 使用类型提示 (Type Hints)
- ✅ 编写清晰的 Docstring
- ✅ 返回结构化的数据(通常是字典)
- ✅ 包含错误处理
- ❌ 避免使用全局状态
- ❌ 不要在模块级别执行副作用操作
这是 AI 理解如何调用你的预制件的"API 契约"。必须与 src/main.py 中的函数签名保持一致。
字段说明:
{
"schema_version": "1.0", // 清单模式版本(固定)
"id": "hello-world-prefab", // 全局唯一的预制件 ID
"version": "1.0.0", // 语义化版本号(与 pyproject.toml 和 Git Tag 一致)
"name": "预制件名称", // 可读的预制件名称
"description": "预制件功能描述", // 详细功能说明
"tags": ["tag1", "tag2"], // 标签列表,用于分类和搜索
"entry_point": "src/main.py", // 入口文件(固定)
"dependencies_file": "pyproject.toml", // 依赖文件(固定)
"functions": [ // 函数列表
{
"name": "analyze_dataset", // 函数名(必须与代码一致)
"description": "分析数据集并返回统计结果", // 功能描述
"parameters": [ // 参数列表
{
"name": "data",
"type": "array", // 使用 JSON Schema 类型名
"description": "数字列表",
"required": true
},
{
"name": "operation",
"type": "string", // 使用 JSON Schema 类型名
"description": "操作类型:'statistics', 'sum', 'average'",
"required": false,
"default": "statistics"
}
],
"returns": { // 返回值描述(结构化 schema)
"type": "object",
"description": "返回结果对象",
"properties": {
"success": {
"type": "boolean",
"description": "操作是否成功"
},
"data": {
"type": "object",
"description": "成功时的结果数据",
"optional": true
},
"error": {
"type": "string",
"description": "错误信息",
"optional": true
},
"error_code": {
"type": "string",
"description": "错误代码",
"optional": true
}
}
}
}
],
"execution_environment": { // 执行环境配置(可选)
"cpu": "1", // CPU 核心数
"memory": "512Mi" // 内存大小
}
}支持的类型:
基础类型(对应 JSON Schema):
string- 字符串number- 数字(整数或浮点数)integer- 整数boolean- 布尔值object- 对象/字典array- 数组/列表
平台感知类型(用于文件处理):
InputFile- 输入文件OutputFile- 输出文件
当你的预制件需要处理文件(如图片、视频、文档等)时,需要使用固定的文件路径约定。平台会自动将用户上传的文件放置到指定目录,并在函数执行完成后收集输出文件。
输入文件路径规则:
data/inputs/{files中的key名称}/
输出文件路径规则:
data/outputs/
如果你的函数需要接收文件输入,在 prefab-manifest.json 中这样声明:
{
"functions": [{
"name": "process_video",
"description": "处理视频文件",
"parameters": [],
"files": {
"input": {
"type": "InputFile",
"description": "需要处理的视频文件",
"required": true,
"accept": ".mp4,.avi,.mov"
}
},
"returns": {
"type": "object",
"description": "处理结果"
}
}]
}关键点:
files字段中的 key(如"input")决定了输入文件的路径type: "InputFile"表示这是输入文件accept可选,用于限制文件类型
from pathlib import Path
def process_video() -> dict:
"""处理视频文件"""
# 固定路径:data/inputs/{key}/
# 这里的 "input" 对应 manifest 中 files.input 的 key
DATA_INPUTS = Path("data/inputs/input")
DATA_OUTPUTS = Path("data/outputs")
# 确保输出目录存在
DATA_OUTPUTS.mkdir(parents=True, exist_ok=True)
try:
# 扫描输入文件(平台会自动将文件放到这里)
input_files = list(DATA_INPUTS.glob("*"))
if not input_files:
return {
"success": False,
"error": "未找到输入文件",
"error_code": "NO_INPUT_FILES"
}
# 处理第一个文件
input_file = input_files[0]
print(f"处理文件: {input_file}")
# 执行你的业务逻辑...
# result = do_something(input_file)
# 将输出文件保存到固定路径(平台会自动收集)
output_file = DATA_OUTPUTS / "output.mp4"
# save_result(output_file)
return {
"success": True,
"data": {
"processed_file": str(output_file.name),
"input_file": str(input_file.name)
}
}
except Exception as e:
return {
"success": False,
"error": str(e),
"error_code": "PROCESSING_ERROR"
}❌ 错误示例:缺少 key
# 这样会找不到文件!
DATA_INPUTS = Path("data/inputs") # 缺少 manifest 中定义的 key✅ 正确示例:包含完整路径
# 如果 manifest 中是 files.input
DATA_INPUTS = Path("data/inputs/input")
# 如果 manifest 中是 files.video
DATA_INPUTS = Path("data/inputs/video")
# 如果 manifest 中是 files.document
DATA_INPUTS = Path("data/inputs/document")路径匹配规则:
- Manifest 中的
files.{key}→ 代码中的data/inputs/{key}/ files.input→data/inputs/input/files.video→data/inputs/video/files.images→data/inputs/images/
多文件输入: 如果需要接收多个文件,在 manifest 中定义多个 key:
{
"files": {
"video": {
"type": "InputFile",
"description": "视频文件"
},
"subtitle": {
"type": "InputFile",
"description": "字幕文件",
"required": false
}
}
}代码中分别访问:
video_path = Path("data/inputs/video")
subtitle_path = Path("data/inputs/subtitle")输出文件命名:
- 输出文件统一保存到
data/outputs/目录 - 文件名可以自定义,建议使用有意义的名称
- 平台会自动收集该目录下的所有文件
如果你的预制件需要使用 API Key、数据库连接字符串等敏感信息,可以在函数定义中声明 secrets 字段。平台会引导用户配置这些密钥,并在运行时自动注入到环境变量中。
在 manifest.json 中声明 secrets:
{
"functions": [
{
"name": "fetch_weather",
"description": "获取城市天气信息",
"parameters": [...],
"secrets": [
{
"name": "WEATHER_API_KEY",
"description": "用于认证天气服务的 API 密钥",
"instructions": "请访问 https://www.weather-provider.com/api-keys 注册并获取您的免费 API Key",
"required": true
}
]
}
]
}在代码中使用 secrets:
import os
def fetch_weather(city: str) -> dict:
"""获取城市天气信息"""
# 从环境变量中读取密钥(平台会自动注入)
api_key = os.environ.get('WEATHER_API_KEY')
if not api_key:
return {
"success": False,
"error": "未配置 WEATHER_API_KEY",
"error_code": "MISSING_API_KEY"
}
# 使用 API Key 调用第三方服务
# response = requests.get(api_url, headers={"Authorization": f"Bearer {api_key}"})
...Secrets 字段规范:
name(必需): 密钥名称,必须是大写字母、数字和下划线(如API_KEY,DATABASE_URL)description(必需): 密钥用途的简短描述instructions(推荐): 指导用户如何获取该密钥的说明required(必需): 布尔值,标识该密钥是否为必需
本模板包含完整的 secrets 使用示例,详见 src/main.py 中的 fetch_weather 函数。
在 pyproject.toml 中添加你的依赖:
[project]
# 运行时依赖(会被打包到最终产物中)
dependencies = [
"requests>=2.31.0",
"pandas>=2.0.0",
]
[project.optional-dependencies]
# 开发/测试依赖(不会被打包)
dev = [
"pytest>=7.4.0",
"flake8>=6.1.0",
"pytest-cov>=4.1.0",
]使用 uv 管理依赖:
# 添加运行时依赖
uv add requests pandas
# 添加开发依赖
uv add --dev pytest flake8
# 同步依赖
uv sync --dev使用真实数据文件进行测试 - 这是我们的核心测试理念。
本模板展示了如何使用真实媒体文件(tests/test.mp4)进行功能测试:
# tests/test_video.py
import os
import pytest
from src.main import video_to_audio
class TestVideoToAudio:
@pytest.fixture
def test_video_path(self):
"""提供真实的测试视频文件"""
return os.path.join(os.path.dirname(__file__), "test.mp4")
def test_video_to_audio_default(self, test_video_path):
"""使用真实视频测试转换功能"""
result = video_to_audio(test_video_path)
assert result["success"] is True
assert os.path.exists(result["data"]["output_file"])测试数据最佳实践:
- ✅ 将小型真实数据提交到
tests/目录(< 5MB) - ✅ 测试可重现、可审核
- ❌ 避免仅用 mock 数据
运行测试:
# 运行所有测试(使用 uv)
uv run --with pytest pytest tests/ -v
# 运行特定测试
uv run --with pytest pytest tests/test_video.py -v
# 查看测试覆盖率
uv run --with pytest --with pytest-cov pytest tests/ --cov=src --cov-report=html验证 prefab-manifest.json 与代码的一致性:
python scripts/validate_manifest.py此脚本会检查:
- ✅ Manifest 中声明的函数是否都存在于
main.py - ✅ 函数参数的名称和必选/可选属性是否匹配
⚠️ main.py中的公共函数是否都在 Manifest 中声明
整个发布流程完全自动化,你只需要:
- 更新版本号: 编辑
prefab-manifest.json,修改version字段 - 提交更改:
git add . && git commit -m "Release v1.0.0" - 创建标签:
git tag v1.0.0(版本号必须与 manifest 一致) - 推送标签:
git push origin v1.0.0
GitHub Actions 将自动执行以下步骤:
graph LR
A[推送 Tag] --> B[代码检查]
B --> C[运行测试]
C --> D[验证 Manifest]
D --> E[打包预制件]
E --> F[创建 Release]
F --> G[上传附件]
- 格式: Python Wheel (
.whl)(例如hello_world_prefab-0.1.0-py3-none-any.whl) - 内容:
src/目录(包含所有源代码)prefab-manifest.json(元数据文件)- 所有运行时依赖(自动包含)
- 位置: GitHub Release 附件
- 优势: 标准 Python 包格式,兼容性更好,安装更便捷
本模板自带一个完整的科学计算示例预制件,包含一个功能丰富的函数:
支持多种操作类型:
# 完整统计
result = analyze_dataset([1, 2, 3, 4, 5], "statistics")
# {"success": True, "data": {"operation": "statistics", "statistics": {...}}}
# 求和
result = analyze_dataset([10, 20, 30], "sum")
# {"success": True, "data": {"operation": "sum", "value": 60, "count": 3}}
# 平均值
result = analyze_dataset([2, 4, 6], "average")
# {"success": True, "data": {"operation": "average", "value": 4.0, "count": 3}}你可以直接修改这个示例,或者完全替换为自己的业务逻辑。
当你的预制件发布后,AI 平台将能够:
- 自动发现: 通过
prefab-manifest.json理解预制件的功能 - 智能调用: 根据用户的自然语言需求,选择合适的函数并传递参数
- 解释结果: 将函数返回值转换为用户友好的输出
用户体验示例:
用户: "帮我分析这组数据的统计信息:[10, 20, 30, 40, 50]" AI: 调用
analyze_dataset([10, 20, 30, 40, 50], "statistics")AI: "已完成分析:共 5 个数据点,平均值 30.0,最大值 50,最小值 10"
A: 当然可以!使用 uv add package-name 添加运行时依赖,CI/CD 会自动打包。
# 添加运行时依赖(会被打包)
uv add requests pandas
# 添加开发依赖(不会被打包)
uv add --dev pytest-mockA: 推荐使用 secrets 功能:
- 在 manifest.json 中声明密钥(推荐)- 平台会引导用户配置,并自动注入到环境变量
- 通过函数参数传递 - 适用于非敏感的配置项
- 绝对不要将密钥硬编码到代码中
示例: 参见本模板的 fetch_weather 函数及其 manifest 配置。
更多信息请参阅上方的 密钥管理 章节。
A: 可以!你可以在 src/ 目录中创建多个模块,但 main.py 必须是唯一的入口点。
示例结构:
src/
├── main.py # 主入口文件
├── utils/ # 工具模块包
│ ├── __init__.py
│ └── math_utils.py # 数学工具
└── other_module.py # 其他模块(可选)
使用方式:
# src/main.py
try:
# 优先使用相对导入(打包时)
from .utils import helper_function
except ImportError:
# 回退到绝对导入(开发/测试时)
from utils import helper_function
def my_function():
return helper_function()本模板已包含完整的多文件示例,参见 src/utils/ 目录。
A:
- 可重现性 - 任何人都能运行测试并得到相同结果
- 可审核性 - 社区可以验证预制件确实能处理真实数据
- CI/CD 自动化 - GitHub Actions 可以自动运行完整测试
最佳实践:
- 使用小型但真实的测试数据(如 5 秒的视频片段)
- 在 README 中说明测试数据的来源和用途
- 如果数据涉及版权,使用自己创建的测试数据
A:
- 查看 GitHub Actions 的日志输出
- 本地运行相同的命令进行复现:
uv run --with pytest pytest tests/ -v- 测试失败?uv run --with flake8 flake8 src/- 代码风格问题?uv run python scripts/validate_manifest.py- Manifest 不一致?
- 检查是否使用了正确的 uv 环境
A: 遵循语义化版本 (Semantic Versioning):
- 主版本号 (MAJOR): 不兼容的 API 更改
- 次版本号 (MINOR): 向后兼容的功能新增
- 修订号 (PATCH): 向后兼容的问题修复
示例: v1.2.3 → 1.2.3
A: 可以!将仓库设为私有即可。Release 也会是私有的。
欢迎为此模板贡献改进!请:
- Fork 此仓库
- 创建特性分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'Add some amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 开启 Pull Request
本项目采用 MIT 许可证。详见 LICENSE 文件。
祝你开发愉快!🎉
如果这个模板对你有帮助,请给我们一个 ⭐ Star!