@weisiren000/oiiai
v0.2.2
Published
统一的 AI Provider 接口封装,支持 OpenRouter、OpenAI、Anthropic 等
Downloads
428
Maintainers
Readme
🤖 @weisiren000/oiiai
统一的 AI Provider 接口封装库
支持 OpenRouter · Gemini · Groq · HuggingFace · ModelScope · DeepSeek · Poe · Nova · Zhipu · SiliconFlow
📖 详细文档 · 🚀 快速开始 · 💡 示例 · 🔗 Fluent API
✨ 特性
- 🔌 统一接口 - 所有 Provider 使用相同 API,学会一个就会全部
- 🎯 Fluent API - 全新链式调用和预设实例,极简代码完成 AI 调用
- 🧠 Reasoning 支持 - 统一的思考模式配置,自动转换各 Provider 格式
- 🌊 流式输出 - 支持实时流式响应,区分思考/回答内容
- 💬 多轮对话 - 内置对话会话管理,自动维护上下文
- 📦 TypeScript - 完整类型定义,开发体验友好
- 🔧 可扩展 - 轻松实现自定义 Provider
- 🧪 智能模型检测 - 自动识别思考模型,智能降级处理
📦 安装
npm install @weisiren000/oiiai🚀 快速开始
方式一:Fluent API(推荐 ⭐)
最简洁的使用方式,支持预设实例和链式调用:
import { deepseek, openrouter, oiiai } from '@weisiren000/oiiai';
// 🎯 预设实例 - 一行代码完成调用
deepseek.configure({ apiKey: 'your-key' });
const answer = await deepseek.ask('deepseek-chat', '你好');
// 🔗 链式调用 - 灵活配置
const answer = await oiiai
.use('deepseek')
.key('your-key')
.model('deepseek-chat')
.system('你是一个友好的助手')
.temperature(0.7)
.ask('你好');
// 🌊 流式输出
for await (const chunk of deepseek.stream('deepseek-chat', '写首诗')) {
process.stdout.write(chunk.text);
}
// 💬 多轮对话
const chat = deepseek.chat('deepseek-chat');
await chat.send('你好');
await chat.send('继续上面的话题');方式二:工厂函数
传统方式,适合需要更多控制的场景:
import { ai, createProvider } from '@weisiren000/oiiai';
// 快捷工厂
const provider = ai.deepseek('your-api-key');
const answer = await provider.ask('deepseek-chat', '你好');
// 完整配置
const provider = createProvider({
provider: 'openrouter',
apiKey: 'your-api-key',
baseUrl: 'https://custom.openrouter.ai/api/v1', // 可选
});🎯 Fluent API(新)
全新的 Fluent API 提供两种使用模式:
预设实例
预配置的 Provider 实例,开箱即用:
import {
deepseek,
openrouter,
gemini,
groq,
zhipu,
siliconflow,
} from '@weisiren000/oiiai';
// 配置 API Key(二选一)
deepseek.configure({ apiKey: 'your-key' }); // 显式配置
openrouter.fromEnv(); // 从环境变量读取 (OPENROUTER_API_KEY)
// 简单问答
const answer = await deepseek.ask('deepseek-chat', '什么是 TypeScript?');
// 带选项的问答
const answer = await deepseek.ask('deepseek-chat', '解释量子计算', {
system: '你是一个科学家',
temperature: 0.7,
maxTokens: 1000,
reasoning: { effort: 'high' },
});
// 流式输出
for await (const chunk of deepseek.stream('deepseek-chat', '写一首诗')) {
if (chunk.type === 'reasoning') {
console.log('[思考]', chunk.text);
} else {
process.stdout.write(chunk.text);
}
}
// 带回调的流式输出
await deepseek.streamWithCallbacks('deepseek-chat', '分析这个问题', {
onReasoning: text => console.log('[思考]', text),
onContent: text => process.stdout.write(text),
onDone: result => console.log('\n完成!', result),
});链式构建器
灵活的链式调用,精细控制每个参数:
import { oiiai } from '@weisiren000/oiiai';
// 基础用法
const answer = await oiiai
.use('deepseek')
.key('your-key')
.model('deepseek-chat')
.ask('你好');
// 完整配置
const answer = await oiiai
.use('openrouter')
.key('your-key')
.model('anthropic/claude-sonnet-4')
.system('你是一个专业的代码助手')
.temperature(0.7)
.maxTokens(2000)
.reasoning({ effort: 'high' })
.ask('如何实现快速排序?');
// 流式输出
const stream = oiiai
.use('gemini')
.key('your-key')
.model('gemini-2.5-flash')
.stream()
.ask('写一个故事');
for await (const chunk of stream) {
process.stdout.write(chunk.text);
}预设实例与构建器互转
从简单开始,需要时再增加复杂度:
import { deepseek } from '@weisiren000/oiiai';
deepseek.configure({ apiKey: 'your-key' });
// 从预设实例获取构建器
const builder = deepseek.builder('deepseek-chat');
// 继续链式配置
const answer = await builder
.system('你是一个诗人')
.temperature(0.9)
.ask('写一首关于春天的诗');多模态支持
Fluent API 链式构建器原生支持多模态输入(图像、视频、音频),提供简洁的链式调用接口:
import { oiiai, siliconflow } from '@weisiren000/oiiai';
// 配置
siliconflow.configure({ apiKey: 'your-key' });
// 图像分析
const answer = await oiiai
.use('siliconflow')
.key('your-key')
.model('Qwen/Qwen2.5-VL-72B-Instruct')
.image('https://example.com/image.jpg', { detail: 'high' })
.ask('描述这张图片');
// 多图对比
const answer = await oiiai
.use('siliconflow')
.key('your-key')
.model('Qwen/Qwen2.5-VL-72B-Instruct')
.image('https://example.com/image1.jpg')
.image('https://example.com/image2.jpg')
.ask('比较这两张图片');
// 视频分析
const answer = await oiiai
.use('siliconflow')
.key('your-key')
.model('Qwen/Qwen3-Omni-30B-A3B-Instruct')
.video('https://example.com/video.mp4', { maxFrames: 4, fps: 1 })
.ask('视频里发生了什么?');
// 音频理解
const answer = await oiiai
.use('siliconflow')
.key('your-key')
.model('Qwen/Qwen3-Omni-30B-A3B-Instruct')
.audio('https://example.com/audio.mp3')
.ask('这段音频说了什么?');
// 混合多模态 + 流式输出
for await (const chunk of oiiai
.use('siliconflow')
.key('your-key')
.model('Qwen/Qwen3-Omni-30B-A3B-Instruct')
.image('https://example.com/image.jpg')
.audio('https://example.com/audio.mp3')
.stream()
.ask('分析这张图片和音频')) {
process.stdout.write(chunk.text);
}多模态方法说明
image(url, options?)- 添加图像内容url: 图像 URL 或 Base64 (data:image/jpeg;base64,...)options.detail:'auto' | 'low' | 'high'- 分析精度
video(url, options?)- 添加视频内容url: 视频 URL 或 Base64 (data:video/mp4;base64,...)options.maxFrames: 最大提取帧数(默认取决于模型)options.fps: 每秒提取帧数options.detail:'auto' | 'low' | 'high'- 分析精度
audio(url)- 添加音频内容url: 音频 URL 或 Base64 (data:audio/mp3;base64,...)
注意: 多模态功能需要使用支持多模态的模型(如 SiliconFlow 的 Qwen VL 系列)。
多轮对话
内置对话会话管理,自动维护上下文:
import { deepseek } from '@weisiren000/oiiai';
deepseek.configure({ apiKey: 'your-key' });
// 创建对话会话
const chat = deepseek.chat('deepseek-chat', {
system: '你是一个友好的助手',
temperature: 0.7,
});
// 多轮对话
const reply1 = await chat.send('你好,我叫小明');
console.log(reply1); // "你好小明!很高兴认识你..."
const reply2 = await chat.send('我叫什么名字?');
console.log(reply2); // "你叫小明..."
// 流式对话
for await (const chunk of chat.sendStream('给我讲个笑话')) {
process.stdout.write(chunk.text);
}
// 查看对话历史
console.log(chat.getHistory());
// 清空历史开始新对话
chat.clearHistory();💡 使用示例
简单问答
const answer = await provider.ask('model-id', '什么是 TypeScript?');带系统提示
const answer = await provider.askWithSystem(
'model-id',
'你是一个专业的代码助手',
'如何定义 TypeScript 接口?'
);完整对话
const result = await provider.chat({
model: 'model-id',
messages: [
{ role: 'system', content: '你是一个友好的助手' },
{ role: 'user', content: '你好!' },
],
temperature: 0.7,
maxTokens: 1000,
});
console.log(result.content); // 回答内容
console.log(result.usage); // Token 使用情况流式输出
for await (const chunk of provider.chatStream({
model: 'model-id',
messages: [{ role: 'user', content: '写一首诗' }],
})) {
if (chunk.type === 'reasoning') {
process.stdout.write(`[思考] ${chunk.text}`);
} else {
process.stdout.write(chunk.text);
}
}思考模式 (Reasoning)
const result = await provider.chat({
model: 'deepseek/deepseek-r1',
messages: [{ role: 'user', content: '9.11 和 9.9 哪个大?' }],
reasoning: {
effort: 'high', // 'off' | 'low' | 'medium' | 'high'
},
});
console.log('思考过程:', result.reasoning);
console.log('最终答案:', result.content);多模态图像理解(SiliconFlow)
SiliconFlow 支持多模态输入,可以处理图像、视频、音频:
import { siliconflow } from '@weisiren000/oiiai';
siliconflow.configure({ apiKey: 'your-key' });
// 分析图片
const answer = await siliconflow.chat('Qwen/Qwen2.5-VL-72B-Instruct', {
messages: [
{
role: 'user',
content: [
{
type: 'image_url',
image_url: { url: 'https://example.com/image.jpg' },
},
{ type: 'text', text: '描述这张图片' },
],
},
],
});
// 分析视频
const answer2 = await siliconflow.chat('Qwen/Qwen3-Omni-30B-A3B-Instruct', {
messages: [
{
role: 'user',
content: [
{
type: 'video_url',
video_url: {
url: 'data:video/mp4;base64,...',
max_frames: 4,
fps: 1,
},
},
{ type: 'text', text: '视频里发生了什么?' },
],
},
],
});🔧 支持的 Provider
| Provider | 服务商 | Reasoning 参数 | 支持思考模型 | 环境变量 |
| ------------- | ------------- | ---------------------------- | ------------ | --------------------- |
| deepseek | DeepSeek | thinking.type: 'enabled' | ✅ | DEEPSEEK_API_KEY |
| openrouter | OpenRouter | reasoning.effort | ✅ | OPENROUTER_API_KEY |
| gemini | Google Gemini | reasoning_effort | ✅ | GEMINI_API_KEY |
| groq | Groq | reasoning_format: 'parsed' | ✅ | GROQ_API_KEY |
| huggingface | HuggingFace | 取决于具体模型 | ⚠️ 部分模型 | HUGGINGFACE_API_KEY |
| modelscope | 魔搭社区 | enable_thinking | ✅ | MODELSCOPE_API_KEY |
| poe | Poe | reasoning_effort | ✅ | POE_API_KEY |
| nova | AWS Nova | reasoningConfig.type | ✅ | NOVA_API_KEY |
| zhipu | 智谱AI | 暂不支持 | ❌ | ZHIPU_API_KEY |
| siliconflow | SiliconFlow | thinking_budget | ✅ | SILICONFLOW_API_KEY |
📝 常用模型
// DeepSeek
'deepseek-chat'; // DeepSeek-V3 通用对话
'deepseek-reasoner'; // DeepSeek-R1 推理模型
// OpenRouter
'openai/gpt-4o';
'anthropic/claude-sonnet-4';
'deepseek/deepseek-r1';
// Gemini
'gemini-2.5-flash';
'gemini-2.5-pro';
// Groq
'llama-3.3-70b-versatile';
'mixtral-8x7b-32768';
// Poe (使用 bot 名称)
'GPT-4o';
'Claude-3.5-Sonnet';
// AWS Nova
'nova-2-lite-v1';
'nova-2-v1';
'nova-premier-v1';
// 智谱AI (Zhipu)
'glm-4-plus'; // 最强大的通用模型
'glm-4-flash'; // 快速响应模型
'glm-4-air'; // 轻量级模型
'glm-4-long'; // 长文本处理模型
// SiliconFlow
'deepseek-ai/DeepSeek-V3'; // 通用对话
'deepseek-ai/DeepSeek-R1'; // 推理模型
'Qwen/Qwen2.5-VL-72B-Instruct'; // 视觉理解
'Qwen/Qwen3-Omni-30B-A3B-Instruct'; // 多模态全能
'Qwen/Qwen3-VL-7B-Instruct'; // 视觉模型
'zai-org/GLM-4.6V'; // 视觉对话🌍 环境变量
推荐使用 .env 文件管理 API 密钥:
# .env
DEEPSEEK_API_KEY=sk-xxx
OPENROUTER_API_KEY=sk-or-xxx
GEMINI_API_KEY=xxx
GROQ_API_KEY=gsk_xxx
HUGGINGFACE_API_KEY=hf_xxx
MODELSCOPE_API_KEY=xxx
POE_API_KEY=xxx
NOVA_API_KEY=xxx
ZHIPU_API_KEY=xxximport 'dotenv/config';
import { deepseek, openrouter, zhipu } from '@weisiren000/oiiai';
// 从环境变量读取配置
deepseek.fromEnv();
openrouter.fromEnv();
zhipu.fromEnv();
const answer = await deepseek.ask('deepseek-chat', '你好');
const answer2 = await zhipu.ask('glm-4-flash', '你好');🧪 高级用法
智能模型检测与降级
import { ModelDetection, detectByModelName } from '@weisiren000/oiiai';
// 基于模型名称模式检测
const characteristics = detectByModelName('deepseek-r1');
console.log(characteristics.behavior); // 'thinking-first'
// 自定义降级策略
provider.configureFallback({
enabled: true,
returnReasoningAsContent: true,
extractConclusionFromReasoning: true,
});场景化问答
const answer = await provider.askWithScenario(
'deepseek-r1',
'证明勾股定理',
'math' // 'simple' | 'math' | 'reasoning' | 'fast'
);🛠️ 自定义 Provider
使用适配器模式(推荐)
import {
BaseAdapter,
ProviderRegistry,
RequestBuilder,
StreamProcessor,
} from '@weisiren000/oiiai';
class MyAdapter extends BaseAdapter {
readonly name = 'my-provider';
getEndpointUrl(baseUrl: string): string {
return `${baseUrl}/v1/chat/completions`;
}
buildChatRequest(options: ChatOptions): Record<string, unknown> {
return RequestBuilder.buildChatBody(options);
}
parseChatResponse(
response: Record<string, unknown>,
model: string
): ChatResult {
// 解析响应
}
extractStreamChunk(delta: Record<string, unknown>): StreamChunk | null {
// 提取流式数据块
}
}
// 注册并使用
ProviderRegistry.register(new MyAdapter());
const provider = createProvider({ provider: 'my-provider', apiKey: 'xxx' });🏗️ 架构概览
┌─────────────────────────────────────────────────────────┐
│ Fluent API (新) │
│ 预设实例 / 链式构建器 / 对话会话 │
├─────────────────────────────────────────────────────────┤
│ 用户层 (API) │
│ createProvider / ai 快捷函数 │
├─────────────────────────────────────────────────────────┤
│ 注册层 (Registry) │
│ ProviderRegistry │
├─────────────────────────────────────────────────────────┤
│ 适配器层 (Adapter) │
│ OpenRouterAdapter / GeminiAdapter / GroqAdapter ... │
│ ✨ 统一支持多种 reasoning 字段备用方案 │
├─────────────────────────────────────────────────────────┤
│ 客户端层 (Client) │
│ HttpProviderClient │
├─────────────────────────────────────────────────────────┤
│ 工具层 (Utils) │
│ StreamProcessor / RequestBuilder / ConfigValidator │
└─────────────────────────────────────────────────────────┘适配器层增强
所有 Provider 适配器现在都支持多种 reasoning 字段的备用方案,确保最大兼容性:
- 优先使用
reasoning_content(最常见) - 备用
reasoning(部分 Provider) - 备用
thoughts(Gemini 等)
这意味着无论 Provider 使用哪种字段格式,都能正确识别和提取思考内容。
❓ 故障排除
常见问题
Q: 为什么某些思考模型返回的 content 为空?
A: 思考模型在低 token 限制下可能只输出 reasoning。启用智能降级策略或增加 maxTokens 即可解决。
Q: 如何自定义 API 地址?
A: 使用 baseUrl 参数:
// Fluent API
deepseek.configure({ apiKey: 'xxx', baseUrl: 'https://custom.api.com' });
// 或链式调用
oiiai.use('deepseek').key('xxx').baseUrl('https://custom.api.com');Q: 流式输出中如何区分思考和回答?
A: 检查 chunk.type:'reasoning' 表示思考内容,'content' 表示最终回答。所有 Provider 的适配器都已统一支持多种 reasoning 字段格式(reasoning_content / reasoning / thoughts),确保最大兼容性。
错误处理
import { ConfigurationError, APIError } from '@weisiren000/oiiai';
try {
const answer = await deepseek.ask('model', 'question');
} catch (error) {
if (error instanceof ConfigurationError) {
console.error('配置错误:', error.message);
} else if (error instanceof APIError) {
console.error('API 错误:', error.message);
}
}📚 更多文档
- API 参考 - 完整的 API 文档
- Provider 指南 - 各 Provider 详细说明
- 快速上手指南 - 新手入门教程
- 贡献指南 - 如何参与贡献
📄 License
MIT
