AI 层 — @mariozechner/pi-ai
概述
@mariozechner/pi-ai 是 Pi 的统一 LLM API 层,提供:
- 多 Provider 统一接口(OpenAI、Anthropic、Google 等)
- 自动模型发现和 Provider 配置
- Token 和费用追踪
- 简单的上下文持久化和跨模型切换
- TypeBox 类型安全工具定义
⚠️ 注意:该库只包含支持工具调用(Function Calling)的模型,因为这是 Agent 工作流的必要功能。
支持的 Provider
| Provider | 说明 |
|---|---|
| OpenAI | GPT-4o、GPT-4o-mini 等 |
| Azure OpenAI | Azure 托管的 OpenAI 模型 |
| OpenAI Codex | ChatGPT Plus/Pro 订阅(需 OAuth) |
| Anthropic | Claude 系列模型 |
| Gemini 系列 | |
| Vertex AI | Google Cloud Vertex AI |
| Mistral | Mistral AI 模型 |
| Groq | Groq 推理服务 |
| Cerebras | Cerebras 推理 |
| xAI | Grok 模型 |
| OpenRouter | 聚合多个 Provider |
| Vercel AI Gateway | Vercel AI 网关 |
| MiniMax | MiniMax |
| GitHub Copilot | 需 OAuth |
| Amazon Bedrock | AWS Bedrock |
| Kimi For Coding | Moonshot AI |
| Ollama/vLLM/LM Studio | 任何 OpenAI 兼容 API |
快速开始
安装
npm install @mariozechner/pi-ai
基本用法
import { getModel, stream, complete, Context, Tool } from '@mariozechner/pi-ai';
// 获取模型(自动类型提示)
const model = getModel('openai', 'gpt-4o-mini');
// 定义工具(使用 TypeBox 确保类型安全)
const tools: Tool[] = [{
name: 'get_time',
description: '获取当前时间',
parameters: {
type: 'object',
properties: {
timezone: { type: 'string', description: '时区(如 America/New_York)' }
}
}
}];
// 构建上下文(可序列化、可跨模型传输)
const context: Context = {
systemPrompt: '你是一个有用的助手。',
messages: [{ role: 'user', content: '现在几点了?' }],
tools
};
// 流式响应
const s = stream(model, context);
for await (const event of s) {
switch (event.type) {
case 'text_delta':
process.stdout.write(event.delta);
break;
case 'toolcall_end':
console.log(`调用工具: ${event.toolCall.name}`);
console.log(`参数: ${JSON.stringify(event.toolCall.arguments)}`);
break;
case 'done':
console.log(`完成: ${event.reason}`);
break;
}
}
工具系统(Tools)
定义工具
import { Type, Tool } from '@mariozechner/pi-ai';
const weatherTool: Tool = {
name: 'get_weather',
description: '获取指定位置的天气',
parameters: Type.Object({
location: Type.String({ description: '城市名称或坐标' }),
units: Type.Optional(Type.String({ description: '温度单位' }))
})
};
处理工具调用
const response = await complete(model, context);
// 检查响应中的工具调用
for (const block of response.content) {
if (block.type === 'toolCall') {
// 执行工具
const result = await executeWeather(block.arguments);
// 添加工具结果到上下文
context.messages.push({
role: 'toolResult',
toolCallId: block.id,
toolName: block.name,
content: [{ type: 'text', text: JSON.stringify(result) }],
isError: false,
timestamp: Date.now()
});
}
}
流式工具调用(Partial JSON)
在流式响应中,工具参数是逐步解析的,可以实时更新 UI:
for await (const event of stream(model, context)) {
if (event.type === 'toolcall_delta') {
// event.partial.content[event.contentIndex].arguments 包含部分解析的 JSON
// 可以实时显示正在输入的参数
}
if (event.type === 'toolcall_end') {
// 工具调用完成,参数已完整
console.log(event.toolCall.name, event.toolCall.arguments);
}
}
图像输入(Vision)
支持视觉能力的模型可以处理图片:
import { readFileSync } from 'fs';
const imageBuffer = readFileSync('image.png');
const base64Image = imageBuffer.toString('base64');
const response = await complete(model, {
messages: [{
role: 'user',
content: [
{ type: 'text', text: '这张图片里有什么?' },
{ type: 'image', data: base64Image, mimeType: 'image/png' }
]
}]
});
思考/推理(Thinking/Reasoning)
统一接口
import { getModel, completeSimple } from '@mariozechner/pi-ai';
const model = getModel('anthropic', 'claude-sonnet-4-20250514');
const response = await completeSimple(model, {
messages: [{ role: 'user', content: '解方程: 2x + 5 = 13' }]
}, {
reasoning: 'medium' // 'minimal' | 'low' | 'medium' | 'high'
});
for (const block of response.content) {
if (block.type === 'thinking') {
console.log('思考过程:', block.thinking);
} else if (block.type === 'text') {
console.log('回答:', block.text);
}
}
Provider 特定选项
// OpenAI Reasoning
await complete(openaiModel, context, { reasoningEffort: 'medium' });
// Anthropic Thinking
await complete(anthropicModel, context, {
thinkingEnabled: true,
thinkingBudgetTokens: 8192
});
// Google Gemini Thinking
await complete(googleModel, context, {
thinking: { enabled: true, budgetTokens: 8192 }
});
流事件参考
| 事件类型 | 说明 |
|---|---|
start | 流开始 |
text_start | 文本块开始 |
text_delta | 文本片段 |
text_end | 文本块完成 |
thinking_start | 思考块开始 |
thinking_delta | 思考片段 |
thinking_end | 思考块完成 |
toolcall_start | 工具调用开始 |
toolcall_delta | 工具参数流式 |
toolcall_end | 工具调用完成 |
done | 流完成 |
error | 错误发生 |
跨 Provider 切换
pi-ai 支持在会话中途切换到不同的模型:
// 切换到另一个 Provider/模型
const newModel = getModel('anthropic', 'claude-sonnet-4-20250514');
const continuation = await complete(newModel, context);
上下文可序列化,可以轻松在不同模型间传递。