avatar

Neo·元

算法的尽头,认知的倒影

  • 首页
  • 三千问道
  • 万法归宗
  • 诗酒田园
  • 关于NeoBlog
主页 本地大模型分离部署逻辑推理服务器实战(下)
文章

本地大模型分离部署逻辑推理服务器实战(下)

发表于 18天前 更新于 18天前
作者 Neo
14~19 分钟 阅读

3、异步升级思路:

Python环境加入Redis:

pip install redis

使用AioRedis消除线程阻塞,配合FastAPI 实现高并发,Nginx禁用缓冲及超长等待,Python加入心跳保活,前端防止SSE响应并加入重连

2、代码升级:

异步服务层:

发送请求:

import redis.asyncio as redis
import json
import logging

logger = logging.getLogger(__name__)

class AsyncRedisStreamService:
    def __init__(self, host='localhost', port=6379, db=0):
        self.redis_client = redis.Redis(host=host, port=port, db=db, decode_responses=True)

    async def publish_chunk(self, task_id: str, chunk: str, status: str = "processing"):
        """异步发布推理片段"""
        channel = f"stream:{task_id}"
        message = json.dumps({"task_id": task_id, "chunk": chunk, "status": status})
        await self.redis_client.publish(channel, message)

    async def get_pubsub(self):
        """获取异步 PubSub 对象"""
        return self.redis_client.pubsub()

    async def close(self):
        await self.redis_client.aclose()

利用 aio-pika 和 aioredis 实现全异步链路:

import aio_pika
import json
import asyncio
from langchain_community.llms import Ollama
from app.services.async_redis_service import AsyncRedisStreamService

llm = Ollama(model="llama3")
redis_service = AsyncRedisStreamService()


async def process_task(message: aio_pika.IncomingMessage):
    async with message.process():
        body = json.loads(message.body.decode())
        task_id = body['task_id']

        try:
            # LangChain 异步流式推理
            async for chunk in llm.astream(f"请总结:{body['cleaned_content']}"):
                await redis_service.publish_chunk(task_id, chunk)

            await redis_service.publish_chunk(task_id, "", status="completed")
        except Exception as e:
            await redis_service.publish_chunk(task_id, str(e), status="failed")


async def main():
    connection = await aio_pika.connect("amqp://guest:guest@localhost/")
    channel = await connection.channel()
    queue = await channel.declare_queue("llm_inference_queue", durable=True)
    await queue.consume(process_task)
    print("Async Consumer Started...")
    await asyncio.Future()


if __name__ == "__main__":
    asyncio.run(main())

异步接口层:

import json
from fastapi import APIRouter, BackgroundTasks, HTTPException
from app.schemas.models import CleanRequest, InferenceResult
from app.services.producer import process_and_publish_task
from app.services.state_store import task_results
from fastapi.responses import StreamingResponse
from app.services.async_redis_service import AsyncRedisStreamService

import asyncio
router = APIRouter()

@router.post("/clean-and-submit")
async def submit_task(request: CleanRequest, background_tasks: BackgroundTasks):
    try:
        task_id = await process_and_publish_task(request)
        return {"task_id": task_id, "status": "submitted"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/result/{task_id}", response_model=InferenceResult)
def get_result(task_id: str):
    if task_id not in task_results:
        raise HTTPException(status_code=404, detail="Task not found")
    data = task_results[task_id]
    return InferenceResult(task_id=task_id, status=data["status"], result=data.get("result"))


@router.get("/stream/{task_id}")
async def stream_result(task_id: str):
    async def event_generator():
        service = AsyncRedisStreamService()
        pubsub = await service.get_pubsub()
        await pubsub.subscribe(f"stream:{task_id}")
        last_heartbeat = asyncio.get_event_loop().time()

        try:
            async for message in pubsub.listen():
                if message['type'] == 'message':
                    data = json.loads(message['data'])
                    yield f"data: {json.dumps(data)}\n\n"
                    last_heartbeat = asyncio.get_event_loop().time()

                    if data.get('status') in ['completed', 'failed']:
                        break

                # 心跳保活:若 15 秒无数据,发送注释行防止连接断开
                elif asyncio.get_event_loop().time() - last_heartbeat > 15:
                    yield ": heartbeat\n\n"
                    last_heartbeat = asyncio.get_event_loop().time()

        except asyncio.CancelledError:
            pass
        finally:
            await pubsub.unsubscribe(f"stream:{task_id}")
            await service.close()

    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "X-Accel-Buffering": "no"  # 关键:禁用 Nginx 缓冲
        }
    )

Nginx配置文件优化:

location /api/v1/stream/ {

    proxy_pass http://127.0.0.1:8000;

    
    # 关键配置:禁用代理缓冲

    proxy_buffering off;

    
    # 确保 HTTP 版本支持长连接

    proxy_http_version 1.1;

    proxy_set_header Connection "";
  

    # 增加超时时间,适应长时推理任务

    proxy_read_timeout 3600s;

    proxy_send_timeout 3600s;

    
    # 禁用 gzip 压缩,避免分块传输编码冲突

    gzip off;

}

前端优化:

在HTTP Header加入

Cache-Control: no-cache

前端处理SSE时,加入自动重连:


const eventSource = new EventSource('/api/v1/stream/123');

// 设置重连时间为 3 秒

eventSource.onopen = () => {

    console.log('Connection opened');

};

eventSource.onmessage = (event) => {

    const data = JSON.parse(event.data);

    updateUI(data);

};

eventSource.onerror = (err) => {

    console.error('Connection lost, reconnecting...', err);

};

后端指定重连时间:

yield "retry: 3000\n\n"

万法归宗
AI
许可协议:  CC BY 4.0
分享

相关文章

8月 11, 2026

浅谈LangChain\LangGraph(下)

前言: 之前已经在本地跑通了LangChain的Demo项目了,接下来要改造成LangGraph,首先分析一下langGraph的几大优势点: 我的个人总结: 1、从线性管道到状态机节点(类似从二维升级到了三维,单线程变成多线程) 2、控制流变成循环、分支,比原先的单向高级了 3、容错性变强、支持回

8月 10, 2026

浅谈LangChain\LangGraph(上)

前言: 简单聊一下使用LangChain的一些心得,个人感觉就是操作大模型调用自己的向量数据库,然后触发自定义工具包的一个生产框架,主要包括RAG(向量数据库)和Agent(工具包)两部分核心组成。 RAG一般来源于企业生产中的文档资料,需要转换成大模型识别的向量数据库,一般要先把Word\Exce

7月 31, 2026

中小企业私有化大模型硬件配置实战

站在中小企业的视角,自研私有化大模型的核心诉求从来不是极致高并发、超大参数量模型集群,而是低成本采购、单人可运维、稳定支撑日常业务问答、文档摘要、内部知识库检索这类轻量化场景。 市面上很多算力教程都是面向互联网大厂、AI 实验室撰写,动辄多卡分布式、A100/H100 专业算力卡,完全脱离中小团队的

下一篇

本地大模型分离部署逻辑推理服务器实战(上)

上一篇

道家 因果

最近更新

  • 浅谈LangChain\LangGraph(下)
  • 浅谈LangChain\LangGraph(上)
  • 中小企业私有化大模型硬件配置实战
  • Token 暴涨、上下文爆炸的 5 种真实业务优化
  • FastAPI + AioRedis 消除线程阻塞实战

热门标签

AI

©2026 All Rights Reserved Neo 鲁ICP备2026037083号