从 0 到 1 搭建可商用的 AI 聊天机器人300 行代码搞定 RAG 流式输出摘要拒绝“Demo 一时爽上线火葬场”。本文摒弃冗长的理论直接提供一套基于LangChain Chroma FastAPI的生产级 RAG 解决方案。包含完整的上下文管理、流式输出以及商用级别的限流与日志处理核心代码仅需300 行。一、痛点引入为什么 90% 的 RAG 项目都跑不起来在当前的 AI 落地浪潮中许多开发者在搭建 RAG检索增强生成系统时会陷入以下困境教程脱离实际网上的教程大多停留在 Jupyter Notebook 里的玩具代码一旦放入生产环境立刻面临并发崩溃、内存泄漏等问题。上下文管理混乱多轮对话时历史消息要么丢失要么无限膨胀导致 Token 超限和成本失控。流式输出卡顿前端体验极差要么一次性全量返回要么流式输出时断时续缺乏标准的 SSE (Server-Sent Events) 实现。缺乏商用兜底没有接口限流、没有请求日志、没有优雅的错误降级直接被恶意请求打穿。今天我们将用不到300 行核心 Python 代码一次性解决上述所有痛点交付一个可直接部署商用的 AI 聊天机器人后端。二、技术选型为了保证轻量、高效且易于维护我们采用以下技术栈编排框架LangChain使用最新的 LCEL 语法性能更好逻辑更清晰向量数据库ChromaDB轻量级支持本地持久化无需额外部署重型数据库Web 框架FastAPI原生支持异步和 SSE 流式输出性能极佳大模型 APIOpenAI API如 gpt-4o-mini兼顾速度与成本国内模型平替方案只需修改base_url和model参数即可无缝切换至DeepSeek (deepseek-chat)或阿里云通义千问 (qwen-plus)成本可降低80%以上。三、分步实现核心代码0. 环境准备pipinstalllangchain0.3.0langchain-community langchain-openai chromadb fastapi uvicorn python-dotenv slowapi1. 文档加载与分块 向量数据库初始化我们将文档处理与向量库初始化封装为独立函数支持增量更新。importosfromdotenvimportload_dotenvfromlangchain_community.document_loadersimportTextLoaderfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain_community.vectorstoresimportChromafromlangchain_openaiimportOpenAIEmbeddings load_dotenv()# 支持国内模型平替只需修改 OPENAI_API_BASE 和 OPENAI_MODEL_NAMEos.environ.setdefault(OPENAI_API_BASE,https://api.openai.com/v1)os.environ.setdefault(OPENAI_MODEL_NAME,gpt-4o-mini)definit_vectorstore(docs_path:strdata.txt):初始化或加载向量数据库embeddingsOpenAIEmbeddings()ifos.path.exists(./chroma_db):print(加载已有向量数据库...)returnChroma(persist_directory./chroma_db,embedding_functionembeddings)print(正在加载并切分文档...)loaderTextLoader(docs_path,encodingutf-8)documentsloader.load()# 按 500 token 切分重叠 50 token保证上下文连贯性text_splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50)textstext_splitter.split_documents(documents)print(正在构建向量索引...)vectorstoreChroma.from_documents(texts,embeddings,persist_directory./chroma_db)returnvectorstore2. 基础检索链构建 上下文记忆管理使用 LangChain 的RunnableWithMessageHistory优雅解决多轮对话的上下文记忆问题。fromlangchain_openaiimportChatOpenAIfromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain.chainsimportcreate_history_aware_retriever,create_retrieval_chainfromlangchain.chains.combine_documentsimportcreate_stuff_documents_chainfromlangchain_community.chat_message_historiesimportChatMessageHistoryfromlangchain_core.runnables.historyimportRunnableWithMessageHistorydefbuild_rag_chain(vectorstore):构建带历史记忆的 RAG 链llmChatOpenAI(temperature0.1,streamingTrue)# 开启流式支持retrievervectorstore.as_retriever(search_kwargs{k:3})# 每次检索 Top 3# 1. 上下文感知检索器将用户当前问题结合历史对话进行重写提升检索准确率contextualize_q_promptChatPromptTemplate.from_messages([(system,根据以下聊天历史将用户的最新问题重写为一个独立的、可检索的问题。如果没有历史直接返回原问题。),MessagesPlaceholder(chat_history),(human,{input})])history_aware_retrievercreate_history_aware_retriever(llm,retriever,contextualize_q_prompt)# 2. QA 提示词结合检索到的文档和历史进行回答qa_promptChatPromptTemplate.from_messages([(system,你是一个专业的 AI 助手。请仅根据以下提供的上下文回答问题。\n\n上下文:\n{context}),MessagesPlaceholder(chat_history),(human,{input})])question_answer_chaincreate_stuff_documents_chain(llm,qa_prompt)# 3. 组合成完整的 RAG 链rag_chaincreate_retrieval_chain(history_aware_retriever,question_answer_chain)# 4. 包装为带记忆的版本 (通过 session_id 隔离不同用户的对话)store{}defget_session_history(session_id:str):ifsession_idnotinstore:store[session_id]ChatMessageHistory()returnstore[session_id]returnRunnableWithMessageHistory(rag_chain,get_session_history,input_messages_keyinput,history_messages_keychat_history,output_messages_keyanswer,)3. 流式输出实现 (FastAPI)利用 FastAPI 的StreamingResponse和 LangChain 的astream实现丝滑的打字机效果。importuuidimportjsonimportloggingfromfastapiimportFastAPI,HTTPExceptionfromfastapi.responsesimportStreamingResponsefrompydanticimportBaseModelfromslowapiimportLimiter,_rate_limit_exceeded_handlerfromslowapi.utilimportget_remote_addressfromslowapi.errorsimportRateLimitExceeded# 初始化 FastAPI 与 限流器appFastAPI(title商用 RAG Chatbot API)limiterLimiter(key_funcget_remote_address)app.state.limiterlimiter app.add_exception_handler(RateLimitExceeded,_rate_limit_exceeded_handler)# 初始化全局组件vectorstoreinit_vectorstore()rag_chainbuild_rag_chain(vectorstore)classChatRequest(BaseModel):message:strsession_id:str|NoneNone# 前端传入用于维持多轮对话app.post(/api/chat/stream)limiter.limit(10/minute)# 商用限流单 IP 每分钟最多 10 次请求asyncdefchat_stream(request:ChatRequest):session_idrequest.session_idorstr(uuid.uuid4())# 配置请求日志logging.info(f[{session_id}] 收到请求:{request.message})try:asyncdefgenerate():# 使用 astream_events 获取更细粒度的流式控制asyncforeventinrag_chain.astream_events({input:request.message},config{configurable:{session_id:session_id}},versionv2):# 仅拦截 LLM 生成的 token 流ifevent[event]on_chat_model_stream:tokenevent[data][chunk].contentiftoken:yieldfdata:{json.dumps({token:token},ensure_asciiFalse)}\n\n# 流结束标志yielddata: [DONE]\n\nreturnStreamingResponse(generate(),media_typetext/event-stream)exceptExceptionase:logging.error(f[{session_id}] 处理失败:{str(e)})raiseHTTPException(status_code500,detail服务器内部错误请稍后重试)四、商用优化限流、日志与错误处理上述代码中已经内置了商用必备的三大防护机制接口限流引入 slowapi通过limiter.limit(10/minute)防止单 IP 恶意刷接口耗尽 Token 额度。生产环境中建议将key_func替换为基于 Redis 的分布式限流。结构化日志使用logging记录session_id和用户输入方便后续通过 ELK 或 Loki 进行链路追踪和审计。优雅降级全局try-except捕获异常避免将底层的 LangChain 堆栈信息暴露给前端统一返回标准的 HTTP 500 JSON 响应。五、部署指南Docker 一键部署到服务器为了方便运维我们提供标准的 Docker 部署方案。1. 创建 requirements.txtfastapi uvicorn langchain0.3.0 langchain-community langchain-openai chromadb python-dotenv slowapi2. 创建 DockerfileFROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000, --workers, 4]3. 创建 docker-compose.ymlversion:3.8services:rag-bot:build:.ports:-8000:8000environment:-OPENAI_API_KEYyour_api_key_here-OPENAI_API_BASEhttps://api.openai.com/v1volumes:-./chroma_db:/app/chroma_db-./data.txt:/app/data.txtrestart:always4. 一键启动docker-composeup-d--build六、效果演示与完整代码仓库前端可以通过标准的 EventSource 或 fetch API 消费该流式接口consteventSourcenewEventSource(/api/chat/stream?message你好session_id123);eventSource.onmessage(event){if(event.data[DONE]){eventSource.close();return;}constdataJSON.parse(event.data);console.log(data.token);// 追加到前端 UI 即可实现打字机效果};完整代码仓库已开源包含前端测试页面与完整的错误处理逻辑。GitHub: github.com/your-repo/commercial-rag-bot示例链接
从 0 到 1 搭建可商用的 AI 聊天机器人:300 行代码搞定 RAG + 流式输出
发布时间:2026/6/5 12:28:48
从 0 到 1 搭建可商用的 AI 聊天机器人300 行代码搞定 RAG 流式输出摘要拒绝“Demo 一时爽上线火葬场”。本文摒弃冗长的理论直接提供一套基于LangChain Chroma FastAPI的生产级 RAG 解决方案。包含完整的上下文管理、流式输出以及商用级别的限流与日志处理核心代码仅需300 行。一、痛点引入为什么 90% 的 RAG 项目都跑不起来在当前的 AI 落地浪潮中许多开发者在搭建 RAG检索增强生成系统时会陷入以下困境教程脱离实际网上的教程大多停留在 Jupyter Notebook 里的玩具代码一旦放入生产环境立刻面临并发崩溃、内存泄漏等问题。上下文管理混乱多轮对话时历史消息要么丢失要么无限膨胀导致 Token 超限和成本失控。流式输出卡顿前端体验极差要么一次性全量返回要么流式输出时断时续缺乏标准的 SSE (Server-Sent Events) 实现。缺乏商用兜底没有接口限流、没有请求日志、没有优雅的错误降级直接被恶意请求打穿。今天我们将用不到300 行核心 Python 代码一次性解决上述所有痛点交付一个可直接部署商用的 AI 聊天机器人后端。二、技术选型为了保证轻量、高效且易于维护我们采用以下技术栈编排框架LangChain使用最新的 LCEL 语法性能更好逻辑更清晰向量数据库ChromaDB轻量级支持本地持久化无需额外部署重型数据库Web 框架FastAPI原生支持异步和 SSE 流式输出性能极佳大模型 APIOpenAI API如 gpt-4o-mini兼顾速度与成本国内模型平替方案只需修改base_url和model参数即可无缝切换至DeepSeek (deepseek-chat)或阿里云通义千问 (qwen-plus)成本可降低80%以上。三、分步实现核心代码0. 环境准备pipinstalllangchain0.3.0langchain-community langchain-openai chromadb fastapi uvicorn python-dotenv slowapi1. 文档加载与分块 向量数据库初始化我们将文档处理与向量库初始化封装为独立函数支持增量更新。importosfromdotenvimportload_dotenvfromlangchain_community.document_loadersimportTextLoaderfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain_community.vectorstoresimportChromafromlangchain_openaiimportOpenAIEmbeddings load_dotenv()# 支持国内模型平替只需修改 OPENAI_API_BASE 和 OPENAI_MODEL_NAMEos.environ.setdefault(OPENAI_API_BASE,https://api.openai.com/v1)os.environ.setdefault(OPENAI_MODEL_NAME,gpt-4o-mini)definit_vectorstore(docs_path:strdata.txt):初始化或加载向量数据库embeddingsOpenAIEmbeddings()ifos.path.exists(./chroma_db):print(加载已有向量数据库...)returnChroma(persist_directory./chroma_db,embedding_functionembeddings)print(正在加载并切分文档...)loaderTextLoader(docs_path,encodingutf-8)documentsloader.load()# 按 500 token 切分重叠 50 token保证上下文连贯性text_splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50)textstext_splitter.split_documents(documents)print(正在构建向量索引...)vectorstoreChroma.from_documents(texts,embeddings,persist_directory./chroma_db)returnvectorstore2. 基础检索链构建 上下文记忆管理使用 LangChain 的RunnableWithMessageHistory优雅解决多轮对话的上下文记忆问题。fromlangchain_openaiimportChatOpenAIfromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain.chainsimportcreate_history_aware_retriever,create_retrieval_chainfromlangchain.chains.combine_documentsimportcreate_stuff_documents_chainfromlangchain_community.chat_message_historiesimportChatMessageHistoryfromlangchain_core.runnables.historyimportRunnableWithMessageHistorydefbuild_rag_chain(vectorstore):构建带历史记忆的 RAG 链llmChatOpenAI(temperature0.1,streamingTrue)# 开启流式支持retrievervectorstore.as_retriever(search_kwargs{k:3})# 每次检索 Top 3# 1. 上下文感知检索器将用户当前问题结合历史对话进行重写提升检索准确率contextualize_q_promptChatPromptTemplate.from_messages([(system,根据以下聊天历史将用户的最新问题重写为一个独立的、可检索的问题。如果没有历史直接返回原问题。),MessagesPlaceholder(chat_history),(human,{input})])history_aware_retrievercreate_history_aware_retriever(llm,retriever,contextualize_q_prompt)# 2. QA 提示词结合检索到的文档和历史进行回答qa_promptChatPromptTemplate.from_messages([(system,你是一个专业的 AI 助手。请仅根据以下提供的上下文回答问题。\n\n上下文:\n{context}),MessagesPlaceholder(chat_history),(human,{input})])question_answer_chaincreate_stuff_documents_chain(llm,qa_prompt)# 3. 组合成完整的 RAG 链rag_chaincreate_retrieval_chain(history_aware_retriever,question_answer_chain)# 4. 包装为带记忆的版本 (通过 session_id 隔离不同用户的对话)store{}defget_session_history(session_id:str):ifsession_idnotinstore:store[session_id]ChatMessageHistory()returnstore[session_id]returnRunnableWithMessageHistory(rag_chain,get_session_history,input_messages_keyinput,history_messages_keychat_history,output_messages_keyanswer,)3. 流式输出实现 (FastAPI)利用 FastAPI 的StreamingResponse和 LangChain 的astream实现丝滑的打字机效果。importuuidimportjsonimportloggingfromfastapiimportFastAPI,HTTPExceptionfromfastapi.responsesimportStreamingResponsefrompydanticimportBaseModelfromslowapiimportLimiter,_rate_limit_exceeded_handlerfromslowapi.utilimportget_remote_addressfromslowapi.errorsimportRateLimitExceeded# 初始化 FastAPI 与 限流器appFastAPI(title商用 RAG Chatbot API)limiterLimiter(key_funcget_remote_address)app.state.limiterlimiter app.add_exception_handler(RateLimitExceeded,_rate_limit_exceeded_handler)# 初始化全局组件vectorstoreinit_vectorstore()rag_chainbuild_rag_chain(vectorstore)classChatRequest(BaseModel):message:strsession_id:str|NoneNone# 前端传入用于维持多轮对话app.post(/api/chat/stream)limiter.limit(10/minute)# 商用限流单 IP 每分钟最多 10 次请求asyncdefchat_stream(request:ChatRequest):session_idrequest.session_idorstr(uuid.uuid4())# 配置请求日志logging.info(f[{session_id}] 收到请求:{request.message})try:asyncdefgenerate():# 使用 astream_events 获取更细粒度的流式控制asyncforeventinrag_chain.astream_events({input:request.message},config{configurable:{session_id:session_id}},versionv2):# 仅拦截 LLM 生成的 token 流ifevent[event]on_chat_model_stream:tokenevent[data][chunk].contentiftoken:yieldfdata:{json.dumps({token:token},ensure_asciiFalse)}\n\n# 流结束标志yielddata: [DONE]\n\nreturnStreamingResponse(generate(),media_typetext/event-stream)exceptExceptionase:logging.error(f[{session_id}] 处理失败:{str(e)})raiseHTTPException(status_code500,detail服务器内部错误请稍后重试)四、商用优化限流、日志与错误处理上述代码中已经内置了商用必备的三大防护机制接口限流引入 slowapi通过limiter.limit(10/minute)防止单 IP 恶意刷接口耗尽 Token 额度。生产环境中建议将key_func替换为基于 Redis 的分布式限流。结构化日志使用logging记录session_id和用户输入方便后续通过 ELK 或 Loki 进行链路追踪和审计。优雅降级全局try-except捕获异常避免将底层的 LangChain 堆栈信息暴露给前端统一返回标准的 HTTP 500 JSON 响应。五、部署指南Docker 一键部署到服务器为了方便运维我们提供标准的 Docker 部署方案。1. 创建 requirements.txtfastapi uvicorn langchain0.3.0 langchain-community langchain-openai chromadb python-dotenv slowapi2. 创建 DockerfileFROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000, --workers, 4]3. 创建 docker-compose.ymlversion:3.8services:rag-bot:build:.ports:-8000:8000environment:-OPENAI_API_KEYyour_api_key_here-OPENAI_API_BASEhttps://api.openai.com/v1volumes:-./chroma_db:/app/chroma_db-./data.txt:/app/data.txtrestart:always4. 一键启动docker-composeup-d--build六、效果演示与完整代码仓库前端可以通过标准的 EventSource 或 fetch API 消费该流式接口consteventSourcenewEventSource(/api/chat/stream?message你好session_id123);eventSource.onmessage(event){if(event.data[DONE]){eventSource.close();return;}constdataJSON.parse(event.data);console.log(data.token);// 追加到前端 UI 即可实现打字机效果};完整代码仓库已开源包含前端测试页面与完整的错误处理逻辑。GitHub: github.com/your-repo/commercial-rag-bot示例链接