共计 4037 个字符,预计需要花费 11 分钟才能阅读完成。
背景痛点:为什么需要封装 Skill?
裸写 Skill 代码时,开发者常遇到以下典型问题:

- 硬编码逻辑 :业务规则直接写在事件回调里,修改需求时需要全局搜索替换
- 缺乏错误隔离 :一个第三方 API 调用失败导致整个 Skill 崩溃
- 状态管理混乱 :用全局变量维护对话状态,并发请求时数据互相覆盖
- 扩展成本高 :新增功能时需重构核心逻辑,违反开闭原则 (OCP)
以电商退货场景为例,原始代码可能长这样:
// 反例:所有逻辑耦合在单个处理器中
app.handle('return_request', async (req) => {
const orderId = req.query.orderId; // 直接访问原始请求
const user = getUserFromSession(); // 隐含依赖全局状态
if (!orderId) return {error: 'Missing orderId'}; // 非结构化错误
try {const order = await legacyDB.query(`SELECT * FROM orders...`); // SQL 注入风险
if (order.status !== 'delivered') throw new Error('Invalid status');
await thirdPartyAPI.refund(orderId); // 无重试机制
return {success: true}; // 非标准响应格式
} catch (e) {console.error(e); // 直接吞没错误
throw e; // 向上抛出原始错误
}
});
分层架构设计
采用经典的三层架构,各层职责如下:
- API 层 (Interface Layer)
- 请求 / 响应数据标准化
- 身份认证与授权
-
协议转换(如 HTTP 到内部 DTO)
-
业务层 (Domain Layer)
- 核心业务逻辑编排
- 事务边界控制
-
异常转换
-
持久层 (Data Layer)
- 数据访问抽象
- 缓存策略
- 第三方服务熔断
层间通过接口抽象通信,例如业务层定义:
interface IOrderRepository {getOrderById(id: string): Promise<Order>;
createReturn(request: ReturnRequest): Promise<ReturnTicket>;
}
核心实现细节
标准化请求验证
使用 Zod 实现类型安全的请求校验:
// 定义请求契约
const ReturnRequestSchema = z.object({orderId: z.string().uuid(),
reason: z.enum(['damaged', 'wrong_item']),
attachments: z.array(z.string().url()).optional()});
type ReturnRequest = z.infer<typeof ReturnRequestSchema>;
// 验证中间件
const validate = (schema: z.ZodSchema) => {return (req: Request) => {const result = schema.safeParse(req.body);
if (!result.success) {throw new ValidationError(result.error); // 统一错误类型
}
return result.data;
};
};
状态机管理多轮对话
使用 XState 实现退货流程:
stateDiagram-v2
[*] --> Init
Init --> Validation: submit_request
Validation --> Approval: requires_approval
Validation --> Processing: auto_approve
Approval --> Processing: manager_approved
Approval --> Rejected: manager_rejected
Processing --> Completed: refund_success
Processing --> Failed: refund_failed
对应实现代码:
const returnMachine = createMachine({
id: 'return',
initial: 'init',
states: {
init: {on: { SUBMIT: 'validation'}
},
validation: {
invoke: {
src: 'validateOrder',
onDone: [{ target: 'approval', cond: 'needsApproval'},
{target: 'processing'}
],
onError: 'failed'
}
}
// ... 其他状态
}
});
带重试的第三方调用
实现指数退避重试策略:
def call_with_retry(
func: Callable,
max_retries: int = 3,
initial_delay: float = 0.1
) -> Any:
retry_count = 0
delay = initial_delay
while retry_count <= max_retries:
try:
return func()
except TransientError as e:
if retry_count == max_retries:
raise
sleep(delay)
delay *= 2 # 指数退避
retry_count += 1
代码规范实践
使用 Decorator 进行权限校验
function requireRole(role: UserRole) {
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {const context = getCurrentContext();
if (!context.user.roles.includes(role)) {throw new ForbiddenError(`Requires ${role} role`);
}
return original.apply(this, args);
};
};
}
class OrderController {@requireRole('CSR')
async approveReturn(id: string) {// 业务逻辑}
}
单元测试样例
测试验证逻辑的三种场景:
describe('ReturnRequest Validation', () => {
// 正常案例
it('should accept valid request', () => {const validReq = { orderId: 'd3b8a1...', reason: 'damaged'};
expect(() => ReturnRequestSchema.parse(validReq)).not.toThrow();});
// 边界案例
it('should reject empty reason', () => {const invalidReq = { orderId: 'd3b8a1...', reason: ''};
expect(() => ReturnRequestSchema.parse(invalidReq)).toThrow();});
// 错误案例
it('should reject invalid UUID', () => {const invalidReq = { orderId: '123', reason: 'damaged'};
expect(() => ReturnRequestSchema.parse(invalidReq)).toThrow();});
});
生产环境关键考量
并发控制方案
使用 Redis 实现分布式锁:
def process_return(order_id):
lock_key = f"return_lock:{order_id}"
# 获取锁(设置 10 秒过期)if not redis.set(lock_key, 1, nx=True, ex=10):
raise ConcurrentModificationError()
try:
# 核心业务逻辑
return process_refund(order_id)
finally:
# 释放锁
redis.delete(lock_key)
敏感数据处理
加密存储 OAuth token:
class TokenStorage {constructor(private crypto: CryptoService) {}
async saveToken(userId: string, token: string) {
const encrypted = await this.crypto.encrypt({
keyId: 'kms_key_1',
data: token
});
await db.tokens.upsert({where: { userId},
data: {encryptedToken: encrypted}
});
}
}
五大典型反模式与修复
- 上帝对象 (God Object)
- 反例:单个类处理所有业务逻辑
-
修复:按单一职责原则拆分
-
过度暴露实现
- 反例:返回完整的数据库模型
-
修复:定义独立的 DTO 类
-
忽略幂等性 (Idempotency)
- 反例:重复请求导致多次扣款
-
修复:设计幂等键 (idempotency key)
-
阻塞式 IO
- 反例:同步调用外部服务
-
修复:改用异步非阻塞模式
-
魔法字符串 (Magic String)
- 反例:if (status === ‘APPROVED’)
- 修复:使用枚举或常量
总结与思考
通过分层设计和契约编程,我们构建出具备以下特性的 Skill 组件:
- 可测试性:各层接口明确,便于 mock
- 可观测性:关键路径埋点完善
- 容错能力:错误隔离 + 自动恢复
值得深入探讨的问题:
1. 在微服务架构下,如何平衡 Skill 的自治性与跨服务一致性?
2. 当业务规则频繁变化时,有哪些动态策略配置的最佳实践?
正文完
发表至: 软件开发
近一天内
