AI 时代我的开发工作流:从踩坑复盘到多项目并行验证
Source: https://innei.in/posts/tinkering/ai-era-dev-workflow-review-and-verify
Author: Innei (@__oQuery) · X thread: https://x.com/__oQuery/status/2089240475643633733
AI 时代我的开发工作流:从踩坑复盘到多项目并行验证
作者: @__oQuery
原文链接: https://innei.in/posts/tinkering/ai-era-dev-workflow-review-and-verify
前言#前言
对于技术文章来说,我已经很久没有写过了。我上一篇技术文章应该是发布在今年 4 月底的时候,我不写技术文章的原因,也是因为大部分值得写的内容,以前都是自己花了很多时间踩坑,然后记录下来告诉以后的人,或者留给以后的自己去复盘,能有一些值得看的东西。
但现在有了 AI 之后,自己很少再会去琢磨、去钻研到很深度的东西。再者,技术类文章往往都比较枯燥,而且一些比较晦涩的理解,可能现在的人也没有耐心去读完,反手基本都是扔给 AI 去读。
另一个比较大的变化是,我正在慢慢从一个对技术钻研过深的方向,转变为能够同时进行多个产品迭代和开发的职责。这也是现阶段 AI 发展所带来的一个变化。
在年初的时候,我每个月差不多才花 50 亿到 60 亿的 token,全部加起来一个月也就这么多。而到了现在的 8 月份,我可能两天就能用掉这么多 token,直接翻了 15 倍。
怎么样才能成为时间管理大师?
比如在只有一人、两台电脑(或者一台电脑,我目前是两台电脑)的情况下,如何在同一时间段内,同时进行开发四五个项目?
其实在 AI 以前,我的 ADHD(注意力不集中)带来一个问题:我经常会在三四个上下文中不停跳出。
我很容易健忘,开了很多事项之后,回过头来可能就忘了。等再次看到的时候才发现,哦,原来我之前还有这么一个事情还没去跟进。而在现在看来,它可能又是一种优势,也可能是之前造就的这种能力,让我现在有可以去同时进行这么多项目的能力(比如 mx-space、afilmory、kansoku、yohaku、Torrent Vibe)。
说了那么多,我也是想讲解一下我日常开发的一些工作流,以及后面我编写技术类文章的可能性。
当然,大概率是会越来越少了。近这几个月以来,所有的技术类文章完全是通过 AI 自动生成的,很多读者看到后来也不想看了。不过,这些文章本来也不是给人看的,它更多的是在使用我的工作流复盘后自动总结出来的。
后面我也将介绍它是如何工作的。
前面说了这么多想法,接下来我要分享两个点。
第一个是,怎样把曾经需要手动沉淀、踩过坑的一些复盘经验整理出来?当然,现在这一部分完全是由 AI session 来驱动的。也就是说,我们现在一般都是通过一个 AI 长对话来进行踩坑和解决问题。
至于到最后复盘时,如何让这一段对话变成有意义的东西?这需要一个载体。它的载体可以是文章,也可以是 skill。而我选择的载体,是通过工作流直接帮我生成一篇技术类文章,并且附带一个 Skill
第二是如何同时进行多个项目的开发。这主要涉及到两点:
1. 上下文切换:你需要对每个项目都有所了解,至少要知道自己具体在做什么 2. 自动化验证:如何让验证流程自动化?需求写得再快,如果没有自动化验证,而是需要手动介入去验证和验收,其实要花不少时间
复盘:把踩坑会话沉淀为文章与 Skill#复盘把踩坑会话沉淀为文章与-skill
我的个人网站中,技术类文章最近的五六篇或者以上完全由 AI 生成。为了过滤掉这些 AI 生成的文章,我很贴心地在文章列表中添加了“无 AI 写作”的筛选。
为了打通这一个闭环的链路,我在前几个月的时间里,为我的网站增加了一个 CLI。AI 操作 CLI 比直接操作 MCP 和调用接口方便得多。
为了能让 AI 在技术类文章中加入更多可交互和丰富的数据与信息展示,我放弃了传统的 Markdown。
因为传统的 Markdown 能承载的信息格式太局限了。如果你去扩展 Markdown 的语法,显然 AI 要花很长的时间去理解;并且最大的问题是,Markdown 不是 block 的东西,再加上复杂的自定义语法,很容易让 AI 写坏。所以后面我选择了富文本编辑器,去实现了一套我们后续可以去自定义、并且可以实现更多可交互特征的一种信息格式。
那么这种信息格式在后续的时候,可以通过 XML 的方式来进行修改。然后基于它,扩展了 MapNode, ExcalidrawNode 等交互节点。当然,我这里想说的是,数据格式并不是重点,只是我这里使用了它,你也可以参考。
接下来就来讲一讲,我这个 skill 它做了什么事。他怎么样去总结前面的 session,然后最后输出成一篇文章的。
MD
---
name: session-to-skill-and-blog
description: >
Convert a completed engineering session into a narrative blog and zero or
more reusable operational skills. Use when Innei explicitly asks to
productize, document, or publish a finished session ("写成 skill 再写一篇
blog", "沉淀一下这次的折腾", "productize this session", or "publish this as
a skill and a writeup"). Classify project-local facts separately.
---
# session-to-skill-and-blog
Turn session evidence into the appropriate durable outputs:
- a blog that explains the experience, reasoning, and conclusion;
- zero or more skills that let a future agent execute reusable capabilities;
- project documentation for facts and conventions that remain local.
Do not force a one-to-one pair. One blog may attach no skill, one skill, or
several skills; one skill may support several later blogs. The outputs share
evidence, not structure.
**Confirm authoring choices, then classify.** For every accepted skill
candidate, author and push the skill before writing the blog. This
preserves the operational contract before narrative compression. If intake
said no skill, or no candidate passes the skill gate, write the blog
without inventing a skill.
## References
This file is a thin index. Load the matching reference when you start the
actual work:
| File | When to load |
| ---- | ------------ |
| [`references/writing-style.md`](./references/writing-style.md) | Before drafting prose — reading contract, title and slug, sections, narrative, argument, narrator, and anti-slop editing. |
| [`references/node-usage.md`](./references/node-usage.md) | Before using any extension node — deletion test, escalation ladder, catalog rule. |
| [`references/visuals.md`](./references/visuals.md) | When prose creates a visual-explanation question, or when uploading image assets. |
| [`references/editorial-models.md`](./references/editorial-models.md) | Only when revising the editorial policy — primary-source research and derived principles. |
| [`references/publish-flow.md`](./references/publish-flow.md) | When previewing / creating / editing / publishing the post. |
| [`references/widget-template/`](./references/widget-template/DESIGN.md) | When authoring a new `<dynamic>` widget. |
| `references/envelope.template.xml` | Copy as the post envelope before pasting the LiteXML body. |
| `no-ai-slop` (via `load-no-ai-slop.sh`) | After the draft is written, before publishing — detect candidates, revise manually, rerun. |
For LiteXML tag syntax itself, load the litexml-authoring skill (fresh via
`load-litexml.sh`) — this skill governs *whether/when*, that one governs *how*.
## Configuration
`~/.config/innei-skills/config.json` (see `references/config.example.json`):
{ "skill_repo_dir": "~/git/innei-repo/SKILL" }
Missing key → fallback to `~/git/innei-repo/SKILL`.
Domains: `infrastructure` / `automation` / `writing` / `research` / `content`.
Prereqs once per machine: `npm i -g @mx-space/cli` (Node ≥ 22, needs the
`draft` command group — check `mxs draft --help`); `mxs auth login`.
## Scripts
Define `$S` once per session. Search known locations; the first that
contains `resolve-skill-repo.sh` wins:
S="" for cand in \ "$HOME/.claude/skills/session-to-skill-and-blog/scripts" \ "$HOME/.codex/skills/session-to-skill-and-blog/scripts" \ "$HOME/.agents/skills/session-to-skill-and-blog/scripts" \ "$(git rev-parse --show-toplevel 2>/dev/null)/.claude/skills/session-to-skill-and-blog/scripts" \ "$(git rev-parse --show-toplevel 2>/dev/null)/.agent/skills/session-to-skill-and-blog/scripts" \ "$(git rev-parse --show-toplevel 2>/dev/null)/skills/automation/session-to-skill-and-blog/scripts" do [ -n "$cand" ] && [ -f "$cand/resolve-skill-repo.sh" ] && { S="$(cd "$cand" && pwd)"; break } done [ -n "$S" ] || { echo "error: cannot locate session-to-skill-and-blog/scripts" >&2; exit 1; } REPO="$(bash "$S/resolve-skill-repo.sh")"
| Script | What it does |
| ------ | ------------ |
| `resolve-skill-repo.sh` | Print absolute path to the SKILL repo (config-driven, with fallback). |
| `scaffold-skill.sh` | Create dir + stub SKILL.md + README row (alphabetical, domain-scoped) + both flat symlinks; `git add` staged. |
| `load-litexml.sh` | `degit` the latest `litexml-authoring` subtree into `~/.cache/`. |
| `load-no-ai-slop.sh` | `degit` the latest `no-ai-slop` skill into `~/.cache/`. If unavailable, report it and continue with the internal hard-ban sweep. |
| `push-skill.sh` | Idempotent `mxs snippet put sk/<name>/SKILL.md --type skill`, plus sibling assets as `--type text`. Emits the snowflake id on stdout. |
| `create-draft.sh` | `mxs draft create` with `aiGen=2`, `--open`, `--silent` → `{ ok, id }`; `--skill-id <id>` (repeatable) threads ids into `meta.skillIds`. |
| `get-post.sh` | `mxs post get <slug> --output xml` — round-trip step 1. |
| `update-post.sh` | `mxs post update <slug> --file …` — strips `<state>`, then updates. |
| `image-meta.mjs` | Emit `width` / `height` / `thumbhash` for a LiteXML `<img>`. Run from a project that has `sharp` + `thumbhash` (e.g. mx-core). |
## Workflow
[0] Confirm persona and skill pairing (interactive tool if available) [1] Inventory and classify session evidence [2] State and evaluate each capability thesis intake = none ──> skip to [5] rejected ──> blog or project documentation accepted ──> one coherent skill [3] Scaffold, author, validate, commit, and push accepted skills [4] Push accepted skills to mx-core and collect their ids [5] Write the blog from the narrative evidence [6] Publish via mxs with zero or more --skill-id arguments
### [0] Confirm authoring choices
Do this before [1]. If the triggering message already answered both
questions, record those answers and continue. Otherwise ask, then wait.
If the runtime has an interactive question tool (`AskUserQuestion`,
`ask_user_question`, or equivalent), ask both questions in one call.
If no such tool exists, ask the same two questions in chat. Do not start
[1] until both answers are recorded.
Ask in Chinese. Map the answers as follows; do not invent extra questions.
1. 你想用哪种写作人格去编写这篇文章?
| Option | Record as | Meaning |
| ------ | --------- | ------- |
| Agent 第一人称 | `agent` | 「我」是 agent |
| 站长第一人称 | `site-owner` | 「我」是 Innei |
| 中性叙述 | `neutral` | 不用「我」 |
| 看材料再定 | `defer` | Choose after the spine |
Narrator attribution lives in
[`writing-style.md`](./references/writing-style.md). A custom "Other"
answer maps to the closest of these four, or follows the user's wording
when it already names a narrator.
2. 这篇文章需要搭配一个 skill 吗?
| Option | Record as | Effect |
| ------ | --------- | ------ |
| 需要 | `required` | Run [2]–[4]; a failing gate still yields a blog without a skill |
| 不需要 | `none` | Skip [2]–[4]; write the blog only |
| 看材料再定 | `defer` | Existing semantic gate decides |
A recorded `agent` / `site-owner` / `neutral` overrides the spine default
in `writing-style.md`. `none` skips skill work even if a candidate would
pass.
### [1] Inventory and classify
Collect decision points, failed assumptions, symptom-to-cause evidence,
commands, reusable procedures, safety boundaries, verification results, and
project-local facts. Classify each item by its future function:
| Destination | Include | Exclude |
| ----------- | ------- | ------- |
| Blog | Context, chronology, argument, representative failures, and interpretation | Exhaustive operating instructions |
| Skill | Repeatable action, decision boundary, non-obvious constraint, and observable proof | Session chronology and personal reflection |
| Project documentation | Repository-specific ownership, commands, architecture, and persistent local conventions | General reusable workflow |
Treat code or configuration length only as a resource-planning signal. It is
not evidence that a skill should exist.
### [2] State and evaluate the capability thesis
If intake recorded `none`, skip this step and [3]–[4].
Write this sentence before scaffolding a candidate:
> This skill helps an agent **[action] [target]** when **[trigger]**, while
> preserving **[constraint]**, and verifies success through **[observable
> outcome]**.
Reject or redirect the candidate unless every gate passes:
| Gate | Pass condition | If it fails |
| ---- | -------------- | ----------- |
| Triggerability | A concrete future user request can activate it. | Keep the material in the blog. |
| Repeatability | The action or decision is likely to recur. | Use the blog or project documentation. |
| Knowledge delta | It teaches non-obvious procedure, local integration, or a hard-won failure boundary. | Do not create a skill. |
| Coherence | It has one trigger family, one operational target, and one primary outcome. | Split independent capabilities. |
| Verifiability | Success is externally observable. | Treat it as analysis or reference material. |
| Stability | The core method survives routine version changes. | Move volatile facts to references or project documentation. |
| Boundary clarity | It states exclusions and stopping conditions. | Narrow the capability. |
Name accepted skills with a concise, verb-led target and action. Prefer
`split-dokploy-traffic-safely` over `traefik-notes`, and
`migrate-nextjs-rsc-under-cdn-constraints` over `nextjs-migration`.
Keep one capability thesis per skill. Split candidates when their triggers,
targets, or completion criteria can vary independently. Place cross-project
capabilities in this repository; place facts that only future work in one
repository needs in that repository's agent or project documentation.
Plan bundled resources by function, not by arbitrary line count:
| Resource | Add when |
| -------- | -------- |
| `scripts/` | An operation is deterministic, fragile, or repeatedly rewritten. |
| `references/` | Schemas, protocols, detailed examples, or volatile facts would obscure the operational core. |
| `assets/` | The skill must copy or transform an output resource. |
Do not create empty resource directories.
### [3] Scaffold, author, and push accepted skills
bash "$S/scaffold-skill.sh" <domain> <skill-name> "<one-line purpose>"
Use the scaffold once for each accepted capability. Author the skill as an
execution interface for a future agent, not as a compressed version of the
blog.
Every generated skill requires this contract:
| Required element | Standard |
| ---------------- | -------- |
| Frontmatter | Include only `name` and `description`. Put both capability and all trigger conditions in `description`; do not repeat a body-level "When to use" section. |
| Capability boundary | State the outcome, prerequisites, exclusions, and stopping conditions. |
| Operational core | Give the shortest sufficient procedure or decision path in dependency order. Use imperative instructions. |
| Verification | Prove the externally meaningful outcome, including safety checks where relevant. |
Add the following sections only when they carry real operational information:
| Conditional element | Add when |
| ------------------- | -------- |
| Decision table | Multiple conditions select different actions. |
| Flow or architecture diagram | Ownership, sequence, or data flow is difficult to understand linearly. |
| Pitfalls | Observed failures have recognizable symptoms and actionable fixes. |
| Rollback | The procedure changes external or difficult-to-recover state. |
| Examples | An example materially clarifies input, output, or a decision boundary. |
Do not emit empty sections to satisfy a template. Do not repeat generic
technical knowledge. Keep the main file below 500 lines and use progressive
disclosure for details.
Validate each folder with the available skill validator before committing.
Then commit and push the accepted skill:
cd "$REPO" && git add "skills/<domain>/<skill-name>" && git commit -m "feat: add <skill-name> skill" && git push
The pre-commit hook enforces: README row exists **inside the matching
domain table**; both flat symlinks present and resolved. Skill URL (for
reference only — never mentioned in the blog body; the skill card carries
the linkage):
`https://github.com/Innei/SKILL/tree/main/skills/<domain>/<skill-name>`
### [4] Push accepted skills to mx-core
For every accepted skill, push its SKILL.md to mx-core's snippet store so the
reader-facing `<SkillCardList>` can render it and the public raw URL
(`${MXS_API_URL}/api/v3/s/sk/<name>`) exists.
SKILL_ID=$(bash "$S/push-skill.sh" "$REPO/skills/<domain>/<skill-name>/SKILL.md")
Run the command once per skill and retain every returned id. The script is
idempotent — `mxs snippet put` upserts by path.
Sibling asset files are pushed as `--type text` under `sk/<name>/` —
the backend rejects `--type skill` for any path not ending in `/SKILL.md`,
and without them relative links inside SKILL.md 404 on the public site.
Capture the returned id; step [6] threads it through `create-draft.sh`.
If a skill never reaches mx-core, the blog may still publish without that
install card. If no skill candidate passed the gate, skip this step entirely.
### [5] Write the blog
Load [`writing-style.md`](./references/writing-style.md),
[`node-usage.md`](./references/node-usage.md), and
[`visuals.md`](./references/visuals.md) before drafting. Do not restate
those rules here.
Use the recorded narrator. If intake recorded `defer`, choose after the
spine per `writing-style.md`.
After choosing the reader contract and article spine, derive a working title
and stable slug. Finalize the title after the draft proves its central claim;
do not allow a sharper generalization to erase the defining technology or
system from the title.
Once the draft is complete:
SLOP_CACHE=$(bash "$S/load-no-ai-slop.sh") || { echo "no-ai-slop unavailable; continue with the internal hard-ban sweep" }
Medium: default LiteXML (for Innei's blog).
LITEXML_CACHE=$(bash "$S/load-litexml.sh")
Plain Markdown is fine when no haklex-specific tags are needed.
Do not convert the skill body into article sections. Reconstruct the blog from
the narrative evidence: establish the problem, expose the consequential
decisions, support claims with concrete evidence, and state the resulting
view. A rejected skill candidate may still supply valuable narrative material.
### [6] Publish via `mxs`
Follow [`publish-flow.md`](./references/publish-flow.md) end to end —
including the post-`--file` metadata re-attach and the post-publish metadata
verification. Pass zero or more `--skill-id` arguments according to the
accepted and successfully pushed skills. Paste the final URL back into the
originating session.
## Failure boundaries
Only mistakes that happen **before** the reference files are loaded.
Publish, voice, and node rules live in those files.
| Mistake | Fix |
| ------- | --- |
| Skipping intake when the trigger did not already answer | Ask both questions before [1]; use the interactive tool when it exists. |
| Choosing narrator after a recorded intake persona | Use the recorded narrator. |
| Authoring a skill after intake `none` | Skip [2]–[4]. |
| Forcing every blog to have exactly one skill | Apply the semantic gate; allow zero, one, or several skills. |
| Deriving the skill scope from the blog title | Define a future trigger, action, boundary, and observable outcome. |
| Creating a skill because the session contains long code | Require repeatability and a non-obvious knowledge delta first. |
| Combining independent triggers in one skill | Split by trigger family, target, and completion criterion. |
| Copying the blog chronology into SKILL.md | Preserve only the executable method and decision boundaries. |
| Adding empty workflow, pitfalls, or diagram sections | Include conditional sections only when they improve execution. |
| Repeating trigger rules in a body-level "When to use" section | Put all triggering information in the frontmatter description. |
| Blog before an accepted skill | Finish and push every accepted skill before drafting the blog. |
| SKILL.md contains large deterministic procedures inline | Move repeated or fragile operations to `scripts/`; move detailed supporting material to `references/`. |
| Mentioning the skill in the blog body | Zero in-text mention. `meta.skillIds` renders the skill card. |
| `--no-verify` to bypass the pre-commit hook | Fix the root cause. The hook now requires the README row inside the matching domain table. |
| Hardcoding the SKILL repo path in shell | `bash "$S/resolve-skill-repo.sh"`. |
| Locating `$S` via `~/.claude/skills/...` only | Use the search loop above. |
| Stale local `litexml-authoring` / `no-ai-slop` clone | `load-litexml.sh` / `load-no-ai-slop.sh` refresh via degit. If no-ai-slop cannot load, skip and say so. |
| Skill written in Chinese | Skill in English. Blog in Innei's chosen language (default Chinese). |
| Skipping `push-skill.sh` and embedding only the GitHub URL | The install card reads `meta.skillIds`. Without `--skill-id`, it never renders. |
| Form / narrator / voice / slop mistakes | `writing-style.md`. |
| Title states a lesson but drops the defining technology | Restore the identity anchor, then qualify it with the earned claim. |
| Node sprinkling, invented `<dynamic>` URLs | `node-usage.md`. |
| Draft/meta/`<state>` / category / publish mistakes | `publish-flow.md`. |
## Verification
- [ ] `$S` resolved via the search loop; `bash "$S/resolve-skill-repo.sh"` points at a real directory before any write.
- [ ] Intake answers recorded (or already present in the trigger) before [1].
- [ ] Draft narrator matches the recorded persona, or the deferred spine rule.
- [ ] Skill work skipped when intake said `none`; gates still applied when `required` or `defer`.
- [ ] Session evidence was classified among blog, reusable skill, and project documentation.
- [ ] Every skill has a capability thesis and passes all seven semantic gates.
- [ ] Every skill has one trigger family, one operational target, and one primary observable outcome.
- [ ] Frontmatter contains only `name` and `description`; the description carries all trigger conditions.
- [ ] The body contains the capability boundary, operational core, and verification without empty conditional sections.
- [ ] Scripts, references, and assets exist only when they improve deterministic reuse or progressive disclosure.
- [ ] Every accepted skill passed validation and the repository pre-commit hook; `git push` succeeded.
- [ ] Every successfully published skill returned a snowflake id and its `${MXS_API_URL}/api/v3/s/sk/<name>` URL resolves.
- [ ] Blog body has **zero** mention of the skill — the skill card carries the linkage.
- [ ] Voice, node, and visual checks in `writing-style.md` / `node-usage.md` / `visuals.md` passed.
- [ ] Final title preserves the technical identity anchor and makes no claim broader than the evidence; slug uses stable searchable terms.
- [ ] `no-ai-slop` detect sweep rerun after manual edits with no unresolved finding; if the loader failed, the internal hard-ban sweep still passed and the failure was reported.
- [ ] `meta.skillIds` contains exactly the successfully pushed skills; it is absent or empty when no skill passed the gate.
- [ ] Publish checklist in `publish-flow.md` passed; final post URL pasted back into the originating session.
展开
https://github.com/Innei/SKILL/blob/main/skills/automation/session-to-skill-and-blog/SKILL.md
SKILL.md (368) 决定「要不要做、做不做得成」——只在这里做判断
├─ references/ (1041) 决定「怎么写」——按需加载,不进默认上下文
│ writing-style.md 470 编辑标准 / 读者契约 / 脊柱 / 标题 / 叙述者 / 反 slop
│ publish-flow.md 219 mxs 版本级的发布正确性
│ node-usage.md 174 节点该不该用
│ visuals.md 134 图该不该画、怎么算 thumbhash
│ editorial-models.md 44 政策的一手来源(明确写「日常写作不要加载」)
└─ scripts/ (8) 确定性操作——不留给模型判断
上面这个结构分层,也是为了避免把太多的规则直接扔到模型上下文之后,导致注意力丢失。
那么就会有一个索引,指导你该怎么去做。
开始之前,先确定是要输出文章,还是同时输出 skill?因为我之前做的 CLI 可以让 AI 去修改之前的文章,或者是在创建文章之前进行草稿预览和二次修改。
类似的,还要确定一个写作人格。我在这个 skill 中确定了三种写作的方向,对应三种人格。
选完人格之后,就是这篇文章的框架设定。比如说,它是一篇教程类文章,还是一篇可复用的一些经验总结和设计规则?
这里我设定了三种不同的类型,默认一般都是写经验总结,也就是 pattern。
pattern 的写法会比较随意:没有模板:没有规定的 block 顺序,没有「Pattern 1/2/3」标题公式,没有固定章节形状。
然后就是后面的链路,我有专门一个 skill 去消除 AI Slop。虽然说有这样一个步骤,但是难免还是会有很多。但我觉得,既然都是 AI 写的,那这个其实也不是重点,毕竟它也不是给人类可读的。
之后就是打草稿 - 修改的 loop 直到发布。
Whiteboard
这里有篇文章也可以看一下。
[
把 AI session 沉淀成两份资产
本文介绍了一套将AI协作session产物固化为skill和blog的工作流。核心是anchor skill的五步骨架,遵循“skill先,blog后”的铁律,确保操作约束可执行。工作流依赖三个构件:mxs CLI管理发布,LiteXML处理富文本格式,litexml CLI负责渲染。文章还讨论了根据内容选择agent或site-owner视角的persona规则,并记录了一次dogfood中暴露的五个底层bug,验证了工作流的自我修复能力。
](https://innei.in/posts/tech/skill-first-blog-second-my-session-to-asset-pipeline)
验证:多项目并行下的自动化验收#验证多项目并行下的自动化验收
同时开发这么多个项目的话,肯定需要人工去介入,手动验证一些 UI 以及流程。如果 UI/UX 验证功能的流程不正确,是非常困难的,况且本来切换上下文就是一件非常费力的事情。
那么,这个步骤就必须要给它自动化掉。
现在最新的一些旗舰模型,其实已经把 verify 的能力训练到模型里面去了。它会在自主实现完一个功能之后,通过各种方式(比如操控浏览器、使用 CDP 等)去验证整个链路是否存在问题,直到验证通过为止。