Code Apps 目前是我在 Power Platform 里最喜欢的东西。它们贴合我一直认为微软应该走的那条 AI 路线——“自动化底层的代码,而不是自动化 UI”,这恰恰是 LLM 擅长的地方。

但我用下来发现 Code Apps 有几个问题:

打开网易新闻 查看精彩图片

顺便提一句,虽然我也摆弄 TypeScript,但我骨子里还是更习惯 JavaScript,也喜欢亲手造东西。所以那些觉得“没必要搞这些,LLM 会把复杂的事全干了”的人,你们说的也可能没错。

于是我想了一个路子:基于 Power App SDK,做一个 Code Apps 的复刻版。

这个项目断断续续搞了一阵子。真正让一切串联起来的契机,是微软发布了 Power Platform CLI 的 NPM 包。这意味着我可以在自己的解决方案里直接构建它,而不必把它当成外部依赖。

我的计划是给 SDK 写一个转换流程,把它变成一份去掉构建阶段的纯 JavaScript 文件,我就能在这份文件上继续搭建。我设想中需要这些文件:

* 标准 Code App 文件(始终必需的那几个)

我琢磨的几个默认连接器,覆盖了超过九成的使用场景:

下一步就是改善 LLM 构建 Code Apps 的方式。因为在默认情况下,LLM 只想搭建普通的 web 应用。为此我划分出两大块:agent 和 skill。

agent.md 文件相当于一份放在 VS Code 里的系统提示词,它得让 LLM 明白这是一个 Code App,并知道该去调用 SDK,而不是随手写个 fetch()。skill.md 文件则针对每个连接器,确保 LLM 会正确更新 power.config.json,不犯那些低级错误。

这些都从一个简单基础盘起步,随着实际搭应用的经历不断叠加。应用做得越多,我能拿来“训练”LLM 的经验也就越多。

这样一来,制作者确实能开箱即用地构建 Code App,但依然需要手动添加数据源的 schema,才能帮到 LLM,并且仍然要用到一条 CLI 命令才能发布到 Power Platform。

到这里,第1和第2点我已经搞定了。那第3和第4呢?这正是需要我动手搞点东西的时候(也是我最享受的部分)。

要让这个流程顺畅起来,我就得替换掉 CLI 命令,这就意味着要做一个新的界面。有点矛盾的是,我决定采用的思路居然是——再造一个 CLI。

做出这个决定,基于三个理由。

首先,我可以批量改进命令,还能添加新命令。举个例子,想添加新连接器时,我让它直接去找第一个可用的有效连接来用,省得再从 URL 里翻找连接 ID。

第二个,也是最重要的原因:CLI 可以成为任何界面的基础。

这样一来,我们手里就有了一层 Code App JavaScript 文件,这些文件被 CLI 调用,再由其他应用去进一步使用。当我更新这些文件——比如加入新的连接器、升级 SDK——更新就会层层传递下去;如果我给 CLI 加新命令(就像后来加上的调用流那样),它同样会向下传递到各个应用。

第三,我就是特别特别想自己做个 CLI 出来。

这下,一个制作者就能在不需要和外部 CLI 较劲的情况下,快速让一个原型跑起来。整套设计把底层代码全数打包成 JavaScript 文件,又用 CLI 充当骨架和分发通道。每追加一个连接器模板或修正一次 SDK 行为,都会顺着工具链自动蔓延到所有依赖它的上层应用。这意味着后来的使用者甚至不用关心底层到底改动过什么,只需要拿着简化后的指令集开始写逻辑。

这种把构建步骤剥离、靠单一入口文件驱动的模式,也意外地降低了排查错误的难度。过去面对一整套 TypeScript 的复杂构建链,定位一个字段映射错误可能要翻好几层编译中间产物;现在文件结构足够扁平,在代码编辑器里全局搜索某个属性名,几乎立刻就能看到究竟是哪一步把参数传丢了。对于动不动要让 AI 帮忙改代码的开发者来说,一个平铺直叙、能被一眼看到底的文件结构,显然比多层继承的工程目录友好得多。

连接器模板从一开始就按照常用数据源来预制,后续又跟着真实应用场景持续补充。每一次联调新数据源时暴露出的共性错误,都会被收进对应技能文件里,形成一个不断膨胀的排错清单。这样一来,LLM 在生成调用代码时不再是“尝试一个差不多的写法”,而是直接命中先前被验证过的那一种。这条反馈闭环走得越久,模型踩坑的次数就越少,生成结果的第一版可用率自然也就越高了。