# IELTS Buddy 的扩展工程经验

本参考从 IELTS Buddy 的当前工程约定、架构快照、能力契约和发布／可观测性文档中提炼。第 1、2、5、6、7 节是多端或长期运行项目可按需采用的通用经验；第 3、4 节只在明确需要对外 Agent API 或站内 Agent 时阅读。不应把成熟产品的多应用拓扑和门禁倒灌到刚起步的小项目。

## 1. 需要 BFF 时，保持它是薄适配层

浏览器需要 HttpOnly Cookie 转发、服务端凭据隔离、上传代理、协议转换或流式代理时，Web BFF 可以是有价值的边界：

```text
浏览器
  -> 同源 BFF
  -> 业务 API
  -> 领域服务
  -> 数据库
```

BFF 只处理 Cookie／凭据转发、参数适配、请求体限制、上传、流式响应和浏览器错误呈现；业务写入、授权和持久化仍在 API。流式聊天可保持上游的流与必要状态码，不强制转换成普通 JSON。若没有这些边界，直接使用 API，避免多一层网络与重复错误处理。

在 API／BFF 边界使用同一份严格 schema，拒绝非法 JSON、未知字段、缺失字段和不符合限制的输入。不可把解析失败静默改成空对象。高风险的 BFF 响应应校验上游结构，并保留真实 HTTP 状态；只有本地会话无效才清理本地登录态，不能将一般 5xx 误判为用户退出。

## 2. 共享代码按运行时依赖而非名称划分

IELTS Buddy 的包边界给出了一个实用的上限：

- 共享 request／response schema、领域 command 和凭据边界放在一个 schema 包；
- 仅供编译期的类型、枚举和常量放在零运行时依赖的类型包；
- 多应用复用且无业务状态的纯函数放在 utilities 包；
- 数据库、网络 client、云 SDK、用户上下文和领域服务留在所属应用；
- 共享 UI 只提炼已经跨应用重复的基础组件与 design token。

这避免了“shared”变成依赖所有东西的黑洞，也不要求单应用在没有重复时提前拆包。路由只负责身份与 schema 入口，service 拥有业务规则；BFF 和 Agent Service 都不能直接变成业务数据库的写入权威。

## 3. 仅在对外 Agent API 或能力分发时：一个 Capability 定义服务多个受控入口

当同一业务能力同时由网站、站内 Agent、对外 Agent API 或公开清单使用时，建立一个编译期 capability 注册表，作为 ID、描述、输入 schema、认证、scope、side effect 与破坏性标记的唯一来源。所有入口从这份定义生成或绑定，不能在网页、API、manifest 和 Skill 中各维护一份工具描述。

公开 discovery 只暴露实时、受审查的能力摘要。对外 API 应以“读取事实、受约束状态写入、稳定引用和 deep link”为核心；不要把网站专属的长交互、正式作答生命周期、浏览器动作或服务端 AI 判断包装成任意远程操作。管理员能力另设注册表和最小权限检查，成功写入保留审计记录。

若需要把可安装 Skill 分发给用户，公开 Skill 仓库独立于主产品仓库，采用版本化 API／manifest 协作。主产品不在运行时生成 Skill 文件，也不把内部题库、用户资料、部署细节或私有 workflow 复制进公开 Skill。

## 4. 仅在有 Agent 时：运行事实、业务事实和审计事实分开

连续对话从服务端有序消息日志恢复；模型看到的紧凑 Tool observation 与能力记录只服务上下文承接。完整 Run、步骤、调用尝试、用量、错误和最终消息持久化状态属于审计；计划、练习、资产等领域实体属于业务事实。三者不可相互代替。

对有外部副作用的 Agent 操作，区分用户意图（action）与实际执行（attempt）。执行成功但尚未读回验证、被幂等重放替代、取消、过期和最终消息持久化失败，应各自有真实含义；不能全都压缩为“Agent 失败”。这一分层只在产品已经需要可恢复执行和运行审计时引入，普通聊天不必预建完整状态体系。

## 5. 可观测性为诊断服务，而非预建平台

将入站请求 ID（缺失时生成）贯穿 BFF、API、外部调用、Agent run 和审计记录。API 统一输出服务端耗时；前端异常进入已有产品事件通道；浏览器 smoke 报告应包含 URL、console／page error 和截图路径，而非只有退出码。

日志、分析和 smoke 产物只用 request ID、run ID、版本等最小关联字段；不得记录 token、Cookie、完整手机号、原始用户文本、音频或未脱敏 prompt。性能优化前记录可比较基线，如 p50／p95、错误率、构建大小、Agent 终态失败率或业务成功率；不因单次慢请求新建性能平台或做结构重写。

## 6. 发布、迁移和故障证据

发布链路应有唯一所有权：构建特定提交产物、准备候选、执行获准的在线迁移、健康检查、切流和回退各有明确责任。复杂的长期运行项目可使用 migration ledger／checksum，确保同一 SQL 不被悄悄改写或重复执行；新项目不必为此先造一套迁移平台，但已应用迁移永不改写仍是底线。

在线 schema 变化采用扩展 → 应用切换 → 收缩。候选启动或切流失败时，保持旧服务，不要把数据库回退想象成代码回退。备份频率、镜像清理、回退槽数和发布门禁是项目运行策略，必须由负责人明确决定，不能从 IELTS Buddy 或 Study Buddy 自动照搬。

发布完成的证据不仅是容器 healthy：还应能核对活跃版本／流量指向、迁移水位、关键 API 就绪以及浏览器关键链路。选择与风险相称的检查，避免把所有生产流程一律升级为重型发布仪式。

## 7. 文档从小索引逐步长成知识体系

项目小的时候，顶层 `AGENTS.md`、`docs/README.md` 和少数当前契约已经足够。随着架构、能力、工程和数据问题开始有不同读者，再分为对应子目录并各设索引。带核验日期的“当前实现快照”尤其适合多应用项目：从实际 manifest、入口文件、Schema、迁移和部署配置重新核对当前拓扑，并列出已知差异。

维护整改、发布审计、故障复盘、迁移 runbook 和实验设计要与当前规范分开。它们提供历史证据，不能反向成为所有新功能的强制流程。文档越多，越需要明确哪一份是当前事实、哪一份只是历史或计划。

## 采纳检查

采纳上述经验前，逐项回答：当前具体问题是什么？是否已有第二个调用方／端？能否由现有模块内部解决？新增层会让调用者少知道什么？如何验证它不复制业务权威或泄漏数据？若答案仍是“以后可能会用”，保持现有更小的设计。
