构建迷你 Agent
目标
从零实现一个能工作的 AI Agent,包含:
- 与 Gemini API 交互
- 两个工具:读文件、执行命令
- 完整的 Agent 循环
代码约 100 行,可直接运行。
完整代码
typescript
// mini-agent.ts
import { GoogleGenerativeAI } from '@google/generative-ai'
import * as fs from 'fs/promises'
import { exec } from 'child_process'
import { promisify } from 'util'
const execAsync = promisify(exec)
// ============ 1. 定义工具 ============
const tools = {
read_file: {
declaration: {
name: 'read_file',
description: '读取指定路径的文件内容',
parameters: {
type: 'object',
properties: {
path: { type: 'string', description: '文件路径' }
},
required: ['path']
}
},
execute: async (args: { path: string }) => {
try {
const content = await fs.readFile(args.path, 'utf-8')
return { content: content.slice(0, 5000) } // 限制大小
} catch (e: any) {
return { error: `读取失败: ${e.message}` }
}
}
},
run_command: {
declaration: {
name: 'run_command',
description: '执行 shell 命令并返回输出',
parameters: {
type: 'object',
properties: {
command: { type: 'string', description: '要执行的命令' }
},
required: ['command']
}
},
execute: async (args: { command: string }) => {
try {
const { stdout, stderr } = await execAsync(args.command, {
timeout: 30000
})
return { stdout, stderr }
} catch (e: any) {
return { error: `命令失败: ${e.message}` }
}
}
}
}
// ============ 2. 初始化 Gemini ============
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!)
const model = genAI.getGenerativeModel({
model: 'gemini-2.5-flash',
systemInstruction: `你是一个编程助手。可以读取文件和执行命令来帮助用户。
每次只做一件事,完成后告诉用户结果。`,
tools: [{
functionDeclarations: Object.values(tools).map(t => t.declaration)
}]
})
// ============ 3. Agent 主循环 ============
const MAX_TURNS = 10
async function runAgent(userMessage: string): Promise<string> {
const chat = model.startChat()
let response = await chat.sendMessage(userMessage)
let turns = 0
while (turns < MAX_TURNS) {
turns++
const functionCalls = response.response.functionCalls()
// 没有工具调用,返回文本响应
if (!functionCalls || functionCalls.length === 0) {
return response.response.text()
}
// 执行工具调用
const results: any[] = []
for (const call of functionCalls) {
console.log(`[工具] ${call.name}(${JSON.stringify(call.args)})`)
const tool = tools[call.name as keyof typeof tools]
if (!tool) {
results.push({
functionResponse: {
name: call.name,
response: { error: `未知工具: ${call.name}` }
}
})
continue
}
const result = await tool.execute(call.args as any)
console.log(`[结果] ${JSON.stringify(result).slice(0, 200)}...`)
results.push({
functionResponse: {
name: call.name,
response: result
}
})
}
// 发送工具结果,继续对话
response = await chat.sendMessage(results)
}
return '达到最大轮次限制'
}
// ============ 4. 运行 ============
async function main() {
const task = process.argv[2] || '列出当前目录的文件'
console.log(`\n任务: ${task}\n`)
console.log('---')
const result = await runAgent(task)
console.log('---')
console.log(`\n回答:\n${result}`)
}
main().catch(console.error)运行示例
bash
# 设置 API Key
export GEMINI_API_KEY=your-api-key
# 运行
npx ts-node mini-agent.ts "读取 package.json 并告诉我项目名称"输出:
任务: 读取 package.json 并告诉我项目名称
---
[工具] read_file({"path":"package.json"})
[结果] {"content":"{\"name\":\"@google/gemini-cli\",..."}...
---
回答:
项目名称是 `@google/gemini-cli`代码解析
1. 工具定义
每个工具包含:
declaration:JSON Schema 格式的定义,告诉 LLM 这个工具做什么execute:实际执行逻辑
typescript
const tools = {
read_file: {
declaration: { /* LLM 看到的定义 */ },
execute: async (args) => { /* 实际执行 */ }
}
}2. 初始化模型
typescript
const model = genAI.getGenerativeModel({
model: 'gemini-2.5-flash',
systemInstruction: '...', // 定义 Agent 行为
tools: [{ functionDeclarations: [...] }] // 告诉 LLM 有哪些工具
})3. Agent 循环
核心逻辑:
typescript
while (turns < MAX_TURNS) {
const functionCalls = response.response.functionCalls()
if (!functionCalls?.length) {
return response.response.text() // 完成
}
// 执行工具
const results = await executeTools(functionCalls)
// 发送结果,继续对话
response = await chat.sendMessage(results)
}与 gemini-cli 的对比
| 特性 | 迷你 Agent | gemini-cli |
|---|---|---|
| 代码量 | ~100 行 | ~10000 行 |
| 工具数量 | 2 个 | 10+ 个 |
| 流式输出 | 无 | 有 |
| 用户确认 | 无 | 完整策略引擎 |
| 上下文管理 | 无 | Token 压缩 |
| 循环检测 | 仅轮次限制 | 多策略检测 |
| 错误处理 | 基础 | 重试、恢复 |
| 会话持久化 | 无 | Checkpoint |
添加更多工具
扩展很简单,只需添加到 tools 对象:
typescript
const tools = {
// 现有工具...
write_file: {
declaration: {
name: 'write_file',
description: '写入文件',
parameters: {
type: 'object',
properties: {
path: { type: 'string' },
content: { type: 'string' }
},
required: ['path', 'content']
}
},
execute: async (args: { path: string; content: string }) => {
await fs.writeFile(args.path, args.content)
return { success: true }
}
},
list_directory: {
declaration: {
name: 'list_directory',
description: '列出目录内容',
parameters: {
type: 'object',
properties: {
path: { type: 'string', description: '目录路径,默认当前目录' }
}
}
},
execute: async (args: { path?: string }) => {
const files = await fs.readdir(args.path || '.')
return { files }
}
}
}小结
这个迷你 Agent 展示了 AI Agent 的核心原理:
- 定义工具告诉 LLM 能做什么
- 循环调用 LLM 直到任务完成
- 执行工具并把结果反馈给 LLM
虽然简单,但已经是一个能工作的 Agent。
下一步
在此基础上添加更多功能:扩展功能 →