avatar

Neo·元

算法的尽头,认知的倒影

  • 首页
  • 时代视野
  • 生活随笔
  • 关于Neo·元
主页 本地大模型分离部署逻辑推理服务器实战(下)
文章

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

发表于 2026-07-25 更新于 2026-07- 25
作者 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-NC 4.0
分享
本文同步发布于个人博客 Neo·元,转载请注明出处。

相关文章

7月 31, 2026

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

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

7月 31, 2026

Token 暴涨、上下文爆炸的 5 种真实业务优化

做大模型应用,最容易被忽视但最致命的问题就是 Token 爆炸。很多项目原型跑得很好,一上线就崩,不是模型不行,而是上下文直接撑爆。 固定做 5 件事,基本能把 Token 压到原来的 1/3 甚至更少。 第一,历史对话必须截断。没有人需要无限长的上下文,保留最近 5~10 轮足够。 第二,系统提示

7月 31, 2026

SSE 流式返回不稳定问题彻底解决

在私有化大模型项目里,想要实现类似 ChatGPT 逐字输出的流式效果,绝大多数人都会选择 SSE 方案。前后端框架集成看起来简单,但真正部署到公网环境后,各类隐性问题会陆续暴露:前端经常莫名断连、模型生成到一半数据流中断、部分网络环境下完全收不到推送内容。过去一段时间,我在三个不同的项目中都碰到同

下一篇

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

上一篇

SSE 流式返回不稳定问题彻底解决

最近更新

  • 人工智能时代的破局与探索:编程与创作
  • 中小企业私有化大模型硬件配置实战
  • Token 暴涨、上下文爆炸的 5 种真实业务优化
  • SSE 流式返回不稳定问题彻底解决
  • 本地大模型分离部署逻辑推理服务器实战(下)

热门标签

Tools DeepSeek AI times LangChain RAG LangGraph

©2026 All Rights Reserved Neo 鲁ICP备2026037083号