前端开发者转 AI 工程:别只会调 API,用 1 个客服 Agent 交付作品

4 阅读10分钟

作者:前端转 AI 深度实践者

【省流助手/核心观点】:前端开发者转 AI 工程,真正的分水岭不是“会不会调大模型 API”,而是能不能把模型放进一个可控的工程系统里。一个可交付的 AI 项目,至少要具备结构化输出、RAG、Tool Calling、Agent Loop、失败处理、可观测性、安全边界和测试场景。30 天训练的毕业项目,不应该追求炫,而应该追求清楚、可靠、可复盘。


很多前端开发者开始学 AI,第一目标通常是:

我想把大模型接进项目里。

这是一个好起点。

但如果 30 天后,你只是会写:

await client.chat.completions.create({
  model: "xxx",
  messages: [{ role: "user", content: "帮我总结一下" }]
});

那还不够。

因为真实 AI 工程不是“调一下模型,然后把文本显示到页面上”。

真实 AI 工程要面对:

  • 模型输出不稳定。
  • 用户问题不标准。
  • 资料检索不准确。
  • 工具参数会出错。
  • 外部接口会失败。
  • 高风险操作不能直接执行。
  • 线上问题需要排查。
  • 团队需要能维护。

所以第 30 篇不再引入一个新概念。

我们做一件更重要的事:

把前面学过的能力,组合成一个可交付的小项目。

1. 痛点:只会调 API,离交付 AI 工程还差很远

很多 AI demo 的代码长这样:

async function askAi(question: string) {
  const response = await llm.chat(question);
  return response.text;
}

这段代码不是没用。

它能帮你迈出第一步。

但它不能回答工程问题:

  1. 模型返回 JSON 失败怎么办?
  2. 答案有没有引用来源?
  3. 用户问订单时,数据来自哪里?
  4. 工具调用失败后怎么停?
  5. 高风险操作谁来确认?
  6. 用户反馈“AI 不靠谱”时怎么排查?

如果这些问题都没有答案,它就只是一个 demo。

能交付的 AI 工程项目,必须把模型、数据、工具、流程、安全、日志和测试组合起来。

2. 毕业项目:AI 客服 Agent

这个毕业项目可以叫:

AI 客服 Agent

它不需要一开始就接真实大模型,也不需要接真实数据库。

你可以用 mock 数据、mock 模型和本地页面完成。

重点不是“看起来多智能”。

重点是它有没有 AI 工程项目该有的结构。

它至少应该能处理:

  • 查询订单状态。
  • 查询售后政策。
  • 判断是否需要创建客服工单。
  • 对高风险操作进行确认。
  • 遇到失败时重试、降级或停止。
  • 输出 trace、事件日志和运行报告。

这听起来不像一个玩具 demo。

它已经开始像一个系统。

3. 30 天应该怎么拆?

可以按 4 个阶段推进。

第 1 周:会调模型,但不相信模型
第 2 周:接入 RAG,让答案有依据
第 3 周:接入 Tool Calling,让系统能办事
第 4 周:补 Agent Loop、失败处理、安全和可观测性

每周的目标不是“学更多概念”,而是交付一个能跑的切片。

第 1 周:结构化输出和兜底

你要做到:

  • 模型返回结构化 JSON。
  • 程序能校验输出。
  • 解析失败时能兜底。
  • 页面能展示成功态和错误态。

第 2 周:RAG 和引用来源

你要做到:

  • 用户问题能检索知识库。
  • 答案带引用来源。
  • 资料不足时拒答。
  • 能看见命中的 chunks。

第 3 周:Tool Calling 和工具 Schema

你要做到:

  • 模型能提出工具调用。
  • 程序能校验工具名和参数。
  • 工具有风险等级和权限要求。
  • 高风险工具不会自动执行。

第 4 周:Agent 工程化

你要做到:

  • Agent 能按计划多步执行。
  • 失败时能 retry、fallback、pause、stop。
  • 每次运行有 trace 和结构化事件。
  • 至少覆盖 6 个测试场景。

4. 错误做法:把所有东西塞进一个函数

很多毕业项目会写成这样:

async function runAiCustomerService(question: string) {
  const prompt = `你是一个客服助手,请回答:${question}`;
  const answer = await llm.chat(prompt);
  return answer;
}

或者稍微复杂一点:

async function runEverything(question: string) {
  const intent = await llm.chat(`判断用户意图:${question}`);
  const docs = await searchDocs(question);
  const order = await getOrderStatus(question);
  const answer = await llm.chat(`
意图:${intent}
资料:${JSON.stringify(docs)}
订单:${JSON.stringify(order)}
请回答用户。
`);

  return answer;
}

这种写法一开始很快,但后面会很痛。

因为 Prompt、检索、工具调用、权限、失败处理、日志、最终回答全混在一起。

一旦用户说“答案不对”,你很难判断到底是哪一层出了问题。

5. 正确做法:把 AI 项目拆成 7 层

一个可交付的 AI 客服 Agent,可以拆成 7 层:

用户输入
-> 意图识别 / mockModel
-> RAG 检索 searchDocs
-> 计划生成 createPlan
-> 工具执行 runToolSafely
-> 失败处理 handleStepFailure
-> 最终回答 + 运行报告

代码目录可以这样组织:

src/ai-customer-agent/
  mock-data.ts
  tools.ts
  tool-registry.ts
  rag.ts
  planner.ts
  executor.ts
  safety.ts
  observability.ts
  demo.ts

注意,这里最重要的不是文件多。

而是边界清楚。

每一层都能单独测试、单独替换、单独排查。

6. 最小类型设计:先把工程边界写出来

先定义毕业项目的核心类型:

type AgentTask =
  | "check_order"
  | "check_policy"
  | "create_ticket"
  | "cancel_order";

type PlanStep = {
  id: string;
  goal: string;
  task: AgentTask;
  toolName: string;
  args: Record<string, unknown>;
  status:
    | "pending"
    | "running"
    | "done"
    | "failed"
    | "skipped"
    | "paused"
    | "fallback";
  observation?: unknown;
  error?: unknown;
};

type AgentRunResult = {
  ok: boolean;
  answer: string;
  plan: PlanStep[];
  events: AgentEvent[];
  report: AgentRunReport;
};

这些类型会逼你思考:

  • 任务类型有哪些?
  • 每一步要调用什么工具?
  • 步骤有哪些状态?
  • 运行结果要返回什么?
  • 排查时需要看哪些信息?

这就是工程化的价值。

7. 工具不是函数列表,而是能力契约

毕业项目至少要有 4 个工具:

getOrderStatus(orderId)
searchPolicy(keyword)
createSupportTicket(orderId, issue)
cancelOrder(orderId)

但不要只写函数。

还要写工具配置:

type ToolDefinition = {
  name: string;
  description: string;
  riskLevel: "low" | "medium" | "high";
  requiredPermission: string;
  requiresConfirmation: boolean;
  handler: (args: Record<string, unknown>) => Promise<unknown>;
};

const getOrderStatusTool: ToolDefinition = {
  name: "getOrderStatus",
  description: "查询订单物流状态,不用于取消订单或发起退款。",
  riskLevel: "low",
  requiredPermission: "order:read",
  requiresConfirmation: false,
  handler: async (args) => {
    return {
      orderId: args.orderId,
      status: "shipping",
      eta: "2026-05-10"
    };
  }
};

这份配置代表很多工程意识:

  • 工具是做什么的。
  • 参数需要什么。
  • 风险有多高。
  • 用户需要什么权限。
  • 是否需要确认。

函数解决“怎么做”。

Schema 和配置解决“什么时候能做、谁能做、怎么安全地做”。

8. Agent 不能只会成功路径

毕业项目必须覆盖失败路径。

至少支持这些错误:

type ToolErrorType =
  | "timeout"
  | "not_found"
  | "empty_result"
  | "permission_denied"
  | "confirmation_required"
  | "invalid_arguments";

处理策略也要清楚:

const failureStrategies = {
  timeout: "retry",
  empty_result: "fallback",
  not_found: "stop",
  permission_denied: "stop",
  confirmation_required: "pause",
  invalid_arguments: "stop"
} as const;

这很重要。

真实用户不会只走你精心设计的成功路径。

他们会问错订单号,会没有权限,会遇到空政策,会触发高风险动作。

一个能上线的 AI 功能,必须能体面地失败。

9. 可观测性是毕业项目的必选项

毕业项目每次运行都应该返回:

type AgentRunPayload = {
  answer: string;
  report: AgentRunReport;
  events: AgentEvent[];
  plan: PlanStep[];
};

其中:

  • answer 是给用户看的最终回答。
  • report 是给开发者看的运行摘要。
  • events 是可追踪的结构化日志。
  • plan 是 Agent 的执行过程。

这套输出会让你具备复盘能力。

用户说“AI 回答不对”时,你能看到:

  • 创建了什么计划。
  • 调用了哪些工具。
  • 哪一步失败。
  • 是否重试。
  • 是否降级。
  • 最终答案依据什么生成。

没有可观测性的 Agent,就是一个看起来很自信但无法复盘的黑盒。

10. 安全边界决定它能不能接真实业务

AI 客服 Agent 里最危险的工具是:

cancelOrder(orderId)

这个工具不能直接执行。

即使用户说:

帮我取消订单 A1001。

系统也应该先返回确认请求:

type ConfirmationRequest = {
  toolName: "cancelOrder";
  argsSummary: string;
  message: string;
  status: "pending";
};

用户确认后再执行。

这不是“AI 不够智能”。

这是系统负责。

任何有副作用、不可逆、会影响用户权益的工具,都必须有权限和确认。

模型可以建议动作,但程序必须掌握执行权。

11. 毕业项目的 6 个测试场景

一个合格的毕业项目,至少要覆盖这些场景:

  1. 普通用户查询订单成功。
  2. 订单不存在,Agent 停止并说明。
  3. 查询订单延迟补偿,结合订单和政策回答。
  4. 政策为空,Agent 降级且不编造。
  5. 普通用户创建工单,权限不足。
  6. 客服用户取消订单,先确认,确认后执行。

这 6 个测试很朴素,但覆盖了 AI 工程最重要的几类路径:

  • 成功。
  • 失败。
  • 降级。
  • 权限不足。
  • 高风险确认。
  • 可追踪输出。

如果你的项目能把这些跑清楚,就已经比很多“只有成功路径”的 AI demo 更扎实。

12. 生产环境避坑指南

1. 不要一开始就接真实模型和真实写入工具

先用 mockModel 和 mock data 跑通工程骨架。

等流程稳定后,再替换真实模型和真实后端。

2. 不要把工具越接越多

毕业项目 4 个工具就够。

工具少而清晰,比工具多而混乱更像工程项目。

3. 不要只验收最终答案

必须同时检查 answerplaneventsreport

只看最终答案,很容易漏掉中间步骤的错误。

4. 不要把安全确认留到最后补

只要工具有副作用,权限和确认就应该从第一版设计进去。

后补安全边界,往往会改动整个执行链路。

5. 不要用“看起来聪明”当验收标准

验收标准应该是:

  • 是否能稳定跑完 6 个测试场景?
  • 失败时是否能停止或降级?
  • 高风险操作是否会暂停确认?
  • 每次运行是否可复盘?

13. 前端开发者这 30 天真正学到了什么

从前端转 AI 工程,不是把 JavaScript 忘掉,然后从零变成算法工程师。

更现实的路线是:把你的工程经验迁移过来。

你已经懂:

  • 状态管理。
  • API 契约。
  • 表单校验。
  • 错误态。
  • loading 和 empty。
  • 权限按钮。
  • 确认弹窗。
  • 埋点和日志。
  • 前后端联调。

这些在 AI 工程里全部有对应物:

  • messages 是状态。
  • Tool Schema 是 API 契约。
  • 参数校验是表单校验。
  • empty_result 是 empty state。
  • confirmation_required 是确认弹窗。
  • traceId 是 requestId。
  • Agent Loop 是状态和副作用循环。
  • RAG 评估是质量回归。

所以你不是跨到一个完全陌生的行业。

你是在把已有工程能力,扩展到模型、检索和工具系统上。

14. 30 天后的下一步

完成毕业项目后,可以继续往这些方向深入:

  • mockModel 换成真实大模型。
  • 用 FastAPI 或 Node.js 把 Agent 封成后端服务。
  • 做一个前端聊天页面。
  • 接入真实向量检索。
  • 把 events 写入数据库。
  • 做一套 Agent 评测集。
  • 增加更严格的权限和审计。
  • 学习生产级 Agent 框架。

但无论往哪走,都不要丢掉这 30 天建立的底层判断:

AI 工程不是让模型独自表演,而是把模型、数据、工具、流程、安全和观测组合成可靠系统。

## 结语

30 天训练的终点,不是“学完了 AI”。

它只是把你从门口带到了第一块真正的工程地面上。

你已经不只是知道怎么调用模型。

你开始知道怎么约束模型,怎么给模型工具,怎么处理失败,怎么追踪过程,怎么保护高风险动作,怎么把一个 AI 功能做成能被团队维护的小系统。

这就是前端开发者转 AI 工程最重要的一步:

**从“让模型回答”,走向“让系统可靠”。**