ModelFusion
用于构建AI应用的TypeScript库。
简介 | 快速安装 | 用法 | 文档 | 示例 | 贡献 | modelfusion.dev
简介
[!重要] ModelFusion 已加入 Vercel 并正在集成到 Vercel AI SDK 中。我们正将 modelfusion 的最佳部分带入 Vercel AI SDK,从文本生成、结构化对象生成和工具调用开始。请查看 AI SDK 了解最新进展。
ModelFusion 是一个抽象层,用于将AI模型集成到JavaScript和TypeScript应用程序中,统一了常见操作的API,例如 文本流、对象生成 和 工具使用。它提供支持生产环境的功能,包括可观察性钩子、日志记录和自动重试。您可以使用 ModelFusion 来构建AI应用程序、聊天机器人和代理。
- 供应商中立:ModelFusion 是一个非商业的开源项目,由社区驱动。您可以与任何支持的提供商一起使用。
- 多模态:ModelFusion 支持多种模型,包括文本生成、图像生成、视觉、文本转语音、语音转文本和嵌入模型。
- 类型推断和验证:ModelFusion 尽可能推断 TypeScript 类型并验证模型响应。
- 可观察性和日志记录:ModelFusion 提供了一个观察者框架和日志支持。
- 弹性和健壮性:ModelFusion 通过自动重试、节流和错误处理机制确保无缝操作。
- 为生产而构建:ModelFusion 完全支持树摇动,可以在无服务器环境中使用,仅使用最小的依赖集。
快速安装
npm install modelfusion
或者使用入门模板:
- ModelFusion 终端应用 starter
- Next.js,Vercel AI SDK,Llama.cpp 和 ModelFusion starter
- Next.js,Vercel AI SDK,Ollama 和 ModelFusion starter
用法示例
[!提示] 基本示例是入门并与文档并行探索的好方法。您可以在 examples/basic 文件夹中找到它们。
您可以使用环境变量(如 OPENAI_API_KEY
)或将它们作为选项传递给模型构造函数来提供不同集成的API密钥。
生成文本
使用语言模型和提示生成文本。如果模型支持,您可以流式传输文本。如果模型支持,您可以使用图像进行多模态提示(例如,llama.cpp)。
您可以使用prompt styles来使用文本、指令或聊天提示。
generateText
import { generateText, openai } from "modelfusion";
const text = await generateText({
model: openai.CompletionTextGenerator({ model: "gpt-3.5-turbo-instruct" }),
prompt: "编写一个关于机器人学习爱的短篇故事:\n\n",
});
提供商:OpenAI,OpenAI compatible,Llama.cpp,Ollama,Mistral,Hugging Face,Cohere
streamText
import { streamText, openai } from "modelfusion";
const textStream = await streamText({
model: openai.CompletionTextGenerator({ model: "gpt-3.5-turbo-instruct" }),
prompt: "编写一个关于机器人学习爱的短篇故事:\n\n",
});
for await (const textPart of textStream) {
process.stdout.write(textPart);
}
提供商:OpenAI,OpenAI compatible,Llama.cpp,Ollama,Mistral,Cohere
使用多模态提示流文本
多模态视觉模型(如GPT 4 Vision)可以处理作为提示的一部分的图像。
import { streamText, openai } from "modelfusion";
import { readFileSync } from "fs";
const image = readFileSync("./image.png");
const textStream = await streamText({
model: openai
.ChatTextGenerator({ model: "gpt-4-vision-preview" })
.withInstructionPrompt(),
prompt: {
instruction: [
{ type: "text", text: "详细描述图像。" },
{ type: "image", image, mimeType: "image/png" },
],
},
});
for await (const textPart of textStream) {
process.stdout.write(textPart);
}
提供商:OpenAI,OpenAI compatible,Llama.cpp,Ollama
生成对象
使用语言模型和架构生成类型化对象。
generateObject
生成与架构匹配的对象。
import {
ollama,
zodSchema,
generateObject,
jsonObjectPrompt,
} from "modelfusion";
const sentiment = await generateObject({
model: ollama
.ChatTextGenerator({
model: "openhermes2.5-mistral",
maxGenerationTokens: 1024,
temperature: 0,
})
.asObjectGenerationModel(jsonObjectPrompt.instruction()),
schema: zodSchema(
z.object({
sentiment: z
.enum(["positive", "neutral", "negative"])
.describe("情感。"),
})
),
prompt: {
system:
"你是一个情感评估者。" +
"分析以下产品评论的情感:",
instruction:
"打开包装后,我遇到了非常难闻的气味,即使洗了之后也没有消失。再也不会买了!",
},
});
streamObject
流式传输与架构匹配的对象。最终部分之前的部分对象是无类型的JSON。
import { zodSchema, openai, streamObject } from "modelfusion";
const objectStream = await streamObject({
model: openai
.ChatTextGenerator(/* ... */)
.asFunctionCallObjectGenerationModel({
fnName: "generateCharacter",
fnDescription: "生成角色描述。",
})
.withTextPrompt(),
schema: zodSchema(
z.object({
characters: z.array(
z.object({
name: z.string(),
class: z
.string()
.describe("角色类别,如战士、法师或盗贼。"),
description: z.string(),
})
),
})
),
prompt: "为一个奇幻角色扮演游戏生成3个人物描述。",
});
for await (const { partialObject } of objectStream) {
console.clear();
console.log(partialObject);
}
生成图像
从提示生成图像。
import { generateImage, openai } from "modelfusion";
const image = await generateImage({
model: openai.ImageGenerator({ model: "dall-e-3", size: "1024x1024" }),
prompt: "以19世纪早期绘画风格描绘西方的邪恶女巫",
});
提供商:OpenAI (Dall·E),Stability AI,Automatic1111
生成语音
将文本合成语音(音频)。也称为文本转语音(TTS)。
generateSpeech
generateSpeech
将文本合成语音。
import { generateSpeech, lmnt } from "modelfusion";
// `speech` 是一个包含MP3音频数据的 Uint8Array
const speech = await generateSpeech({
model: lmnt.SpeechGenerator({
voice: "034b632b-df71-46c8-b440-86a42ffc3cf3", // Henry
}),
text:
"晚上好,女士们,先生们!今晚的电波中有令人兴奋的消息," +
"滚石乐队公布了 'Hackney Diamonds',这是他们近二十年来首次推出的新歌," +
"其中有光辉的Lady Gaga,奇妙的Stevie Wonder,以及已故的Charlie Watts留下的最后节拍。",
});
提供商:Eleven Labs,LMNT,OpenAI
streamSpeech
generateSpeech
通过文本或文本流生成语音块流。根据模型的不同,这可以完全是双工的。
import { streamSpeech, elevenlabs } from "modelfusion";
const textStream: AsyncIterable<string>;
const speechStream = await streamSpeech({
model: elevenlabs.SpeechGenerator({
model: "eleven_turbo_v2",
voice: "pNInz6obpgDQGcFmaJgB", // Adam
optimizeStreamingLatency: 1,
voiceSettings: { stability: 1, similarityBoost: 0.35 },
generationConfig: {
chunkLengthSchedule: [50, 90, 120, 150, 200],
},
}),
text: textStream,
});
for await (const part of speechStream) {
// each part is a Uint8Array with MP3 audio data
}
提供者: Eleven Labs
生成转录
将语音(音频)数据转录为文本。也称为语音转文本(STT)。
import { generateTranscription, openai } from "modelfusion";
import fs from "node:fs";
const transcription = await generateTranscription({
model: openai.Transcriber({ model: "whisper-1" }),
mimeType: "audio/mp3",
audioData: await fs.promises.readFile("data/test.mp3"),
});
提供者: OpenAI (Whisper), Whisper.cpp
嵌入值
为文本和其他值创建嵌入。嵌入是表示值在模型上下文中本质的向量。
import { embed, embedMany, openai } from "modelfusion";
// 嵌入单个值:
const embedding = await embed({
model: openai.TextEmbedder({ model: "text-embedding-ada-002" }),
value: "起初,诺克斯不知道该如何处理狗崽。",
});
// 嵌入多个值:
const embeddings = await embedMany({
model: openai.TextEmbedder({ model: "text-embedding-ada-002" }),
values: [
"起初,诺克斯不知道该如何处理狗崽。",
"他敏锐地观察并吸收了周围的一切,从天上的鸟到森林中的树。",
],
});
提供者: OpenAI, OpenAI compatible, Llama.cpp, Ollama, Mistral, Hugging Face, Cohere
分类值
将值分类到一个类别中。
import { classify, EmbeddingSimilarityClassifier, openai } from "modelfusion";
const classifier = new EmbeddingSimilarityClassifier({
embeddingModel: openai.TextEmbedder({ model: "text-embedding-ada-002" }),
similarityThreshold: 0.82,
clusters: [
{
name: "政治" as const,
values: [
"他们将拯救国家!",
// ...
],
},
{
name: "闲聊" as const,
values: [
"今天天气怎么样?",
// ...
],
},
],
});
// 强类型结果:
const result = await classify({
model: classifier,
value: "你不喜欢政治吗?",
});
分类器: EmbeddingSimilarityClassifier
分词文本
将文本拆分为标记并从标记中重构文本。
const tokenizer = openai.Tokenizer({ model: "gpt-4" });
const text = "起初,诺克斯不知道该如何处理狗崽。";
const tokenCount = await countTokens(tokenizer, text);
const tokens = await tokenizer.tokenize(text);
const tokensAndTokenTexts = await tokenizer.tokenizeWithTexts(text);
const reconstructedText = await tokenizer.detokenize(tokens);
提供者: OpenAI, Llama.cpp, Cohere
工具
工具是可以由AI模型执行的函数(及其相关元数据)。它们对构建聊天机器人和代理非常有用。
ModelFusion提供了几个开箱即用的工具:Math.js, MediaWiki Search, SerpAPI, Google Custom Search。你也可以创建自定义工具。
运行工具
使用runTool
,你可以要求一个兼容工具的语言模型(例如OpenAI chat)调用一个工具。runTool
首先生成一个工具调用,然后使用参数执行工具。
const { tool, toolCall, args, ok, result } = await runTool({
model: openai.ChatTextGenerator({ model: "gpt-3.5-turbo" }),
tool: calculator,
prompt: [openai.ChatMessage.user("十四乘以十二是多少?")],
});
console.log(`工具调用:`, toolCall);
console.log(`工具:`, tool);
console.log(`参数:`, args);
console.log(`成功:`, ok);
console.log(`结果或错误:`, result);
运行多个工具
使用runTools
,你可以要求一个语言模型生成多个工具调用以及文本。模型将选择哪些工具(如果有)应该使用哪些参数调用。文本和工具调用都是可选的。此功能执行工具。
const { text, toolResults } = await runTools({
model: openai.ChatTextGenerator({ model: "gpt-3.5-turbo" }),
tools: [calculator /* ... */],
prompt: [openai.ChatMessage.user("十四乘以十二是多少?")],
});
代理循环
你可以使用runTools
实现一个代理循环,响应用户消息并执行工具。了解更多。
向量索引
const texts = [
"彩虹是一种在某些气象条件下会发生的光学现象。",
"它是由光在水滴中的折射、内部反射和色散引起的,导致在天空中出现连续的光谱。",
// ...
];
const vectorIndex = new MemoryVectorIndex<string>();
const embeddingModel = openai.TextEmbedder({
model: "text-embedding-ada-002",
});
// 更新索引 - 通常在摄取过程中完成:
await upsertIntoVectorIndex({
vectorIndex,
embeddingModel,
objects: texts,
getValueToEmbed: (text) => text,
});
// 从向量索引中检索文本块 - 通常在查询时完成:
const retrievedTexts = await retrieve(
new VectorIndexRetriever({
vectorIndex,
embeddingModel,
maxResults: 3,
similarityThreshold: 0.8,
}),
"彩虹和水滴"
);
可用的向量存储: Memory, SQLite VSS, Pinecone
文本生成提示样式
你可以使用不同的提示样式(如文本、指令或聊天提示)与ModelFusion文本生成模型。这些提示样式可以通过.withTextPrompt()
、.withChatPrompt()
和.withInstructionPrompt()
方法访问:
文本提示样式
const text = await generateText({
model: openai
.ChatTextGenerator({
// ...
})
.withTextPrompt(),
prompt: "写一个关于机器人学习爱的短故事",
});
指令提示样式
const text = await generateText({
model: llamacpp
.CompletionTextGenerator({
// 使用llama.cpp运行https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF
promptTemplate: llamacpp.prompt.Llama2, // 设置提示模板
contextWindowSize: 4096, // Llama 2上下文窗口大小
maxGenerationTokens: 512,
})
.withInstructionPrompt(),
prompt: {
system: "你是一个故事作家。",
instruction: "写一个关于机器人学习爱的短故事。",
},
});
聊天提示样式
const textStream = await streamText({
model: openai
.ChatTextGenerator({
model: "gpt-3.5-turbo",
})
.withChatPrompt(),
prompt: {
system: "你是一位著名的诗人。",
messages: [
{
role: "user",
content: "给一个机器人取个名字。",
},
{
role: "assistant",
content: "我建议取名为Robbie。",
},
{
role: "user",
content: "写一个关于Robbie学习爱的短故事。",
},
],
},
});
图像生成提示模板
你也可以对图像模型使用提示模板,例如使用基本的文本提示。这作为简写方法提供:
const image = await generateImage({
model: stability
.ImageGenerator({
//...
})
.withTextPrompt(),
prompt:
"19世纪早期绘画风格的西方邪恶女巫",
});
提示模板 | 文本提示 |
---|---|
Automatic1111 | ✅ |
Stability | ✅ |
元数据和原始响应
当你将fullResponse
参数设置为true
时,ModelFusion模型函数返回丰富的响应,包括原始(原始)响应和元数据。
// 访问原始响应(需要类型化)和元数据:
const { text, rawResponse, metadata } = await generateText({
model: openai.CompletionTextGenerator({
model: "gpt-3.5-turbo-instruct",
maxGenerationTokens: 1000,
n: 2, // 生成2个完成
}),
prompt: "写一个关于机器人学习爱的短故事:\n\n",
fullResponse: true,
});
<SOURCE_TEXT>
console.log(metadata);
// cast to the raw response type:
for (const choice of (rawResponse as OpenAICompletionResponse).choices) {
console.log(choice.text);
}
Logging and Observability
ModelFusion 提供了一个观察者框架和日志支持。您可以轻松追踪运行和调用层次结构,并且您可以添加自己的观察者。
启用函数调用的日志记录
import { generateText, openai } from "modelfusion";
const text = await generateText({
model: openai.CompletionTextGenerator({ model: "gpt-3.5-turbo-instruct" }),
prompt: "写一个关于机器人学习爱的短篇故事:\n\n",
logging: "detailed-object",
});
文档
指南
集成
示例和教程
展示
API 参考
更多示例
基础示例
几乎所有单独函数和对象的示例。强烈推荐入门使用。
故事讲述者
多模态, 对象流, 图片生成, 文本转语音, 语音转文本, 文本生成, 对象生成, 嵌入值
StoryTeller 是一个探索性的 web 应用,为学龄前儿童创建简短的音频故事。
聊天机器人 (Next.JS)
Next.js 应用, OpenAI GPT-3.5-turbo, 流式传输, 中止处理
一个带有 AI 助手的 web 聊天应用,作为 Next.js 应用实现。
使用 PDF 聊天
终端应用, PDF 解析, 内存向量索引, 检索增强生成, 假设文档嵌入
向 PDF 文档提问并从文档中获取答案。
Next.js / ModelFusion 演示
Next.js 应用, 图片生成, 转录, 对象流, OpenAI, Stability AI, Ollama
使用 ModelFusion 和 Next.js 14 (App Router) 的示例:
- 图片生成
- 语音录制和转录
- 对象流式传输
双工语音流(使用 Vite/React 和 ModelFusion Server/Fastify)
语音流, OpenAI, Elevenlabs 流式传输, Vite, Fastify, ModelFusion 服务器
给出一个提示,服务器返回文本和语音流响应。
BabyAGI 代理
终端应用, 代理, BabyAGI
BabyAGI 经典版和 BabyBeeAGI 的 TypeScript 实现。
维基百科代理
终端应用, ReAct 代理, GPT-4, OpenAI 函数, 工具
从维基百科获取问题的答案,例如"谁出生在前,爱因斯坦还是毕加索?"
中学数学代理
终端应用, 代理, 工具, GPT-4
解决中学数学问题的小代理。它使用计算器工具来解题。
从 PDF 到推文
终端应用, PDF 解析, 递归信息提取, 内存向量索引, 样式示例检索, OpenAI GPT-4, 成本计算
从 PDF 中提取有关主题的信息,并用你的风格写一条推文。
Cloudflare Workers
Cloudflare, OpenAI
使用 ModelFusion 和 OpenAI 在 Cloudflare Worker 上生成文本。
贡献
贡献指南
阅读 ModelFusion 贡献指南,了解开发流程,如何提出错误修复和改进建议,以及如何构建和测试你的更改。 </SOURCE_TEXT>