AI Agent 底座完整入门:从 API 到 Runtime
Scope boundary / Current legacy Task examples(2026-07-15):本文关于 API、SDK、CLI、MCP、Skills、approval、audit 和 runtime 的通用解释仍可参考;其中 lead_outreach / lead_follow_up / retention、旧 task lifecycle 与 Objective-first 例子不是 Target contract。Task domain 与 AI runtime 统一以 Task System Design V3 为准。
写给:正在判断“我们要不要做 API / SDK / CLI / MCP / Botmux / Codex / Agent Runtime”的产品与工程同学。
结论先说:不要从零造一个 Codex 或 Claude Code。先把 retaintive 的业务能力做成可靠 API、状态机和可审计数据,再按需要包 SDK / CLI / MCP / Skills,最后接入 Botmux、Lark、dashboard 等工作流入口。
0. 这篇文档怎么读
这是一篇 one-stop 文档,目标是把容易混在一起的概念放到同一张地图里:
- HTTP / API / REST / OpenAPI / Webhook 到底是什么?
- 有了 HTTP API,为什么还要 SDK / CLI?
- SDK 和 CLI 是上下级,还是 API 上面的并列包装?
- MCP、Function calling、Connector、Skill 有什么区别?
- Agent Runtime 是什么,和 Codex CLI / Botmux 有什么关系?
- retaintive 如果要做 AI follow-up、评价分析、客户召回,哪些层 MVP 必须做,哪些可以以后补?
- 哪些东西应该用现成工具,哪些必须自己做?
推荐阅读顺序:
先看 1-2:建立全局地图
再看 3:用一个 retaintive 例子跑完整链路
再看 4-6:补齐基础层、操作面、运行层概念
再看 7-11:做产品和工程取舍
retaintive 当前的现实起点是:
已有:
Hono backend API
-> frontend 通过 Hono RPC fetch client / AppType 调 API
还不是:
OpenAPI-first public developer platform
public SDK
public CLI
hosted MCP server
下一步如果要让 Codex / Botmux / CI / agent 稳定操作 retaintive,最现实路线是:
选少数稳定核心 API
-> 写出或生成 OpenAPI schema
-> 生成 internal client
-> 做 thin CLI
-> 后续再产品化成 public SDK / public CLI / MCP / Skills
1. 核心结论
AI Agent 的“基座”不是一个模型,也不是一个聊天框。一个能进入真实业务流的 agent 至少需要:
LLM
+ instructions / skills
+ context / memory
+ tools / APIs / CLI / MCP
+ loop
+ state
+ queue / scheduler
+ permissions / policy
+ human approval
+ logs / traces / evals
+ product surface
但这不代表我们要全部从零开发。正确取舍是:
不要重复造:
coding agent runtime
repo editing agent
Lark CLI runtime
通用 MCP protocol
必须自己做:
retaintive data model
store / tenant isolation
usage metering
approval queue
audit log
LLM Gateway
call / lead / review / follow-up 的业务状态机
一句话:
API 是地基,OpenAPI 是机器可读合同,SDK / CLI / MCP 是从合同长出来的操作面,Skill 是 SOP,Runtime 是执行现场,Policy 是刹车。retaintive 要赢,重点不是重复造工具,而是把健身房客户运营这套业务事实和审核闭环做扎实。
2. 一张完整分层图
把 AI Agent 产品想成从“业务事实”一路包装到“人类可监督的自动化执行”:
Domain / Data model / Source of Truth
↓
业务服务代码
↓
API contract: REST / GraphQL / Webhook / Event stream / OpenAPI schema
↓
Docs + Sandbox + Test data
↓
+---------------------------+------------------------------+-------------------------------+
| SDK | CLI / Dev tools | Tool layer |
| 给代码 import 用 | 给 terminal / CI / agent 用 | Function calling / MCP / |
| | Logs / Local tunnel | Skills / Tool schema |
+---------------------------+------------------------------+-------------------------------+
↓
Agent Runtime: loop / state / memory / queue / scheduler / sandbox
↓
Policy layer: auth / scopes / approvals / audit / risk controls
↓
Product surface: Web dashboard / Lark / Slack / IDE / Desktop app
核心判断:
越靠下越像“产品事实”,越靠上越像“AI 怎么使用这些事实”。
如果底层数据模型和状态机不稳定,上面接 MCP、Botmux、Codex 只会让不稳定更快暴露。
注意:这张图不是说必须先做 SDK 才能做 CLI。SDK、CLI、MCP / Tool layer 是 API 上面的 sibling wrappers,面向不同使用者:
2026 年的主流方向是:尽量让这些 wrapper 从同一份 OpenAPI schema 生成或半生成,再做少量手工包装和产品化治理。
3. 一个 retaintive 例子:Call-to-Follow-up
用一个具体、好理解的 retaintive 场景先跑一遍全链路。
目标:
潜在客户给健身房打电话,问价格和课程,但没有预约。
Retaintive 从通话记录和转录里识别 follow-up 机会。
AI 生成 follow-up draft。
老板或销售审核后发送 SMS / Email。
发送结果和后续预约效果回流到 dashboard。
这个例子会贯穿后面的概念。
3.1 业务事实层
系统必须先知道哪些对象是真实存在的:
stores
contacts / customers
calls
call_transcripts
leads
lead_status_changes
tasks
follow_up_candidates
follow_up_drafts
approval_items
message_sends
usage_events
audit_logs
这些是 Source of Truth。Agent 可以总结、推荐、生成草稿,但不能把聊天记录当数据库。
3.2 业务服务层
业务服务代码负责真正的规则:
这通电话属于哪个 store?
这个 caller 是新 lead 还是已有 customer?
通话里有没有价格、trial、schedule、cancellation 等意图?
这个 lead 是否需要 follow-up?
follow-up 文案是否只能先生成 draft?
谁有权限 approve?
这次 LLM 调用和发送动作计入哪个 client / store?
无论入口是 dashboard、API、CLI、MCP 还是 Lark card,规则都应该落到同一套 service / API boundary,不要散落在 prompt 或脚本里。
3.3 API 层
把关键动作做成稳定 API:
GET /stores/{store_id}/follow-up-candidates
POST /follow-up-drafts
GET /approval-items?status=pending
POST /approval-items/{id}/approve
POST /messages/send
POST /usage-events
API 使用者看到的是 endpoint、request、response、error。平台内部做的是 auth、store isolation、idempotency、audit、usage metering 和 business validation。
3.4 OpenAPI / SDK / CLI / MCP 层
同一个 POST /follow-up-drafts 能长出多种操作面:
OpenAPI schema
-> generated internal client
-> thin CLI
-> MCP tool schema
-> docs / mock / contract tests
工程师或 agent 可以跑:
retaintive follow-up candidates --store-id store_123 --format json
retaintive follow-up draft create --lead-id lead_456 --tone friendly --format json
retaintive approval list --status pending --format json
外部 AI client 看到的可能是:
tool name: create_follow_up_draft
input schema: { store_id, lead_id, tone }
output schema: { draft_id, status, message_preview }
Skill 则告诉 agent:
When handling follow-up messages:
1. Read candidate context first.
2. Create follow_up_draft only.
3. Never send SMS directly from generated content.
4. Put every external message into approval queue.
5. Record usage_event and audit_log.
3.5 Runtime / surface 层
MVP 可以先不用复杂 multi-agent runtime。更准确地说,Retaintive 现在和近期都应该先用确定性 workflow 管理业务事实和 task lifecycle:
RingCentral call ended / lead email received / transcript ready
-> backend workflow ingests raw event
-> processing worker writes calls / transcripts / leads / contacts
-> task workflow creates or updates lead_outreach / lead_follow_up / retention tasks
-> dashboard shows task and contact timeline
-> staff or manager works the task
-> completion / outcome / audit is written back
这里使用的是 live Tasks Schema 的 typeCategory 名称:lead_outreach 是新 lead 首次联系任务,lead_follow_up 是 lead 后续跟进任务,投诉或流失风险类处理落到 retention。UI 可以写成 complaint / retention 这种人类可读标签,但 API、prompt 和 tooling 不应创建 complaint 或 legacy follow_up category。
Agent 不应该绕过这套 workflow 自己决定 task lifecycle。更合适的角色是读取 workflow 产物、生成解释、草稿、摘要和建议,并把高风险动作交给人审批:
lead_outreach task created / lead_follow_up task overdue / retention task created
-> agent summarizes context
-> agent drafts suggested reply or manager brief
-> approval_item or review card is created
-> human approves / edits / rejects
-> backend workflow performs the real mutation and writes audit log
以后接 Lark / Botmux:
Boss in Lark:
"show overdue lead_follow_up tasks and retention tasks"
Botmux / command bridge:
-> runs stable CLI or calls API
-> returns task summary / approval card
-> human approves / edits / rejects
-> backend enforces policy and writes audit log
这个例子的关键不是“AI 写文案”,而是:
事实来自 SoT
动作通过 API
工具从 OpenAPI / client / CLI / MCP 暴露
草稿进入 approval
发送有 audit
task lifecycle 仍由 workflow 管理
结果能回流
4. 基础层概念
这一层回答:系统到底承认什么事实,怎么把能力稳定开放出来。
4.1 Domain / Data model / Source of Truth
Domain 是业务世界里的对象和规则。对 retaintive 来说,是门店、会员、lead、call、review、task、campaign、approval。
Data model 是这些对象在系统里的结构。比如 lead 有 store_id、手机号、最近通话、状态、来源、follow-up 记录。
Source of Truth (SoT) 是系统承认的事实来源。比如某个 lead 是否需要跟进,不能靠 AI 聊天记录判断,应该靠数据库里的 call、transcript、lead status、task、message history 判断。
为什么重要:Agent 可以推理,但不能替代事实库。没有 SoT,AI 会把“听起来对”当成“系统事实”。
4.2 业务服务代码
业务服务代码是真正执行规则的后端:
客户是否符合 follow-up 条件?
评价是不是负面?
这个门店是否允许发 SMS?
这个用户是否能批准发送?
这个请求是否跨 store?
API、SDK、CLI、MCP 最后都只是入口,真正的规则应该在业务服务里统一执行。不要把核心规则散落在 prompt、CLI 脚本、MCP server 或前端按钮里。
4.3 HTTP / HTTPS
HTTP 是两台机器在网络上说话的常见协议。你打开网页、调用 API,大多都在用 HTTP。
HTTPS 是 HTTP 加密版。生产环境 API 必须用 HTTPS。
一个 HTTP request 大概长这样:
POST /follow-up-drafts HTTP/1.1
Host: api.retaintive.com
Authorization: Bearer <TOKEN>
Content-Type: application/json
{"store_id":"store_123","lead_id":"lead_456"}
成功 response 大概长这样:
HTTP/1.1 201 Created
Content-Type: application/json
Request-Id: req_abc123
{
"draft_id": "draft_789",
"status": "pending_approval",
"message": "Hi Jane, thanks for calling about our trial class..."
}
失败 response 也会用同一套 HTTP 结构表达错误:
HTTP/1.1 403 Forbidden
Content-Type: application/json
Request-Id: req_def456
{
"error": {
"code": "missing_scope",
"message": "Token does not have follow_up_drafts:write scope."
}
}
HTTP response 里最关键的是三块:
如果用 HTTPS,业务层看到的 method、path、headers、body 基本还是同一套 HTTP 内容。区别在外层传输:
HTTP:
client -> plain HTTP request -> server
HTTPS:
client -> TLS encrypted connection -> HTTP request inside TLS -> server
所以文档里通常会画 HTTP request,而不是单独画一份 HTTPS request。真实调用时 URL 会写成:
https://api.retaintive.com/follow-up-drafts
HTTP / HTTPS 只管“怎么传话”,不管你的业务是什么意思。POST /follow-up-drafts 的业务含义、201 Created 代表什么、missing_scope 怎么处理,都来自 API contract 和后端 route handler,不来自 HTTP 协议本身。
4.4 API
API 是系统对外开放的能力入口。它规定外部可以让系统做什么、怎么传参数、会返回什么。
比如:
GET /stores/{store_id}/follow-up-candidates
POST /follow-up-drafts
POST /approval-items/{id}/approve
POST /messages/send
API 有两种视角:
API 使用者看到:
POST /follow-up-drafts
Authorization: Bearer <TOKEN>
body: { store_id, lead_id }
API 作者内部实现:
route handler
-> auth / scope check
-> store access validation
-> idempotency check
-> followUpService.createDraft(...)
-> usage_event
-> audit_log
-> response JSON
API 是所有上层包装的地基。SDK、CLI、MCP、dashboard 最后都应该调用同一套 API 或同一套 service layer。
4.5 REST / GraphQL / gRPC
这些是 API 的不同设计风格:
retaintive 这种 B2B SaaS,外部/内部业务 API 默认用 REST 最稳。复杂 dashboard 查询可以考虑 GraphQL,但不要为了潮流引入。
4.6 OpenAPI / API contract
OpenAPI 是机器可读的 API 合同,描述 endpoint、参数、返回、错误码、auth。
它的价值:
- 自动生成 API docs。
- 自动生成 SDK。
- 自动生成或半生成 CLI。
- 自动生成或半生成 MCP server / tool schema。
- 自动生成 mock / contract test。
- 让 AI / agent 更容易理解你的 API。
但这里要分清两件事:
OpenAPI 是 source of truth。
Generator 是把 OpenAPI 变成 SDK / CLI / docs / MCP 的工具。
一个好的 OpenAPI operation 不只是写 POST /follow-up-drafts,还应该写清:
paths:
/follow-up-drafts:
post:
operationId: createFollowUpDraft
tags: [follow-up]
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [store_id, lead_id]
properties:
store_id:
type: string
lead_id:
type: string
tone:
type: string
responses:
"201":
description: Follow-up draft created
"403":
description: Missing scope or store access
这些字段会影响:
- SDK 里方法叫什么:
client.followUps.createDraft(...)。
- CLI 里命令叫什么:
retaintive follow-up draft create。
- MCP tool 叫什么:
create_follow_up_draft。
- 文档里怎么分组。
- agent 怎么理解这个工具的输入、输出和错误。
不是所有 generator 能力一样:
所以更准确的说法是:
OpenAPI 可以驱动 SDK / CLI / MCP / docs 的生成。
但生成质量取决于 API 设计、operationId、tags、schema、error model、auth model 和 generator 配置。
没有 OpenAPI,团队和外部集成方只能读自然语言文档,容易 drift。有 OpenAPI 但写得粗糙,也会生成出难用的 SDK / CLI / MCP。
Hono 里能不能自动生成 OpenAPI
可以半自动,但不是装一个包就能从任意 Hono handler 里完美猜出来。
如果代码只有这样:
app.post("/follow-up-drafts", async (c) => {
const body = await c.req.json();
const draft = await followUpService.createDraft(body);
return c.json(draft, 201);
});
工具很难准确知道:
body 里哪些字段 required?
tone 有哪些 enum?
response 长什么样?
403 / 409 / 429 error 怎么返回?
需要什么 auth scope?
operationId 应该叫什么?
所以现实做法是:给 route boundary 补 request / response schema,再由 Hono OpenAPI 工具生成 openapi.json。
常见选择:
npm install @hono/zod-openapi zod
或:
npm install hono-openapi @hono/standard-validator
# 再安装你选择的 schema library,比如 Zod / Valibot / ArkType / TypeBox
概念化代码:
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
const CreateFollowUpDraftInput = z.object({
store_id: z.string(),
lead_id: z.string(),
tone: z.enum(["friendly", "concise", "professional"]).optional(),
}).openapi("CreateFollowUpDraftInput");
const FollowUpDraft = z.object({
draft_id: z.string(),
status: z.literal("pending_approval"),
message: z.string(),
}).openapi("FollowUpDraft");
const createFollowUpDraftRoute = createRoute({
method: "post",
path: "/follow-up-drafts",
operationId: "createFollowUpDraft",
tags: ["follow-up"],
request: {
body: {
content: {
"application/json": {
schema: CreateFollowUpDraftInput,
},
},
},
},
responses: {
201: {
description: "Follow-up draft created",
content: {
"application/json": {
schema: FollowUpDraft,
},
},
},
},
});
const app = new OpenAPIHono();
app.openapi(createFollowUpDraftRoute, async (c) => {
const body = c.req.valid("json");
const draft = await followUpService.createDraft({
storeId: body.store_id,
leadId: body.lead_id,
tone: body.tone,
});
return c.json({
draft_id: draft.draftId,
status: draft.status,
message: draft.message,
}, 201);
});
app.doc("/openapi.json", {
openapi: "3.0.0",
info: {
title: "Retaintive API",
version: "1.0.0",
},
});
这时 GET /openapi.json 就能返回机器可读的 API schema。后面再用这份 schema 生成 internal client、CLI、SDK、MCP tool schema 或 docs。
选择上可以这样判断:
Retaintive 自己怎么选,集中看 8.1 当前状态。这里先记住一件事:@hono/zod-openapi 和 hono-openapi 都是生成 OpenAPI 的方式,不是业务架构本身;业务边界、auth、error model、scope、idempotency 仍然要自己设计。
关键点:工具能帮你生成格式和重复代码,但不能替你决定 API 设计。 store_id 怎么传、错误结构怎么统一、scope 怎么命名、哪些 response 要写清楚,这些仍然需要我们设计。
4.7 Auth / Identity / Scope
Auth 管“谁在调用”。
Identity 管“代表谁调用”:用户、bot、service account、tenant。
Scope 管“能做什么”:只读、创建 draft、发送短信、审批、管理 billing。
对 AI Agent 来说这层特别重要,因为 agent 可能会代表人做事:
代表老板批准 follow-up message
代表 system 每天生成 draft
代表 support 查看某个客户数据
代表 bot 写入 Lark Base
如果 identity 和 scope 不清楚,agent 就会变成一把没有边界的远程钥匙。
4.8 Webhook / Event stream
API 是“我主动问你”。Webhook / event stream 是“事情发生了你主动告诉我”。
例子:
RingCentral call ended -> webhook 通知 retaintive -> call ingestion workflow
Call transcript generated -> event 触发 contact / lead analysis workflow
Lead email received -> lead-tracking workflow creates lead_outreach task
Complaint detected -> task workflow creates retention task (UI label: complaint / retention)
Task overdue -> event 或 scheduled scan 触发 reminder / summary workflow
每天早上 9 点 -> scheduler 扫描 missed calls / overdue lead tasks
每周一 8 点 -> scheduler 生成 weekly operator report
Webhook 也有两种视角:
事件发送方看到:
POST https://api.retaintive.com/webhooks/ringcentral
headers: signature / timestamp
body: call ended event
retaintive 接收方内部实现:
verify signature
-> deduplicate event_id
-> write raw event
-> enqueue call analysis job
-> return 200 quickly
注意:event / scheduler 触发的不一定是“自由 agent”。在 Retaintive 这种业务系统里,第一层通常应该是确定性 workflow:写入 raw event、去重、更新 calls / leads / tasks、维护 task lifecycle。Agent 更适合接在 workflow 后面,处理解释、摘要、草稿、排序和人类审批入口。
不推荐:
call ended
-> agent 自己决定是否创建 task / 改 lead status / 发送消息
推荐:
call ended
-> backend workflow 更新 calls / leads / tasks
-> lead_outreach / lead_follow_up / retention task created or overdue
-> agent 生成 context summary / suggested reply / manager brief
-> human approval for external messages
-> backend workflow writes final mutation and audit log
所以“Agent 产品不能只靠人来问”的意思不是所有 event 都直接交给 agent,而是系统应该能被 event / scheduler 主动推动;其中确定性状态变更交给 workflow,模糊判断和自然语言产物交给 agent,并把高风险动作交给人审批。
5. 操作面概念
这一层回答:同一个 API 能力,怎么包装给代码、人、CI、agent、外部 AI client 使用。
5.1 SDK
SDK 是给程序员在代码里调用 API 的库。
用户如果不用 SDK,就要自己写 HTTP:
await fetch("https://api.retaintive.com/follow-up-drafts", {
method: "POST",
headers: { Authorization: `Bearer ${token}` },
body: JSON.stringify({
store_id: "store_123",
lead_id: "lead_456",
}),
});
SDK 用户看到的是普通代码调用,不需要看见 HTTP 细节:
const client = new RetaintiveClient({
apiKey: process.env.RETAINTIVE_API_KEY,
});
await client.followUps.createDraft({
storeId: "store_123",
leadId: "lead_456",
});
SDK 内部最终还是会发 HTTP request。下面是概念化示例,不代表一定要手写这一层:
class RetaintiveClient {
constructor(private options: { apiKey: string }) {}
followUps = {
createDraft: async (input: { storeId: string; leadId: string }) => {
return fetch("https://api.retaintive.com/follow-up-drafts", {
method: "POST",
headers: {
Authorization: `Bearer ${this.options.apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
store_id: input.storeId,
lead_id: input.leadId,
}),
});
},
};
}
2026 年更常见的做法不是从零手写所有 SDK method,而是:
OpenAPI schema
-> SDK generator
-> generated typed client
-> 少量配置 / wrapper / publishing workflow
SDK 解决的是开发效率、类型、retry、auth、错误处理。它主要给工程师写代码时用。SDK / CLI 可以做客户端 retry 和友好错误,但 backend 仍然必须自己做 auth、scope、idempotency、audit、rate limit 和 business validation。
SDK 不是所有 SaaS 的第一优先级。如果前端、后端和 worker 都在同一个系统边界内,后端内部应该优先调用 service layer,而不是绕一圈 HTTP 再通过 SDK 调自己:
推荐:
backend route -> followUpService.createDraft(...)
不推荐:
backend route -> SDK -> HTTP API -> 同一个 backend
SDK 真正有价值的场景是:外部开发者、partner integration、POS 系统、mobile app、多个内部服务,或已经有 OpenAPI schema、可以低成本生成 typed client。
5.2 Generated internal client
generated internal client 是先不对外发布的 SDK。它不是给客户安装的 npm package,而是给我们自己的 CLI、测试、worker 或 future MCP server 用的 typed API client。
OpenAPI schema
-> generator
-> internal client
-> our CLI / tests / internal jobs call this client
调用方看到的是:
await internalClient.followUps.createDraft({
storeId: "store_123",
leadId: "lead_456",
});
它内部负责:
storeId -> store_id
leadId -> lead_id
Authorization header
baseUrl
timeout
retry
error mapping
typed response
对 retaintive 来说,如果暂时没有外部开发者,就可以先不发布官方 SDK;但可以先生成一个 internal client 给 CLI、测试和未来 MCP server 复用。
5.3 CLI / Thin CLI
CLI 是命令行工具。它让人、脚本、CI、agent 在 terminal 里操作系统。
CLI 用户看到的是 terminal 命令:
retaintive follow-up candidates --store-id store_123 --format json
retaintive approval list --status pending --format json
thin CLI 是一层很薄的 terminal wrapper。它自己不应该重新写一套业务逻辑,只做三件事:
1. 解析 terminal flags
2. 调 generated internal client / SDK
3. 把结果用 JSON / table 输出,并设置 exit code
CLI command 内部应该像这样薄:
const result = await internalClient.followUps.createDraft({
storeId: options.storeId,
leadId: options.leadId,
});
console.log(JSON.stringify(result, null, 2));
完整链路是:
OpenAPI schema
-> generated internal client
-> thin CLI
-> POST /follow-up-drafts
-> backend service
一句话:SDK 给代码用,CLI 给 terminal 用。
CLI 有三种实现方式:
方式 A: CLI 直接调 API
retaintive CLI
-> fetch("POST /follow-up-drafts")
-> backend
方式 B: CLI 复用 SDK / generated client
retaintive CLI
-> internalClient.followUps.createDraft(...)
-> client 内部调 API
-> backend
方式 C: OpenAPI 直接生成 CLI
OpenAPI schema
-> CLI generator
-> generated CLI wraps generated SDK or generated client
-> backend
方式 A 开发最快,适合 MVP、内部工具、只有少量命令时。但风险是:如果每个 CLI command 都自己写 fetch、auth header、error handling,以后再补 SDK 时会发现逻辑散落在很多文件里。
更稳的 MVP 写法是:
cli/commands/follow-up-create.ts # 只负责参数解析、输出格式、exit code
cli/internal-client/follow-ups.ts # 负责 createDraft(...)
cli/internal-client/request.ts # 负责 baseUrl、auth、timeout、error mapping
以后升级成正式 SDK 或 generated SDK 时,大致变成:
packages/retaintive-sdk/src/follow-ups.ts
packages/retaintive-sdk/src/request.ts
cli/commands/follow-up-create.ts -> import SDK
方式 C 是 2026 年越来越常见的 API DevEx 路线。Speakeasy 的 CLI generator 会从 OpenAPI spec 生成 Go/Cobra CLI,并包装 generated Go SDK;Stainless 和 Fern 也公开支持从 OpenAPI spec 生成 CLI / SDK / docs / MCP 这类 developer interface。
这也解释了为什么“SDK 可以生成”和“CLI 复用 SDK”并不矛盾:很多 generated CLI 本来就是包装 generated SDK。我们不一定要手写 SDK,但最好让 CLI 复用同一个 generated client / generated SDK,而不是 CLI 自己散落 HTTP 调用。
生成 CLI 的优势是快、覆盖面广、和 API spec 同步;缺点是默认命令体验未必符合人和 agent 的真实工作流。比如 API operation 可能叫 createFollowUpDraft,但人类更想要:
retaintive follow-up draft create --store-id store_123 --lead-id lead_456 --format json
agent 更需要稳定的 JSON 输出、可预测的 exit code、清晰的 --dry-run、--as user/bot、--confirm 等风险控制。生成 CLI 后通常仍需要一层产品化整理。
这几个经常被忽略,但是真正决定开发体验。
对 retaintive 来说,未来也应该有 test store、test customer、test call、test review,而不是拿真实客户数据试 agent。
这是“你自己的产品内 AI assistant”最常用的工具调用方式。
比如老板在 retaintive dashboard 里点:
帮我总结这家门店本周未跟进 lead,并生成 follow-up 草稿
你的后端可以把几个 function 暴露给模型:
get_follow_up_candidates(store_id, date_range)
create_follow_up_draft(lead_id, tone)
create_approval_item(draft_id)
这不需要 MCP。因为 AI 在你的产品里,你的 backend 直接控制工具和权限。
Function calling 的两种视角:
产品用户看到:
“帮我总结这家门店本周未跟进 lead,并生成 follow-up 草稿”
backend 内部实现:
LLM chooses tool: get_follow_up_candidates(...)
-> backend validates store access
-> service reads leads
-> LLM drafts follow-up
-> backend writes approval_item
-> UI shows editable draft
5.6 MCP
MCP (Model Context Protocol) 是 AI client 和外部工具之间的标准协议。
它适合这个问题:
客户想在自己的 Claude / ChatGPT / Cursor 里连接 retaintive,
让外部 AI 安全读取门店数据、创建 draft、查询指标。
MCP server 暴露工具 schema,AI client 通过 tools/list 和 tools/call 使用它。
MCP 的两种视角:
AI client 看到:
tool name: create_follow_up_draft
input schema: { store_id, lead_id, tone }
output schema: { draft_id, status }
MCP server 作者内部实现:
receive tools/call
-> validate OAuth token / tenant
-> check tool allowlist and scope
-> call retaintive REST API or service layer
-> return structuredContent
重要判断:
客户在我们的 dashboard 里用 AI -> Function calling 更直接
客户在自己的 AI client 里接我们 -> MCP 更合适
内部 agent 在 terminal 里操作 -> CLI + Skill 往往更快
5.7 Connector
Connector 是已经封装好的外部系统连接器。比如 GitHub connector、Lark connector、Stripe connector、Sentry connector。
它和 MCP / CLI 的关系取决于实现:
有的 connector 背后是 MCP
有的 connector 背后是平台私有 API
有的 connector 背后是 OAuth + REST API
产品判断上不用纠结名字,重点看:
- 它能不能读写你需要的对象?
- Auth 和 scope 能不能控?
- 有没有 audit?
- 有没有 rate limit 和错误处理?
5.8 Skill
Skill 是给 agent 的可复用操作指南。它通常是 Markdown,告诉 agent:
什么时候使用这个工具
命令怎么跑
哪些动作需要人类确认
遇到权限错误怎么处理
输出应该怎么组织
Skill 不直接执行外部操作。它教 agent 用 CLI / MCP / API。
Skill 的两种视角:
agent 看到:
“遇到 follow-up message 需求时,先 create draft,再进 approval queue,不要直接 send”
Skill 作者写的是:
SKILL.md
- trigger conditions
- allowed commands/tools
- safety rules
- output format
- troubleshooting steps
对比:
Lark CLI 的方向很典型:它既有大量 CLI commands,又有 AI Agent Skills。也就是说,CLI 提供手,Skill 教怎么用手。
6. Agent 运行层概念
这一层回答:agent 活在哪里,怎么持续跑,怎么被人监督。
6.1 Agent Runtime
Agent Runtime 是 agent 的运行现场。它管理:
loop
state
memory
queue
scheduler
tool calls
sandbox
approval
retry
trace
一个最小 loop 可以理解成:
observe context
-> plan
-> choose tool
-> run tool
-> inspect result
-> ask human if risky
-> write state / produce artifact
-> continue or stop
Runtime 解决的是“agent 活在哪里”:
- 任务从哪里来:event、cron、Lark message、dashboard button。
- 任务状态存哪里:database、queue、Beads、workflow table。
- 工具怎么调用:API、CLI、MCP、SDK。
- 失败怎么重试:retry、dead letter、human escalation。
- 高风险动作怎么拦:approval、policy、scope。
- 结果怎么给人看:dashboard、Lark card、PR、email draft。
不要把 runtime 和模型混在一起。模型负责推理,runtime 负责让推理过程在真实系统里可恢复、可审计、可控制。
Workflow 和 Agent 的边界
Retaintive 现在很多核心能力本质上是 workflow,不应该为了“更 AI”就改成自由 agent:
RingCentral event ingestion
lead email polling
transcript processing
contact / lead analysis pipeline
task creation / update / close
dashboard aggregation
message send logging
这些 workflow 的特点是:
输入清楚
状态机清楚
幂等和重试重要
错误要可恢复
结果要可审计
不能让模型随意修改事实
所以当前正确路线不是“把 workflow 替换成 agent”,而是:
Workflow owns state and lifecycle.
Agent assists with reasoning, language, prioritization, and human interface.
例子:
lead_outreach task created
-> workflow 写入 task
-> agent 解释为什么这是 high priority
-> agent 起草 manager brief 或 follow-up draft
-> human approves if message will be sent
-> workflow 执行发送和 audit
retention task created (UI label: complaint / retention)
-> workflow 写入 retention task
-> agent 总结 complaint history 和建议处理话术
-> manager 审核
-> workflow 记录 outcome / complaint_resolved / audit
daily schedule
-> scheduler 扫描 overdue tasks / missed calls / stale leads
-> agent 生成 morning summary
-> manager 在 dashboard / Lark 里处理
未来可以升级成 agentic workflow,但边界仍然应该保留:
确定性状态变更:
workflow / service layer
模糊判断、语言产物、排序、解释:
agent
外部触达、删除、审批、生产影响:
human approval + policy + audit
6.2 State / Memory / Queue / Scheduler
这些是让 agent 从“一问一答”变成“能持续工作”的关键。
不要把 memory 和 SoT 混为一谈。Memory 可以帮助表达,SoT 决定事实。
6.3 Policy / Approval / Audit
Policy 是刹车系统。
read-only 可以自动
create draft 可以自动
send SMS 必须 human approval
delete customer 禁止 agent 执行
跨 store 数据默认拒绝
Audit 是事后可解释:
谁触发了任务
agent 读了哪些数据
生成了什么 draft
谁批准了
什么时候发出
发给了谁
没有 policy 和 audit,AI Agent 很难进入真实商业工作流。
6.4 Observability / Traces / Evals
Observability 告诉你系统发生了什么。
Trace 告诉你 agent 每一步怎么做的。
Eval 告诉你模型输出有没有变好或变坏。
对 AI 功能来说,只看“有没有报错”不够,还要看:
follow-up 文案是否符合品牌 tone
是否误把低意向 lead 当成高意向 lead
是否重复触达同一客户
是否漏掉关键 objections
是否违反审批规则
长期稳定性靠 eval 和 trace,不靠“我感觉这次回答还行”。
6.5 Product surface
Product surface 是人类使用和监督 agent 的地方:
Web dashboard
Lark card
Slack thread
Email draft
IDE panel
Desktop app
surface 的核心不是“展示 AI 很聪明”,而是让人类可以:
- 看懂 AI 做了什么。
- 编辑 AI 草稿。
- 批准或驳回。
- 追踪结果。
- 发现错误并纠正系统。
Product surface 的两种视角:
老板看到:
待审核 follow-up 草稿
编辑 / 批准 / 驳回按钮
发送结果和效果回流
系统内部实现:
approval_item.status = pending
-> user edits draft
-> approve action checks permission
-> send job enqueued
-> message_sends row written
-> audit log written
7. 怎么选择:API、SDK、CLI、MCP、Skill、UI
7.1 同一个能力可以有多种入口
底层能力是“创建 follow-up 草稿”。它可以同时被 API、SDK、CLI、MCP 和产品 UI 使用:
Web dashboard button
-> internal API / service layer
Backend worker / separate service
-> SDK / generated internal client
-> REST API / service layer
Engineer / CI / Codex / Claude Code
-> CLI
-> REST API / service layer
External AI client
-> MCP tool
-> REST API / service layer
关键原则:入口可以很多,业务规则只能有一份。 权限、计量、审核、幂等、审计都应该在 API 或 service layer 收口,不要复制到每个入口里。
7.2 选择表
7.3 MCP 和 CLI 不是替代关系
MCP 不是 API 的替代品,也不是 CLI 的替代品。它是 AI client 和工具之间的标准协议。
AI client
-> MCP tools/list
-> MCP tools/call(create_follow_up_draft)
-> MCP server
-> retaintive REST API
MCP server 可以直接调 REST API,也可以调用 CLI,但要分场景:
Stripe 现在同时提供 CLI、MCP server、Agent Toolkit,说明这几层不是互斥的,而是面向不同使用者。
7.4 一个 API 要同时做 SDK 和 CLI,需要什么
推荐投入顺序:
MVP 内部使用:
API -> OpenAPI schema -> generated internal client -> thin CLI
长期 developer experience:
API + high-quality OpenAPI schema
-> generated SDK
-> generated or curated CLI wrapping the same client
-> generated MCP / tool schema
-> Skills / docs / tests
8. Retaintive 当前状态和投入顺序
8.1 当前状态
从现有架构文档看,retaintive 当前主要是:
Hono backend API
-> Hono RPC fetch client / AppType
-> frontend web app
这对内部 web app 很好,因为前后端能共享类型。但它不是一套 public OpenAPI-first developer platform。也就是说,我们现在不应该假装已经有 Stripe 式 SDK / CLI / MCP 生态。
两者不是竞争关系:
更准确地说:
Hono = API 怎么实现
OpenAPI = API 怎么被机器和外部系统理解、生成、测试、调用
plain Hono + Hono RPC / AppType 本身仍然是 API,只是它的 source of truth 是 TypeScript route 类型,而不是一份独立的 openapi.json:
所以 plain Hono + Hono RPC / AppType 和 API 不是两层东西;它是一种 API 实现 + 内部 typed client 方式。OpenAPI-first 是在 API 之外再把合同标准化,方便更多机器和外部系统使用。
所以 Retaintive 不需要换掉 Hono。推荐路线是:
保留 Hono backend
-> 给核心 endpoint 补 Zod / OpenAPI schema
-> 生成 openapi.json
-> 生成 internal client
-> 做 thin CLI
-> 以后再生成 public SDK / MCP / docs / sandbox
更具体的阶段拆法:
Phase 1:
用 @hono/zod-openapi 做 /v3/agent 的 3-5 个核心 endpoint
Phase 2:
openapi.json -> generated internal client
Phase 3:
thin CLI 调 internal client
Phase 4:
Botmux / Codex / CI 用 CLI 操作 Retaintive
Phase 5:
如果以后真的开放给客户或 partner:
Speakeasy / Fern / Stainless 生成 public SDK / docs / CLI / MCP
@hono/zod-openapi 的典型写法是:
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
const CreateDraftInput = z.object({
store_id: z.string(),
lead_id: z.string(),
tone: z.enum(["friendly", "concise", "professional"]).optional(),
}).openapi("CreateDraftInput");
const DraftResponse = z.object({
draft_id: z.string(),
status: z.literal("pending_approval"),
message: z.string(),
}).openapi("DraftResponse");
const createDraftRoute = createRoute({
method: "post",
path: "/follow-up-drafts",
operationId: "createFollowUpDraft",
tags: ["follow-up"],
request: {
body: {
content: {
"application/json": {
schema: CreateDraftInput,
},
},
},
},
responses: {
201: {
description: "Follow-up draft created",
content: {
"application/json": {
schema: DraftResponse,
},
},
},
},
});
export const agentRoutes = new OpenAPIHono();
agentRoutes.openapi(createDraftRoute, async (c) => {
const body = c.req.valid("json");
const draft = await followUpService.createDraft(body);
return c.json(draft, 201);
});
agentRoutes.doc("/openapi.json", {
openapi: "3.0.0",
info: {
title: "Retaintive Agent API",
version: "1.0.0",
},
});
再把它 mount 到现有 Hono app:
app.route("/v3/agent", agentRoutes);
这说明 OpenAPIHono 适合新 route group,不要求把整个现有 app 一次性改写。
OpenAPI-first 不代表以后不能改 API。区别是:一旦它变成 contract,每次修改都要按兼容性处理:
内部-only API 可以更快改;external / agent-facing API 要更稳。现实做法是版本化和扩展优先:
/v3/agent/follow-up-drafts
-> 新增字段优先 optional
-> breaking change 新开 /v4 或新 operationId
-> old endpoint 保留一段 deprecation window
已有 route 很多时,全量迁移成本高,不是因为 OpenAPIHono 本身难,而是因为迁移会牵动每个 endpoint 的边界合同:
request schema
response schema
error schema
auth / scope
tenant / store access
operationId / tags
tests
frontend hc<AppType> 调用
如果只是为了“看起来 OpenAPI-first”重写所有 route,风险大于收益。更合理的是只把 agent、CLI、partner 真会用的能力先合同化。
前端如果仍是我们自己的 web app,hono/client + AppType 仍然适合:
import { hc } from "hono/client";
import type { AppType } from "./server";
const client = hc<AppType>("https://api.retaintive.com");
这里 frontend 只 import TypeScript type,不会把 server runtime bundle 进前端。它解决的是同一个 TypeScript monorepo 内部的 end-to-end type safety。
但它不等于 OpenAPI-first developer platform。CLI、MCP、外部 partner、跨语言 SDK、contract tests 更应该基于 openapi.json:
openapi.json
-> openapi-typescript + openapi-fetch
-> generated internal client
-> thin CLI
如果要生成 Vue Query / MSW mock,可以看 Orval;如果以后要做公开的 SDK / docs / CLI / MCP suite,再评估 Speakeasy / Fern / Stainless。
如果我们不把 SDK / CLI 暴露给 external people,只做内部 AI agent,也不一定一开始就需要 public SDK 或 public CLI。选择取决于 agent 跑在哪里:
因此,内部 agent 的 MVP 可以不做 public SDK;但如果 agent 不是直接运行在 backend 进程里,而是在 Botmux / Codex 这种 CLI runtime 里,thin CLI + generated internal client 会很有价值。
一句话判断:plain Hono + Hono RPC / AppType 是现在内部开发的快路;@hono/zod-openapi 是未来新 agent-facing API 的稳路;hono-openapi 是老 route 的迁移路。
类比:
Hono backend API = 厨房里的做菜流程
OpenAPI-first developer platform = 对外菜单、点餐合同、配送规则和测试厨房
8.2 MVP 必须做
1. Domain model / SoT
store、contact、call、lead、follow_up_draft、approval、usage_event、audit_log
2. API
创建 draft、列审核队列、批准发送、记录 usage、记录发送结果
3. OpenAPI schema
至少覆盖核心 API 的 request、response、error、auth、operationId 和 examples
4. Generated internal client / thin CLI
给工程师、CI、Codex、Botmux 一个稳定操作面,不需要一开始发布 public SDK
5. LLM Gateway
所有 LLM 调用统一经过这里
6. Usage metering
per-client / per-store 用量记录,支持套餐和超额
7. Human approval
AI 只能出 draft,不能直接发 SMS / WhatsApp / Email
8. Basic product surface
审核队列、编辑、批准、驳回、发送记录
9. Audit log
谁生成、谁改、谁批准、发给谁、何时发送
8.3 MVP 可以先不做
多语言官方 SDK
公开 CLI
公开 MCP server
复杂 multi-agent runtime
长期 memory
自动 schedule UI
多模型复杂动态路由
客户自带 ChatGPT/Claude 连接
注意:不是永远不做,而是不要在业务状态还没稳定前做。
8.4 长期稳定性必须补
public SDK / public CLI
webhooks / event stream
sandbox / test mode
MCP server 或 hosted MCP integration
policy engine
evals / traces / regression suite
integration health check
rate limit / quota / billing reconciliation
8.5 推荐投入顺序
Phase 1: data model + API + OpenAPI schema + approval + usage metering
Phase 2: generated internal client + thin CLI
Phase 3: stabilize task workflow, especially lead_outreach / lead_follow_up / retention task lifecycle
Phase 4: agent-assisted task summaries, morning summary, and review / complaint-handling drafts
Phase 5: recall / campaign Skill, 加 human approval + touch channel
Phase 6: RingCentral / POS / review platform events, 建闭环
Phase 7: LLM Gateway + audit log + basic evals 深化
Phase 8: Lark / Botmux control plane, 放进真实工作流
Phase 9: public SDK / generated CLI / MCP server, 面向客户或 partner
为什么先做 task workflow 和 agent-assisted summaries,再做主动召回:
lead_outreach / lead_follow_up / retention task、overdue task 更接近现有 Retaintive workflow。
- Agent 可以先做摘要、解释、草稿和排序,不直接拥有 task lifecycle。
- 先做 draft 和 approval,比直接自动触达风险低。
- 主动召回会触达真实客户,必须先有 approval、audit、usage metering 和发送日志。
- 低风险场景能先验证 LLM Gateway、计量、UI、权限模型。
9. 什么自己做,什么不要重复造
9.1 不要重复造
9.2 必须自己做
10. Codex、Claude Code、Botmux、lark-cli 的关系
2026-06-15 本机验证快照:
codex-cli 0.139.0
Claude Code 2.1.172
botmux 2.34.0
lark-cli 1.0.52
这些工具的关系:
几个容易混的概念:
Codex CLI = /opt/homebrew/bin/codex 这个可执行程序
Codex CLI session = 一次运行中的 Codex 对话/任务上下文
Botmux session = Lark chat/thread/topic 映射到一个 CLI session
openai/codex repo = Codex CLI 的开源源码,不等于每次使用都要 clone
所以 Botmux 使用 Codex 时,通常是启动本机已安装的 codex 命令,不是把 openai/codex repo 当作项目依赖 clone 进来。版本号只是当前机器快照,长期文档判断应以官方 docs、command --version 和实际部署配置为准。
11. 传统 API 公司怎么 AI-native 化
成熟 API 公司通常会从 API 往上补开发者体验,再补 AI-native 工具层:
API
-> OpenAPI schema
-> generated docs / SDK / CLI / test fixtures
-> sandbox / logs / webhook tooling
-> MCP / Agent Toolkit / Skills
-> runtime / workflow / approval / audit
几个参考模式:
对传统 API 公司来说,AI-native 不是把 ChatGPT 接到客服入口就结束,而是:
把业务能力变成机器可读合同
把合同生成稳定操作面
把操作面放进可审批、可审计、可观察的 runtime
12. 最终判断
你真正要学会的不是“怎么写一个 CLI”或“怎么接一个 MCP server”,而是这套 platform thinking:
先定义业务事实和权限边界,再把能力包成 API,并用 OpenAPI schema 固化合同;之后尽量生成 SDK / CLI / MCP / docs,再做少量产品化包装;需要 agent 持续执行时加 runtime;所有外部影响动作都必须经过 policy、approval、audit。
对 retaintive 来说,最应该投入的不是重造 agent runtime,而是:
- 把 gym / studio 业务对象建成清晰 SoT。
- 把 AI 输出变成 draft + approval + audit 的状态机。
- 把所有 LLM 调用收进 LLM Gateway。
- 把 usage metering 从第一天做成一等公民。
- 把触达、回流、效果分析做成闭环。
- 用 OpenAPI + generator + Codex / Claude Code / Botmux / lark-cli / MCP 作为工具层,而不是从零造。
一句话版本:
API 是地基,OpenAPI 是机器可读合同,SDK / CLI / MCP 是从合同长出来的操作面,Skill 是 SOP,Runtime 是执行现场,Policy 是刹车。retaintive 要赢,重点不在重复造工具,而在把健身房客户运营这套业务事实和审核闭环做扎实。
Sources