Pi从入门到精通:用极简Agent构建供应链智能助手

Pi 是 Mario Zechner 发起的开源 Agent Harness。它不是一个大模型,而是一套把大模型、上下文、工具、会话和终端界面组合起来的运行框架。它既提供可以直接使用的编程 Agent,也提供 SDK、RPC、Skills 和 Extensions,适合继续封装成企业内部的 AI 助手。

本文以 2026 年 8 月 1 日的官方版本为基准,从安装和第一次对话开始,逐步讲到项目规则、模型配置、技能、扩展工具、SDK、Java 系统集成、安全控制和效果评估。业务示例统一使用供应链系统中的订单、库存、采购和补货场景。

Pi 已迁移到 earendil-works/pi,npm 包也已改为 @earendil-works/*。旧的 badlogic/pi-mono@mariozechner/* 资料可能仍能搜索到,但新项目应使用当前名称。

Pi Agent Harness组件架构

一、先理解Pi解决什么问题

一个可执行的 AI Agent 至少需要五部分:

  1. 模型:负责理解目标、推理和决定下一步动作。
  2. 上下文:告诉模型项目结构、业务术语和工程约束。
  3. 工具:让模型读取文件、执行命令或调用业务接口。
  4. Agent 循环:重复执行“模型判断、调用工具、读取结果、继续判断”。
  5. 会话:保存消息、工具结果、模型状态和上下文压缩结果。

Pi 把这些能力拆成多个包:

职责
@earendil-works/pi-ai 统一不同模型提供商的调用接口
@earendil-works/pi-agent-core Agent 循环、工具调用和状态管理
@earendil-works/pi-coding-agent 可直接使用的 CLI、SDK、会话和扩展系统
@earendil-works/pi-tui 终端交互界面

因此,Pi 有四种常见用法:

  • 直接运行 pi,把它当作终端编程助手。
  • 运行 pi -p,完成一次性、非交互任务。
  • 运行 pi --mode rpc,通过 JSONL 接入 Java、Python 或桌面应用。
  • 在 Node.js/TypeScript 服务中使用 AgentSession SDK。

二、安装Pi并完成第一次运行

1. 检查Node.js版本

当前 pi-coding-agent 要求 Node.js >=22.19.0

1
2
node --version
npm --version

如果版本过低,先通过 Node.js 官方安装包、nvm 或 fnm 升级。

2. 全局安装

1
2
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
pi --version

--ignore-scripts 会阻止依赖安装阶段执行生命周期脚本,Pi 的正常 npm 安装不依赖这些脚本。

Windows PowerShell、macOS 和 Linux 都可以使用相同的 npm 安装命令。如果安装成功但提示找不到 pi,应检查 npm 全局可执行目录是否已加入 PATH

1
npm config get prefix

3. 登录模型提供商

进入任意项目目录后启动:

1
2
cd /path/to/supply-chain-system
pi

在 Pi 里执行:

1
/login

可以选择官方支持的订阅登录,也可以使用 API Key。以 PowerShell 为例,临时设置 OpenAI API Key:

1
2
$env:OPENAI_API_KEY="你的API Key"
pi

Linux 或 macOS:

1
2
export OPENAI_API_KEY="你的API Key"
pi

不要把 API Key 写入 Git 仓库、AGENTS.md、提示词或日志。也可以通过 /login 把凭证交给 Pi 管理,默认凭证文件位于 ~/.pi/agent/auth.json

4. 第一次供应链任务

先让 Pi 理解项目,不要一上来就让它改代码:

1
2
3
请先读取 README.md、pom.xml 和订单、库存、采购模块的目录结构。
说明创建采购订单后,库存预占、补货计算和供应商下单分别在哪些模块完成。
只分析,不修改文件,也不要执行写数据库的命令。

Pi 默认给模型提供 readwriteeditbash 四个工具。模型并不是直接操作电脑,而是在 Agent 循环中选择工具,Pi 执行工具后把结果返回给模型。

三、用AGENTS.md建立项目规则

AI 在供应链项目里最容易犯的错误,不是 Java 语法错误,而是误解库存口径、订单状态和事务边界。应在仓库根目录创建 AGENTS.md,把长期有效的规则放进去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Supply Chain Project Instructions

## Modules
- order-service: 销售订单和状态流转
- inventory-service: 现存量、预占量、冻结量和库存流水
- procurement-service: 采购申请、采购订单和供应商协同
- replenishment-service: 安全库存与补货建议

## Business Rules
- 可用库存 = 现存量 - 预占量 - 冻结量。
- 库存扣减必须使用带数量条件的原子更新,并记录库存流水。
- 同一个 businessRequestId 重试时不得重复预占或释放库存。
- 采购订单状态只能按状态机流转,禁止直接覆盖状态。
- 跨服务一致性使用本地事务加 Outbox 事件,不创建分布式大事务。

## Safety
- 默认只允许查询本地开发库,不连接生产数据库。
- 未经明确确认,不执行 INSERT、UPDATE、DELETE、DDL 和消息重放。
- 不读取或输出 .env、密钥、Token、客户手机号和供应商银行信息。

## Verification
- Java 代码修改后运行 mvn -pl <module> test。
- 库存并发逻辑必须增加重复请求、库存不足和并发扣减测试。
- 数据库变更必须提供可回滚迁移脚本和索引影响说明。

Pi 启动时会加载全局 ~/.pi/agent/AGENTS.md,以及当前目录和父目录中的 AGENTS.mdCLAUDE.md。修改规则后执行 /reload,或者重新启动 Pi。

项目规则应该描述稳定事实,不要把某次临时需求全部塞进去。临时需求应放在单独的需求文档中,再通过 @文件名 引用。

四、掌握一套可靠的日常开发流程

以“订单创建时预占库存”为例,可以把一次任务拆成五个阶段。

阶段1:建立上下文

1
2
读取 @AGENTS.md、@docs/inventory-model.md,搜索现有的库存扣减、释放、流水和幂等实现。
列出相关文件、当前调用链、事务边界和测试入口。不要修改代码。

这一步要求 Pi 先找到项目里的真实模式,避免凭经验发明不存在的层次和组件。

阶段2:输出实施计划

1
2
3
4
5
6
7
8
9
10
11
需求:订单创建成功后预占库存;订单取消或支付超时后释放;重复消息不能重复处理。

请给出实施计划,必须包含:
1. 正常流程和异常流程。
2. 表字段、唯一键、版本号和条件更新SQL。
3. 本地事务与Outbox事件边界。
4. 幂等键定义和重复消费处理。
5. 需要修改的文件清单。
6. 单元测试、并发测试和集成测试用例。

只输出计划,等待确认后再编码。

阶段3:小步实现

确认计划后再执行:

1
2
按计划先完成库存预占的领域逻辑和仓储层,只修改 inventory-service。
不要修改公共依赖版本。完成后展示差异并运行该模块测试。

一次只改变一个业务闭环。订单、库存、采购三个服务同时大改,会让上下文迅速膨胀,也会增加错误定位成本。

阶段4:验证业务不变量

至少检查以下不变量:

  • 可用库存不能为负数。
  • 相同幂等键只能产生一次库存流水。
  • 释放数量不能超过原预占数量。
  • 数据库回滚时不能留下已发送但无法追踪的业务事件。
  • 消息重复、乱序、延迟时,最终状态仍然正确。

可以让 Pi 主动补测试:

1
根据本次 diff 检查库存不变量。补充库存不足、相同幂等键重复请求、20线程并发预占、事务回滚四组测试,然后运行测试并解释失败原因。

阶段5:审查和提交

1
2
审查当前 git diff,优先寻找数据一致性、并发、幂等、空值、越权和日志泄密问题。
没有阻塞问题后,给出建议的提交信息,但不要自动推送。

这个流程的重点是把“理解、计划、实现、验证、审查”分开。模型能力再强,也不应该跳过业务确认和可重复验证。

五、模型、思考强度与会话管理

切换模型

在交互模式中:

1
/model

也可以使用 Ctrl+L 打开模型选择器,使用 Shift+Tab 切换思考强度。简单的格式调整不需要高强度推理;跨服务库存一致性、死锁分析和数据迁移则适合更高强度。

项目级 .pi/settings.json 可以保存团队约定,例如:

1
2
3
4
5
6
7
8
9
{
"defaultProvider": "openai",
"defaultModel": "你的模型ID",
"defaultThinkingLevel": "medium",
"enabledModels": [
"openai/*",
"anthropic/*"
]
}

模型 ID 会随提供商更新,先用 /modelpi --list-models 查看当前可用值,不要照抄过时文章里的模型名。

管理长任务

1
2
3
pi -c                  # 继续最近会话
pi -r # 浏览历史会话
pi --name "库存预占改造"

交互模式还提供 /new/resume/tree/fork/clone。建议一个会话只解决一个明确问题。需求方向发生变化时,通过 /fork 保留原分支,比在同一上下文里反复推翻更清晰。

接入本地模型

Pi 可以通过 ~/.pi/agent/models.json 接入 Ollama、LM Studio、vLLM 等 OpenAI 兼容服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "你的本地模型ID",
"reasoning": false
}
]
}
}
}

本地模型适合代码检索、摘要和低风险分类,但是否能处理复杂库存一致性问题,必须通过真实测试集评估,不能只看通用排行榜。

六、用Skill沉淀供应链知识

AGENTS.md 是所有任务都要遵守的项目规则,Skill 则是按需加载的专业流程。可以创建:

1
.pi/skills/supply-chain-review/SKILL.md

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
name: supply-chain-review
description: 审查订单、库存、采购和补货代码。当任务涉及库存数量、状态机、幂等、消息或供应链数据一致性时使用。
---

# Supply Chain Review

1. 先识别业务实体、状态和数量口径。
2. 画出同步调用、事务提交和异步消息的先后顺序。
3. 检查幂等键来源、唯一约束和重复消息处理。
4. 检查库存更新是否包含 `available_qty >= request_qty` 条件。
5. 检查超时、取消、部分成功和补偿路径。
6. 检查日志是否泄露客户、供应商或凭证信息。
7. 输出按严重程度排序的问题,并给出文件位置和测试建议。

项目被信任后,Pi 会发现 .pi/skills/ 下的技能。重载后可以显式调用:

1
/skill:supply-chain-review 审查本次库存预占改动

Skill 可以附带 scripts/references/assets/。例如把库存字段字典、订单状态机和消息规范放进 references/,只有任务需要时才加载,能减少固定上下文占用。

七、用Extension接入只读库存接口

Skill 只是告诉模型怎么工作,Extension 才能注册真正可调用的工具。下面创建一个项目级只读库存查询工具:

1
.pi/extensions/inventory-query.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";

export default function (pi: ExtensionAPI) {
pi.registerTool({
name: "query_inventory",
label: "Query Inventory",
description: "按SKU和仓库查询只读库存快照,不执行预占、扣减或释放",
parameters: Type.Object({
sku: Type.String({ description: "SKU编码" }),
warehouseCode: Type.String({ description: "仓库编码" }),
}),
async execute(_toolCallId, params, signal) {
const baseUrl = process.env.SCM_API_BASE_URL;
const token = process.env.SCM_API_TOKEN;

if (!baseUrl) {
throw new Error("SCM_API_BASE_URL is not configured");
}

const url = new URL("/api/v1/inventory/availability", baseUrl);
url.searchParams.set("sku", params.sku);
url.searchParams.set("warehouseCode", params.warehouseCode);

const headers: Record<string, string> = {
Accept: "application/json",
};
if (token) headers.Authorization = `Bearer ${token}`;

const response = await fetch(url, { headers, signal });
if (!response.ok) {
throw new Error(`Inventory API failed: HTTP ${response.status}`);
}

const snapshot = await response.json();
return {
content: [
{
type: "text",
text: JSON.stringify(snapshot, null, 2),
},
],
details: {
sku: params.sku,
warehouseCode: params.warehouseCode,
status: response.status,
},
};
},
});
}

配置环境变量后启动 Pi:

1
2
3
$env:SCM_API_BASE_URL="https://scm-api.example.internal"
$env:SCM_API_TOKEN="短期只读Token"
pi

首次加载项目级 Extension 时,Pi 会要求确认是否信任项目。执行 /reload 后,可以输入:

1
查询 SKU-10001 在 WH-SZ-01 的库存快照,结合近30天日均销量和7天采购提前期判断是否需要补货。只生成建议,不创建采购单。

这个工具应使用专门的只读服务账号,并在 API 网关限制路径、仓库范围、频率和返回字段。不要为了方便给 Agent 一个可以调用任意内部接口的管理员 Token。

八、使用SDK构建补货建议服务

如果要把 Pi 嵌入 Node.js 服务,使用 SDK 比启动子进程更直接:

1
npm install @earendil-works/pi-coding-agent typebox

下面是一个最小的补货建议 Agent。真实项目应把 queryReplenishmentInputs 替换成经过鉴权的内部 API 客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import {
createAgentSession,
defineTool,
ModelRuntime,
SessionManager,
} from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";

const scmApiBaseUrl = process.env.SCM_API_BASE_URL;
const scmApiToken = process.env.SCM_API_TOKEN;
if (!scmApiBaseUrl || !scmApiToken) {
throw new Error("SCM_API_BASE_URL and SCM_API_TOKEN must be configured");
}

const replenishmentInputs = defineTool({
name: "get_replenishment_inputs",
label: "Get Replenishment Inputs",
description: "读取SKU补货计算所需的库存、销量、在途和提前期数据",
parameters: Type.Object({
sku: Type.String(),
warehouseCode: Type.String(),
}),
async execute(_toolCallId, params, signal) {
const query = new URLSearchParams({
sku: params.sku,
warehouseCode: params.warehouseCode,
});
const response = await fetch(
`${scmApiBaseUrl}/api/v1/replenishment/inputs?${query}`,
{
headers: {
Authorization: `Bearer ${scmApiToken}`,
},
signal,
},
);
if (!response.ok) throw new Error(`SCM API returned ${response.status}`);
const data = await response.json();
return {
content: [{ type: "text", text: JSON.stringify(data) }],
details: { sku: params.sku, warehouseCode: params.warehouseCode },
};
},
});

const modelRuntime = await ModelRuntime.create();
const { session } = await createAgentSession({
modelRuntime,
sessionManager: SessionManager.inMemory(process.cwd()),
tools: ["get_replenishment_inputs"],
customTools: [replenishmentInputs],
});

session.subscribe((event) => {
if (
event.type === "message_update" &&
event.assistantMessageEvent.type === "text_delta"
) {
process.stdout.write(event.assistantMessageEvent.delta);
}
});

await session.prompt(`
分析 SKU-10001 在 WH-SZ-01 的缺货风险。
先调用工具获取事实,再按以下公式给出建议:
补货点 = 提前期日均需求 + 安全库存。
输出事实、计算过程、风险、建议数量和需要人工确认的假设。
禁止创建采购单。
`);

这段代码只开放了一个自定义工具,没有给 Agent bashwriteedit。服务端 Agent 应按场景建立工具白名单,不要照搬编程助手的默认权限。

九、Java系统通过RPC接入Pi

供应链后台通常是 Java 技术栈。此时可以单独部署一个 Pi Agent Sidecar,由 Java 服务通过 RPC 调用:

1
pi --mode rpc --no-session

RPC 使用标准输入和标准输出传输 JSONL,每行一个 JSON 对象。Java 服务发送:

1
{"id":"replenishment-10001","type":"prompt","message":"分析SKU-10001在WH-SZ-01的缺货风险,只输出补货建议"}

Pi 会先返回请求是否被接受,再持续输出 message_updatetool_execution_starttool_execution_endagent_end 等事件。

生产环境建议采用以下结构:

  1. Java 业务服务负责登录态、租户、权限和参数校验。
  2. Node.js Agent 服务或 Pi RPC Sidecar 负责会话和模型编排。
  3. Agent 只能通过受控工具访问订单、库存和采购 API。
  4. 工具层统一做超时、重试、熔断、脱敏和审计。
  5. 采购单创建等写操作进入待审批队列,由业务服务执行。

不要为每个请求临时启动一个 Pi 进程。可以维护固定数量的 Sidecar,按租户和任务隔离会话;如果主系统本身可以部署 Node.js 服务,优先使用 SDK,类型和生命周期管理会更简单。

十、供应链补货Agent的完整技术方案

Pi供应链补货Agent执行流程

一个可上线的补货 Agent 可以分成四层。

1. 入口层

  • Web、企业微信或 ERP 页面接收用户问题。
  • Java 网关校验用户、租户、仓库和数据权限。
  • 把自然语言转换为带 requestId 的 Agent 请求。

2. Agent编排层

  • Pi AgentSession 保存一次分析任务的上下文。
  • 系统提示词限定角色、公式、输出格式和禁止事项。
  • Skill 提供补货分析步骤和业务术语。
  • 模型决定先查询哪些事实,再形成结论。

3. 工具层

至少拆成这些只读工具:

  • get_inventory_snapshot:现存、预占、冻结、可用和在途库存。
  • get_sales_forecast:历史销量、预测量和促销修正。
  • get_supplier_lead_time:供应商交期、最小起订量和包装倍数。
  • get_open_purchase_orders:未关闭采购单和预计到货日期。
  • calculate_replenishment:使用确定性代码计算补货点和建议量。

计算公式应该由确定性工具执行,而不是让模型心算。例如:

1
2
3
4
有效库存位置 = 可用库存 + 在途库存 - 已分配未出库数量
补货点 = 采购提前期内预测需求 + 安全库存
建议补货量 = max(0, 目标库存 - 有效库存位置)
最终采购量 = 按最小起订量和包装倍数向上取整

模型负责解释数据、识别异常和组织建议,确定性程序负责算数、状态校验和写入。

4. 审批与执行层

Agent 的结果先形成 ReplenishmentProposal

1
2
3
4
5
6
7
8
9
{
"requestId": "RP-20260801-0001",
"sku": "SKU-10001",
"warehouseCode": "WH-SZ-01",
"suggestedQty": 240,
"reasonCodes": ["BELOW_REORDER_POINT", "LEAD_TIME_RISK"],
"evidenceVersion": "inventory-88921",
"status": "PENDING_APPROVAL"
}

审批通过后,由采购服务重新读取库存版本、校验建议是否过期,再创建采购申请。不要让模型直接拼接 SQL 写数据库,也不要把“模型已经判断正确”当作越过业务校验的理由。

十一、生产安全与权限控制

Pi 默认没有内置沙箱。bash、Extension 和第三方 Package 都以 Pi 进程的系统权限运行。项目信任机制只能控制是否加载项目资源,不等于运行时安全边界。

生产环境至少落实以下措施:

  1. 进程隔离:在容器、虚拟机或受限系统账号中运行 Agent。
  2. 工具白名单:业务 Agent 不开放任意 bash、文件写入和通用 HTTP 工具。
  3. 最小权限:库存工具只读,且限制租户、仓库、接口和字段。
  4. 人工审批:采购下单、库存调整、价格修改必须经过确认。
  5. 参数校验:服务端重新校验 SKU、数量、状态和数据版本。
  6. 凭证隔离:Token 存在密钥系统或环境变量中,不进入模型上下文。
  7. 防提示词注入:把接口返回的数据当作不可信数据,不执行其中夹带的指令。
  8. 审计留痕:记录用户、模型、会话、工具、脱敏参数、耗时、结果版本和审批人。
  9. 预算控制:限制单次任务轮数、上下文、Token、超时和并发数。
  10. 降级策略:模型或工具不可用时回退到传统规则引擎和人工流程。

第三方 Skill、Extension 和 Pi Package 可能包含可执行代码,安装前必须审查源码并固定版本。

十二、评估Agent是否真的可用

不要用“回答看起来不错”作为上线标准。可以从历史供应链数据中构造一套脱敏测试集:

  • 正常补货 SKU。
  • 促销导致需求突增的 SKU。
  • 有大量在途库存的 SKU。
  • 供应商延迟交付的 SKU。
  • 库存数据缺失或时间戳过期的 SKU。
  • 多仓调拨比采购更合适的 SKU。
  • 最小起订量和包装倍数冲突的 SKU。

关键指标包括:

指标 说明
工具选择准确率 是否调用了正确的事实查询和计算工具
参数准确率 SKU、仓库、租户和时间范围是否正确
事实一致率 输出数字是否与工具结果一致
建议接受率 采购人员接受或小幅调整建议的比例
危险动作率 未审批写入、越权访问等事件,目标必须为0
任务成功率 在超时和重试限制内完成的比例
P95耗时与成本 评估交互体验和规模化成本

每次升级模型、提示词、Skill 或 Extension,都应重放同一批测试集并比较结果。只有回归指标稳定,才能扩大业务范围。

十三、常见问题排查

pi命令不存在

检查 Node.js 版本、全局安装结果和 npm prefix:

1
2
3
node --version
npm list -g @earendil-works/pi-coding-agent
npm config get prefix

登录成功但找不到模型

先执行 pi --list-models,检查提供商凭证和 models.json。自定义无密钥本地服务也需要占位 apiKey,否则模型可能不会出现在可用列表中。

项目Skill或Extension没有加载

确认目录分别是 .pi/skills/.pi/extensions/,确认已经信任当前项目,然后执行 /reload。非交互模式不会显示信任对话框,需要预先保存信任决策,或者在明确理解风险时使用一次性的 --approve

Agent修改范围越来越大

重新开会话,把任务缩小到一个模块;在提示词中列出允许修改的目录;先让 Pi 输出文件清单和计划,再允许编辑。

结果包含正确解释但数字算错

把公式和取整规则实现成确定性工具。模型只能传入参数、调用工具和解释结果,不能作为财务、库存或采购数量的唯一计算器。

十四、推荐的进阶路线

  1. 第一天:完成安装、登录、文件引用、模型切换和会话恢复。
  2. 第二天:为现有 Java 供应链项目编写 AGENTS.md
  3. 第三天:用 Pi 完成一个低风险代码审查和测试补充任务。
  4. 第四天:创建供应链审查 Skill,沉淀团队检查清单。
  5. 第五天:编写一个只读库存查询 Extension。
  6. 第六天:使用 SDK 构建补货建议原型,并建立离线测试集。
  7. 第七天以后:接入审批、审计、监控、限流和容器隔离,再考虑试点上线。

总结

Pi 的价值不在于预置了多少复杂流程,而在于它提供了一套小而清晰的 Agent 基础能力:统一模型接口、Agent 循环、会话、工具、TUI、Skills、Extensions、SDK 和 RPC。初学时可以直接使用 CLI,提高 Java 项目的检索、修改和测试效率;进阶后可以通过 Skill 固化供应链知识,通过 Extension 接入内部只读 API;真正上线时,则应使用 SDK 或 RPC,把 Pi 放在权限、审批和审计体系之内。

供应链 Agent 最可靠的职责是“查询事实、执行确定性计算、解释风险、生成建议”,而不是绕过业务服务直接修改库存和采购数据。把模型的推理能力与传统系统的规则、事务和权限结合起来,才是从能演示走向能生产的关键。

参考资料

Loop Engineering实战:从日志巡检到供应链异常修复闭环

从一次性修复到持续治理

最近在整理 Codex 和 Agent 工作流时,我越来越觉得,AI 编程真正值得关注的地方,已经不只是“怎么写一个更好的提示词”,而是怎么把 AI agent 放进一个持续运转的工程循环里:自动发现问题、定位根因、生成修复、跑测试、部署预发,再由独立验证环节判断是否真的修好。

换句话说,AI 编程的瓶颈,已经不只是“写代码慢不慢”,而是“发现问题、修复问题、验证问题、沉淀经验”这条维护链路是不是还靠人手动推动。

如果人每天都要打开日志平台、复制错误、问 AI、改代码、跑测试、提合并、盯预发,那 AI 只是提高了某个环节的速度。Loop Engineering 要做的,是把整条链路设计成能自己转起来的闭环。

Loop Engineering供应链异常修复闭环

工程循环的五个必要环节

Loop Engineering 的重点不是让 AI “更会写代码”,而是把问题发现、任务隔离、修复执行、独立验证和经验沉淀组织成可重复运行的工程流程。自动化程度必须由风险等级决定,尤其不能默认把生产数据修改和生产发布交给 agent。

我把它总结成四个观点。

第一,维护循环才是真正瓶颈。

AI 已经能很快生成代码,但线上系统的问题不会自动消失。日志分散、错误类型多、排查链路长、测试和部署还要人工推动,才是工程效率真正卡住的地方。

第二,Loop 比一次性 Agent 多了“持续性”。

普通 Harness 是一次会话里给 AI 工具,比如 shell、git、日志查询、测试命令。Loop 在它之上增加了调度、状态、独立验证和跨轮记忆。也就是说,它不是“这次帮我修一下”,而是“每天自己巡检、自己修、自己验,必要时通知人”。

第三,Loop 需要五个动作。

1
2
3
4
5
发现:找出该处理的问题。
交付:把问题隔离给 agent 执行。
验证:让独立检查环节判断结果。
持久化:把结论、失败和修复经验记录下来。
调度:让这套流程定时或按事件反复运行。

第四,Loop 需要六类组件。

1
2
3
4
5
6
Connectors:连接日志、监控、发布、通知等系统。
Automations:定时巡检或事件触发。
Skills:把诊断、修复、发布流程写成 SOP。
Worktrees:隔离不同修复任务,避免互相污染。
Independent verifier:用独立上下文或独立检查程序验证,避免修复者自证。
State:在工单、数据库或版本化文档中记录历史结论、修复方案和巡检状态。

这里还有一个很重要的判断标准:不是所有任务都值得建 Loop。适合建 Loop 的任务,通常要满足四个条件:重复发生、验证能自动化、成本可控、agent 有足够工具。

放到供应链系统里怎么理解

供应链系统非常适合用 Loop Engineering 的思路,因为它的异常不是一次性的。

比如这些问题会反复出现:

1
2
3
4
5
6
7
订单履约超时。
采购到货数量和采购单不一致。
库存预占失败。
出库单状态卡住。
消息消费失败。
供应商回传状态延迟。
报表统计口径和业务事实不一致。

传统做法是:运营或研发发现异常,去查订单、查库存流水、查 MQ、查日志、查数据库,再手动判断是否要修代码或补数据。

Loop Engineering 的做法是把这条链路设计成系统:

1
2
3
4
5
6
7
8
9
每天自动扫描异常订单和错误日志。
按业务类型归类:库存、采购、发货、消息、报表。
让 Codex 读取相关代码、日志和数据样本。
生成根因报告和最小修复方案。
补测试或验证 SQL。
修复一个小切片。
跑测试和回归查询。
通过后提交变更,失败则进入调试循环。
超过重试次数就停止,并把问题交给人。

这样 Codex 不只是“写代码的人”,而是整个维护循环里的执行者。

Codex 供应链案例

假设供应链系统里有一个反复出现的问题:采购到货后,部分订单的库存流水已经写入,但采购到货单状态仍停留在“部分到货”,导致后续财务暂估和供应商履约报表都不准。

这个需求不要直接让 Codex 改代码。先把 loop 定义清楚。

第一步,用普通任务说明定义目标。不同 Codex 版本和使用界面支持的能力并不完全相同,因此不要假设 /goal 是所有环境都可用的通用命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
请把下面内容作为本次持续排查任务的目标:
持续排查并修复供应链系统里的采购到货状态异常问题。

目标:
1. 找出近 7 天库存流水已写入但到货单状态未正确更新的样本;
2. 定位是代码逻辑、消息消费、事务回滚还是历史数据导致;
3. 如果是代码问题,生成最小修复并补充测试;
4. 跑相关测试和验证 SQL;
5. 输出修复报告、风险点和人工验收清单。

停止条件:
- 找到明确根因并完成修复;或
- 连续两轮验证失败;或
- 需要真实数据库权限、生产凭证、业务口径确认。

第二步,让 Codex 先做发现。

1
2
3
4
5
6
7
8
9
10
11
请先不要改代码。
请读取项目规则、采购到货模块、库存流水模块、消息消费模块和相关测试。

同时整理需要验证的数据条件:
1. purchase_receipt 状态不是 COMPLETED;
2. stock_ledger 已存在对应 receipt_id;
3. receipt_item 的 received_qty 已等于 planned_qty;
4. 最近 7 天内出现;
5. 排除人工关闭或取消的单据。

输出异常样本查询 SQL、可能原因列表和下一步排查计划。

第三步,把诊断流程沉淀成 skill 思路。

1
2
3
4
5
6
请按 supply-chain-receipt-diagnosis skill 的方式执行:
1. 先确认业务状态机;
2. 再查库存流水和到货明细;
3. 再查消息消费日志;
4. 再看最近相关 git diff;
5. 最后输出事实、推理、结论,不要跳步。

如果还没有这个 skill,可以先把它当成提示词使用。等这类问题出现三次以上,就值得写成真正的 SKILL.md

第四步,让 Codex 生成修复计划。

1
2
3
4
5
6
7
8
请基于上面的诊断结果,生成修复计划,不要直接改代码。

计划必须包含:
1. 要修改的 Service、Mapper、消息消费者或定时补偿任务;
2. 要新增的单元测试和集成测试;
3. 是否需要补偿历史数据;
4. 事务边界和幂等风险;
5. 回滚方案。

第五步,小步实现。

1
2
3
4
5
6
7
8
9
现在只实现第一步:补充一个失败测试。

测试场景:
库存流水写入成功,到货明细数量已满足完成条件,但到货单状态仍未更新。

要求:
- 先让测试失败;
- 不修改业务实现;
- 完成后展示测试名称和失败原因。

第六步,再让 Codex 做最小修复。

1
2
3
4
5
6
7
8
现在根据失败测试做最小修复。

要求:
- 不改接口协议;
- 不重构无关代码;
- 保持现有事务模型;
- 如果涉及消息重复消费,必须加幂等判断;
- 修复后运行相关测试。

第七步,独立验证。

1
2
3
4
5
6
7
8
请用 code review 的方式审查当前 diff。

重点检查:
1. 是否只是修复采购到货状态异常;
2. 是否会影响少到、多到、不合格品逻辑;
3. 是否有重复消费导致状态反复更新的问题;
4. 库存流水和到货状态是否在同一事务或有补偿机制;
5. 测试是否覆盖重复消息和事务失败。

第八步,持久化经验。

1
2
3
4
5
6
7
8
请把这次问题总结成一条可复用的排查规则:
- 触发条件;
- 相关表;
- 相关日志;
- 常见根因;
- 验证 SQL;
- 修复注意事项;
- 下次自动巡检建议。

这一步形成可审计的状态记录。记录应放在团队可维护的工单、runbook 或版本库中,不能只依赖某次对话的上下文。

完整闭环与质量门禁

对供应链系统来说,一个可落地的 Codex Loop 可以这样走:

1
2
3
4
5
6
7
8
9
10
11
定时巡检
-> 查询异常订单/到货单/库存流水
-> Codex 读取代码和日志
-> 生成根因报告
-> 写失败测试
-> 最小修复
-> 跑测试和验证 SQL
-> 独立 review
-> 预发验证
-> 人工确认生产发布
-> 记录经验和新规则

关键不是追求“全自动发布生产”,而是按风险设置质量门禁。涉及库存数量、金额、权限和生产数据修复时,应要求人工审批、双人复核、审计记录和可执行的回滚方案。

落地限制与治理措施

第一个限制,是验证器不够强。

如果只有单元测试,AI 可能把错误隐藏掉,比如把错误日志降级,或者只处理 happy path。解决办法是至少三层验证:单元测试、业务 SQL 校验、预发环境回归。

第二个限制,是成本容易失控。

每天全量扫日志、读代码、跑大模型诊断,很容易消耗大量 token。解决办法是分级:先用简单规则和小模型筛选高风险问题,再把少量问题交给 Codex 深度处理。

第三个限制,是工具链建设成本高。

Loop 不是只写提示词,它需要日志查询、测试命令、发布脚本、通知通道、状态记录。解决办法是先选一个窄场景,比如“采购到货状态异常”,不要一上来覆盖整个供应链。

第四个限制,是自动修复可能误伤。

供应链系统里状态机、库存、财务、报表互相影响,自动修复不能绕过人。解决办法是设置硬停止条件:涉及金额、库存数量、生产数据修复、权限变更时,必须人工审批。

第五个限制,是经验没有沉淀。

如果每次排查都停留在一次对话里,下一次还是从零开始。解决办法是把常见问题写入 skill、runbook、异常规则库或巡检配置,让 loop 越跑越聪明。

总结

Loop Engineering 最值得借鉴的地方,是它把 AI 编程从一次性任务推进到生产闭环。它不是让 AI 一次性写更多代码,而是设计一套能持续发现问题、修复问题、验证问题、沉淀经验的系统。

放到供应链系统里,我认为最适合先做的不是“让 Codex 自动开发大需求”,而是“让 Codex 自动巡检和修复高频异常”。比如采购到货状态异常、库存流水不一致、消息消费失败、订单履约超时。

真正稳的 AI 工程化,不是把人完全拿掉,而是让人从手动推动循环,变成设计循环、审查风险和批准关键节点。

参考资料

CC Switch管理Codex多套配置:认证、供应商与本地路由

为什么需要配置管理

最近使用 Codex 做代码任务时,我越来越明显地感觉到,AI 编程工具本身已经不是唯一问题,真正容易乱的是账号、模型、API、MCP 和本地配置。

比如一台电脑上可能同时有个人 ChatGPT 账号、公司授权账号、测试账号;有时候想用官方 Codex 登录状态,有时候又想切到第三方 OpenAI 兼容 API;再加上 ~/.codex/auth.json~/.codex/config.toml、MCP 配置和项目里的 AGENTS.md,时间一长就很容易不知道当前 Codex 到底在用哪个账号、哪个模型、哪个接口。

cc-switch 要解决的就是这个问题。它不是模型,也不是 Codex 的替代品,而是一个 AI 编程工具的配置管理面板。我的理解是:Codex 负责干活,cc-switch 负责把账号、供应商、模型和路由管理清楚。

cc-switch管理多个GPT账号给Codex使用

适用场景与合规边界

先说结论:cc-switch 适合管理多套 AI 编程配置,但不要把它理解成“无限切账号绕过限制”的工具。

我觉得它最适合三类场景。

第一类,是个人账号和公司账号分开。比如个人项目用自己的 ChatGPT / Codex 账号,公司项目用公司授权账号,避免上下文、账单和权限混在一起。

第二类,是官方登录和第三方 API 分开。Codex App 或 Codex CLI 可能需要官方登录状态,但实际模型请求可以根据任务切到不同 provider,比如 OpenAI 官方、OpenAI 兼容网关、团队内部代理或其他模型服务。

第三类,是不同任务使用不同模型。轻量任务用便宜模型,复杂重构用更强模型,长上下文分析用支持更大上下文的 provider。

这里要注意一个边界:多个账号必须是你自己合法拥有或团队授权使用的账号,不要把多账号当成规避平台限额的手段。auth.json、API Key、refresh token 都属于敏感凭证,不要截图、不要提交到 Git、不要发给别人。

先理解 Codex 的两个关键配置

Codex 本地一般会涉及两个重要文件:

1
2
~/.codex/auth.json
~/.codex/config.toml

auth.json 更像登录态,保存官方 ChatGPT / Codex OAuth 登录缓存。它很敏感,不应该手工复制、上传或分享。

config.toml 是 Codex 的运行配置文件,可包含模型、模型供应商、接口地址和相关选项。认证信息如何保存取决于登录方式、Codex 版本以及 CC Switch 的配置模式,不应把某一种文件布局当成长期稳定的公开接口。

CC Switch 在管理 Codex 时,主要价值是减少手工修改配置文件的次数。尤其是在切换不同 provider 时,它会按当前版本支持的方式更新 Codex 配置。操作前仍应备份配置,并在升级后核对 CC Switch 的发布说明。

如果你不了解这两个文件,就很容易出现一个错觉:Codex 界面显示的是 A 账号,所以请求一定走 A 账号。实际不一定。官方登录状态、模型请求路由、账单来源可能是三件事,需要分别确认。

安装与变更前准备

Windows 上可以直接去 GitHub Releases 下载 .msi 安装包,或者使用 portable zip。

macOS 可以使用 Homebrew:

1
2
brew tap farion1231/ccswitch
brew install --cask cc-switch

Linux 可以下载 .deb 或 AppImage。服务器上如果没有桌面环境,也可以使用 Web 版本,默认端口是 17666

安装后,先不要急着添加一堆账号。建议先做三件事:

1
2
3
1. 确认 Codex CLI 或 Codex App 可以正常启动;
2. 确认 cc-switch 能看到 Codex 这个应用入口;
3. 备份当前 ~/.codex 目录,避免误操作后不好恢复。

备份可以这样做:

1
cp -r ~/.codex ~/.codex.backup.$(date +%Y%m%d)

Windows PowerShell 可以用:

1
Copy-Item "$env:USERPROFILE\.codex" "$env:USERPROFILE\.codex.backup.20260705" -Recurse

方式一:保留官方登录并切换Provider

这是需要同时保留官方登录能力和第三方 provider 时的一种用法。官方认证保留在当前 CC Switch 版本中是可选设置,默认值和写入方式可能随版本变化,应以当前发布说明为准。

第一步,在 cc-switch 的 Codex 面板里选择 OpenAI Official。如果没有,就从 preset 里添加一个。

第二步,启动 Codex,完成一次官方 ChatGPT / Codex 登录。登录后,Codex 会把登录缓存写到 ~/.codex/auth.json

第三步,回到 cc-switch,打开:

1
Settings -> General -> Codex App Enhancements

打开类似这样的选项:

1
Keep official login when switching third-party providers

这个开关的意思是:切换第三方 provider 时,尽量保留官方登录缓存,不要反复覆盖 auth.json。这样 Codex 仍然能识别官方账号,而模型请求可以走当前选中的 provider。

第四步,在 Codex 面板里新增 provider。比如你可以添加一个 OpenAI 兼容 API、团队代理网关,或者其他支持 Responses API / Chat Completions 的模型服务。

第五步,切换 provider 后重启 Codex。这个动作很重要,因为 Codex 通常在启动时读取 config.toml 和模型列表。你切换 provider 后不重启,可能还在用旧配置。

验证时不要只看 Codex 显示的账号。应该同时看三处:

1
2
3
1. cc-switch 当前启用的 Codex provider;
2. cc-switch routing / request log 是否有请求;
3. provider 后台余额或调用记录是否发生变化。

如果 Codex 仍显示官方账号,但 provider 后台出现调用记录,这是正常的:官方账号负责登录态,实际模型请求走当前 provider。

方式二:通过OAuth Auth Center隔离授权账号

CC Switch 的 OAuth Auth Center 可以管理多个经过本人或组织授权的 ChatGPT / Codex OAuth 账号。该能力仍带有版本和合规风险,适合做身份、权限和账单隔离,不应被用于共享凭证或规避平台限制。

需要区分两件事:在 Codex 中切换本人获授权的登录身份,与把 Codex OAuth 服务反向代理给其他工具并不是同一种操作。后者可能受到 OpenAI 与上游服务条款限制。启用任何 OAuth reverse proxy 或第三方转发功能前,应阅读当前版本的风险提示和相关服务条款;公司环境还需要经过安全与合规审批。

大致步骤是:

1
2
3
4
5
6
7
8
1. 打开 Settings -> OAuth Auth Center;
2. 在 ChatGPT / Codex OAuth 区域点击登录;
3. 按提示复制设备验证码;
4. 打开授权地址并登录第一个 ChatGPT 账号;
5. 授权成功后,账号会出现在 Logged-in Accounts;
6. 点击 Add Another Account,再登录第二个账号;
7. 每个 provider 选择对应账号保存;
8. 通过 provider 卡片或托盘菜单切换。

这里要特别小心:不要导出 token,也不要手工复制 refresh token。一个更好的习惯是只让 cc-switch 自己维护 OAuth 状态。账号过期就重新登录,不要把凭证文件拿来传来传去。

如果是多人共用一台开发机,更建议每个人使用自己的系统用户,或者至少明确命名 provider:

1
2
3
codex-personal-gpt
codex-company-gpt
codex-test-gpt

名字要能看出用途,不要只叫 account1account2。半年后再看,自己也会忘。

方式三:协议不兼容时使用Local Routing

部分第三方 provider 只提供 Chat Completions 兼容协议,而 Codex 使用的工具调用和流式事件更接近 Responses API。直接修改接口地址可能出现模型目录、流式响应或工具调用不兼容,此时可评估使用 CC Switch Local Routing 做协议转换。

不同版本的菜单名称可能变化,当前版本可从 Routing 相关设置进入:

1
Settings -> Routing -> Local Routing

打开主开关后,默认本地服务一般是:

1
127.0.0.1:15721

然后只勾选 Codex 的 routing takeover。这样 Codex 请求会先到本地 cc-switch 路由,再由 cc-switch 转发给真正的 provider。

这个模式有两个好处。

第一,真实 API Key 不一定直接暴露在 Codex 当前配置里,可以由 cc-switch 的 provider 配置管理。

第二,可以处理协议不完全一致的问题,比如把 Codex 的请求转换成上游 provider 能接受的格式。

但本地路由也会多一层故障点。如果 Codex 返回 404、模型不存在、流式响应异常,要优先检查:

1
2
3
4
5
1. provider 是否需要 Local Routing;
2. Local Routing 主开关是否启动;
3. Codex routing takeover 是否打开;
4. model mapping 是否写对;
5. Codex 是否已经重启。

本地路由位于代码、提示词和模型服务之间,也扩大了敏感数据的处理边界。使用前应确认日志是否记录请求正文、凭证如何存储、上游是否保留数据,以及团队代码是否允许发送给该 provider。

日常使用与审计流程

我会把日常流程固定成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
开始任务前:
1. 打开 cc-switch;
2. 确认当前 Codex provider;
3. 确认账号用途:个人、公司还是测试;
4. 确认模型和路由状态;
5. 再启动 Codex。

任务执行中:
1. 不在对话里粘贴 API Key;
2. 不让 Codex 输出 auth.json;
3. 大任务先让 Codex 计划,再执行;
4. 涉及敏感代码或生产数据时缩小上下文。

任务结束后:
1. 看 provider 调用记录;
2. 看本地 git diff;
3. 如果切过账号,回到默认 provider;
4. 必要时清理临时日志和敏感文件。

这个流程看上去啰嗦,但能避免很多麻烦。AI 工具越自动化,越需要把“当前是谁在用、用哪个模型、请求去哪儿了”这件事弄清楚。

常见故障与安全风险

第一个坑,是把多账号当成额度池。这个风险很高,也不稳定。账号切换应该服务于权限隔离、账单隔离和项目隔离,而不是绕限制。

第二个坑,是手动复制 auth.json。这个文件里可能包含敏感登录缓存,复制来复制去很容易泄露,也容易因为凭证轮换导致失效。

第三个坑,是切换 provider 后不重启 Codex。很多配置是在启动时加载的,特别是模型列表和 config.toml

第四个坑,是只看 Codex 界面上的账号显示。实际请求走哪里,要看 cc-switch 当前 provider、routing log 和 provider 侧账单记录。

第五个坑,是 provider 名字乱。建议用用途命名,比如 personal-openai-officialcompany-openai-gatewaytest-codex-oauth

总结

cc-switch 对 Codex 最大的价值,不是“多一个工具”,而是让账号、模型、路由和配置变得可控。

如果只是偶尔用 Codex,一个官方登录就够了。但如果你同时维护个人项目、公司项目、测试环境,还要在官方账号和不同 provider 之间切换,那么 cc-switch 可以明显降低配置混乱。

我的建议是:先从一个官方账号加一个 provider 开始,跑通登录、切换、重启、验证这条链路;等流程稳定后,再添加第二个 GPT 账号。不要一开始就把所有账号和模型都塞进去,越复杂越容易排查困难。

真正好用的 AI 编程环境,不是账号越多越好,而是每一次启动 Codex 前,都清楚当前账号是谁、请求会去哪、出了问题该看哪里。

参考资料

CodeGraph与Ponytail组合实战:让Agent找得准、改得少

CodeGraph 和 Ponytail 经常一起出现在 Agent 工具列表中,但两者不是同一类插件:CodeGraph 解决“代码在哪里、如何调用、改动影响哪里”,Ponytail 解决“理解之后,最少需要构建什么”。单独使用任何一个都不完整。

只使用 CodeGraph,Agent 可能准确找到十个相关文件,却顺手设计新的接口、工厂和扩展框架;只使用 Ponytail,Agent 可能写出一个很小的补丁,却因为没有发现另一个调用入口而遗漏真实根因。组合后的正确顺序是先扩大理解范围,再缩小实现范围。

本文从 Codex 的安装配置开始,设计一套适用于 Java 供应链项目的完整工作流,并以“部分出库订单取消后正确释放剩余预占库存”为例,演示结构查询、影响分析、最小方案、实现、索引同步、双重审查和测试选择。

CodeGraph与Ponytail供应链Agent闭环

一、先明确两个工具的职责

工具 输入 输出 不负责什么
CodeGraph 本地项目源码和结构查询 相关源码、调用路径、符号关系、影响范围 不决定需求是否合理,不证明代码正确
Ponytail 已理解的需求、代码和工程约束 最小正确实现策略、过度设计审查 不自动建立完整代码图,不替代安全审查

组合后的职责链:

1
2
3
4
5
6
7
CodeGraph:找到真实业务流和共享边界
-> 人与Agent:确认业务不变量和需求范围
-> Ponytail:选择最高层可复用方案
-> Codex:实施最小改动
-> CodeGraph:重新检查影响和测试范围
-> Ponytail Review:删除人为增加的复杂度
-> 普通Review和测试:验证正确性、安全与数据一致性

这里最重要的是顺序。Ponytail 官方规则也要求先读懂问题并追踪真实流程,不能为了追求小 diff 而跳过理解。CodeGraph 正好为这一步提供预构建的项目关系上下文。

二、组合方案的技术架构

一套推荐的开发机架构包括:

1
2
3
4
5
6
7
8
Codex CLI或桌面版
├─ CodeGraph MCP
│ └─ .codegraph/codegraph.db(本地SQLite索引)
├─ Ponytail插件
│ ├─ Session/Prompt/Subagent生命周期Hook
│ └─ ponytail、review、audit、debt等Skills
├─ Git工作区
└─ Maven/Gradle、JUnit、Testcontainers和数据库迁移工具

CodeGraph 的索引数据库留在项目 .codegraph/ 中,其内部 .gitignore 会忽略生成的索引文件;不要把 SQLite、锁和日志提交到仓库。可以提交的是项目级 codegraph.json,因为它定义了团队共同的 include、exclude 和扩展名映射。

Ponytail 的模式通常是个人会话状态,项目不应依赖某位开发者恰好启用了 full。真正不可违反的供应链规则必须写入版本控制内的 AGENTS.md,并由测试和数据库约束执行。

三、一次完成安装与验证

1. 安装CodeGraph

已有 Node.js 时:

1
2
3
npm install -g @colbymchenry/codegraph
codegraph version
codegraph install --target=codex --location=global --yes

为供应链项目初始化索引:

1
2
3
cd D:\projects\supply-chain-platform
codegraph init
codegraph status

2. 安装Ponytail

1
2
codex plugin marketplace add DietrichGebert/ponytail
codex plugin add ponytail@ponytail

启动 Codex,进入 /hooks,审阅并信任 Ponytail 的生命周期 Hook。然后重启 Codex 或桌面应用并新建任务。

3. 验证两个插件

在终端先验证图查询:

1
codegraph explore "库存预占的创建、发货扣减和取消释放如何连接"

在 Codex 中验证 Ponytail:

1
2
@ponytail-help
@ponytail full

再执行组合探针:

1
2
使用 CodeGraph 找到库存释放的全部调用者,并按 Ponytail full 判断项目中是否已有可复用的幂等处理。
只输出分析结果,不修改代码。

如果 Agent 没有调用 codegraph_explore,检查项目是否有有效 .codegraph/ 索引以及 Codex 是否在安装 CodeGraph 后重启。如果 Ponytail 没有报告当前模式,检查插件、Node.js 和 Hook 信任状态。

四、统一项目规则

供应链项目根目录的 AGENTS.md 可以加入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# AI Development Workflow

## Understand Before Editing
- 回答代码结构、业务流和影响范围问题时,优先使用CodeGraph。
- 修改公共方法、DTO、事件或Mapper前,检查调用者和影响范围。
- 图中缺失的消息Topic、反射、动态SQL和外部系统关系必须读取配置或测试确认。
- CodeGraph提示索引待同步时,读取最新文件或执行状态检查。

## Minimal Implementation
- 理解完整流程后执行Ponytail决策阶梯。
- 优先复用项目现有领域服务、事务模板、幂等组件和测试工具。
- 禁止没有真实第二个实现的接口、工厂和策略注册中心。
- 禁止为推测需求增加配置、表字段、消息Topic和新依赖。
- 每次只修改完成当前业务闭环所必需的文件。

## Supply Chain Invariants
- 可释放量 = 预占量 - 已出库量 - 已释放量,结果不得小于0。
- 同一消费方和事件ID只能产生一次业务副作用。
- 库存余额、库存流水、幂等记录和Outbox必须遵守已定义的事务边界。
- 租户、仓库、SKU、批次和货主数据权限不可删除。
- 金额和数量口径必须保持精度、单位与舍入规则。

## Verification
- Ponytail Review不能替代正确性、安全和性能Review。
- 核心库存改动至少验证部分出库、重复事件、并发和事务回滚。
- CodeGraph affected只用于选择附加测试,固定核心回归集始终运行。

如果 CodeGraph 安装器已经写入带标记的说明区块,不要在整理 AGENTS.md 时删除标记。团队规则放在单独标题下,避免升级或卸载时与工具管理的区块混在一起。

五、完整案例与需求边界

业务问题:订单预占 10 件商品,仓库已出库 4 件。此时用户取消剩余部分,系统应释放 6 件预占库存。由于消息系统至少一次投递,相同取消事件可能重复到达,但只能产生一次释放流水。

已知约束:

  • 已出库 4 件不能回到可售库存。
  • 释放量不能超过剩余预占量。
  • 重复事件不能产生第二条流水。
  • 库存余额、流水和幂等记录必须原子提交。
  • 正常整单取消、支付超时和人工取消仍要保持兼容。
  • 本次不建设通用库存策略平台。

这个需求很适合组合使用两个工具:CodeGraph 需要先找出全部入口和共享计算位置,Ponytail 再阻止 Agent 为一个公式差异创建一套策略体系。

六、阶段1:建立干净基线

开始任务前执行:

1
2
3
git status --short
codegraph status
mvn -pl inventory-service -am test

目的分别是:

  1. 确认不会覆盖用户已有改动。
  2. 确认图索引可用且没有待同步文件。
  3. 确认目标模块在改动前是绿的。

如果工作区已有无关修改,记录并避开;不要为了让 Agent 获得“干净环境”而重置他人的工作。

七、阶段2:让CodeGraph追踪真实业务流

第一条提示只做结构分析:

1
2
3
4
5
6
7
8
9
10
11
12
使用 CodeGraph 分析“订单取消后释放库存”的完整调用链,只分析,不修改代码。

请返回:
1. Kafka或应用入口;
2. 订单ID、事件ID、SKU和数量如何传递;
3. 可释放数量在哪个方法计算;
4. 库存余额、预占记录、库存流水和幂等记录分别在哪里写入;
5. 本地事务边界;
6. 正常取消、支付超时、人工取消和售后入口;
7. 现有单元测试和集成测试。

对配置、反射、动态SQL或跨服务关系明确标注“图外待确认”。

查询应尽量包含真实业务动作,而不是只问“库存模块怎么工作”。拿到候选符号后,继续收窄:

1
2
使用 CodeGraph 详细分析 InventoryReservation.releasableQty 及全部调用者。
返回该方法源码、调用路径和修改它的影响范围。

也可以人工运行:

1
2
codegraph callers InventoryReservation.releasableQty
codegraph impact InventoryReservation.releasableQty --depth 4

假设结果显示:

1
2
3
4
5
6
7
OrderCancelledConsumer
PaymentTimeoutConsumer
ManualOrderCloseService
-> InventoryReleaseApplicationService.release
-> InventoryReservation.releasableQty
-> InventoryReservationRepository.save
-> InventoryLedgerRepository.append

这说明修复应围绕共享领域方法评估,而不是只修改最初报错的 OrderCancelledConsumer

八、阶段3:补齐图外事实

CodeGraph 是静态代码图,异步 Topic、MyBatis 动态 SQL 和 Spring 运行时代理可能需要额外确认。让 Agent 读取:

1
2
3
4
5
6
7
8
基于CodeGraph结果,再读取以下图外证据:
- OrderCancelled Topic与Consumer Group配置;
- InventoryReservationMapper.xml中的条件更新SQL;
- 事务注解和传播级别;
- processed_event唯一索引迁移;
- 重复投递集成测试。

将“源码图确认”“配置确认”“仍是推测”分成三组输出。

供应链系统的关键关系经常由字符串连接:例如生产者发送 order.cancelled.v2,消费者监听 ${topic.order-cancelled}。图中没有直接调用边,不代表业务链不存在。

完成后整理一张事实表:

事实 证据 状态
所有取消入口最终调用同一 release 方法 CodeGraph调用路径 已确认
可释放量未扣除 shippedQty 领域方法源码 已确认
幂等记录与库存写入同一事务 事务代码和集成测试 已确认
外部WMS可能晚到回传 接口文档,当前仓库无实现 待业务确认

只有已确认事实才能作为实现依据;未确认项要么继续取证,要么明确排除在本次需求之外。

九、阶段4:运行Ponytail决策阶梯

现在才进入最小方案阶段:

1
2
3
4
5
6
7
8
9
10
11
12
@ponytail full

基于刚才确认的调用链和事实表,给出最小正确方案。
逐项回答:
1. 是否需要新增能力;
2. 项目里已有哪个共享边界可以修复;
3. 是否已有幂等组件和条件更新模式;
4. 是否需要新接口、工厂、策略、配置、表或依赖;
5. 最少修改哪些文件;
6. 必须新增哪些测试。

不要编码,先输出方案和被拒绝的过度设计选项。

合理的决策记录可能是:

1
2
3
4
5
6
需求需要实现:部分出库取消是现有业务分支。
项目已有共享边界:InventoryReservation.releasableQty。
项目已有幂等组件:ProcessedEventExecutor,无需新建Redis锁。
数据库已有version条件更新,无需新锁框架。
最小改动:修正一个领域公式,补充两个测试;必要时调整已有SQL条件。
跳过:ReleaseStrategy接口、CancelTypeFactory、新配置项、新依赖和新表。

Ponytail 不应该为了“少改文件”拒绝必要的数据库约束或集成测试。如果调查发现现有 SQL 没有原子条件,新增迁移或 Repository 修改就是当前需求的真实复杂度,不能省略。

十、阶段5:实施最小正确修改

假设现有领域方法错误地写成:

1
2
3
public int releasableQty() {
return reservedQty - releasedQty;
}

最小根因修复是:

1
2
3
public int releasableQty() {
return Math.max(0, reservedQty - shippedQty - releasedQty);
}

但单看这一行还不能提交。必须检查数量类型、状态约束和并发更新方式。如果数量允许小数,应该使用项目现有的 BigDecimal 或数量值对象,而不是照抄 int 示例。

Repository 的条件更新可以保持原子约束:

1
2
3
4
5
6
7
UPDATE inventory_reservation
SET released_qty = released_qty + #{releaseQty},
version = version + 1,
updated_at = CURRENT_TIMESTAMP
WHERE id = #{id}
AND version = #{version}
AND reserved_qty - shipped_qty - released_qty >= #{releaseQty}

应用服务校验更新行数:

1
2
3
4
5
6
7
8
int updated = reservationRepository.release(
reservation.id(),
releaseQty,
reservation.version()
);
if (updated != 1) {
throw new ConcurrentInventoryChangeException(reservation.id());
}

如果这些 SQL 和异常处理已经存在,本次只需要改公式和测试,不能为了文章示例重复创建。Agent 的实现提示应明确:

1
2
3
4
按确认方案实施,只修改共享可释放量计算和对应测试。
复用现有幂等执行器、Repository条件更新和异常类型。
不要创建新接口、工厂、配置、新表或新依赖。
完成后展示diff并运行inventory-service测试。

十一、阶段6:同步图并复查影响

保存文件后,CodeGraph 会监听变化并增量同步。先检查:

1
codegraph status

如果运行环境禁用了自动同步,执行:

1
codegraph sync

然后要求 Agent 基于最新图复查:

1
2
使用 CodeGraph 基于最新索引重新分析 InventoryReservation.releasableQty。
确认所有调用者仍走共享实现,列出本次改动的影响范围和可能遗漏的测试。

这里不是机械地重复第一次查询。第一次是决定改哪里,第二次是确认实际 diff 是否符合计划,以及是否因改名、移动或新增调用产生了新的影响。

十二、阶段7:先做Ponytail Review

1
@ponytail-review

可以增加供应链上下文:

1
2
3
@ponytail-review
审查当前diff中的过度设计,只列出可删除或复用项。
不要把并发条件、事务、幂等、库存流水、权限和必要测试当作冗余。

预期它会发现类似问题:

1
2
InventoryReleaseStrategy.java: yagni: 只有一个实现,直接保留现有领域方法。
CancelInventoryProperties.java: delete: 没有任何环境修改该开关,本需求不需要配置。

如果当前 diff 已经只有公式和测试,正确结果可以是 Lean already. Ship.。这只表示没有明显过度设计,不表示正确性已经验证。

十三、阶段8:再做普通正确性审查

执行独立提示:

1
2
3
4
5
6
7
8
9
10
11
按正常代码审查标准检查当前diff。
优先查找:
1. 部分出库数量计算错误;
2. 重复消息与幂等事务边界;
3. 并发更新丢失;
4. 释放量为负或超过剩余预占;
5. 租户、仓库和货主越权;
6. 库存余额与流水不一致;
7. 测试缺口。

使用CodeGraph确认问题涉及的调用者,但以实际源码、SQL和测试为证据。

Ponytail Review 明确不负责正确性、安全和性能。这两轮 Review 不能合并成一句“帮我审查一下”,否则 Agent 可能只选择其中一个视角。

十四、阶段9:选择并运行测试

先运行固定目标测试:

1
2
mvn -pl inventory-service -Dtest=InventoryReservationTest test
mvn -pl inventory-service -Dtest=OrderCancellationInventoryIT test

核心用例至少包括:

1
2
3
4
5
6
预占10,出库0,释放10
预占10,出库4,释放6
预占10,出库10,释放0
同一事件重复两次,只产生一条释放流水
两个线程并发释放,最终释放量不超过可释放量
库存写入异常,幂等记录和流水全部回滚

再用 CodeGraph 查找附加回归测试:

1
2
git diff --name-only origin/master...HEAD |
codegraph affected --stdin --filter "**/*Test.java" --quiet

根据输出运行关联模块:

1
mvn -pl inventory-service,order-service -am test

affected 只能根据代码依赖提供候选测试。消息 Topic、外部 WMS 和数据库触发器可能不在静态依赖图中,因此固定的库存核心回归集不能被它替换。

十五、可复用的组合提示模板

1. 缺陷定位

1
2
3
4
5
使用 CodeGraph 追踪【现象】涉及的完整调用链和全部调用者。
将代码图证据、配置证据和推测分开。
确认根因位置后,使用 Ponytail full 设计最小正确修复。
复用项目现有模式,不新增推测性抽象。
实施后同步索引、复查影响、运行Ponytail Review、普通Review和相关测试。

2. 新增功能

1
2
3
4
需求:【业务需求】。
先用 CodeGraph 找出相似功能、公共入口、持久化边界和测试模式。
再按 Ponytail 阶梯判断能否复用项目、标准库、平台或现有依赖。
先给计划,不编码。计划必须列出业务不变量、最小文件清单、明确不做的内容和验证命令。

3. 安全重构

1
2
3
4
使用 CodeGraph 分析【符号】的调用者、被调用者和影响范围。
目标是减少重复,不改变外部行为。
使用 Ponytail full 选择删除或内联方案,禁止顺便引入新框架。
重构前后运行同一测试集,并比较公共API和数据库行为。

4. PR审查

1
2
3
4
先用 CodeGraph 根据diff检查公共符号影响和遗漏调用者。
再运行 Ponytail Review 寻找过度设计。
最后独立检查正确性、安全、并发、事务、幂等和测试缺口。
按严重程度输出发现,每条给文件和行号。

十六、在CI中使用CodeGraph,Ponytail留在开发环节

CodeGraph 的 CLI 适合在 CI 中辅助选择测试,但每次 CI 是否重建索引要考虑缓存、平台和执行时间。一个简单流程是:

1
2
3
4
5
6
检出代码
-> 恢复与当前OS匹配的CodeGraph缓存
-> codegraph status或init
-> codegraph sync
-> codegraph affected选择附加测试
-> 运行固定核心测试 + 附加测试

示意 PowerShell:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ErrorActionPreference = "Stop"

if (-not (Test-Path ".codegraph\codegraph.db")) {
codegraph init
} else {
codegraph sync
}

$changed = git diff --name-only "$env:BASE_SHA...$env:GITHUB_SHA"
$tests = $changed | codegraph affected --stdin --filter "**/*Test.java" --quiet
$tests | Set-Content affected-tests.txt

mvn -pl inventory-service -am test

不要在 Windows 与 Linux Runner 间复用同一 SQLite 索引缓存。索引及锁与操作系统相关,缓存键至少包含 OS、CodeGraph 版本和源码提交。

Ponytail 更适合开发和审查阶段,因为它通过 Agent 指令影响实现选择。CI 不应该靠 Ponytail 判断是否可以发布;CI 应使用可重复的编译、测试、静态检查、数据库迁移验证和安全扫描。

十七、组合使用的反模式

1. 让Ponytail先决定只改一个文件

还没查调用链就限定一个文件,可能把正确方案排除。应该先用 CodeGraph 扩大认知,再用 Ponytail 缩小实际改动。

2. CodeGraph返回十个文件就全部修改

相关文件不等于必须修改的文件。图结果用于理解和影响评估,Ponytail 决策阶梯用于判断哪些文件真正需要变化。

3. 把图中没有边当作没有业务关系

消息 Topic、反射、动态 SQL 和外部系统调用可能在图外。必须结合配置、日志和测试。

4. 用最少行数代替最小风险

删除唯一键、事务、幂等和测试会减少行数,但增加数据风险。最小正确实现以行为和风险为边界,不以 LOC 排名。

5. 只做Ponytail Review

它只检查过度设计,不检查正确性、安全和性能。必须再做普通 Review。

6. 每次查询都问整个系统

CodeGraph 的 explore 会返回密集源码上下文。长会话中反复询问大范围架构会占据上下文。应该以一个业务流或一个核心符号为单位查询,需求方向改变时开新任务。

7. 自动执行所有建议

CodeGraph 和 Ponytail 都是辅助工具。删除公共接口、修改库存 SQL、调整事务传播和执行数据库迁移必须经过人工业务与工程审查。

十八、安全与隐私

组合使用时要检查两种扩展权限:

  • CodeGraph MCP 能读取项目索引和返回源码片段。
  • Ponytail Hook 能在会话生命周期中注入规则。

安全建议:

  1. 只从官方仓库安装,安装前审阅脚本、插件清单和 Hook。
  2. 固定并分批升级版本,不在核心仓库自动追随未知更新。
  3. CodeGraph 索引本地运行,但返回给云模型的源码仍受模型数据策略约束。
  4. 不索引密钥、生产数据导出、客户隐私和供应商银行信息。
  5. Agent 默认不连接生产数据库,不执行写操作和消息重放。
  6. 需要时运行 codegraph telemetry off,并核对组织遥测政策。
  7. Ponytail 不能覆盖权限、审计和安全规则。

十九、常见冲突与排查

CodeGraph已安装,但Agent仍使用普通搜索

检查:

1
2
codegraph status
codegraph install --print-config codex

重启 Codex,并确认项目中存在有效索引。提示里明确要求“使用 CodeGraph”,以验证接入是否正常。

Ponytail让Agent过早缩小范围

把任务拆成两个阶段:第一阶段只允许 CodeGraph 分析,第二阶段才启用 @ponytail full 设计实现。也可以临时使用 lite

CodeGraph结果与最新源码不一致

1
2
codegraph status
codegraph sync

如果工具返回待同步提示,直接读取该文件最新内容,不要引用旧片段继续修改。

Ponytail报告接口多余,但它是外部系统边界

保留接口,并在 AGENTS.md 或架构决策记录中写明边界目的。单实现数量不是唯一判断标准,WMS、ERP 和承运商 Adapter 可能需要稳定隔离外部契约。

子Agent没有遵守工具规则

CodeGraph 安装器会把 CLI 指引写入 Agent 说明,以覆盖看不到 MCP 初始化指令的子 Agent;Ponytail 的 Hook 也会向子 Agent 注入模式。仍然不稳定时,减少子 Agent 使用,或在任务提示中显式重复“先 CodeGraph、后 Ponytail”的顺序。

二十、衡量组合方案是否有效

建议记录四组指标。

理解效率

  • 开始编码前的工具调用数。
  • 找到正确公共边界所需时间。
  • Review 阶段发现的遗漏调用者数量。

改动复杂度

  • 每个需求修改文件数和有效代码行。
  • 新增依赖、接口、工厂和配置项数量。
  • Ponytail Review 可删除行数。

交付质量

  • 编译和测试一次通过率。
  • 回滚、热修和线上数据修复次数。
  • 库存、金额、状态机和幂等相关缺陷。

Agent成本

  • 单任务 Token 和工具调用数。
  • 会话压缩次数。
  • 因上下文不清重复读取文件的次数。

目标不是把所有数字都降到最低。好的组合方案应该让 Agent 更早找到正确位置、提交更小的改动,同时保持或提高测试与生产质量。

二十一、推荐的进阶路线

  1. 入门:安装两个工具,在一个服务上完成结构查询和 Ponytail Review。
  2. 熟练:把“图查询、事实表、最小方案、双重 Review”固化成提示模板。
  3. 进阶:为公共符号改动建立 CodeGraph 影响分析检查,并按模块选择测试。
  4. 团队化:统一 AGENTS.mdcodegraph.json、核心回归集和升级策略。
  5. 度量化:以遗漏调用者、改动范围和生产缺陷评估,而不是只看 Token 或代码行。

总结

CodeGraph 与 Ponytail 组合的核心不是“装两个插件”,而是建立正确的工程顺序:先用代码图找到真实调用链和影响范围,再用最小实现规则消除不必要的抽象,最后用测试和普通审查验证业务正确性。

在供应链系统中,可以把这套方法概括为:理解要宽,改动要窄,验证要深。CodeGraph 让理解更有证据,Ponytail 让实现更克制,而库存不变量、事务、幂等、权限和测试决定最终结果能否上线。

参考资料

Ponytail从入门到精通:让Agent用最少代码实现供应链需求

AI 编程 Agent 很容易把一个简单需求扩展成一套新框架:只有一个实现却先建接口,只有一种策略却加工厂,为一个固定值增加配置中心,或者为了未来可能出现的场景提前设计多层抽象。代码可以运行,但维护成本、测试范围和故障面都被放大。

Ponytail 是一套面向编程 Agent 的最小实现规则、生命周期 Hook 和 Skills。它要求 Agent 先理解真实调用链,再依次判断能否不做、复用现有实现、使用标准库、平台原生能力或已有依赖,最后才编写完成当前需求所必需的最少代码。

本文从 Codex 安装和模式切换开始,结合供应链系统中的库存释放、采购审批、报表导出和幂等消费,讲清楚如何使用 Ponytail 控制改动范围,以及哪些正确性和安全能力绝对不能被“精简”。

Ponytail最小实现决策阶梯

一、Ponytail是什么

Ponytail 不是模型、代码搜索引擎、静态分析器或自动重构工具。它主要由三部分组成:

  1. 行为规则:定义 Agent 写代码前应经过的最小实现决策阶梯。
  2. 生命周期 Hook:在会话启动和子 Agent 启动时注入当前规则。
  3. Skills:提供模式切换、过度设计审查、全仓审计和技术债清单等命令。

它解决的是“Agent 应该构建多少东西”,而不是“Agent 是否理解整个代码库”。如果 Agent 没有先读懂业务调用链,Ponytail 也可能让它在错误位置提交一个很小但不完整的补丁。因此其核心原则是:

1
2
3
先完整理解问题
-> 再选择最省的正确方案
-> 保留必要的校验、安全和测试

在供应链系统里,这一点尤其重要。一条库存释放逻辑可能由订单取消、支付超时、售后退款和人工关闭共同调用。最小正确改动可能是在共享领域服务增加一次幂等控制,而不是只在某个 Consumer 里增加一行判断。

二、Ponytail的决策阶梯

Ponytail 要求 Agent 在编码前从上到下判断,命中第一种可行方案后停止继续扩展:

  1. 需求是否真的需要实现:纯推测需求遵循 YAGNI,暂不构建。
  2. 项目里是否已有实现:优先复用现有 Helper、领域服务、约束和团队模式。
  3. 标准库是否支持:使用 JDK、框架标准 API 或语言内置能力。
  4. 平台原生能力是否支持:数据库约束、HTML 原生控件、操作系统能力优先。
  5. 现有依赖是否支持:复用已安装依赖,不为几行逻辑新增库。
  6. 是否一行即可完成:一行足够就不创建新的层次。
  7. 最后才编写最小可用实现

例如“采购单号不能重复”,不应该先写一个分布式锁框架。决策阶梯可能得到:

1
2
3
4
5
需求需要存在
-> 项目没有统一防重组件
-> JDK不能跨实例保证唯一
-> 数据库唯一约束可以原子保证
-> 使用UNIQUE KEY,不新增分布式锁

对应的数据库迁移:

1
2
3
ALTER TABLE purchase_order
ADD CONSTRAINT uk_purchase_order_tenant_no
UNIQUE (tenant_id, purchase_order_no);

应用层仍然需要把唯一键冲突转换为明确的业务错误,但不需要自己实现一套先查后写的锁协议。

三、在Codex中安装Ponytail

1. 安装插件

在终端执行两个独立命令:

1
2
codex plugin marketplace add DietrichGebert/ponytail
codex plugin add ponytail@ponytail

Ponytail 的 Codex 插件使用轻量生命周期 Hook,因此 node 需要位于非交互 Shell 的 PATH 中:

1
2
node --version
Get-Command node

如果 Node.js 不可用,Skills 仍可能被发现,但会话自动激活与规则注入不会完整工作。

2. 检查并信任Hook

启动 Codex 后打开:

1
/hooks

审阅 Ponytail 注册的 Hook 脚本和路径,确认来源是已安装插件后再授权。Hook 能在会话生命周期中注入指令,属于高信任扩展,不应该对来源不明的插件直接点击允许。

Codex 桌面版安装后需要重启应用,再新建一个任务,使插件和 Hook 按新会话加载。

3. 验证插件

在 Codex 中调用帮助 Skill:

1
@ponytail-help

然后查看当前模式:

1
@ponytail

Codex 使用 @skill-name 方式调用 Skill。其他 Agent 可能使用 /ponytail 斜杠命令,文章或截图里的命令需要按实际宿主转换。

4. 卸载

1
codex plugin remove ponytail

插件可能在用户配置目录保留模式配置或状态文件。需要彻底清理时,应先按官方卸载说明运行仓库提供的清理脚本,再移除插件,避免插件删除后脚本也消失。

四、选择lite、full、ultra和off

Ponytail 提供三个工作强度和一个关闭状态:

模式 行为 供应链项目建议
lite 完成用户要求,同时指出更简单方案 遗留系统、需求尚未收敛、团队初次试用
full 强制执行完整决策阶梯,默认模式 常规功能、缺陷修复、重构和日常开发
ultra 删除优先,强烈挑战推测需求 清理脚手架、原型、明确的过度设计治理
off 停止注入 Ponytail 规则 需要完整探索多个架构方案或与规则冲突时

在 Codex 中可以这样表达:

1
2
3
@ponytail lite
@ponytail full
@ponytail ultra

关闭时使用:

1
stop ponytail

或者在支持斜杠命令的宿主中使用 /ponytail off

供应链核心链路建议默认使用 full,不要把 ultra 当作常驻模式。库存、支付、采购金额和对账逻辑通常存在大量非功能约束;过于激进地追求删除,可能把必要的并发控制、审计和补偿路径误判为冗余。

五、配置默认模式

默认模式是 full。临时设置环境变量:

1
2
$env:PONYTAIL_DEFAULT_MODE="lite"
codex

Linux 或 macOS:

1
2
export PONYTAIL_DEFAULT_MODE=lite
codex

也可以写入用户配置。Windows 默认位置:

1
%APPDATA%\ponytail\config.json

内容:

1
2
3
{
"defaultMode": "full"
}

macOS 和 Linux 默认位置:

1
~/.config/ponytail/config.json

优先级为:

1
2
3
PONYTAIL_DEFAULT_MODE环境变量
> config.json的defaultMode
> full

团队不应把个人的全局模式当作项目规则。项目必须保留自己的 AGENTS.md,明确哪些校验、事务和测试属于业务底线,无论 Agent 使用什么模式都不能删除。

六、供应链案例:导出采购到货差异报表

需求如下:

在采购到货差异页面增加 CSV 导出,字段与当前列表一致,最多导出 5000 条。

普通 Agent 容易新增:

  • ReportExporter 接口。
  • CsvReportExporter 实现。
  • ExporterFactory
  • 新的 CSV 第三方依赖。
  • 异步任务、进度表和下载中心。
  • 为未来 Excel 和 PDF 格式预留策略。

但当前需求只有一个格式、固定字段和明确上限。Ponytail full 应先检查项目已有能力:

1
2
3
4
使用 Ponytail full 完成采购到货差异CSV导出。
先搜索项目现有导出实现和已安装依赖,再决定是否新增代码。
不得改变列表筛选口径,最多5000条,保留权限与CSV注入防护。
先给出最小方案,确认后实现。

如果订单模块已经使用 Apache Commons CSV,那么最小方案通常是复用该依赖和现有响应工具,不再新增抽象:

1
2
3
4
5
6
@GetMapping(value = "/arrival-differences/export", produces = "text/csv")
public void export(ArrivalDifferenceQuery query, HttpServletResponse response) throws IOException {
permissionService.checkCanViewProcurement(query.tenantId());
List<ArrivalDifferenceRow> rows = reportService.query(query.withLimit(5000));
csvResponseWriter.write(response, "arrival-differences.csv", rows);
}

这里的“最小”不是把所有逻辑塞进 Controller。reportService.querycsvResponseWriter 已存在,所以直接复用。权限校验、数据上限、编码、转义和 CSV 公式注入防护不能为了减少行数而删掉。

什么时候才引入异步导出?可以设定可观测触发条件:

  • 单次导出超过同步网关超时时间。
  • 数据量从 5000 增长到百万级。
  • 用户明确需要历史任务、重试和下载留存。
  • 导出计算明显影响在线数据库。

触发前不构建任务中心,就是 YAGNI;触发后仍坚持同步导出,则变成忽视真实约束。

七、供应链案例:修复重复库存释放

假设 OrderCancelledConsumer 重复收到消息,导致库存释放两次。最危险的“最小补丁”是只在 Consumer 内用内存 Set 记住事件 ID:

1
private final Set<String> processed = ConcurrentHashMap.newKeySet();

它代码很少,但多实例、重启和事务回滚后都不可靠。Ponytail 明确要求先理解完整调用链,最小方案必须是最小正确方案。

应该先问:

1
2
3
4
使用 Ponytail full 修复重复库存释放。
先追踪 OrderCancelledConsumer 到库存余额和流水的真实调用链,查找项目已有幂等组件。
不得使用JVM本地集合,不新增分布式锁,除非现有事务方案无法满足。
同一事件只能释放一次,并且幂等记录、库存余额、库存流水必须原子提交。

如果项目已有 ProcessedEventExecutor,应复用它:

1
2
3
4
5
6
7
8
@Transactional
public void onMessage(OrderCancelled event) {
processedEventExecutor.runOnce(
"ORDER_CANCELLED",
event.eventId(),
() -> inventoryReleaseService.release(event.orderId())
);
}

数据库层保留唯一约束:

1
2
CREATE UNIQUE INDEX uk_processed_event_consumer_id
ON processed_event (consumer_name, event_id);

这比新建 Redis 锁服务更小,也比 JVM 内存 Set 更正确。还必须验证:

  • runOnce 与库存写入是否在同一个事务传播范围。
  • 唯一键冲突是否按“已经处理”返回,而不是重试失败。
  • 业务异常回滚时幂等记录是否一起回滚。
  • 同一订单的不同合法事件是否不会互相阻塞。
  • 至少有重复事件和事务回滚测试。

Ponytail 的“Bug fix = 修根因,不修症状”在这里体现为:公共幂等边界的一处正确修复,比在每个 Consumer 增加不同判断更少、更稳定。

八、用AGENTS.md建立不可精简的底线

在供应链项目根目录加入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Supply Chain Engineering Rules

## Minimal Implementation
- 优先复用项目已有领域服务、Validator、Repository和测试工具。
- 不为单一实现新增接口、工厂或策略注册中心。
- 不为固定值增加配置项,不为推测需求搭建扩展框架。
- 新增依赖前必须证明JDK、Spring、数据库和现有依赖无法解决。

## Never Simplify Away
- 租户、仓库、数据权限和信任边界输入校验。
- 库存非负约束、幂等键、唯一键和并发条件更新。
- 采购单与订单状态机校验。
- BigDecimal金额计算、舍入规则和币种口径。
- 本地事务、Outbox事件、审计流水和防数据丢失错误处理。
- 核心逻辑至少一个可运行测试,公共契约必须保留回归测试。

## Change Scope
- 修改前追踪真实调用链和全部调用者。
- 每次只完成当前需求,不顺便重构无关模块。
- 删除公共能力前,先证明没有生产调用者和反射、配置入口。

这份文件负责业务安全边界,Ponytail 负责实现风格。两者组合后,Agent 不会把“最短 diff”误解为“删掉所有看起来复杂的东西”。

九、ponytail-review:检查当前改动

完成编码后调用:

1
@ponytail-review

这个 Skill 只关注过度设计,常见标签包括:

  • delete:死代码、未使用扩展点和推测功能。
  • stdlib:手写了标准库已有的能力。
  • native:依赖或代码重复平台原生能力。
  • yagni:单实现接口、没人设置的配置和只有一个调用者的层。
  • shrink:同一逻辑可以明显减少代码。

供应链 PR 中可以这样调用:

1
2
3
4
5
6
7
@ponytail-review
只审查当前 git diff 是否存在:
1. 单实现接口和只有一个产品的工厂;
2. 重复已有幂等组件或CSV导出组件;
3. 为未来格式、未来仓库类型建立的未使用扩展点;
4. 可由数据库唯一约束替代的应用层防重代码。
不要把事务、权限、审计、幂等和必要测试标记为可删除。

必须再执行一次普通代码审查。官方 Skill 明确把正确性、安全和性能问题排除在 Ponytail Review 范围之外。因此完整顺序是:

1
2
3
4
Ponytail审查过度设计
-> 普通审查正确性与回归
-> 安全与数据一致性审查
-> 运行测试

不要因为 @ponytail-review 没有发现问题,就判断代码可以上线。

十、ponytail-audit:审计整个仓库

@ponytail-audit 会扫描整个代码库,按可删除规模排序,适合治理历史过度设计:

1
2
3
4
@ponytail-audit
审计 procurement-service 的过度设计,只输出报告,不修改代码。
优先寻找单实现接口、纯转发包装器、未使用配置、重复工具类和已有标准能力的手写实现。
排除数据权限、审计、事务、补偿、幂等和外部系统适配层。

对于大型供应链仓库,不建议第一次就扫描全部模块。可以按域分批:

  1. 采购询报价模块。
  2. 采购订单模块。
  3. 库存预占模块。
  4. 仓储作业模块。
  5. 对账与结算模块。

每个发现都要验证真实调用者、运行时配置和生产流量。审计报告只是候选删除清单,不会自动证明代码无用,也不会自动应用修改。

十一、用ponytail-debt管理有边界的简化

有些需求可以先采用简单方案,但必须写清容量上限和升级触发条件。例如补货任务当前只有单实例,可以使用全局锁:

1
2
3
4
// ponytail: 单实例全局锁;部署多实例或任务等待超过30秒时升级为数据库租约锁
synchronized void generateReplenishmentSuggestions() {
generator.generate();
}

这条注释不是鼓励永久留下临时实现,而是记录:

  • 简化了什么。
  • 当前上限在哪里。
  • 什么指标触发升级。
  • 下一步应该采用什么方案。

调用债务 Skill:

1
@ponytail-debt

它会读取 ponytail: 注释并形成清单,同时标记没有触发条件的高腐化风险条目。需要持久化时,可以要求写入 PONYTAIL-DEBT.md,再由团队在迭代计划中评审。

以下注释不合格:

1
// ponytail: 以后优化

它没有容量上限、指标或升级路径,等同于不可执行的 TODO。

十二、建立团队级Ponytail工作流

阶段1:先理解需求和调用链

1
2
读取需求、AGENTS.md和相关源码,追踪入口到数据库或外部系统的真实流程。
列出业务不变量、信任边界和现有可复用组件。只分析,不编码。

Ponytail 不负责代码索引。大型项目可以配合 CodeGraph,或者使用 Codex 内置搜索和读取工具完成这一步。

阶段2:逐级判断

要求 Agent 输出简短的决策记录:

1
2
3
4
5
6
7
按 Ponytail 阶梯判断:
- 是否需要实现;
- 项目内已有能力;
- JDK/Spring/数据库原生能力;
- 已安装依赖;
- 最小新增代码。
说明命中的最高层以及被跳过的抽象。

阶段3:限定改动范围

1
2
3
只修改 inventory-service 内与幂等消费直接相关的文件。
不升级依赖,不创建新框架,不重构无关命名。
保留事务、唯一约束、库存流水和现有日志。

阶段4:验证

非简单一行代码至少留下一个可运行检查。供应链核心逻辑通常不应只满足这个最低标准,而要按风险增加测试:

  • 重复消息测试。
  • 并发库存扣减或释放测试。
  • 事务回滚测试。
  • 多租户和越权测试。
  • 金额边界和舍入测试。
  • 数据库迁移兼容性测试。

阶段5:双重审查

1
@ponytail-review

然后再执行:

1
按正常代码审查标准检查当前diff,重点检查正确性、并发、事务、幂等、权限、日志泄密和测试缺口。

十三、哪些东西不能为了少写而删除

以下能力通常看起来“啰嗦”,但在供应链系统中属于真实复杂度:

1. 信任边界校验

来自 API、消息队列、Excel 导入和外部 ERP 的数据都不可信。租户、仓库、SKU、数量、币种和状态必须校验。

2. 防止数据丢失的错误处理

库存写入成功但事件发送失败、采购单更新成功但审计记录失败,都会形成不可追踪状态。Outbox、本地事务和可重试错误分类不能为了减少文件数而删除。

3. 安全与权限

数据权限、审计、脱敏、SQL 参数化和密钥隔离不是过度设计。即使只有一个调用者也必须保留。

4. 必要的业务抽象

单实现接口不一定都多余。外部 WMS、ERP、支付网关的 Adapter 接口可以隔离外部契约;领域端口也可能承担依赖倒置和测试替身职责。判断依据是它是否形成真实边界,而不是实现数量。

5. 可运行验证

金额、解析器、分支、循环、并发和安全逻辑必须有测试。最少代码不等于没有回归证据。

十四、何时暂停Ponytail

以下场景可以暂时切换到 liteoff

  • 架构探索阶段需要比较多个方案,而不是立即实现。
  • 法规、审计或客户合同明确要求完整文档和控制措施。
  • 系统正处于故障处置,需要先保守止损再讨论最小重构。
  • 迁移任务要求双写、影子流量和回滚通道,代码增量本身就是风险控制。
  • 用户明确要求一个完整扩展框架,并且已确认多个真实实现方。

暂停规则不是放弃工程约束。即使 Ponytail 关闭,也应继续限制无关改动并运行完整验证。

十五、常见问题

安装后没有自动生效

检查 Node.js 是否在 PATH,在 /hooks 中审阅并信任 Hook,然后重启 Codex 并新建任务。

Agent仍然创建很多文件

明确使用 full,并在提示中列出禁止项:

1
使用 Ponytail full。禁止单实现接口、工厂、未来配置和新依赖;先复用项目现有模式。

同时检查需求本身是否真的要求跨模块改动。有时文件多是业务边界造成的,不是过度设计。

Agent删掉必要校验

这是错误使用,不是合格的 Ponytail 结果。把不可删除项写入 AGENTS.md,恢复校验并补充回归测试。Ponytail 官方规则明确禁止精简信任边界校验、安全和防数据丢失错误处理。

Review报告与普通Review冲突

Ponytail Review 只讨论复杂度。正确性、安全和性能结论应以普通代码审查与测试证据为准。

ultra模式一直拒绝需求

切回 fullliteultra 适合挑战推测需求,不适合所有生产开发。如果用户已经明确坚持完整需求,Agent 应执行,而不是反复争论。

十六、评估是否产生价值

可以连续统计十个真实 PR:

  • 每个需求新增和删除的有效代码行。
  • 修改文件数量。
  • 新增依赖数量。
  • 新增接口、工厂、配置项数量。
  • Code Review 中的过度设计意见数量。
  • 正确性缺陷和回滚次数。
  • 从任务开始到测试通过的时间。

评价标准不能只有“代码行更少”。如果行数下降但缺陷增加,说明团队把最小实现误用了。理想结果是:改动范围更小、依赖更少、验证不下降、生产缺陷不增加。

总结

Ponytail 提供的是一套可持续执行的 YAGNI 与复用优先机制。它让 Agent 在新增代码前先检查项目、标准库、平台和现有依赖,并通过 review、audit 和 debt Skills 把过度设计治理延伸到提交之后。

在供应链项目中,正确用法是“完整理解,最小实现,保留业务底线”。库存幂等、事务、权限、金额精度、状态机、审计和测试不是可以随意裁剪的复杂度。Ponytail 应减少人为制造的复杂度,而不是否认业务本身的复杂度。

参考资料