之前在业务迭代中想把开源的千问系列模型部署到本地,再配合一套 Agent 评估框架跑通完整的智能体任务链路,结果反复卡在环境兼容、模型下载和框架对接这几个环节上。网上的资料大多只讲其中一段,要么单独说模型部署,要么单独聊 Agent 概念,很少有把“本地模型 + Agent 框架 + 任务评估”串成闭环的完整教程。本文整合一套可落地的实操方案,从环境准备、模型部署、框架安装,到一个最小可运行的 Agent 示例,全部基于开源免费组件实现,不调用云端付费 API。新手入门、后端项目做技术预研都能直接复用。
1. 背景与核心概念
1.1 什么是“本地部署大模型”
本地部署大模型,就是把开源的大语言模型权重下载到自己的机器上,通过推理框架加载模型,对外提供类似 ChatGPT 的对话或函数调用能力。和调用云端 API 相比,本地部署有三个明显优势:
- 数据不出内网:请求和响应都在本地完成,适合企业内部数据处理场景。
- 按次调用零成本:只要硬件能跑起来,模型推理不按 token 计费。
- 可定制性强:可以换模型、改参数、接私有工具,不受平台限制。
代价也很明确:需要一张显存足够的显卡,或者一台内存足够大的机器;模型越大,对硬件要求越高。
标题里的“千问”通常指阿里开源的通义千问(Qwen)系列模型。需要先说明一点:社区里流传的“千问 3.8”不是一个严谨的官方版本号,实际操作时建议以 Qwen 官方发布的最新可用版本为准,例如 Qwen3 系列或 Qwen2.5 系列。本文后面的示例统一用“Qwen 系列模型”来描述,部署步骤和对接逻辑是通用的,替换成具体版本号即可。
1.2 什么是 Agent(智能体)
Agent 在技术语境里,指的是一个能“感知环境 → 做出决策 → 执行动作”的自动化程序。放到大模型场景下,Agent 通常指:
- 大模型作为“大脑”,负责理解用户意图。
- 模型会输出工具调用指令,例如调用搜索、计算器、数据库查询等函数。
- 程序解析这些指令,真实执行对应的函数,把结果再交回模型,让模型继续推理。
简单理解:普通聊天是“一问一答”,Agent 是“一问 → 模型思考 → 调用工具 → 拿到结果 → 再回答”的循环过程。
1.3 什么是 Harness
“Harness”在软件工程里原意是“测试夹具”,在 AI Agent 领域,它指代一套用来运行和评估 Agent 的框架。DeepSeek Harness 是 DeepSeek 团队开源的一套 Agent 任务评估框架,核心思路是:
- 在可控的模拟环境中给 Agent 下发任务。
- Agent 调用工具与环境交互。
- 框架记录 Agent 的每一步动作,并根据任务完成度打分。
这样就能量化评估“这个模型 + 这套 Prompt + 这批工具”组合出来的 Agent 到底好不好用,而不是只靠肉眼感觉。
1.4 为什么可以“不花一分钱”
“不花一分钱”成立的前提是:
- 使用开源模型权重,例如 Qwen 系列开源模型。
- 使用开源推理框架,例如 Ollama、vLLM。
- 使用开源评估框架,例如 DeepSeek Harness。
- 算力来自你自己的电脑或内网服务器。
也就是说,软件成本为零,硬件成本得自己承担。如果你的机器带不动大模型,也可以用量化版的小模型(例如 Qwen3 的 4B、8B 量化版),这也是这篇文章要教大家落地的方式。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与版本说明
2.1 硬件建议
本地部署模型最核心的瓶颈是显存。常见经验值如下表,具体数值会因上下文长度、量化方式不同而变化:
| 模型规模 | 最低显存要求 | 运行体验 |
|---|---|---|
| 1B ~ 4B 量化版 | 4GB ~ 6GB | 流畅,适合入门 |
| 7B ~ 8B 量化版 | 8GB ~ 12GB | 可接受,建议 16GB |
| 14B 量化版 | 16GB ~ 24GB | 较流畅 |
| 32B 及以上 | 24GB 以上 | 建议多卡或大显存 |
如果你的机器没有 NVIDIA 显卡,也可以尝试纯 CPU 推理,速度会慢很多,但小模型(4B 量化)在 CPU 上仍然可以跑,只是响应延迟偏高。
2.2 软件环境
本文示例以常见环境为例,版本需要根据你的项目实际情况调整,重点演示配置思路。
| 组件 | 作用 | 说明 |
|---|---|---|
| Ubuntu 22.04 / Windows / macOS | 操作系统 | 命令示例以 Linux 为主 |
| Python 3.10+ | 运行 Agent 脚本和 Harness | 建议使用虚拟环境 |
| Ollama | 本地模型推理服务 | 也可以换成 vLLM 等 |
| Git | 拉取 Harness 源码 | 安装系统自带即可 |
| Docker(可选) | 隔离环境 | Harness 部分场景有用 |
2.3 项目目录规划
建议按下面目录结构来组织整个项目,避免文件散落:
code复制local-agent/
├── models/ # 模型存放(Ollama 默认自动管理)
├── harness/ # DeepSeek Harness 源码
├── agent/ # 我们自己的 Agent 代码
│ ├── agent.py
│ └── config.yaml
└── logs/ # 运行日志
3. 使用 Ollama 本地部署 Qwen 系列模型
3.1 为什么选择 Ollama
Ollama 是目前把开源模型“本地化”最省事的工具之一。它把模型下载、量化、推理服务封装成了一条命令,对外提供 OpenAI 兼容的 HTTP 接口。这意味着你在本地写好调用代码后,以后想切换到云端 API,只需要修改 base_url 和 API Key 即可,代码改动很小。
3.2 安装 Ollama
Linux 安装命令:
bash复制curl -fsSL https://ollama.com/install.sh | sh
macOS 和 Windows 可以直接去 Ollama 官网下载安装包。安装完成后,确认服务是否正常运行:
bash复制ollama --version
3.3 拉取并运行模型
以 Qwen 系列为例,先搜索一下官方仓库里有哪些可用标签:
bash复制ollama search qwen
然后拉取你需要的模型。以 4B 量化版为例:
bash复制ollama pull qwen3:4b
如果你想用更大参数的模型,可以拉取 8B 版本:
bash复制ollama pull qwen3:8b
这里再次提醒:具体的模型名称和标签会随官方更新变化,请以 ollama search qwen 返回结果为准。如果本地显存不够,优先选择带 q4、q8 这类量化标识的标签。
拉取完成后,启动一个常驻服务:
bash复制ollama serve
如果 ollama serve 在终端里运行,说明服务已经监听在 http://127.0.0.1:11434。
3.4 验证模型接口
打开另一个终端,用 curl 测试对话接口:
bash复制curl http://127.0.0.1:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3:4b",
"messages": [{"role": "user", "content": "你好,请简单介绍一下你自己"}]
}'
预期返回一个 JSON,里面包含模型生成的回复文本。看到类似 "role": "assistant" 的内容,就说明本地模型服务已经通了。
3.5 常用 Ollama 命令速查
| 命令 | 作用 |
|---|---|
ollama list |
查看本地已下载的模型 |
ollama pull <模型名> |
下载模型 |
ollama rm <模型名> |
删除模型 |
ollama serve |
启动推理服务 |
ollama stop <模型名> |
停止某个运行中的模型 |
到这里,你已经拥有了一个本地模型服务。接下来的问题是:怎么把它变成一个 Agent,并用 DeepSeek Harness 来评估它的任务完成能力。
4. DeepSeek Harness 框架介绍与安装
4.1 Harness 在整套流程中的位置
刚才部署好的 Ollama 只解决了“模型能聊天”的问题。但 Agent 真正的难点是“模型能不能按照任务要求,在模拟环境里调用工具、完成多步操作”。DeepSeek Harness 就是用来回答这个问题的工具。
工作流程大致是:
- Harness 定义一批任务,每个任务有明确的目标和模拟环境。
- Agent 接收任务描述。
- Agent 调用工具(例如执行 Python 代码、操作文件、查询数据库等)推进任务。
- Harness 记录每一步动作。
- 任务结束后,Harness 根据结果给 Agent 打分。
4.2 拉取 Harness 源码
bash复制git clone https://github.com/deepseek-ai/DeepSeek-Harness.git
cd DeepSeek-Harness
注意:开源项目迭代很快,具体目录结构、依赖名称和启动命令可能变化。下文以“核心思路 + 最小示例”为主,你需要对照你拉下来的仓库 README 做微调。
4.3 创建 Python 虚拟环境并安装依赖
bash复制python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
如果 requirements.txt 不存在,尝试阅读 README 中关于安装依赖的说明。一般来说,这类框架会依赖 openai、pydantic、pyyaml、requests 等常见库。
4.4 理解 Harness 的配置概念
Harness 通常提供一个 YAML 配置入口,里面需要指定:
- 模型服务地址(base_url)。
- 模型名称(model)。
- 工具列表(tools)。
- 任务集(tasks)。
因为我们要对接的是 Ollama 提供的 OpenAI 兼容接口,所以 base_url 一般设置为 http://127.0.0.1:11434/v1。
5. 完整实战:构建一个本地 Agent 并用 Harness 评估
5.1 需求分析
我们先做一个最小但完整的目标:让 Agent 能执行“数字加法”和“获取当前时间”两个工具,然后在 Harness 里完成一个简单的任务,例如“计算 123 + 456,并告诉我结果”。
这个任务看起来简单,但它能验证整条链路:
- 本地模型是否被 Agent 正常调用。
- Agent 是否能识别“需要调用工具”。
- 工具执行结果是否能正确返回给模型。
- Harness 是否能记录并评分。
5.2 编写 Agent 核心代码
文件路径:agent/agent.py
python复制import json
import time
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:11434/v1",
api_key="ollama", # Ollama 本地服务不校验 key,占位即可
)
def call_llm(messages):
"""调用本地 Qwen 模型,返回响应内容"""
response = client.chat.completions.create(
model="qwen3:4b",
messages=messages,
temperature=0.2,
tools=[
{
"type": "function",
"function": {
"name": "add",
"description": "计算两个整数之和",
"parameters": {
"type": "object",
"properties": {
"a": {"type": "integer"},
"b": {"type": "integer"},
},
"required": ["a", "b"],
},
},
},
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "获取当前时间",
"parameters": {
"type": "object",
"properties": {},
},
},
},
],
tool_choice="auto",
)
return response
def execute_tool(name, arguments):
"""执行模型请求的工具,返回给模型的结果"""
if name == "add":
args = json.loads(arguments)
result = args["a"] + args["b"]
return json.dumps({"result": result})
if name == "get_current_time":
return json.dumps({"time": time.strftime("%Y-%m-%d %H:%M:%S")})
return json.dumps({"error": "unknown tool"})
def run_agent(task):
"""运行 Agent 主循环"""
messages = [{"role": "user", "content": task}]
max_steps = 5
for step in range(max_steps):
print(f"Step {step + 1}: calling LLM...")
response = call_llm(messages)
message = response.choices[0].message
if message.tool_calls:
messages.append({
"role": "assistant",
"content": message.content,
"tool_calls": [
{
"id": tc.id,
"type": "function",
"function": tc.function,
}
for tc in message.tool_calls
],
})
for tc in message.tool_calls:
tool_name = tc.function.name
tool_args = tc.function.arguments
print(f"Tool call: {tool_name}({tool_args})")
tool_result = execute_tool(tool_name, tool_args)
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": tool_result,
})
else:
print("Final answer:", message.content)
return message.content
return "Max steps reached."
if __name__ == "__main__":
result = run_agent("请计算 123 + 456 的结果,并告诉我答案")
print("=== Agent Result ===")
print(result)
这段代码的逻辑是:
- 先让模型判断“用户任务需要哪些工具”。
- 如果模型返回
tool_calls,说明它想调用工具,我们执行对应函数,把结果作为tool角色的消息再喂回给模型。 - 模型拿到工具结果后,组织最终答案。
5.3 运行 Agent 验证链路
bash复制cd agent
python agent.py
预期输出大致为:
code复制Step 1: calling LLM...
Tool call: add({"a": 123, "b": 456})
Step 2: calling LLM...
Final answer: 123 + 456 的结果是 579
如果你看到的输出是模型直接给出了答案,没有触发工具调用,也没关系,可能是模型认为这种简单计算可以直接算。更稳妥的测试任务可以是“请使用 get_current_time 工具获取当前时间”,这样模型就必须走工具调用链路。
5.4 接入 Harness 做任务评估
下面我们把上面这个 Agent 包装成一个 Harness 可以调用的任务执行器。不同版本 Harness 的接口差异较大,这里给出一种通用思路:Harness 通过一个配置指定模型和任务,我们把自己的 Agent 函数注册为任务执行器。
文件路径:agent/harness_agent.py
python复制import json
from agent import run_agent
def execute_task(task: str) -> dict:
"""Harness 任务执行入口"""
final_answer = run_agent(task)
return {
"task": task,
"final_answer": final_answer,
"status": "success",
}
if __name__ == "__main__":
sample_task = "请计算 10 + 20 的结果"
print(json.dumps(execute_task(sample_task), ensure_ascii=False, indent=2))
然后在 Harness 配置里,把模型服务指向 Ollama,把任务入口指向 execute_task。
以 YAML 配置为例,说明关键字段含义:
yaml复制# 文件路径:agent/harness_config.yaml
model:
provider: openai
base_url: http://127.0.0.1:11434/v1
model_name: qwen3:4b
agent:
entry: harness_agent.execute_task
max_steps: 5
tasks:
- name: add_task
description: "计算两个数字的和"
prompt: "请计算 123 + 456 的结果"
这里的 entry 字段表示 Harness 加载哪个 Python 函数作为 Agent 入口,tasks 定义评估任务。具体字段名请以你拉取的 Harness 版本 README 为准。
5.5 运行 Harness 评估
bash复制cd DeepSeek-Harness
python run_harness.py --config ../agent/harness_config.yaml
评估完成后,Harness 通常会输出一个结果文件,例如 results.json,里面包含每个任务的执行动作、最终回答和评分。
json复制{
"add_task": {
"final_answer": "579",
"tool_calls": 1,
"score": 1.0
}
}
看到 score: 1.0,说明 Agent 正确完成了任务。到这里,你就把“本地模型 + Agent + Harness 评估”整条链路跑通了。
6. 常见问题与排查思路
本地部署和框架对接中,新手遇到的问题相对集中。下面整理成表格,再逐条展开。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型下载失败 | 网络不稳定或模型名错误 | 重新执行 pull,确认模型标签 |
| Ollama 服务启动后端口被占用 | 11434 端口被其他程序占用 | 修改端口或停掉占用进程 |
| 调用接口报 404 | base_url 路径不对 | 检查是否带上 /v1 |
| 模型回答速度慢 | 显存不足导致部分层跑 CPU | 换更小模型或降低上下文长度 |
| Agent 不触发工具调用 | 模型能力限制或 Prompt 不够明确 | 换更大模型,或加上强制工具调用选项 |
| Harness 找不到入口函数 | 模块路径错误 | 确认 Python 路径和函数名 |
6.1 模型下载失败
现象:
code复制Error: pull model manifest: file does not exist
可能原因:
- 模型名称拼写错误。
- 该模型只存在于另一个仓库命名空间。
排查与解决:
bash复制ollama search qwen
先看一下官方仓库返回的可用模型列表,从输出里复制准确的模型名。如果网络稳定性较差,可以多次重试,或者配置镜像加速。
6.2 Ollama 端口被占用
现象:
code复制listen tcp :11434: bind: address already in use
排查:
bash复制lsof -i :11434
如果发现占用进程,可以选择停掉它,或者给 Ollama 指定其他端口启动。修改 Ollama 服务端口的方式通常是设置环境变量 OLLAMA_HOST:
bash复制OLLAMA_HOST=0.0.0.0:11435 ollama serve
注意修改后,Agent 代码和 Harness 配置里的 base_url 也要同步改成新端口。
6.3 调用接口报 404
这个问题最容易被忽略。Ollama 的 OpenAI 兼容接口地址是:
code复制http://127.0.0.1:11434/v1/chat/completions
一定要包含 /v1。如果你在代码里只写了到 http://127.0.0.1:11434,请求就会打到 Ollama 的原生接口上,路径不匹配时就会返回 404。
6.4 Agent 不触发工具调用
如果模型一轮就直接给出最终答案,说明它认为不需要调用工具。这可能是因为:
- 模型本身是参数较小的量化版,指令遵循能力一般。
- 任务描述里没有明确“必须使用工具”。
解决方式有两种:
- 在任务描述里追加“请使用 add 工具来计算,不要直接回答”。
- 在
tool_choice参数上做调整,某些 OpenAI SDK 支持设置tool_choice="required"或直接指定函数名,强制模型走工具调用分支。不过 Ollama 对tool_choice的支持程度取决于模型,需要实测。
6.5 显存不足导致速度极慢
现象:
- 模型加载后,每轮回答要等很久。
- 系统监控显示 GPU 占用接近 100%,或者反过来 GPU 占用很低但 CPU 很高。
原因通常是模型参数量超过显存,推理框架把部分层卸载到了 CPU,导致整体延迟飙升。解决办法:
- 换更小的量化版本。
- 降低
num_ctx上下文长度,例如限制为 2048。 - 关闭其他占用显存的程序。
在 Ollama 中,可以通过环境变量临时限制上下文长度:
bash复制OLLAMA_CONTEXT_LENGTH=2048 ollama serve
6.6 Harness 找不到入口函数
现象:
code复制ModuleNotFoundError: No module named 'harness_agent'
原因:Harness 运行目录是 DeepSeek-Harness,它无法找到 agent/ 目录下的模块。
解决方式:
- 把
agent目录加入 Python 路径。 - 或者在
DeepSeek-Harness目录下执行时,使用相对路径导入:
python复制import sys
sys.path.insert(0, "../agent")
from harness_agent import execute_task
6.7 排查清单
如果你仍然卡在某一步,按下面的顺序走一遍,通常能自行定位问题:
- Ollama 服务是否在运行,
ollama list是否能看到模型。 - curl 直接调用
/v1/chat/completions是否正常返回。 - Agent 脚本单独运行时,能否完成一次工具调用。
- Harness 的配置里
base_url和model_name是否和 Ollama 匹配。 - 查看 Harness 的日志输出,里面对哪一步失败通常会有明确提示。
7. 最佳实践与工程建议
7.1 模型选择策略
不要一味追求大参数模型。本地 Agent 场景下,模型需要满足的基本要求是“指令遵循能力和工具调用能力”。对于 8B 及以下量级模型,优先选择带 function calling 支持且经过针对性训练的开源版本。实际选型时应该拿“任务完成率”说话,而不是看跑分。
建议在一开始就搭建好 Harness 评估流程,然后用同一个任务集去对比不同模型、不同量化等级的效果,数据会比直觉可靠得多。
7.2 配置管理
模型地址、模型名称、上下文长度、超时时间这些参数,不要散落在代码里。统一放到 YAML 配置文件或环境变量中,方便切换环境。
yaml复制model:
base_url: http://127.0.0.1:11434/v1
name: qwen3:4b
temperature: 0.2
timeout: 60
agent:
max_steps: 5
7.3 工具调用代码的安全边界
Agent 一旦可以调用工具,风险也随之而来。如果你的 Agent 未来会接入真实工具(文件操作、数据库访问、网络请求),务必注意:
- 工具调用必须限定在白名单中。
- 涉及删除、覆盖、写入的操作,先打印执行计划并要求确认。
- 数据库操作只允许参数化查询,禁止直接拼接用户输入。
- 凡是会修改生产环境的动作,都要在测试环境验证后再放开。
本地跑通链路时,可以先让 Agent 只调用“只读类”工具或“无副作用”工具,例如计算、时间查询、文本处理。
7.4 日志与可观测性
Agent 的调试比普通程序更复杂,因为你不仅要看代码执行轨迹,还要看模型每一步的“思考结果”。建议在关键节点打日志:
- 用户输入。
- 模型返回的完整消息。
- 工具调用的名称、参数。
- 工具返回的结果。
- 最终答案。
日志格式推荐 JSON,方便后续用脚本统计分析。
7.5 性能优化方向
本地模型 + Agent 的常见瓶颈有三个:
- 首 token 延迟,也就是“模型开始输出前”的等待时间。
- 上下文太长导致每次请求处理变慢。
- 多轮工具调用中反复传输历史消息,占用带宽和显存。
优化思路:
- 合理裁剪对话历史,只保留必要信息。
- 控制上下文长度。
- 使用量化模型降低显存占用。
- 提高
num_ctx反而可能变慢,小模型不一定需要很长的上下文。
7.6 生产环境注意事项
把这套方案从“本机验证”带到“团队使用”时,要注意下面几点:
- 模型服务不要直接暴露公网,至少加一层认证或内网访问限制。
- Ollama 的
/v1接口没有强认证,内网里其他人知道地址后也能直接调用,建议用网关或反代做访问控制。 - 模型更新时先在 Harness 上跑一遍回归任务,确认工具调用能力没有回退。
- 定期备份 Harness 的任务集和配置,否则很难对比不同版本的模型表现。
8. 总结
这篇文章从一个实际需求出发,完整走了一遍“本地部署千问(Qwen)系列模型 + 构建 Agent + 接入 DeepSeek Harness 评估”的流程。核心收获可以概括为三点:
- 本地模型部署用 Ollama 是最省事的路径,一条命令就能提供 OpenAI 兼容接口。
- Agent 的本质是“模型决策 + 工具执行”的循环,调试时重点看
tool_calls是否触发、工具结果是否正确回传。 - Harness 的价值在于把主观的“看起来回答得不错”变成量化的任务完成率,后续换模型、调 Prompt 都有据可依。
如果你是在自己的电脑上想跑通链路,建议从 4B 左右的量化小模型开始,先把工具调用的链路跑通,再去尝试更大的模型和更复杂的任务集。下一步可以继续研究:
- 给 Agent 接入真实的文件操作工具和数据库查询工具。
- 设计一批自定义任务,形成属于自己的 Agent 评测集。
- 对比不同 Prompt 模板对工具调用成功率的影响。
本地模型、Agent、评估框架这套组合,最吸引人的地方就是“不花钱也能做严肃的技术验证”。硬件只要够用,剩下的就是动手实践和持续调优。如果本文对你有帮助,可以收藏备用,后面实测到新的问题也会继续补充。
