npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@weisiren000/oiiai

v0.2.2

Published

统一的 AI Provider 接口封装,支持 OpenRouter、OpenAI、Anthropic 等

Downloads

428

Readme

🤖 @weisiren000/oiiai

统一的 AI Provider 接口封装库

TypeScript Node.js License npm

支持 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=xxx
import '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);
  }
}

📚 更多文档

📄 License

MIT