第四节:使用 Chainlit 构建生产级聊天应用 概述 本节课重点讲解如何使用 Chainlit 和 Microsoft Foundry Local 构建生产级聊天应用。您将学习如何创建现代化的 AI 对话网页界面、实现流式响应,以及部署具有完善错误处理和用户体验设计的强大聊天应用。 您将构建: Chainlit 聊天应用:具有流式响应的现代化网页界面 WebGPU 演示:基于浏览器的推理,注重隐私保护 开放 WebUI 集成:与 Foundry Local 集成的专业聊天界面 生产模式:错误处理、监控和部署策略 学习目标 使用 Chainlit 构建生产级聊天应用 实现流式响应以提升用户体验 掌握 Foundry Local SDK 的集成模式 应用正确的错误处理和优雅降级方法
本节课重点讲解如何使用 Chainlit 和 Microsoft Foundry Local 构建生产级聊天应用。您将学习如何创建现代化的 AI 对话网页界面、实现流式响应,以及部署具有完善错误处理和用户体验设计的强大聊天应用。
您将构建:
foundry model run phi-4-mini)User Browser ←→ Chainlit UI ←→ Python Backend ←→ Foundry Local ←→ AI Model ↓ ↓ ↓ ↓ ↓ Web UI Event Handlers OpenAI Client HTTP API Local GPU
Foundry Local SDK 模式:
FoundryLocalManager(alias):自动服务管理manager.endpoint 和 manager.api_key:连接详情manager.get_model_info(alias).id:模型标识Chainlit 框架:
@cl.on_chat_start:初始化聊天会话@cl.on_message:处理用户消息cl.Message().stream_token():实时流式响应| 方面 | 本地(Foundry) | 云端(Azure OpenAI) |
|---|---|---|
| 延迟 | 50-200ms(无网络) | ⏱️ 200-2000ms(取决于网络) |
| 隐私 | 数据不离开设备 | ⚠️ 数据发送至云端 |
| 成本 | 硬件后免费 | 按令牌付费 |
| 离线 | ✅ 无需互联网即可运行 | ❌ 需要互联网 |
| 模型规模 | ⚠️ 受硬件限制 | ✅ 可访问最大模型 |
| 扩展性 | ⚠️ 依赖硬件 | ✅ 无限扩展 |
本地优先,云端备选:
async def hybrid_completion(prompt: str, complexity_threshold: int = 100): if len(prompt.split()) < complexity_threshold: return await local_completion(prompt) # Fast, private else: return await cloud_completion(prompt) # Complex reasoning
基于任务的路由:
async def smart_routing(prompt: str, task_type: str): routing_rules = { "code_generation": "local", # Privacy-sensitive "creative_writing": "cloud", # Benefits from larger models "data_analysis": "local", # Fast iteration needed "research": "cloud" # Requires broad knowledge } if routing_rules.get(task_type) == "local": return await foundry_completion(prompt) else: return await azure_completion(prompt)
# Navigate to Module08 directory cd Module08 # Start your preferred model foundry model run phi-4-mini # Run the Chainlit application (avoiding port conflicts) chainlit run samples\04\app.py -w --port 8080
应用会自动在 http://localhost:8080 打开,显示现代化聊天界面。
示例 04 展示了生产级模式:
自动服务发现:
import chainlit as cl from openai import OpenAI from foundry_local import FoundryLocalManager # Global variables for client and model client = None model_name = None async def initialize_client(): global client, model_name alias = os.environ.get("MODEL", "phi-4-mini") try: # Use FoundryLocalManager for proper service management manager = FoundryLocalManager(alias) model_info = manager.get_model_info(alias) client = OpenAI( base_url=manager.endpoint, api_key=manager.api_key or "not-required" ) model_name = model_info.id if model_info else alias return True except Exception as e: # Fallback to manual configuration base_url = os.environ.get("BASE_URL", "http://localhost:51211") client = OpenAI(base_url=f"{base_url}/v1", api_key="not-required") model_name = alias return True
流式聊天处理:
@cl.on_message async def main(message: cl.Message): # Create streaming response msg = cl.Message(content="") await msg.send() stream = client.chat.completions.create( model=model_name, messages=[ {"role": "system", "content": "You are a helpful AI assistant."}, {"role": "user", "content": message.content} ], stream=True ) # Stream tokens in real-time for chunk in stream: if chunk.choices[0].delta.content: await msg.stream_token(chunk.choices[0].delta.content) await msg.update()
环境变量:
| 变量 | 描述 | 默认值 | 示例 |
|---|---|---|---|
MODEL |
使用的模型别名 | phi-4-mini |
qwen2.5-7b |
BASE_URL |
Foundry Local 端点 | 自动检测 | http://localhost:51211 |
API_KEY |
API 密钥(本地可选) | "" |
your-api-key |
高级用法:
# Use different model set MODEL=qwen2.5-7b chainlit run samples\04\app.py -w --port 8080 # Use different ports (avoid 51211 which is used by Foundry Local) chainlit run samples\04\app.py -w --port 3000 chainlit run samples\04\app.py -w --port 5000
示例 04 包含一个全面的 Jupyter Notebook(chainlit_app.ipynb),提供以下功能:
# Ensure you're in the Module08 directory cd Module08 # Activate your virtual environment .venv\Scripts\activate # Install Jupyter and dependencies pip install jupyter notebook jupyterlab ipykernel pip install -r requirements.txt # Register the kernel for VS Code python -m ipykernel install --user --name=foundry-local --display-name="Foundry Local"
使用 VS Code:
.ipynb 扩展名的新文件使用 Jupyter Lab:
# Start Jupyter Lab jupyter lab # Navigate to samples/04/ and create new notebook # Choose Python 3 kernel
# Cell 1: Imports and Setup import os import sys import chainlit as cl from openai import OpenAI from foundry_local import FoundryLocalManager print("✅ Libraries imported successfully")
# Cell 2: Configuration and Client Setup class FoundryClientManager: def __init__(self, model_name="phi-4-mini"): self.model_name = model_name self.client = None def initialize_client(self): # Client initialization logic pass # Initialize and test client_manager = FoundryClientManager() result = client_manager.initialize_client() print(f"Client initialized: {result}")
# Test different configuration methods configurations = [ {"method": "foundry_sdk", "model": "phi-4-mini"}, {"method": "manual", "base_url": "http://localhost:51211", "model": "qwen2.5-7b"}, ] for config in configurations: print(f"\n Testing {config['method']} configuration...") # Implementation here result = test_configuration(config) print(f"Result: {'✅ Success' if result['status'] == 'ok' else '❌ Failed'}")
import asyncio async def simulate_streaming_response(text, delay=0.1): """Simulate how streaming works in Chainlit.""" print(" Simulating streaming response...") for char in text: print(char, end='', flush=True) await asyncio.sleep(delay) print("\n✅ Streaming complete!") # Test the simulation sample_text = "This is how streaming responses work in Chainlit applications!" await simulate_streaming_response(sample_text)
WebGPU 允许直接在浏览器中运行 AI 模型,最大限度地保护隐私并实现零安装体验。本示例展示了使用 ONNX Runtime Web 和 WebGPU 执行的过程。
浏览器要求:
chrome://gpu → 确认“WebGPU”状态if (!('gpu' in navigator)) { /* no WebGPU */ }创建目录:samples/04/webgpu-demo/
index.html:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>WebGPU + ONNX Runtime Demo</title> <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.webgpu.min.js"></script> <style> body { font-family: system-ui, sans-serif; margin: 2rem; } pre { background: #f5f5f5; padding: 1rem; overflow: auto; } .status { padding: 1rem; background: #e3f2fd; border-radius: 4px; } </style> </head> <body> <h1> WebGPU + Foundry Local Integration</h1> <div id="status" class="status">Initializing...</div> <pre id="output"></pre> <script type="module" src="./main.js"></script> </body> </html>
main.js:
const statusEl = document.getElementById('status'); const outputEl = document.getElementById('output'); function log(msg) { outputEl.textContent += `${msg}\n`; console.log(msg); } (async () => { try { if (!('gpu' in navigator)) { statusEl.textContent = '❌ WebGPU not available'; return; } statusEl.textContent = ' WebGPU detected. Loading model...'; // Use a small ONNX model for demo const modelUrl = 'https://huggingface.co/onnx/models/resolve/main/vision/classification/mnist-12/mnist-12.onnx'; const session = await ort.InferenceSession.create(modelUrl, { executionProviders: ['webgpu'] }); log('✅ ONNX Runtime session created with WebGPU'); log(` Input names: ${session.inputNames.join(', ')}`); log(` Output names: ${session.outputNames.join(', ')}`); // Create dummy input (MNIST expects 1x1x28x28) const inputData = new Float32Array(1 * 1 * 28 * 28).fill(0.1); const input = new ort.Tensor('float32', inputData, [1, 1, 28, 28]); const feeds = {}; feeds[session.inputNames[0]] = input; const results = await session.run(feeds); const output = results[session.outputNames[0]]; // Find prediction (argmax) let maxIdx = 0; for (let i = 1; i < output.data.length; i++) { if (output.data[i] > output.data[maxIdx]) maxIdx = i; } statusEl.textContent = '✅ WebGPU inference complete!'; log(` Predicted class: ${maxIdx}`); log(` Confidence scores: [${Array.from(output.data).map(x => x.toFixed(3)).join(', ')}]`); } catch (error) { statusEl.textContent = `❌ Error: ${error.message}`; log(`Error: ${error.message}`); console.error(error); } })();
# Create demo directory mkdir samples\04\webgpu-demo cd samples\04\webgpu-demo # Save HTML and JS files, then serve python -m http.server 5173 # Open browser to http://localhost:5173
开放 WebUI 提供了一个专业的 ChatGPT 风格界面,可连接到 Foundry Local 的 OpenAI 兼容 API。
# Verify Foundry Local is running foundry service status # Start a model foundry model run phi-4-mini # Confirm API endpoint is accessible curl http://localhost:51211/v1/models
# Pull Open WebUI image docker pull ghcr.io/open-webui/open-webui:main # Run with Foundry Local connection docker run -d --name open-webui -p 3000:8080 ^ -e OPENAI_API_BASE_URL=http://host.docker.internal:51211/v1 ^ -e OPENAI_API_KEY=foundry-local-key ^ -v open-webui-data:/app/backend/data ^ ghcr.io/open-webui/open-webui:main
注意: host.docker.internal 允许 Docker 容器访问主机机器(Windows)。
http://localhost:3000http://host.docker.internal:51211/v1foundry-local-key(任意值均可)常见问题:
连接被拒绝:
# Check Foundry Local status foundry service ps netstat -ano | findstr :51211
模型未出现:
foundry model listcurl http://localhost:51211/v1/models开发设置:
# Development with auto-reload and debugging chainlit run samples\04\app.py -w --port 8080 --debug
生产部署:
# Production mode with optimizations chainlit run samples\04\app.py --host 0.0.0.0 --port 8080 --no-cache
端口 51211 冲突预防:
# Check what's using Foundry Local port netstat -ano | findstr :51211 # Use different port for Chainlit chainlit run samples\04\app.py -w --port 8080
健康检查实现:
@cl.on_chat_start async def health_check(): try: # Test model availability response = client.chat.completions.create( model=model_name, messages=[{"role": "user", "content": "test"}], max_tokens=1 ) return {"status": "healthy", "model": model_name} except Exception as e: return {"status": "unhealthy", "error": str(e)}
第四节课程涵盖了构建生产级 Chainlit 应用以支持对话式 AI。您学习了:
示例 04 应用展示了最佳实践,帮助您构建强大的聊天界面,利用 Microsoft Foundry Local 的本地 AI 模型,同时提供卓越的用户体验。
免责声明:
本文档使用AI翻译服务 Co-op Translator 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。