Skip to main content

AI 层 — @mariozechner/pi-ai

概述

@mariozechner/pi-ai 是 Pi 的统一 LLM API 层,提供:

  • 多 Provider 统一接口(OpenAI、Anthropic、Google 等)
  • 自动模型发现和 Provider 配置
  • Token 和费用追踪
  • 简单的上下文持久化和跨模型切换
  • TypeBox 类型安全工具定义

⚠️ 注意:该库只包含支持工具调用(Function Calling)的模型,因为这是 Agent 工作流的必要功能。


支持的 Provider

Provider说明
OpenAIGPT-4o、GPT-4o-mini 等
Azure OpenAIAzure 托管的 OpenAI 模型
OpenAI CodexChatGPT Plus/Pro 订阅(需 OAuth)
AnthropicClaude 系列模型
GoogleGemini 系列
Vertex AIGoogle Cloud Vertex AI
MistralMistral AI 模型
GroqGroq 推理服务
CerebrasCerebras 推理
xAIGrok 模型
OpenRouter聚合多个 Provider
Vercel AI GatewayVercel AI 网关
MiniMaxMiniMax
GitHub Copilot需 OAuth
Amazon BedrockAWS Bedrock
Kimi For CodingMoonshot 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);

上下文可序列化,可以轻松在不同模型间传递。


翻译自 @mariozechner/pi-ai