当前位置: 首页 > news >正文

RAGFLOW使用flask转发的open ai接口

flask转发openai标准接口

背景

搭建RAGFLOW 的过程中,遇到一个比较严重的问题,公司部署的大模型代理需要获取token,且token存在有效期5分钟,在RAGFLOW中不能直接用,所以希望通过flask项目转发请求。

方案

比较好的是,RAGFLOW 可以配置OpenAI-API-Compatible

初始方案是计划准备两个接口,第一个接口/v1/chat/completions

@api_llm_proxy_bp.route("/v1/chat/completions", methods=['POST'])
async def chat_completions():
    payload = request.json
    logger.debug("chat_completions:{}", payload)
    res = await CustommizedAsyncOpenAI().chat.completions.create(**payload)
    json_result = res.to_json()
    logger.debug("chat_completions response:{}", json_result)
    return json_result

CustommizedAsyncOpenAI 是openai._client.AsyncOpenAI的子类,主要作用是封装指定公司大模型的url以及实时获取token放到header里面。

class CustommizedAsyncOpenAI(AsyncOpenAI):
    def __init__(self):
        base_url = get_config().get("llm_config").get("model_host")
        super().__init__(base_url=base_url, api_key="fake key")

    async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
        options = await super()._prepare_options(options)
        options.headers = {
            'Authorization': f'Bearer {TokenHolder().get_token()}'
        }
        return options

另一个接口是向量化接口:/v1/embeddings

@api_llm_proxy_bp.route("/v1/embeddings", methods=['POST'])
async def embeddings():
    payload = request.json
    logger.debug("embeddings:{}", payload)
    res = await CustommizedEmbeddingsOpenAI().embeddings.create(**payload)
    json_result = res.to_json()
    logger.debug("embeddings response:{}", json_result)
    return json_result

CustommizedEmbeddingsOpenAI也是自己写的openai._client.AsyncOpenAI的子类,区别是只对应了公司向量模型的url。

在RAGFLOW 中分别配置chat和embeddings,成功添加模型。

STREAM转发的问题与解决

在RAGFLOW中添加本地文件并解析没有问题,但是后续在使用知识库聊天的时候发现不支持stream请求,导致无法聊天。资料查了半天,对比RAGFLOW处理stream请求的代码,加上了flask 转发open ai的steam标准响应结构:

@api_llm_proxy_bp.route("/v1/chat/completions", methods=['POST'])
async def chat_completions():
    payload = request.json
    logger.debug("chat_completions:{}", payload)
    if payload.get("stream") is True:
        res = CustommizedOpenAI().chat.completions.create(**payload)

        def stream_response():
            for chunk in res:
                logger.info("chat_completions response:{}", chunk.to_json())
                yield f"data:{json.dumps(chunk.to_dict(), ensure_ascii=False)}" + "\n\n"

        return Response(stream_response(), mimetype="text/event-stream")
    else:

        res = await CustommizedAsyncOpenAI().chat.completions.create(**payload)
        json_result = res.to_json()
        logger.debug("chat_completions response:{}", json_result)
        return json_result

上面的重点是两部分:

  1. 第一部分,yield 后面的格式:
yield f"data:{json.dumps(chunk.to_dict(), ensure_ascii=False)}" + "\n\n"
  1. 第二部分,mimetype
Response(stream_response(), mimetype="text/event-stream")

使用的CustommizedOpenAI,是自己实现的openai._client.OpenAI的子类,没有用异步是因为前面异步一直没有成功,现在看原因是data的格式问题,因为有些资料提到flask 异步stream 做的不好,所以先当时暂时使用非异步的方案。

stream 转发的验证

前面因为stream 转发一直没有处理很好,在RAGFLOW中一直没有成功,问题很难排查,原因在于有两层转发,一层是自己的flask项目中的stream转发,另一层是RAGFLOW中也对openai api stream响应做了二次处理,然后再以stream方式响应。

后面反应过来,可以抛开RAGFLOW,验证自己的stream转发是否成功,直接用openai接口去调用自己的接口:

from openai import OpenAI


def test_steam():
    client = OpenAI(api_key="fake key", base_url="http://localhost:5002/agent/api/llm_proxy/v1")

    messages = [
        {"role": "user", "content": "你是谁"},
    ]
    res = client.chat.completions.create(messages=messages, model="gpt-4o-240806-deploy-gs", stream=True)

    for chunk in res:
        print(chunk.to_json())

如果能连续打印如下的结构,说明stream 转发没有问题:

{
  "id": "chatcmpl-B324oTT5jWz3xeACiotosOKzyUk8J",
  "choices": [
    {
      "delta": {
        "content": "忙"
      },
      "finish_reason": null,
      "index": 0,
      "logprobs": null
    }
  ],
  "created": 1740062666,
  "model": "gpt-4o-2024-11-20",
  "object": "chat.completion.chunk",
  "system_fingerprint": "fp_b705f0c291"
}

相关文章:

  • C# 十六进制字符串转换为十进制
  • Error [ERR_REQUIRE_ESM]: require() of ES Module
  • 深入了解 DevOps 基础架构:可追溯性的关键作用
  • 深入理解 C++17 中的 std::atomic<T>::is_always_lock_free
  • 全面了解 Stanford NLP:强大自然语言处理工具的使用与案例
  • 在mfc中使用自定义三维向量类和计算多个三维向量的平均值
  • Alluxio Enterprise AI 3.5 发布,全面提升AI模型训练性能
  • UE 学习记录
  • 2025-02-20 学习记录--C/C++-PTA 7-27 冒泡法排序
  • PT8022W 单触控单输出 LED 调光 IC
  • uni-app小程序开发 基础知识2
  • python-leetcode 39.二叉树的直径
  • 第一篇:DeepSeek-R1 的诞生与背景
  • (蓝桥杯——10. 小郑做志愿者)洛斯里克城志愿者问题详解
  • kill -9 结束某个用户所有进程的方式-linux019
  • 来京东实习的个人收获与总结
  • 【大模型】DeepSeek-RAG 本地化部署与军事情报应用研究报告
  • spring中aop
  • Canvas进阶-2、可视化应用
  • C++ Primer 库-IO类
  • 王庆成:儒家、墨家和洪秀全的“上帝”
  • 伊朗外长: 美伊谈判进展良好,讨论了很多技术细节
  • 新华时评·首季中国经济观察丨用好用足更加积极的财政政策
  • 阿联酋启动第三届全球航空奖评选,奖金总额达百万美元
  • 印媒称印巴在克什米尔控制线沿线发生小规模交火,巴方暂未回应
  • 拉卡拉一季度净利约1亿降超五成,去年净利3.5亿降逾23%