从源码深入理解One-API框架:适配器模式实现LLM接口对接
1. 概述
one-api 是一个开源的 API 框架,基于go语言开发,旨在提供统一的接口调用封装,支持多种 AI 服务平台的集成。通过 Gin 和 GORM 等框架,框架简化了多种 API 服务的调用流程。通过适配器模式实现了与多种 大模型API 服务的集成,而无需每次都重新编写调用逻辑。使得开发者能够专注于业务逻辑,而不是各个平台间的差异化处理。
在本文中,将深入解读 one-api 框架的工作原理,详细讲解框架的结构与实现,并通过集成阿里灵积DashScope大模型服务 API 为例,展示其适配器实现。
2. 路由与控制器
在 one-api 中,所有的 API 请求都会通过 Gin 框架来处理。以下是一个典型的请求路由:
relayV1Router.POST("/chat/completions", controller.Relay)
和大模型交互相关的核心逻辑都集中在 controller.Relay函数中。
如上图是Relay函数的实现,主要完成三个事情:
(1)获取relayMode
(2)根据repayMode请求LLM接口
(3)异常处理及重试
3. GetByPath函数
GetByPath
函数会根据请求路径返回不同的 relayMode
,比如文本生成、图像生成或音频处理等。
4. relayHelper函数
根据获取到的 relayMode,框架会调用不同的处理方法。具体代码如下:
如果 relayMode
为文本请求,则调用 controller.RelayTextHelper(c);
如果是图像生成请求,则调用 RelayImageHelper
等。
5. RelayTextHelper函数
RelayTextHelper 是 one-api 框架中负责处理文本请求的核心函数,它包含了一系列的操作步骤来完成整个请求的处理流程。
- 从请求中获取并验证 textRequest
- 获取待调用的模型名称
- 设置
system prompt
- 获取请求的配额和使用限制
- 预消耗配额
- 根据
APIType
获取适配器adaptor
- 构建对应adaptor的请求体
- 使用对应的adaptor的向大模型发起请求
- 处理封装请求结果
- 最终消耗扣减配额
整个过程绝大多数的过程都是在做参数转换及参数设置,比较关键的一步是“构建实际的请求体”。使用适配器模式对各种大模型接口进行适配,根据不同的apiType
得到不同的适配器对象,如openai.Adaptor、ali.Adaptor、baidu.Adaptor、zhipu.Adaptor等。
注:
apiType
的获取方式为:
meta.APIType = channeltype.ToAPIType(meta.ChannelType)
,即与在one-api管理页面上配置的渠道类型一致,如果配置的是“阿里通义千问”,那么apiType就为apitype.Ali
。具体可参见源码中的relay/channeltype/helper.go
中的ToAPIType(channelType int) int
函数,在此不做赘述。
Adaptor是一个接口,定义了如下方法:
接入第三方LLM接口的时候只需要实现对应的适配器即可完成对接,截止发文当日one-api已经集成了近40家AI厂商的大模型接口,包括国内的baidu、ali、doubao、zhipu等。
6. 阿里灵积DashScope适配
以下是阿里灵积DashScope大模型服务的适配器实现:
package alitype Adaptor struct {meta *meta.Meta
}func (a *Adaptor) Init(meta *meta.Meta) {a.meta = meta
}func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {fullRequestURL := ""switch meta.Mode {case relaymode.Embeddings:fullRequestURL = fmt.Sprintf("%s/api/v1/services/embeddings/text-embedding/text-embedding", meta.BaseURL)case relaymode.ImagesGenerations:fullRequestURL = fmt.Sprintf("%s/api/v1/services/aigc/text2image/image-synthesis", meta.BaseURL)default:fullRequestURL = fmt.Sprintf("%s/api/v1/services/aigc/text-generation/generation", meta.BaseURL)}return fullRequestURL, nil
}func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {adaptor.SetupCommonRequestHeader(c, req, meta)if meta.IsStream {req.Header.Set("Accept", "text/event-stream")req.Header.Set("X-DashScope-SSE", "enable")}req.Header.Set("Authorization", "Bearer "+meta.APIKey)if meta.Mode == relaymode.ImagesGenerations {req.Header.Set("X-DashScope-Async", "enable")}if a.meta.Config.Plugin != "" {req.Header.Set("X-DashScope-Plugin", a.meta.Config.Plugin)}return nil
}func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {if request == nil {return nil, errors.New("request is nil")}switch relayMode {case relaymode.Embeddings:aliEmbeddingRequest := ConvertEmbeddingRequest(*request)return aliEmbeddingRequest, nildefault:aliRequest := ConvertRequest(*request)return aliRequest, nil}
}func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {if request == nil {return nil, errors.New("request is nil")}aliRequest := ConvertImageRequest(*request)return aliRequest, nil
}func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBody io.Reader) (*http.Response, error) {return adaptor.DoRequestHelper(a, c, meta, requestBody)
}func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {if meta.IsStream {err, usage = StreamHandler(c, resp)} else {switch meta.Mode {case relaymode.Embeddings:err, usage = EmbeddingHandler(c, resp)case relaymode.ImagesGenerations:err, usage = ImageHandler(c, resp)default:err, usage = Handler(c, resp)}}return
}func (a *Adaptor) GetModelList() []string {return ModelList
}func (a *Adaptor) GetChannelName() string {return "ali"
}
这段代码实现了 Adaptor 接口,适配了阿里云 AI 服务的请求和响应处理。通过一系列方法,Adaptor 能够完成以下任务:
- 根据请求模式生成 API 请求 URL。
- 设置 HTTP 请求头,包括授权信息、流式请求标识等。
- 将通用请求数据转换为阿里云特定的请求格式。
- 向阿里云服务发起请求,并处理响应。
- 获取支持的模型列表和通道名称。
- 它为 one-api 框架提供了对阿里云 AI 服务的无缝集成,简化了与阿里云接口交互的代码。
总结
综合上述内容,通过一张时序图来说明整个调用流程:
参考说明
one-api:https://github.com/songquanpeng/one-api
gorm: https://gorm.io/zh_CN/docs/index.html
gin: https://gin-gonic.com/zh-cn/docs/
相关文章:
从源码深入理解One-API框架:适配器模式实现LLM接口对接
1. 概述 one-api 是一个开源的 API 框架,基于go语言开发,旨在提供统一的接口调用封装,支持多种 AI 服务平台的集成。通过 Gin 和 GORM 等框架,框架简化了多种 API 服务的调用流程。通过适配器模式实现了与多种 大模型API 服务的集…...
2025年国产化推进.NET跨平台应用框架推荐
2025年国产化推进.NET跨平台应用框架推荐 1. .NET MAUI NET MAUI是一个开源、免费(MIT License)的跨平台框架(支持Android、iOS、macOS 和 Windows多平台运行),是 Xamarin.Forms 的进化版,从移动场景扩展到…...
Tensor 基本操作4 理解 indexing,加减乘除和 broadcasting 运算 | PyTorch 深度学习实战
前一篇文章,Tensor 基本操作3 理解 shape, stride, storage, view,is_contiguous 和 reshape 操作 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started Tensor 基本使用 索引 indexing示例代码 加减…...
图扑 2024 全年精彩回顾 | 稳步向前
2024 年即将过去,回顾这一年,图扑软件在多个领域取得了显著成就,我们斩获多项行业奖项,稳步提升了市场地位,并在产品创新上推出了一系列新功能,提升了用户体验。与此同时,通过与合作伙伴紧密协作…...
[Python学习日记-79] socket 开发中的粘包现象(解决模拟 SSH 远程执行命令代码中的粘包问题)
[Python学习日记-79] socket 开发中的粘包现象(解决模拟 SSH 远程执行命令代码中的粘包问题) 简介 粘包问题底层原理分析 粘包问题的解决 简介 在Python学习日记-78我们留下了两个问题,一个是服务器端 send() 中使用加号的问题,…...
【数据结构】深入解析:构建父子节点树形数据结构并返回前端
树形数据结构列表 一、前言二、测试数据生成三、树形代码3.1、获取根节点3.2、遍历根节点,递归获取所有子节点3.3、排序3.4、完整代码 一、前言 返回前端VO对象中,有列情况列表展示需要带树形结构,例如基于RBAC权限模型中的菜单返回…...
【统计的思想】假设检验(二)
假设检验是根据人为设定的显著水平,对被测对象的总体质量特性进行统计推断的方法。 如果我们通过假设检验否定了零假设,只是说明在设定的显著水平下,零假设成立的概率比较小,并不是说零假设就肯定不成立。如果零假设事实上是成立…...
IT服务规划设计
1. IT服务设计的作用 1) 设计满足需求的IT服务。 2) 设计SAL,测量方法和指标。 3) 设计服务过程及控制方法。...
高效查找:二分查找算法解析
1.二分查找简介 二分查找算法(Binary Search)是一种高效的查找算法,适用于有序数组或序列。它的基本思想是通过逐步缩小查找范围,将查找区间一分为二,直到找到目标值或确定目标值不存在。 算法原理:在数组…...
电脑办公技巧之如何在 Word 文档中添加文字或图片水印
Microsoft Word是全球最广泛使用的文字处理软件之一,它为用户提供了丰富的编辑功能来美化和保护文档。其中,“水印”是一种特别有用的功能,它可以用于标识文档状态(如“草稿”或“机密”)、公司标志或是版权信息等。本…...
我的求职之路合集
我把我秋招和春招的一些笔面试经验在这里发一下,网友们也可以参考一下。 我的求职之路:(1)如何谈自己的缺点 我的求职之路:(2)找工作时看重的点 我的求职之路:(3&…...
FPGA自分频产生的时钟如何使用?
对于频率比较小的时钟,使用clocking wizard IP往往不能产生,此时就需要我们使用代码进行自分频,自分频产生的时钟首先应该经过BUFG处理,然后还需要进行时钟约束,处理之后才能使用。...
【2025最新计算机毕业设计】基于SpringBoot+Vue爬虫技术的咖啡与茶饮料文化平台(高质量源码,可定制,提供文档,免费部署到本地)
作者简介:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容:🌟Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…...
jmeter中对接口进行循环请求后获取相应数据
1、工作中遇到一个场景就是对某个单一接口进行循环请求,并需要获取每次请求后返回的相应数据; 2、首先就在jmeter对接口相关组件进行配置,需要组件有:循环控制器、CSV数据文件设置、计数器、访问接口、HTTP信息头管理器、正则表达…...
RocketMQ 怎么保证消息的可靠性?
目录 1. 消息发送可靠性 1.1 同步发送 1.2 异步发送 1.3 发送重试 1.4 事务消息 2. 消息存储可靠性 2.1 CommitLog 持久化 2.2 刷盘机制 2.3 主从复制 2.4 消息索引 3. 消息消费可靠性 3.1 消费确认机制 3.2 消费重试机制 3.3 消费位点管理 3.4 集群消费与广播消…...
基于 Node.js 的天气查询系统实现(附源码)
项目概述 这是一个基于 Node.js 的全栈应用,前端使用原生 JavaScript 和 CSS,后端使用 Express 框架,通过调用第三方天气 API 实现天气数据的获取和展示。 主要功能 默认显示多个主要城市的天气信息 支持城市天气搜索 响应式布局设计 深色主题界面 优雅的加载动画 技术栈 …...
C++函数初识
文章目录 一、形参带默认值的函数二、inline内联函数三、函数重载 一、形参带默认值的函数 给默认值的时候,从右向左给;调用效率的问题;定义处可以给形参默认值,声明也可以给形参默认值;形参给默认值的时候࿰…...
代码随想录day3
203:移除链表元素:注意虚拟头节点的使用 ListNode* removeElements(ListNode* head, int val) {ListNode* result new ListNode();result->next head;ListNode* current result;while(current ! nullptr && current->next ! nullptr){if(current-…...
论文+AI赋能教育:探索变革路径与创新实践。包括word和pdf格式。
下载地址链接: https://download.csdn.net/download/wanggang130532/90292129https://download.csdn.net/download/wanggang130532/90292129...
ray.rllib 入门实践-5: 训练算法
前面的博客介绍了ray.rllib中算法的配置和构建,也包含了算法训练的代码。 但是rllib中实现算法训练的方式不止一种,本博客对此进行介绍。很多教程使用 PPOTrainer 进行训练,但是 PPOTrainer 在最近的 ray 版本中已经取消了。 方式1࿱…...
uniapp 在线更新应用
在线更新应用及进度条显示 1.比较现安装手机中的apk 与线上apk的版本 getVersion(){var newVersionuni.getStorageSync("newVersion").split(".")var versionplus.runtime.version.split(".") // 获取手机安装的版本var versionNum""…...
中间件安全
一.中间件概述 1.中间件定义 介绍:中间件(Middleware)作为一种软件组件,在不同系统、应用程序或服务间扮演着数据与消息传递的关键角色。它常处于应用程序和操作系统之间,就像一座桥梁,负责不同应用程序间…...
从根源分析,调试,定位和解决MacOS ld: unsupported tapi file type ‘!tapi-tbd‘ in YAML file
你要是遇到同样错误,找一圈都没有解决,建议认真读一下本文,这个应该是最终极的解决办法,从原理上剖析了产生的原因,同时给出来了调试和定位的办法。 maccos使用brew安装了一个gcc14, 结果编译一个最简单的程序都报错&a…...
Linux的权限和一些shell原理
目录 shell的原理 Linux权限 sudo命令提权 权限 文件的属性 ⽂件类型: 基本权限: chmod改权限 umask chown 该拥有者 chgrp 改所属组 最后: 目录权限 粘滞位 shell的原理 我们广义上的Linux系统 Linux内核Linux外壳 Linux严格…...
构建企业级React应用的进阶实践
构建企业级React应用的进阶实践 在当今前端开发领域,React凭借其组件化架构和声明式编程范式,已成为构建复杂用户界面的首选方案。本文将深入探讨React的高级应用场景,通过一系列精心设计的代码示例,展示如何打造高性能、可维护的…...
2024年度总结:技术探索与个人成长的交织
文章目录 前言年度创作回顾:技术深耕与分享数据库技术:MySQL 与 MyBatisJava 及相关技术栈计算机网络:构建网络知识体系思维方式的转变:构建技术知识体系的桥梁 项目实践:人工智能与智慧医疗的碰撞生活与博客的融合与平…...
mysql-06.JDBC
目录 什么是JDBC: 为啥存在JDBC: JDBC工作原理: JDBC的优势: 下载mysql驱动包: 用java程序操作数据库 1.创建dataSource: 2.与服务端建立连接 3.构造sql语句 4.执行sql 5.关闭连接,释放资源 参考代码: 插…...
arm-linux平台、rk3288 SDL移植
一、所需环境资源 1、arm-linux交叉编译器,这里使用的是gcc-linaro-6.3.1 2、linux交叉编译环境,这里使用的是Ubuntu 20.04 3、sdl2源码 https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.30.11.tar.gz 二、代码编译 1、解压sdl2源码…...
CentOS 上安装 Go (Golang)
1. 检查系统环境 确保系统为 CentOS 7 或 CentOS 8,或者其他兼容的 Linux 发行版。 cat /etc/os-release2. 安装依赖 安装一些必要的工具: sudo yum update -y sudo yum install -y wget tar3. 下载 Go 从 Go 官方下载页面获取适用于 Linux 的最新版…...
小哆啦解题记:整数转罗马数字
小哆啦解题记:整数转罗马数字 小哆啦开始力扣每日一题的第十四天 https://leetcode.cn/problems/integer-to-roman/submissions/595220508/ 第一章:神秘的任务 一天,哆啦A梦接到了一项任务——将一个整数转换为罗马数字。他心想:…...
碰撞体问题
用点检测2d物体是否有物体 功能要求是点击空白处取消选中,点击棋子选中所以我做了一个射线检测。但是脑子的惯性让我用的是3D的射线检测。但我们这是一个2D游戏啊。 Vector3 mousePos pos;mousePos.z 10f; // 假设你需要转换到距离相机10单位的世界位置Vector3 …...
HTML<label>标签
例子 三个带标签的单选按钮: <form action"/action_page.php"> <input type"radio" id"html" name"fav_language" value"HTML"> <label for"html">HTML</label><br&…...
「 机器人 」利用数据驱动模型替代仿真器:加速策略训练并降低硬件依赖
前言 在强化学习(Reinforcement Learning, RL)中,策略训练需要大量的交互数据(状态、动作、奖励、下一状态),而这些数据通常来自仿真器或真实硬件。传统高保真仿真器虽然能在一定程度上模拟飞行器的动力学,但往往计算量大、开发成本高,且仍可能与真实环境存在差距。为此…...
.Net Core微服务入门全纪录(六)——EventBus-事件总线
系列文章目录 1、.Net Core微服务入门系列(一)——项目搭建 2、.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上) 3、.Net Core微服务入门全纪录(三)——Consul-服务注…...
QD Laser携“Lantana”激光器参展SPIE光子学西部展2025,聚焦紧凑型设计
据悉,QD Laser公司将在2025年SPIE光子学西部展览会上展出其最新产品——世界最小一体化紧凑型可见光激光器“Lantana”。该展会将于1月28日至30日在旧金山的Moscone中心举行。 在展会期间,QD Laser公司将现场展示这款超小型、轻便设备—— “Lantana”。…...
Docker + Nginx 部署个人静态博客指南
本文是一个使用 Docker 和 Nginx 部署个人静态博客的指南。通过本指南,您可以快速了解如何使用 Docker 和 Nginx 部署自己的静态博客网站。 前提 在开始使用本指南之前,请具备以下前提: 首先你得有个服务器服务器已经安装好Git、Vim等工具一…...
springboot3 集成 knife4j(接口文档)
提示:文章是集成 knife4j,而非 swagger2 或者 swagger3,效果如图 文章目录 前言一、添加依赖二、如何集成1.配置文件2.注解部分1.Tag2.Operation3.Parameter4.Schema 3.使用 总结 前言 提示::大家在开发阶段ÿ…...
批量创建ES索引
7.x from elasticsearch import Elasticsearch# 配置 Elasticsearch 连接 # 替换为你的 Elasticsearch 地址、端口、用户名和密码 es Elasticsearch([http://10.10.x.x:43885],basic_auth(admin, XN272G9THEAPYD5N5QORX3PB1TSQELLB) )# # 测试连接 # try: # # 尝试获取集…...
单路由及双路由端口映射指南
远程登录总会遇到登陆不上的情况,可能是访问的大门没有打开哦,下面我们来看看具体是怎么回事? 当软件远程访问时,主机需要两个条件,一是有一个唯一的公网IP地址(运营商提供),二是开…...
基于Springboot + vue实现的民俗网
“前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站:人工智能学习网站” 💖学习知识需费心, 📕整理归纳更费神。 🎉源码免费人人喜…...
動態住宅IP提升網站訪問成功率
動態住宅IP通常與普通家庭用戶的網路連接相關聯。這種IP地址的特點在於,它是動態變化的,用戶在每次連接時可能會獲得不同的IP地址。這與靜態IP形成了鮮明對比,後者在連接期間保持不變。傳統上,IP地址分為住宅IP和數據中心IP兩類。…...
Java集合学习:HashMap的原理
一、HashMap里的Hash是什么? 首先,我们先要搞清楚HashMap里的的Hash是啥意思。 当我们在编程过程中,往往需要对线性表进行查找操作。 在顺序表中查找时,需要从表头开始,依次遍历比较a[i]与key的值是否相等ÿ…...
使用rsync+inotify简单实现文件实时双机双向同步
使用rsyncinotify简单实现文件实时双机双向同步 实现思路 使用inotify-tools的inotifywait工具监控文件变化,触发后使用rsync做同步。加入系统服务项,实现实时监听,方便管理。 以下配置操作,单向同步,只需在单边部…...
[JavaScript] ES6及以后版本的新特性
文章目录 箭头函数(Arrow Functions)为什么需要箭头函数?箭头函数的完整语法箭头函数中的 this实用场景 解构赋值(Destructuring Assignment)为什么需要解构赋值?数组解构赋值的完整用法对象解构赋值的完整…...
IO进程 寒假作业
一、请使用消息队列实现2个终端之间互相聊天 #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/wait.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> …...
无公网IP 外网访问媒体服务器 Emby
Emby 是一款多媒体服务器软件,用户可以在 Emby 创建自己的个人多媒体娱乐中心,并且可以跨多个设备访问自己的媒体库。它允许用户管理传输自己的媒体内容,比如电影、电视节目、音乐和照片等。 本文将详细的介绍如何利用 Docker 在本地部署 Emb…...
【2025小年源码免费送】
💖学习知识需费心, 📕整理归纳更费神。 🎉源码免费人人喜, 🔥码农福利等你领! 💖山高路远坑又深, 📕大军纵横任驰奔, 🎉谁敢横刀立马行…...
哈希表示例
示例1 两数之和 "两数之和"(Two Sum)是LeetCode上的一个经典算法问题,编号为1,它要求在一个整数数组nums中找到两个不同的索引i和j,使得nums[i] nums[j] target。 问题描述: 给定一个整数数…...
VS企业版和专业版的区别
网上查询vs分析dump文件,查找托管内存泄露,需要使用“调试托管内存”功能,当前安装的vs2022 专用版找不到这个选项,vs2015是ok的,比较版本发现2022是专业版,2015是企业版。网上搜索专业版和企业版差异如下&…...
YOLOv10-1.1部分代码阅读笔记-train.py
train.py ultralytics\models\yolov10\train.py 目录 train.py 1.所需的库和模块 2.class YOLOv10DetectionTrainer(DetectionTrainer): 1.所需的库和模块 from ultralytics.models.yolo.detect import DetectionTrainer from .val import YOLOv10DetectionValidator fr…...