当前 Agent 工程化 的核心。我通过一个完整的代码示例,把它们串起来讲清楚。
一、整体架构图(先有个印象)
text
用户输入
│
▼
┌─────────────────────────────────────────────┐
│ Agent │
│ ┌─────────────────────────────────────────┐ │
│ │ 历史消息 (Messages) │ │
│ │ [{role:user, content}, {role:assistant}]│ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────┐ │
│ │ 工作流 (Workflow) │ │
│ │ Plan → Execute → Observe → Loop │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────┬──────────────┐ │
│ │ 工具调用 │ 子Agent │ Skills │
│ │ (Tools) │ (Sub-Agent) │ (能力集) │
│ └──────────────┴──────────────┘ │
└─────────────────────────────────────────────┘
二、完整代码示例(可直接运行)
用 TypeScript + Bun 实现一个能做数学计算和天气查询的简单 Agent:
typescript
// agent.ts - 一个完整的 Agent 实现
// ==================== 1. 历史消息管理 ====================
interface Message {
role: 'user' | 'assistant' | 'tool';
content: string;
toolCallId?: string;
timestamp: number;
}
class MessageHistory {
private messages: Message[] = [];
private maxTokens: number = 4000;
add(message: Message) {
this.messages.push(message);
this.trimIfNeeded();
}
get() {
return this.messages;
}
getForLLM() {
// 返回 LLM 需要的格式,只保留最近的消息
return this.messages.slice(-20).map(m => ({
role: m.role,
content: m.content
}));
}
private trimIfNeeded() {
// 简化版:超过 50 条就删除一半
if (this.messages.length > 50) {
this.messages = this.messages.slice(-25);
}
}
}
// ==================== 2. 工具定义与调用 ====================
interface Tool {
name: string;
description: string;
parameters: Record<string, any>;
execute: (args: any) => Promise<string>;
}
// 工具1:计算器
const calculatorTool: Tool = {
name: 'calculator',
description: '执行数学计算,支持 + - * / 和 sqrt',
parameters: {
type: 'object',
properties: {
expression: { type: 'string', description: '数学表达式,如 "2+3*4"' }
},
required: ['expression']
},
execute: async (args) => {
try {
// 安全计算(生产环境请用 math.js 等库)
const result = eval(args.expression);
return `计算结果: ${result}`;
} catch (e) {
return `计算错误: ${e.message}`;
}
}
};
// 工具2:模拟天气查询
const weatherTool: Tool = {
name: 'get_weather',
description: '查询指定城市的天气',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: '城市名称' }
},
required: ['city']
},
execute: async (args) => {
// 模拟 API 调用
const weathers = {
'北京': '晴天 25°C',
'上海': '多云 22°C',
'深圳': '阵雨 28°C'
};
return weathers[args.city] || `${args.city} 天气: 晴 20°C`;
}
};
// ==================== 3. 子 Agent(专门处理特定任务)====================
class SubAgent {
name: string;
description: string;
private handler: (input: string) => Promise<string>;
constructor(name: string, description: string, handler: (input: string) => Promise<string>) {
this.name = name;
this.description = description;
this.handler = handler;
}
async run(input: string): Promise<string> {
console.log(` [子Agent:${this.name}] 处理: ${input}`);
return this.handler(input);
}
}
// 创建两个子 Agent
const mathSubAgent = new SubAgent(
'math-expert',
'专门处理复杂数学问题',
async (input) => {
// 模拟复杂计算
await Bun.sleep(500); // 假装在计算
return `【数学专家】计算结果: ${input.replace('计算', '').trim()} = 42`;
}
);
const weatherSubAgent = new SubAgent(
'weather-expert',
'专门处理天气相关问题',
async (input) => {
await Bun.sleep(300);
const city = input.match(/[北京上海深圳广州]+/)?.[0] || '未知';
return `【天气专家】${city},温度适中,建议出门带伞`;
}
);
// ==================== 4. Skill(可复用的能力模块)====================
interface Skill {
name: string;
description: string;
execute: (context: any) => Promise<any>;
}
const loggingSkill: Skill = {
name: 'logging',
description: '记录 Agent 的执行日志',
execute: async (context) => {
console.log(`[LOG] ${new Date().toISOString()} - ${context.action}`);
return { logged: true };
}
};
const memorySkill: Skill = {
name: 'memory',
description: '记住用户的重要偏好',
execute: async (context) => {
// 简化版:存到全局 Map
if (context.preference) {
userPreferences.set(context.userId, context.preference);
}
return { remembered: true };
}
};
const userPreferences = new Map<string, any>();
// ==================== 5. 主 Agent(核心工作流)====================
class SimpleAgent {
private tools: Map<string, Tool> = new Map();
private subAgents: Map<string, SubAgent> = new Map();
private skills: Skill[] = [];
private messageHistory: MessageHistory;
constructor() {
this.messageHistory = new MessageHistory();
this.registerDefaultTools();
}
// 注册工具
registerTool(tool: Tool) {
this.tools.set(tool.name, tool);
console.log(`📦 注册工具: ${tool.name}`);
}
// 注册子 Agent
registerSubAgent(agent: SubAgent) {
this.subAgents.set(agent.name, agent);
console.log(`🤖 注册子Agent: ${agent.name}`);
}
// 注册 Skill
registerSkill(skill: Skill) {
this.skills.push(skill);
console.log(`⚡ 注册Skill: ${skill.name}`);
}
private registerDefaultTools() {
this.registerTool(calculatorTool);
this.registerTool(weatherTool);
this.registerSubAgent(mathSubAgent);
this.registerSubAgent(weatherSubAgent);
this.registerSkill(loggingSkill);
this.registerSkill(memorySkill);
}
// ========== 核心工作流 ==========
async run(userInput: string): Promise<string> {
console.log('\n' + '='.repeat(50));
console.log(`📝 用户: ${userInput}`);
console.log('='.repeat(50));
// Step 1: 添加用户消息到历史
this.messageHistory.add({
role: 'user',
content: userInput,
timestamp: Date.now()
});
// Step 2: 意图识别(简化版,实际应该用 LLM)
const intent = this.analyzeIntent(userInput);
console.log(`🎯 识别意图: ${intent.type}`);
// Step 3: 执行 Skills(前置)
for (const skill of this.skills) {
await skill.execute({ action: intent.type, userId: 'default' });
}
// Step 4: 根据意图分发处理
let result: string;
if (intent.type === 'calculation' && intent.tool) {
// 直接调用工具
result = await this.callTool(intent.tool, intent.args);
}
else if (intent.type === 'weather') {
// 可以调用工具或子 Agent,这里演示委托给子 Agent
result = await this.delegateToSubAgent('weather-expert', userInput);
}
else if (intent.type === 'complex_math') {
result = await this.delegateToSubAgent('math-expert', userInput);
}
else {
// 普通对话
result = await this.generateResponse(userInput);
}
// Step 5: 保存助手回复到历史
this.messageHistory.add({
role: 'assistant',
content: result,
timestamp: Date.now()
});
console.log(`🤖 助手: ${result}`);
return result;
}
// 意图分析(简化版,实际应该调用 LLM)
private analyzeIntent(input: string): {
type: 'calculation' | 'weather' | 'complex_math' | 'chat';
tool?: string;
args?: any;
} {
// 计算器意图
if (input.includes('+') || input.includes('-') || input.includes('*') || input.includes('/') || input.includes('计算')) {
const match = input.match(/[\d\s+-*/()]+/);
if (match && match[0].trim()) {
return { type: 'calculation', tool: 'calculator', args: { expression: match[0] } };
}
}
// 天气意图
if (input.includes('天气')) {
return { type: 'weather' };
}
// 复杂数学
if (input.includes('方程') || input.includes('积分') || input.includes('导数')) {
return { type: 'complex_math' };
}
return { type: 'chat' };
}
// 调用工具
private async callTool(toolName: string, args: any): Promise<string> {
const tool = this.tools.get(toolName);
if (!tool) return `工具 ${toolName} 不存在`;
console.log(`🔧 调用工具: ${toolName}`, args);
return await tool.execute(args);
}
// 委托给子 Agent
private async delegateToSubAgent(agentName: string, input: string): Promise<string> {
const agent = this.subAgents.get(agentName);
if (!agent) return `子Agent ${agentName} 不存在`;
console.log(`🔄 委托给子Agent: ${agentName}`);
return await agent.run(input);
}
// 生成回复(简化版,实际应该调用 LLM)
private async generateResponse(input: string): Promise<string> {
if (input.includes('你好') || input.includes('嗨')) {
return '你好!我是智能助手,可以帮你计算、查天气等。试试说"计算 2+3"或"北京天气"';
}
return `收到: "${input}"。我是一个简单Agent,能处理计算和天气查询。`;
}
// 查看历史消息
showHistory() {
console.log('\n📜 历史消息:');
for (const msg of this.messageHistory.get()) {
console.log(` [${msg.role}] ${msg.content.slice(0, 50)}`);
}
}
}
// ==================== 6. 运行演示 ====================
async function main() {
console.log('🚀 启动 Simple Agent...\n');
const agent = new SimpleAgent();
console.log('\n' + '🌟 Agent 已就绪,开始对话...\n');
// 测试各种场景
await agent.run('你好,你是谁?');
await agent.run('计算 15 + 27');
await agent.run('北京天气怎么样?');
await agent.run('帮我解方程 x^2 = 4');
// 查看历史消息
agent.showHistory();
console.log('\n✅ 演示完成');
}
// 运行
main().catch(console.error);
三、用 Bun 运行
bash
# 安装 bun(如果还没装)
curl -fsSL https://bun.sh/install | bash
# 运行 Agent
bun run agent.ts
输出示例:
text
🚀 启动 Simple Agent...
📦 注册工具: calculator
📦 注册工具: get_weather
🤖 注册子Agent: math-expert
🤖 注册子Agent: weather-expert
⚡ 注册Skill: logging
⚡ 注册Skill: memory
==================================================
📝 用户: 计算 15 + 27
==================================================
🎯 识别意图: calculation
[LOG] 2026-04-04T10:30:00.000Z - calculation
🔧 调用工具: calculator { expression: "15+27" }
🤖 助手: 计算结果: 42
==================================================
📝 用户: 北京天气怎么样?
==================================================
🎯 识别意图: weather
[LOG] 2026-04-04T10:30:01.000Z - weather
🔄 委托给子Agent: weather-expert
[子Agent:weather-expert] 处理: 北京天气怎么样?
🤖 助手: 【天气专家】北京,温度适中,建议出门带伞
四、核心概念对照表
| 概念 | 在这个例子中的体现 | 作用 |
|---|---|---|
| 历史消息 | MessageHistory 类 | 保留对话上下文,支持多轮交互 |
| 工作流 | run() 方法中的 5 个步骤 | 意图识别→技能执行→工具/子Agent→返回结果 |
| 工具调用 | calculatorTool、weatherTool | Agent 通过工具执行具体操作 |
| 子 Agent | mathSubAgent、weatherSubAgent | 专门化处理,可以嵌套调用 |
| Skill | loggingSkill、memorySkill | 可复用的横切能力,可在工作流中自动执行 |
| Bun 一体化 | 一个文件搞定 TypeScript 编译+运行 | 不需要 tsc + node,直接 bun run |
五、关于 Bun 的亮点
你说得对,Bun 的运行时+构建一体化确实很棒:
bash
# 传统 Node + TypeScript 需要:
npm install -g typescript ts-node
tsc agent.ts && node agent.js
# Bun 只需要:
bun run agent.ts # 直接运行,自动编译
Bun 还内置了:
- 包管理器(比 npm/yarn/pnpm 快很多)
- 测试运行器
- 打包器(bun build)
- 原生支持 JSX、TS
运行这个例子后,你会直观感受到一个 Agent 是如何组织起来的。想深入了解哪一块?比如:
- 如何接入真实的 LLM(OpenAI/Claude API)?
- 如何处理更复杂的工作流(循环、重试、并行)?
- 工具调用的 function calling 具体怎么对接?