# 自进化 SDK

让应用在使用中**持续变好**：用户在应用里说一句就改，开发者 / 智能体按证据提改进提案、发新版本——两条路，同一个 SDK。

- **应用里直接改**：应用的用户点右下角「// 改进」，说一句「对话框变大」「隐藏侧边栏」「标题改成客服工作台」，页面马上变。不用改代码、不用发版、不用再去钉钉 / 企业微信 / WorkBuddy 的群里提需求、等人排期。
- **证据与提案**：开发者 / 智能体把反馈、操作、使用、数据画像、用户在应用里做过的改进，加上你手里的文件、技能（SKILL.md）、对话摘录整合起来，提出具体的改进提案；语义类的一键应用成新的语义版本，应用类的交给开发者 / 智能体改代码发新版本——被采纳的反馈自动标记为已处理，闭环。

```js
import { evolve } from "/developer/sdk/v1/aidc.js";

evolve.mount();                                              // 应用里：右下角「// 改进」
const ev = await evolve.evidence({ app: "production-live" });    // 开发者：证据 → 提案（只给本公司开发者）
```

两条路是连着的：

```
用户在应用里说一句 ──▶ 预览（只有自己看得到）──┬─▶ 只给我保留（个人改进，立即生效）
                                               ├─▶ 提交给所有人 ──▶ 开发者采纳 ──▶ 对所有人生效
                                               │                                     └─aidc evolve bake─▶ 写进代码、发新版本
                                               └─▶ 界面改不了的（加功能、改逻辑）──┐
反馈 · 操作 · 使用 · 错误 · 数据画像 · 用户做过的改进 ─▶ 证据 ─▶ 提案 ◀────────────┘
                                                                 └─ 采纳 ─▶ 应用：新语义版本 / 新应用版本
```

试一试：[智能问答台 · 自进化演示](samples.md#自进化演示)（`/nexus/cell-aidc/apps/evolve-demo`，AIDC 成员登录后打开）。

## 一、应用里直接改

用户在应用里提的每一次改进，是一个**改进工程**：一段对话（「对话框变大」→「再大一点」）、编译出的一组**改进指令**、作用范围与状态。

| 状态 | 个人改进 | 全员改进 | 交给开发者的改动 |
| --- | --- | --- | --- |
| 生效中 | 只对提出的人 | 对所有访客 | 已采纳，待开发 |
| 待采纳 | —— | 对提出的人已生效，等开发者 | 等开发者处理 |
| 未采纳 | —— | 退回成提出人的个人改进（提出人的页面不会突然变回去） | 不做 |
| 已撤销 | 提出人撤销 | 开发者撤销 | 提出人撤回 |

谁能做什么：有 AIDC 账号的访客都能给**自己**改；本公司成员（member / editor）可以提交给所有人；采纳、不采纳、撤销全员改进只给本公司开发者。没登录的访客（公开链接）只能预览。权限只在服务端裁决，面板按返回的 `can` 显示按钮。交给开发者的改动就是下面「证据与提案」里的一条应用类提案（原话作证据）。

### 接入：三步

**1. 在页面上标出能改的区域（槽位）**

```html
<section class="chat" data-evolve="chat">
  <div class="messages" data-evolve="messages">…</div>
  <textarea data-evolve="composer" placeholder="输入问题"></textarea>
  <button data-evolve="send">发送</button>
</section>
```

部署时平台从包里扫出所有 `data-evolve="…"`（HTML 属性、脚本里的 `el.dataset.evolve = "…"`），它们就是这个版本的**改进面**；改进只能落在改进面上。另有内置槽位 `page`（整个页面）。

**2. 在清单里给槽位起名字、声明可调参数**

```json
{
  "sdk": ["evolve", "ui"],
  "evolve": {
    "slots": {
      "chat": { "title": "对话框", "aliases": ["聊天框", "对话窗口"] },
      "send": { "title": "发送按钮" }
    },
    "tokens": {
      "--chat-width": { "title": "对话框宽度", "type": "length", "min": "360px", "max": "1100px", "slot": "chat" },
      "--accent": { "title": "强调色", "type": "color" }
    }
  }
}
```

- `slots.<名>.title / aliases`：用户说「对话框变大」就是按它认出来的。没起名字的槽位只能在页面上点选。
- `tokens`：带范围的**可调参数**（CSS 变量，样式里写 `width: var(--chat-width)`）。「对话框变大」优先调挂在对话框上的参数，而且永远落在 `min`–`max` 里——布局不会被改坏。能预见到的调整（尺寸、字号、主色、圆角）都建议做成参数。
- `model`：编译用的模型，缺省 `deepseek-flash`（可选 `gpt-5.4-mini`）。不用写进清单 `models`。

**3. 挂上面板**

```js
const panel = evolve.mount();                   // 右下角「// 改进」
panel.open(); await panel.send("对话框变大");     // 也可以从你自己的按钮触发
```

宽屏时面板停靠在右侧（页面让出位置，改动不会被面板挡住）；手机上是底部抽屉，预览生效后收成一条。面板在 Shadow DOM 里，应用的样式影响不到它，改进也改不到它。`aidc evolve slots` 在本机列出页面上的槽位与清单声明，谁有谁没有。

### 改进指令

一句话编译成的不是代码，是一组白名单里的指令：

| 指令 | 做什么 | 例子 |
| --- | --- | --- |
| `token` | 改应用声明的可调参数（按范围夹紧） | `{"op":"token","name":"--chat-width","value":"768px"}` |
| `style` | 改一个槽位的样式（宽高、间距、字号字重、颜色背景、边框圆角阴影、透明度、显示方式、排列、顺序、缩放） | `{"op":"style","slot":"send","set":{"background-color":"#1e3a8a"}}` |
| `text` | 改只出现一次的槽位的文字 | `{"op":"text","slot":"title","text":"客服工作台"}` |
| `attr` | 改提示文字：`placeholder` / `title` / `aria-label` | `{"op":"attr","slot":"composer","name":"placeholder","value":"问点什么…"}` |
| `reset` | 恢复原样（可只恢复几个属性；个人的恢复也能盖住全员改进） | `{"op":"reset","slot":"sidebar","props":["display"]}` |

- **安全**：值走文法白名单（数字、单位、颜色、关键字、`calc` / `rgb` / `var` 等函数），拼不出 `url(`、`@import`、`;` `{}`、引号、`!important`，也就越不出它改的那条声明；没有定位类属性（`position` / `z-index`），改进只调整应用自己的元素，不能往页面上叠东西；文字一律按纯文本写入。模型编出来的指令逐条校验，不合规的丢掉并告诉用户。
- **快速意图**：常见说法不调模型，在浏览器里 0 毫秒算完——变大 / 变小 / 宽一点 / 高一点 / 字大一点 / 「宽度改成 800」/ 隐藏 / 显示 / 恢复，「稍微」≈ ×1.1、「很多」≈ ×1.5、「两倍」= ×2。话里要提到槽位名字（或先选中一块）；复合要求（「变大并改成橙色」）交给模型。
- **预览 = 保存后**：预览、保存、入口页内联用的是同一个折叠函数（服务端与浏览器共用一份代码），预览看到什么，保存后所有人看到的就是什么。

### 为什么快、为什么便宜

| | 实测（本机 → DeepSeek，2026-09-27） |
| --- | --- |
| 快速意图（变大 / 隐藏 / 恢复…） | 浏览器里 **2 ms**，不联网、不花钱 |
| 模型编译（「发送按钮改成深蓝、气泡圆一点、标题改成客服工作台」） | **1.6–2.0 s**，约 1.2k tokens ≈ **$0.0002–0.0005 / 次**（按应用计费，计入计算分钟） |
| 打开页面 | 覆盖层由服务端**内联进入口页**（CSS 排在应用样式表之后，唯一槽位的文字直接写进 HTML）：首屏就是改进后的样子，不闪、**不多一次请求**；只多一次走索引的查询，只对登记了 `evolve` 的应用 |
| 预览 / 保存后重画 | 只替换一段 `<style>` 的文本 + 少量文字，不重新渲染页面 |

不常驻：没有轮询、没有长连接。别人刚采纳的全员改进，在你下次打开页面、或切回这个页面（离上次核对超过 1 分钟）时带着指纹核一次，没变只回 `changed: false`。

### 长期维护：覆盖层是暂存区，代码才是家

改进叠在版本之上，但不会无限叠下去：

1. **固化**：`aidc evolve bake <slug> --dir <应用目录>` 把对所有人生效的改进写进源码——样式与参数进 `evolve.css`（与覆盖层同一段 CSS，页面渲染逐字节一样，入口页自动链上），文字直接写进静态 HTML；清单 `evolve.baked` 记下固化了哪些，版本号 patch +1。然后照常 `aidc app deploy` → 在 Developer 里看一眼 → `aidc app publish`。新版本上线后这些改进不再叠加，改进工程里显示「已固化进 1.0.1」。文字改在脚本画出来的元素上的改进不固化，继续由覆盖层生效。
2. **改版不怕**：改进指向的是槽位与参数的名字，不是页面结构。新版本去掉了某个槽位，指向它的改进自动跳过（改进工程里标「当前版本已失效」），不报错；回滚到旧版本，它们又回来。
3. **有上限**：每个应用同时叠加的全员改进最多 40 条，到了就先固化；每人的个人改进最多 20 条。
4. **是证据**：用户改了什么、改了几次，是下一个版本最直接的需求——它们出现在 `evolve.evidence()` 的 `evolved` 里，交给开发者的改动就是一条应用类提案。

## 二、证据与提案

只给本公司开发者（开发者 Key、应用里的 developer 访客）。

### 一轮迭代

```js
// 1. 看证据：使用、反馈、操作、错误、语义定义与数据画像（空值率、被人改过几次、样例值），
//    以及用户在应用里直接做过的改进（evolved：改了什么、给谁、留没留下）
const ev = await evolve.evidence({ app: "production-live", days: 30 });

// 2. 让模型起草提案（按公司计费；材料由你带来）
const { proposals } = await evolve.suggest({
  app: "production-live",
  files: [{ name: "生产日报口径.md", text: reportSpec }],
  skills: [{ name: "SKILL.md", text: skillText }],
  conversations: [{ name: "班组长群 09-26", text: chatExcerpt }],
});

// 3. 决定、应用
await evolve.decideProposal(proposals[0].id, "accept");
const { appliedRef } = await evolve.apply(proposals[0].id);   // 语义类 → "v5"（自动发了新语义版本）
await evolve.apply(appProposal.id, { version: "1.2.0" });     // 应用类 → 回填落地它的应用版本号
```

也可以自己（或你的智能体）直接提：

```js
await evolve.propose({
  target: "semantic",
  title: "说清楚「累计合格」的口径",
  rationale: "三条反馈都在问是当班还是当天",
  patch: [
    { op: "describe", entity: "production.order_line", column: "ok", description: "当天到此刻的累计合格件数（报工口径）" },
    { op: "synonyms", entity: "production.order_line", column: "ok", add: ["合格数", "良品数"] },
  ],
  evidence: [{ kind: "feedback", ref: feedbackId, excerpt: "「累计合格」是当班还是当天？" }],
  feedback: [feedbackId],        // 这些反馈 → 已排期；应用后 → 已处理
});
```

### 语义补丁只做加法

| op | 做什么 |
| --- | --- |
| `describe` | 改对象类型 / 属性的显示名、说明、单位 |
| `synonyms` | 加同义词（智能体按业务说法找到属性） |
| `addColumn` | 加一个只在语义层维护的新属性（备注、负责人…） |
| `addEnumValues` | 给枚举加值 |
| `addAction` | 加一个新 Action |

删属性、改类型、改主键这类破坏性变更不走自进化，由开发者手动定义、确认影响后发布。应用补丁前会做引用闭合校验，通不过整条提案不生效。

## 让智能体参与

开发者 Key（`aidc login`）可以管本公司任何应用。带 `<slug>` 的是应用里的改进，不带的是提案（`propose` / `reject` 两边都有：`<slug> <id>` 两个参数的是应用里的改进）。

```bash
# 应用里的改进
aidc evolve list production-live --status proposed          # 待采纳的改进
aidc evolve adopt production-live <id>                      # 采纳（--dry-run 预演）
aidc evolve compile production-live "合格率那一列加粗，标红低于 95% 的"   # 看一句话会变成什么指令
aidc evolve save production-live --ops 指令.json --title "合格率加粗" --scope app   # 智能体直接提交
aidc evolve bake production-live --dir ./production-live && aidc app deploy ./production-live

# 证据与提案
aidc evolve evidence production-live
aidc evolve suggest production-live --file 生产日报口径.md --skill SKILL.md --conversation 群聊.txt
aidc evolve proposals --status open
aidc evolve accept <id> && aidc evolve apply <id>
```

智能体（带开发者 Key）定期：`aidc evolve evidence` → 结合自己的记忆与对话 → `aidc evolve propose --spec …` 或 `aidc evolve suggest` → 人在 Developer 里看提案、`aidc evolve accept` → `aidc evolve apply`。应用类提案由智能体改代码、`aidc app deploy` 进测试、人确认后 `aidc app publish`，最后 `aidc evolve apply <id> --version 1.2.0`。

## API

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/api/v1/developer/evolve/{命名空间}/apps/{slug}/overlay` | 调用方看到的覆盖层（`?since=<指纹>` 没变只回 `changed:false`；`?scope=app` 只要全员的） |
| POST | `/api/v1/developer/evolve/{命名空间}/apps/{slug}/compile` | 一句话 → 改进指令（不落库） |
| GET / POST | `/api/v1/developer/evolve/{命名空间}/apps/{slug}/improvements` | 改进工程列表 / 保存（`clientKey` 幂等，`x-aidc-dry-run` 预演） |
| PATCH | `/api/v1/developer/evolve/{命名空间}/apps/{slug}/improvements/{id}` | `propose` / `adopt` / `reject` / `revert` |
| GET | `/api/v1/developer/evolve/{命名空间}/evidence` | 证据 |
| POST | `/api/v1/developer/evolve/{命名空间}/suggest` | 模型起草提案 |
| GET / POST | `/api/v1/developer/evolve/{命名空间}/proposals` | 提案列表 / 新提案 |
| PATCH | `/api/v1/developer/evolve/{命名空间}/proposals/{id}` | 采纳 / 拒绝 |
| POST | `/api/v1/developer/evolve/{命名空间}/proposals/{id}/apply` | 应用 |

凭证：应用里是页面注入的应用票据（只能改它自己那个应用），CLI / 智能体是开发者 Key（`?channel=test|production`，缺省正式版）。应用里的改进只开给公司命名空间的应用；官方公开应用没有访客身份，只能在页面上预览。

## 浏览器 SDK

| 函数 | 做什么 |
| --- | --- |
| `mount(options?)` | 挂上改进面板，返回 `{ open, close, toggle, send, destroy }`；`label` / `position` / `placeholder` / `open` |
| `compile(text, { slot, thread, draft })` | 一句话 → `{ via: "quick" \| "model", ops, delta, reply, summary, needsCode }`（`ops` 是这一轮之后的完整草稿） |
| `preview(ops)` / `clearPreview()` | 预览一组指令 / 丢掉草稿 |
| `save({ title, thread, ops, scope, kind })` | 保存改进工程（`scope: "personal" \| "app"`，`kind: "request"` = 交给开发者） |
| `list(filters)` / `decide(id, action)` | 改进工程列表 / 提交、采纳、不采纳、撤销 |
| `pick()` / `flash(slot)` | 在页面上点选一块 / 闪一下某块 |
| `overlay()` / `surface()` / `snapshot()` / `refresh()` / `onChange(fn)` | 当前覆盖层、改进面、页面现状、和服务端核一次、变化回调 |
| `evidence({ app, days })` / `suggest({ app, files, skills, conversations })` | 证据 / 模型起草提案 |
| `propose(input)` / `proposals(status)` / `decideProposal(id, "accept" \| "reject")` / `apply(id, { version })` | 提案：新建、列表、采纳 / 拒绝、应用 |

## 旧名（1.2–1.20 的自提升 SDK）

自提升 SDK 在 1.22.0 并进了自进化：「应用里直接改」和「证据与提案」本来就互相引用（界面改不了的改动就是一条应用类提案，用户在应用里做过的改进就是证据），现在是一个 SDK、一页文档、一个命令组。已经写好、发布的应用与脚本不用改，旧写法照样能用：

- 浏览器：`import { improve }`——`improve.evidence / suggest / propose / proposals / apply` 就是 `evolve` 里的同名函数，`improve.decide(id, "accept" | "reject")` 就是 `evolve.decideProposal(…)`；
- 清单：`"sdk": ["improve"]`（部署时归成 `evolve`，登记表显示「自提升 → 自进化」）；
- 命令行：`aidc improve …`（子命令不变，stderr 提示改用 `aidc evolve …`）；
- API：`/api/v1/developer/improve/{命名空间}/…`（响应带 `Deprecation`，`Link` 指向 `/api/v1/developer/evolve/{命名空间}/…`）；应用里的改进从 1.22.0 起在 `/apps/{slug}/` 下，1.12–1.20 的 `/api/v1/developer/evolve/{命名空间}/{slug}/…` 同样照旧可用（`Deprecation` + `Link`）；
- 文档：`/developer/docs/improve` 永久重定向到本页。

新代码一律写 `evolve`。
