找回密码
 立即注册
首页 业界区 科技 Windows 环境下 llama.cpp 编译 + Qwen 模型本地部署全 ...

Windows 环境下 llama.cpp 编译 + Qwen 模型本地部署全指南

梭净挟 前天 23:05

在大模型落地场景中,本地轻量化部署因低延迟、高隐私性、无需依赖云端算力等优势,成为开发者与 AI 爱好者的热门需求。本文聚焦 Windows 10/11(64 位)环境,详细拆解 llama.cpp 工具的编译流程(支持 CPU/GPU 双模式,GPU 加速需依赖 NVIDIA CUDA),并指导如何通过 modelscope 下载 GGUF 格式的 Qwen-7B-Chat 模型,最终实现模型本地启动与 API 服务搭建。

1.打开管理员权限的 PowerShell/CMD,执行以下命令克隆代码:

  1. git clone https://github.com/ggml-org/llama.cpp
  2. mkdir build
  3. cd build
复制代码

2.基础编译(仅 CPU 支持)或者选用GPU 加速编译(已安装 CUDA Toolkit)

  1. 如果只使用CPU则执行如下配置
  2. cmake .. -G "Visual Studio 18 2026" -A x64 -DLLAMA_CURL=OFF
  3. cmake --build . --config Release
  4. 如果已安装 CUDA Toolkit,添加 -DLLAMA_CUDA=ON 开启 GPU 支持
  5. cmake .. -G "Visual Studio 18 2026" -A x64 -DLLAMA_CUDA=ON
  6. cmake --build . --config Release
复制代码

3、下载 GGUF 格式的 Qwen 模型(以 7B 为例)

  1. https://www.modelscope.cn/models
  2. pip install modelscope
  3. modelscope download --model Xorbits/Qwen-7B-Chat-GGUF
复制代码

下载后的保存位置为 \modelscope\hub\models\Xorbits

4、运行模型启动 API 服务(支持 HTTP 调用)

  1. # 命令行启动
  2. chcp 65001
  3. llama-cli.exe -m qwen.gguf -i -c 4096
  4. # CPU 版
  5. llama-server.exe -m qwen.gguf --host 127.0.0.1 --port 11433 -c 4096
  6. # GPU 加速版
  7. llama-server.exe -m qwen-7b-chat.Q4_0.gguf -c 4096 --n-gpu-layers -1
复制代码

5、服务启动后默认监听 http://localhost:8080,可通过 curl 测试调用效果。

  1. curl http://localhost:8080/completion -H "Content-Type: application/json" -d '{
  2. "prompt": "你好,介绍一下通义千问",
  3. "temperature": 0.7,
  4. "max_tokens": 512
  5. }'
复制代码

6、工具测试,通过代码调用大模型测试效果。

基础非流式调用(completion 端点)

  1. import requests
  2. import json
  3. url = "http://localhost:8080/completion"
  4. headers = {"Content-Type": "application/json"}
  5. data = {
  6. "model": "qwen.gguf",
  7. "prompt": "你好,请用100字介绍一下通义千问",
  8. "temperature": 0.7, # 回答随机性(越低越保守)
  9. "max_tokens": 512, # 最大生成token数
  10. "ctx_size": 4096, # 上下文窗口(与服务启动时一致)
  11. "stop": ["<|im_end|>"] # 停止符(适配Qwen的对话格式)
  12. }
  13. try:
  14. response = requests.post(url, headers=headers, data=json.dumps(data), timeout=60)
  15. response.raise_for_status()
  16. result = response.json()
  17. print("生成结果:")
  18. print(result["content"])
  19. except Exception as e:
  20. print(f"调用失败:{e}")
复制代码

多轮对话示例(基于 chat/completions)

  1. import requests
  2. import json
  3. chat_history = []
  4. url = "http://localhost:8080/chat/completions"
  5. headers = {"Content-Type": "application/json"}
  6. def chat_with_model(prompt):
  7. # 添加当前用户消息到历史
  8. chat_history.append({"role": "user", "content": prompt})
  9. data = {
  10. "model": "qwen.gguf",
  11. "messages": chat_history,
  12. "temperature": 0.7,
  13. "max_tokens": 512
  14. }
  15. try:
  16. response = requests.post(url, headers=headers, data=json.dumps(data), timeout=60)
  17. response.raise_for_status()
  18. result = response.json()
  19. answer = result["choices"][0]["message"]["content"]
  20. # 添加助手回答到历史
  21. chat_history.append({"role": "assistant", "content": answer})
  22. return answer
  23. except Exception as e:
  24. return f"调用失败:{e}"
  25. # 多轮对话示例
  26. print("开始多轮对话(输入'退出'结束):")
  27. while True:
  28. user_input = input("你:")
  29. if user_input == "退出":
  30. break
  31. answer = chat_with_model(user_input)
  32. print(f"助手:{answer}\n")
复制代码

带有对话记忆功能测试

  1. import requests
  2. import json
  3. import re
  4. # 初始化对话历史(包含系统提示,引导模型记上下文)
  5. chat_history = [
  6. {"role": "system", "content": "你是一个有帮助的助手,必须记住之前的对话内容,基于上下文回答用户问题。"}
  7. ]
  8. # 你的服务实际地址(保持你原来的 11433 端口和 OpenAI 兼容路径)
  9. url = "http://localhost:11433/chat/completions"
  10. headers = {"Content-Type": "application/json"}
  11. def clean_pad_content(content):
  12. """过滤模型返回的 [PAD...] 垃圾字符"""
  13. return re.sub(r'\[PAD\d+\]', '', content).strip()
  14. def chat_with_model(prompt):
  15. global chat_history
  16. # 添加当前用户消息到历史(关键:上下文靠这个列表传递)
  17. chat_history.append({"role": "user", "content": prompt})
  18. data = {
  19. "model": "qwen.gguf", # 保持你原来的模型名(你的服务识别这个名字)
  20. "messages": chat_history, # 传递完整对话历史
  21. "temperature": 0.7,
  22. "max_tokens": 512,
  23. "stream": False, # 关闭流式输出,适配你的返回格式
  24. "stop": ["[PAD"] # 提前终止 PAD 字符的输出
  25. }
  26. try:
  27. response = requests.post(url, headers=headers, data=json.dumps(data), timeout=60)
  28. response.raise_for_status() # 触发 HTTP 错误(比如 404、500)
  29. result = response.json()
  30. print(f"调试:模型原始返回 = {json.dumps(result, ensure_ascii=False)[:500]}") # 可选:查看原始返回
  31. # 适配你的 OpenAI 兼容格式:从 choices[0].message.content 提取内容
  32. if "choices" in result and len(result["choices"]) > 0:
  33. choice = result["choices"][0]
  34. if "message" in choice and "content" in choice["message"]:
  35. raw_answer = choice["message"]["content"]
  36. answer = clean_pad_content(raw_answer) # 过滤 PAD 垃圾字符
  37. # 关键:将助手回复加入历史,下次请求会带上
  38. chat_history.append({"role": "assistant", "content": answer})
  39. return answer
  40. else:
  41. return f"返回格式异常:缺少 message/content 字段,原始返回:{json.dumps(result, ensure_ascii=False)[:300]}"
  42. else:
  43. return f"返回格式异常:缺少 choices 字段,原始返回:{json.dumps(result, ensure_ascii=False)[:300]}"
  44. except requests.exceptions.ConnectionError:
  45. return "连接失败:请检查本地服务是否在 11433 端口运行"
  46. except requests.exceptions.Timeout:
  47. return "请求超时:模型响应过慢"
  48. except Exception as e:
  49. return f"调用失败:{str(e)},原始返回:{response.text[:300] if 'response' in locals() else '无'}"
  50. # 多轮对话测试(重点测试上下文记忆)
  51. print("开始多轮对话(输入'退出'结束):")
  52. print("提示:先发送 '我的名字是李四',再发送 '我叫什么名字' 测试记忆功能\n")
  53. while True:
  54. user_input = input("你:")
  55. if user_input.strip() == "退出":
  56. break
  57. if not user_input.strip():
  58. print("助手:请输入有效内容!\n")
  59. continue
  60. answer = chat_with_model(user_input)
  61. print(f"助手:{answer}\n")
复制代码

函数工具调用测试

[code]import requests import json import re from datetime import datetime # ====================== 1. 定义可用工具集 ====================== # 工具1:获取当前时间 def get_current_time(): """获取当前的本地时间,格式为 年-月-日 时:分:秒""" current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") return f"当前时间为:{current_time}" # 工具2:加法计算 def calculate_add(a: float, b: float): """计算两个数的加法结果""" return f"{a} + {b} = {a + b}" # 工具注册表(核心:映射工具名到函数和描述,供模型识别) tool_registry = { "get_current_time": { "function": get_current_time, "description": "获取当前的本地时间,无需参数", "parameters": {} # 无参数 }, "calculate_add": { "function": calculate_add, "description": "计算两个数字的加法,需要两个参数:a(数字)、b(数字)", "parameters": { "a": {"type": "float", "required": True, "description": "加数1"}, "b": {"type": "float", "required": True, "description": "加数2"} } } } # ====================== 2. 初始化对话历史和基础配置 ====================== chat_history = [ {"role": "system", "content": """你是一个有帮助的助手,必须记住之前的对话内容,基于上下文回答用户问题。 你可以调用以下工具来辅助回答: 1. get_current_time:获取当前的本地时间,无需参数 2. calculate_add:计算两个数字的加法,需要参数a和b(均为数字) 如果需要调用工具,请严格按照以下JSON格式返回(仅返回JSON,不要加其他内容): {"name": "工具名", "parameters": {"参数名": 参数值}} 如果不需要调用工具,直接回答用户问题即可,不要返回JSON格式。"""} ] # 本地LLM服务地址 url = "http://localhost:11433/chat/completions" headers = {"Content-Type": "application/json"} # ====================== 3. 工具调用相关辅助函数 ====================== def clean_pad_content(content): """过滤模型返回的 [PAD...] 垃圾字符""" return re.sub(r'\[PAD\d+\]', '', content).strip() def parse_tool_call(content): """解析模型返回的内容,提取工具调用指令(JSON格式)""" try: # 提取JSON部分(兼容模型返回时可能带的多余文字) json_match = re.search(r'\{[\s\S]*\}', content) if not json_match: return None tool_call = json.loads(json_match.group()) # 验证必要字段 if "name" in tool_call and "parameters" in tool_call: return tool_call return None except (json.JSONDecodeError, Exception): return None def execute_tool(tool_call): """执行工具调用,返回执行结果""" tool_name = tool_call["name"] parameters = tool_call.get("parameters", {}) # 检查工具是否存在 if tool_name not in tool_registry: return f"错误:不存在名为 {tool_name} 的工具,可用工具:{list(tool_registry.keys())}" tool_info = tool_registry[tool_name] tool_func = tool_info["function"] tool_params = tool_info["parameters"] # 验证必填参数 missing_params = [] for param_name, param_info in tool_params.items(): if param_info.get("required") and param_name not in parameters: missing_params.append(param_name) if missing_params: return f"错误:调用 {tool_name} 缺少必填参数:{', '.join(missing_params)}" # 转换参数类型(比如字符串转数字) try: for param_name, param_info in tool_params.items(): if param_name in parameters: param_type = param_info.get("type", "str") if param_type == "float": parameters[param_name] = float(parameters[param_name]) elif param_type == "int": parameters[param_name] = int(parameters[param_name]) except ValueError as e: return f"错误:参数类型转换失败 - {str(e)}" # 执行工具函数 try: result = tool_func(**parameters) return f"工具调用成功({tool_name}):{result}" except Exception as e: return f"错误:执行 {tool_name} 失败 - {str(e)}" # ====================== 4. 核心对话函数(支持工具调用) ====================== def chat_with_model(prompt): global chat_history # 添加当前用户消息到历史 chat_history.append({"role": "user", "content": prompt}) # 第一步:发送请求,判断是否需要调用工具 data = { "model": "qwen.gguf", "messages": chat_history, "temperature": 0.7, "max_tokens": 512, "stream": False, "stop": ["[PAD"] } try: # 第一次调用模型:获取是否需要工具调用的响应 response = requests.post(url, headers=headers, data=json.dumps(data), timeout=60) response.raise_for_status() result = response.json() # 解析模型原始返回 if "choices" in result and len(result["choices"]) > 0 and "message" in result["choices"][0]: raw_answer = result["choices"][0]["message"]["content"] clean_answer = clean_pad_content(raw_answer) else: return f"返回格式异常:{json.dumps(result, ensure_ascii=False)[:300]}" # 解析是否包含工具调用指令 tool_call = parse_tool_call(clean_answer) if tool_call: print(f"
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册