← 返回首页 循序渐进 · 从代码到运行 · 实战导向

如何构建一个 Agent

每一节都从"我想要某个效果,但当前 chat 做不到"开始,然后新增一个能力。

总览:一个最小 Agent 的调度流程

你会不断循环"下一步决策",在需要信息时调用工具,在需要套路时运行技能,产出后自检,通过后才交付。

用户目标 → State → {下一步?} → TOOL/WRITE/FINAL → 检查 → 交付
步骤 1

从 Chat MVP 开始

需求:先让它能"一问一答"。这一步不是 Agent,但它是后续一切能力的底座。

用户输入 → 模型生成回复 → 输出
export async function chat(message: string) { const reply = await llm.generate({ input: message }) return reply }
步骤 2

我想要更可用的输出 → 加结构化输出

缺口:纯文本经常跑偏。解决:强制一个稳定格式,让"聊天"变成"可交付的结构"。

用户输入 → 加输出约束 → 生成 → 结构化结果
type Output = { title: string; bullets: string[]; next: string[] } export async function chatWithFormat(message: string): Promise<Output> { const reply = await llm.generate({ input: message, instructions: [ "请输出 JSON:{ title, bullets[], next[] }", "bullets 最多 5 条,next 最多 3 条" ] }) return JSON.parse(reply) }
步骤 3

我想做复杂任务 → 加计划(Plan)

缺口:复杂任务一次写完容易漏。解决:先拆成 3-6 步可执行步骤,后续逐步补信息与修正。

目标 → 拆成 3-6 步 → 步骤列表
type Plan = { steps: string[] } export async function makePlan(goal: string): Promise<Plan> { const text = await llm.generate({ input: goal, instructions: ["把目标拆成 3-6 个可执行步骤"] }) return { steps: text.split("\n").filter(Boolean) } }
步骤 4

我想要外部信息/动作 → 加工具(Tools)

缺口:模型会"凭印象猜"。解决:工具把"查/算/读/写"变成可调用动作,拿到结果再继续推进。

Agent → 调用工具 (参数) → 工具返回结果 → Agent 写回状态
type Tool = { name: string run: (input: any) => Promise<any> } const tools: Record<string, Tool> = { weather: { name: "weather", run: async (input) => ({ summary: "周六小雨" }) }, transit: { name: "transit", run: async (input) => ({ summary: "高铁约 30-45 分钟" }) } } export async function callTool(name: string, input: any) { return tools[name].run(input) }
步骤 5

让它可以持续运行 → 循环(Loop)

缺口:一次调用只能得到一个回复。解决:写一个调度器,每轮决定下一步做什么,直到完成任务。

Decide → Tool → Decide → Write → Check → Done
type State = { goal: string plan: string[] notes: string[] } export async function runAgent(goal: string) { const plan = await makePlan(goal) const state: State = { goal, plan: plan.steps, notes: [] } for (let i = 0; i < 8; i++) { const next = await llm.generate({ input: JSON.stringify(state), instructions: ["决定下一步:TOOL:xxx / WRITE:xxx / FINAL:xxx"] }) if (next.startsWith("FINAL:")) return next.slice(6) if (next.startsWith("TOOL:weather")) { const obs = await callTool("weather", { city: "苏州" }) state.notes.push(`weather: ${obs.summary}`) continue } if (next.startsWith("WRITE:")) { state.notes.push(next.slice(6)) continue } } return "未完成:达到最大步数" }
步骤 6

记住用户偏好 → 记忆(Memory)

缺口:每次都重新问用户同样的问题。解决:读写可复用结论,下次直接加载。

偏好/历史 → 上下文 → 运行 → 写入可复用结论 → 记忆
const memory = { preferences: ["不早起", "不吃辣"] } export function loadPreferences() { return memory.preferences } export async function runWithMemory(goal: string) { const prefs = loadPreferences().join("、") return runAgent(`偏好:${prefs}\n目标:${goal}`) }
步骤 7

让它更健壮 → 错误处理(Robust)

缺口:工具调用失败时整个流程崩溃。解决:加 try-catch,失败时降级或重试。

调用工具 → {成功?} → 是→继续 / 否→重试或降级
async function safeToolCall(name: string, input: any) { try { return await callTool(name, input) } catch (e) { return { error: "tool_failed", fallback: "改用已有信息继续" } } }
🎉

恭喜!你已经理解了 Agent 的完整构建过程

从简单的 Chat 开始,逐步添加:结构化输出 → 计划 → 工具 → 循环 → 记忆 → 错误处理

回顾 Agent 工作原理 →