edge ai architecture

边缘 AI 架构设计:在手机和 IoT 上运行 LLM

为什么要把 LLM 放到边缘设备上 2026 年,端侧运行 LLM 不再是学术论文里的概念,而是产品需求。原因很直接: 延迟:云上 LLM 往返延迟 200-800ms,端侧可以做到 20-50ms 隐私:医疗、金融场景的数据不能离开设备 离线:网络不稳定场景(工业、户外)需要离线推理 成本:云端推理 $0.01/千 token,端侧摊到设备折旧里几乎免费 但挑战也真实:手机内存 8-16GB,要跑 7B 模型需要 14GB(FP16),得压缩。 模型压缩三板斧 量化:用更少的 bit 表示权重 量化方案 位宽 7B 模型大小 精度损失 硬件支持 FP16 (基线) 16-bit 13.5 GB 0% 全部 INT8 8-bit 6.8 GB <1% CPU/GPU/NPU INT4 (GPTQ) 4-bit 3.5 GB 2-3% GPU/NPU INT4 (AWQ) 4-bit 3.5 GB 1-2% GPU/NPU INT3 3-bit 2.6 GB 5-8% 部分 NPU 1.58-bit ~2-bit 1.8 GB 8-12% 实验阶段 # 使用 llama.cpp 的量化工具链 # 1. 转换为 GGUF 格式 # python convert.py models/llama-3-8b --outtype f16 --outfile llama-3-8b-f16.gguf # 2. 量化为 INT4 # ./quantize llama-3-8b-f16.gguf llama-3-8b-q4_k_m.gguf Q4_K_M # 在 Python 中使用 llama-cpp-python 加载 from llama_cpp import Llama llm = Llama( model_path="llama-3-8b-q4_k_m.gguf", n_ctx=2048, # 上下文窗口(移动端建议 2048-4096) n_threads=4, # CPU 线程数 n_gpu_layers=0, # 移动端通常 0(纯 CPU) n_batch=512, # 批处理大小 mmap=True, # 内存映射加载,减少内存占用 mmap_timeout=30000, ) response = llm( "解释量子计算的基本原理", max_tokens=256, temperature=0.7, top_p=0.9, ) 蒸馏:小模型学大模型 # 使用 Hugging Face 进行知识蒸馏 from transformers import AutoModelForCausalLM, AutoTokenizer import torch import torch.nn.functional as F teacher = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-70B") student = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-1B") teacher.eval() student.train() optimizer = torch.optim.AdamW(student.parameters(), lr=5e-5) for batch in dataloader: with torch.no_grad(): teacher_logits = teacher(batch["input_ids"]).logits teacher_probs = F.softmax(teacher_logits / 2.0, dim=-1) # 温度=2 student_logits = student(batch["input_ids"]).logits student_log_probs = F.log_softmax(student_logits / 2.0, dim=-1) # KL 散度损失 loss = F.kl_div(student_log_probs, teacher_probs, reduction="batchmean") # 加上 hard label loss loss += 0.3 * F.cross_entropy( student_logits.view(-1, student_logits.size(-1)), batch["labels"].view(-1) ) loss.backward() optimizer.step() optimizer.zero_grad() 剪枝:去掉不重要的权重 # 结构化剪枝:移除整个注意力头或层 import torch.nn.utils.prune as prune def structured_prune(model, amount=0.3): """移除 30% 最不重要的注意力头""" for name, module in model.named_modules(): if isinstance(module, torch.nn.Linear): # 按 L1 范数剪枝 prune.l1_unstructured(module, name="weight", amount=amount) # 固化剪枝 prune.remove(module, "weight") return model # 评估剪枝后的精度 def evaluate_pruned(model, eval_dataset): pruned = structured_prune(model, amount=0.3) # 重新微调恢复精度 trainer = Trainer( model=pruned, args=TrainingArguments( output_dir="./pruned-finetune", num_train_epochs=2, learning_rate=2e-5, ), train_dataset=train_dataset, eval_dataset=eval_dataset, ) trainer.train() return pruned 端侧推理引擎对比 llama.cpp Mobile // Android NDK 集成示例 // JNI 接口:从 Java/Kotlin 调用 llama.cpp #include "llama.h" #include <jni.h> #include <android/log.h> extern "C" JNIEXPORT jlong JNICALL Java_com_example_llm_LlamaEngine_nativeInit(JNIEnv* env, jobject thiz, jstring model_path) { const char* path = env->GetStringUTFChars(model_path, nullptr); llama_backend_init(false); llama_model_params model_params = llama_model_default_params(); model_params.n_gpu_layers = 0; // 移动端纯 CPU model_params.use_mmap = true; llama_model* model = llama_load_model_from_file(path, model_params); env->ReleaseStringUTFChars(model_path, path); return (jlong)model; } extern "C" JNIEXPORT jstring JNICALL Java_com_example_llm_LlamaEngine_nativeGenerate( JNIEnv* env, jobject thiz, jlong model_ptr, jstring prompt, jint max_tokens ) { llama_model* model = (llama_model*)model_ptr; const char* prompt_str = env->GetStringUTFChars(prompt, nullptr); llama_context_params ctx_params = llama_context_default_params(); ctx_params.n_ctx = 2048; ctx_params.n_threads = 4; ctx_params.n_batch = 512; llama_context* ctx = llama_new_context_with_model(model, ctx_params); // Tokenize std::string text(prompt_str); std::vector<llama_token> tokens = llama_tokenize(ctx, text, true); // 生成循环 std::string result; for (int i = 0; i < max_tokens; i++) { if (llama_decode(ctx, llama_batch_get_one(&tokens.back(), 1, i, 0))) break; llama_token new_token = llama_sample_token(ctx, nullptr, 0.8f, 0.9f, 32); if (new_token == llama_token_eos(ctx)) break; tokens.push_back(new_token); result += llama_token_to_piece(ctx, new_token); } llama_free(ctx); env->ReleaseStringUTFChars(prompt, prompt_str); return env->NewStringUTF(result.c_str()); } MLC-LLM # MLC-LLM:使用 TVM 编译器优化,支持 Android/iOS # 编译模型到移动端 """ # 1. 编译模型 python -m mlc_llm compile \ --model llama-3-8b \ --quantization q4f16_1 \ --target android \ --output llama-3-8b-q4f16_1-android.tar # 2. 在 Android 上加载 """ # Swift (iOS) 示例 """ import MLCEngine let engine = MLCEngine() try await engine.load( model: "Llama-3-8B-q4f16_1", modelPath: Bundle.main.path(forResource: "llama-3-8b", ofType: "mlc")! ) let response = try await engine.generate( prompt: "写一首关于秋天的诗", maxTokens: 256, temperature: 0.7 ) """ 引擎性能对比(Llama-3-8B INT4) 引擎 平台 首 token 延迟 吞吐 (tok/s) 内存峰值 包大小 llama.cpp Android 800ms 12-18 4.2 GB 3.5 GB MLC-LLM Android 500ms 18-25 4.0 GB 3.6 GB MLC-LLM iOS (Metal) 200ms 30-40 3.8 GB 3.5 GB ExecuTorch Android 600ms 15-22 4.1 GB 3.5 GB ONNX Runtime Android 900ms 10-15 4.5 GB 4.0 GB NPU 加速 现代手机都有 NPU(神经网络处理器),但 LLM 在 NPU 上的支持还很不成熟。 ...

2026-06-24 · 5 min · 947 words · 硅基 AGI 探索者
meta prompting guide

元提示技术:用 LLM 优化 LLM 的 Prompt

Meta-Prompting 原理 Meta-Prompting 的核心思想:用 LLM 来优化 LLM 的 prompt。这是一种"元"层面的优化——不在 prompt 内部做文章,而是让模型自己去寻找更好的 prompt。 传统流程:人工设计 prompt → 测试 → 人工修改 → 再测试(耗时、依赖经验) Meta-Prompting 流程: 初始 Prompt → LLM 生成候选变体 → 在测试集上评估 → 选择最优 → 迭代 APE:Automatic Prompt Engineer APE (Zhou et al., 2022) 是最早的自动 prompt 生成方法之一: 1. 给 LLM 少量输入-输出示例 2. 让 LLM 推断可能的 instruction (prompt) 3. 在验证集上评估每个候选 prompt 4. 选择表现最好的 import openai def ape_generate(input_output_examples, n_candidates=10): """APE: 自动生成候选 prompt""" examples_str = "\n".join([ f"输入: {ex['input']}\n输出: {ex['output']}" for ex in input_output_examples ]) meta_prompt = f"""观察以下输入-输出对,推断其背后的指令。 {examples_str} 请生成 {n_candidates} 条可能的指令,使模型能根据该指令从输入得到输出。 每条指令独占一行,以数字编号。指令应简洁、准确、可泛化。""" resp = openai.chat.completions.create( model="gpt-4", messages=[{"role": "user", "content": meta_prompt}], temperature=0.9, ) return resp.choices[0].message.content def ape_evaluate(prompt, eval_set): """在验证集上评估 prompt""" correct = 0 for item in eval_set: resp = openai.chat.completions.create( model="gpt-4", messages=[{"role": "user", "content": f"{prompt}\n\n输入: {item['input']}"}], temperature=0.0, ) if resp.choices[0].message.content.strip() == item['output'].strip(): correct += 1 return correct / len(eval_set) def ape_optimize(examples, eval_set, n_candidates=10): """APE 完整流程""" # 1. 生成候选 candidates_text = ape_generate(examples, n_candidates) candidates = [line.split('. ', 1)[1] for line in candidates_text.strip().split('\n') if '. ' in line] # 2. 评估 scores = [(c, ape_evaluate(c, eval_set)) for c in candidates] scores.sort(key=lambda x: x[1], reverse=True) return scores[0] # (best_prompt, score) OPRO:优化 by PROgression OPRO (Yang et al., 2023) 将 prompt 优化建模为优化问题,用 LLM 作为优化器: ...

2026-06-24 · 4 min · 747 words · 硅基 AGI 探索者
鲁ICP备2026018361号