大数跨境

AGENTS.md、Skill 怎么用?一次端侧 NEON 优化把边界说清

AGENTS.md、Skill 怎么用?一次端侧 NEON 优化把边界说清 AI大模型智能体前沿
2026-09-06
3
导读:做一次端侧 NEON 优化,你会同时碰到项目规则、优化流程和可调用代码;放错位置,下一次换算法可能还需要重来一次。

导读端侧图像算法要做 NEON 优化时,团队常把项目约束、优化步骤和具体算子(kernel)混写进同一份 Agent 指令。短期看省事,下一次换算法、换设备或换项目就开始失控。真正要分开的不是文件格式,而是三种不同的复用:项目契约、解决问题的方法,以及可以被直接调用的代码成果。

一次 NEON 优化,为什么会把三件事混在一起?

设想你在做一款端侧相册 App:夜景照片里,路灯和招牌不能亮成一片,暗处的建筑纹理也要保留。高斯模糊不够。局部拉普拉斯滤波(Local Laplacian Filter)要解决的正是“不能只靠一把模糊刷子”这类问题:它把图像拆成多个尺度,在局部亮度附近做非线性重映射,既能压缩明暗,也能选择保留或增强细节。

原始论文的 Figure 1 展示了同一 HDR 厨房场景的三种输出:简单 gamma 色调映射(tone mapping)、保留细节的局部拉普拉斯色调映射,以及更强的细节对比度。真实项目不能只追求“更锐”,还要防止过度处理、光晕伪影(halo)和结果漂移。这张图说明算法输出,不表示任何 NEON 加速结果。

图片说明:论文 Figure 1:同一 HDR 厨房场景的简单 gamma 映射、保留细节的局部拉普拉斯映射与强细节增强映射;不表示 NEON 性能。 图片来源:Local Laplacian Filters Figure 1

算法效果确定后,才轮到 NEON 优化:它是 ARM 处理器上用于单指令多数据(SIMD)并行的指令集。可真让 Agent 开始改代码,问题马上变了。

你希望它知道:这个项目跑在哪类设备上,局部对比度参数允许落在什么范围,哪些典型照片不能出现 halo,必须在哪台基准机上测试,不能破坏哪些标量回退路径。你还希望它按一套可靠过程做事:先做性能分析(profile),再判断金字塔构建、下采样或小型卷积里哪些循环适合 SIMD,接着处理对齐、尾部元素和正确性对照,最后才比较性能。等它真的写出一个可复用的高斯金字塔(Gaussian pyramid)或重建算子,你又不希望下个项目只能靠“再读一次提示词”才能使用。

这三种需求表面上都叫“NEON 优化经验”,实际上不是同一种东西。把它们全塞进 AGENTS.md,这个文件会逐渐变成冗长的操作手册;把它们全做成 Skill,Skill 又会携带当前项目的机型、阈值和目录细节;把它们都留在一段代码里,下一次遇到类似热点又得从头摸索。

先把对象分开,文件应该放哪里就清楚了:项目内持续生效的事实进 AGENTS.md,重复执行的优化方法进 Skill,输入输出契约稳定的实现才进库。

第一层:AGENTS.md 管的是“这个项目必须怎样做”

AGENTS.md 不是某个任务的教程。它是 Agent 进入一个仓库后应持续遵守的项目契约:代码在哪里、测试怎么跑、哪些行为不能越界、什么结果才算通过。

对上面的图像算法项目,它可以写这些事实:

发布目标是哪些 ARM 架构和系统版本;

图像格式、精度容差和标量回退路径;

基准测试的设备、数据集、统计口径与性能门槛;

改动 SIMD 路径后必须跑的正确性测试和回归命令;

哪些目录是公共接口,不能为了局部优化随意改动。

这些内容的共同点是:只要 Agent 在改这个项目,就应该知道它们。它们换一个仓库未必成立,甚至同一套算法换一颗芯片,性能门槛和测试方式也可能不同。

这正符合 AGENTS.md 的作用域。Codex 将它视为仓库中的项目指令:可写代码组织、约定和运行测试方式;文件所在目录树内的代码都受其约束,更深层的文件还可以补充更局部的规则。它适合保存团队已经验证过、每次协作都不想重讲的事实,而不是承载所有可能发生的操作流程。

从算法骨架定位 NEON 热点

论文 Figure 5 把关键数据流画得很清楚:以高斯金字塔(Gaussian pyramid)中的局部值 g₀ 为参照,对输入做点式重映射;由中间结果构造拉普拉斯金字塔(Laplacian pyramid),再把对应系数填入输出金字塔。关键是看清这条数据流怎样决定 NEON 的候选热点。

图片说明:论文 Figure 5:局部值 g₀ 决定输入的重映射函数;中间拉普拉斯金字塔的对应系数被写入输出金字塔。 图片来源:Local Laplacian Filters Figure 5

下面是对应的概念伪代码,省略边界、插值和参数标定,不能直接运行:

TEXT G = buildGaussianPyramid(input)
for level in pyramid_levels:
    for ref in reference_samples:
        remapped = localRemap(input, ref, sigma, alpha, beta)
        coeff[level, ref] = laplacianPyramid(remapped)[level]
    output_coeff[level] = interpolate(coeff[level, :], G[level])
output = reconstructPyramid(output_coeff)

局部重映射决定画面效果;反复出现的金字塔、下采样、上采样与小卷积,才是 profile 后的 NEON 候选循环。这也解释了三层分工:AGENTS.md 固定参数、回归照片和设备;Skill 固定“测热点、标量对照、处理尾部、再测基准”;已验证的 reduceexpand 或定点卷积才进入库。

第二层:Skill 管的是“遇到这类问题,怎样可靠地推进”

Skill 解决的不是“本项目阈值是多少”,而是“当任务是优化 ARM NEON 热点时,应该按什么步骤把不确定性降下来”。它应该有明确输入和输出。

例如,一个 NEON 优化 Skill 的输入可以是热点函数、目标平台、数据类型、现有基线和正确性要求;输出则是:候选向量化策略、实现修改、尾部处理说明、标量对照结果、基准结果,以及没有收益时的停止理由。

其中的流程可以是:

1. 先用 profile 确认热点,而不是见循环就上 intrinsics;

2. 检查循环迭代之间是否独立,数据是否连续,是否存在能安全向量化的算术;

3. 选择合适的 load、store、算术与数据重排方式,并保留无法整除向量宽度的尾部路径;

4. 用标量实现做逐像素或容差范围内的结果对照;

5. 在项目指定设备和口径下比较性能;没有可观测收益就记录原因,不把 intrinsics 当成目的。

Arm 的卷积示例恰好说明了这层边界:NEON 内建函数(intrinsics)能让 C/C++ 在一段明确的卷积循环中并行处理多个元素,但能否获益仍取决于具体热点、数据布局与读写(load/store)方式。局部拉普拉斯滤波不是“一条 NEON 指令”就能完成的算法;真正值得评估的是它反复执行的金字塔构建、下采样、上采样和小型卷积热点。它展示的是一种分析和实现路径,而不是可从项目中剥离出来、对所有图像算法都有效的一行代码。

Skill 的优势在于按任务加载。Agent Skills 的机制是先发现技能名称和描述,只有任务匹配时才读取完整 SKILL.md,并按需执行配套脚本或读取参考资料。因此,NEON Skill 可以带 benchmark 模板、检查清单和 intrinsics 对照资料,却不必让所有日常改文档、改 UI 的任务背上这些上下文。

第三层:真正能直接复用的 NEON 成果,应进入代码库

如果你已经写好一个经过测试的 Gaussian pyramid、上采样重建或定点卷积 kernel,下一次算法需要的是“调用这段实现”,而不是“再让 Agent 依照 Skill 重写一遍”。前提是它的输入输出、精度模型和数据布局已经足够稳定;满足后,才考虑公共算子库、内部模块或稳定接口。

这里有一个容易被忽视的差别:

Skill 复用的是解决问题的方法

算子库复用的是已经实现并验证过的代码

AGENTS.md 复用的是此项目的协作约束

三者可以互相指向,但不要互相代替。一个 Skill 可以要求“先检查是否已有可用公共 kernel”;项目的 AGENTS.md 可以规定“性能关键路径优先评估公共算子,并保留标量回退”;库本身则用 API、测试和版本来保证调用者拿到的是可执行的东西。

这也是为什么“别把 NEON 代码塞进 Skill”并不是反对沉淀经验。相反,它是在保护经验的可用性:流程应该能迁移,代码应该能被链接,项目事实应该留在项目里。

以后再优化另一个算法,应该怎样复用?

把第二个算法带进来,边界会更直观。

如果它仍在同一项目中,现有 AGENTS.md 继续生效:目标设备、精度门槛、测试命令和发布边界不必重讲。Agent 在收到“优化这个热点”的任务后,再激活 NEON Skill,沿用分析、对照和基准流程。新算法的特定数据布局、边界条件和实现,则留在新代码和测试里。

如果它在另一个项目中,不能把旧项目的机型、数据集和性能数字生搬过去。新项目需要自己的 AGENTS.md;同一个 NEON Skill 仍可复用,因为它处理的是通用的工作方法;若旧 kernel 的输入输出契约刚好匹配,才从公共库直接调用。

如果第二个算法只是“也能用 NEON”,但数据依赖强、精度模型不同,或根本不适合复用旧 kernel,那么没有必要硬凑一个库。让 Skill 帮你完成评估,最终选择保留标量实现,也是一种正确交付。

所以,是否抽取不应只问“以后会不会再用”,而要问得更具体:下次复用的是项目规则、优化流程,还是同一段可执行代码?答案不同,落点就不同。

一个避免规则漂移的最小判断法

先看一个总判断:经验的落点取决于下次要复用的对象,而不是它是否“和 NEON 有关”。

下次准备往某个文件追加“经验”前,可以依次问四个问题:

1. 这是不是当前项目每次改动都必须遵守的事实?是,就进 AGENTS.md

2. 这是不是会在多次、甚至多个项目的同类任务中重复执行的步骤?是,就做成 Skill 的流程、脚本或检查清单。

3. 下次是否需要直接调用同一份实现,而不是重新生成?是,就做成模块或算子库。

4. 它是否只描述当前算法的数据、阈值、边界和测试样本?是,就留在当前项目的代码、配置和测试里。

最后一条很重要。很多所谓“可复用经验”其实只是还没有被分清层级的项目细节。过早把它包装成 Skill,会让后续 Agent 带着错误前提工作;过早抽成库,会把不稳定接口固定下来。

AGENTS.md 和 Skill 不是二选一。前者让 Agent 在一个项目里不迷路,后者让它面对一类任务时不从零开始;而真正经得起复用的实现,最终应该由代码与测试来承担。

我的判断很简单:下一次换算法、换项目,甚至换优化方向前,先辨认你要复用的到底是规则、方法还是实现。答案通常已经写在问题里了。

参考资料

OpenAI Codex,AGENTS.md 作用域与优先级说明: https://github.com/openai/codex/blob/main/codex-rs/protocol/src/prompts/base_instructions/default.md

OpenAI Cookbook,Codex 项目 AGENTS.md 的内容边界: https://github.com/openai/openai-cookbook/blob/main/examples/codex/iterating-development-workflows-with-codex.md

Agent Skills,SKILL.md 与渐进式加载机制: https://github.com/agentskills/agentskills

Paris、Hasinoff、Kautz,Local Laplacian Filters: Edge-aware Image Processing with a Laplacian Pyramid: https://people.csail.mit.edu/hasinoff/pubs/ParisEtAl11-lapfilters.pdf

Arm,Neon Intrinsics on Android — Thresholding and Convolution: https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Android%20Dev%20Guides/Neon%20Intrinsics%20on%20Android-%20How%20to%20Truncate%20Thresholding%20and%20Convolution%20of%20a%201D%20Signal.pdf?revision=96af07d9-22f5-4d20-b668-388ebd257230

— THE END —

文章仅做学术分享,如有侵权请联系删除,非常感谢!

【声明】内容源于网络
0
0
AI大模型智能体前沿
分享AI大模型智能体前沿知识,探寻多元应用,洞察未来趋势,带你一路 “卷” 赢行业!🔥
内容 1111
粉丝 0
AI大模型智能体前沿 分享AI大模型智能体前沿知识,探寻多元应用,洞察未来趋势,带你一路 “卷” 赢行业!🔥
总阅读17.0k
粉丝0
内容1.1k