《深入理解 AI Agent:设计原理与工程实践 》实验2-1 本地大模型服务部署与工具调用

1. 项目概览

https://github.com/bojieli/ai-agent-book

local_llm_serving 是《深入理解 AI Agent》第 2 章实验 2-1 的配套项目,主题是本地 LLM 服务部署与工具调用。它不是一个简单的聊天脚本,而是一套跨平台的本地 Agent 演示工程,覆盖:

  • 本地模型服务:Ollama 与 vLLM 两条后端路径;
  • 工具调用:天气、时间、汇率、PDF 解析、代码解释器等内置工具;
  • 流式输出:支持普通回答、思考过程、工具调用片段的实时返回;
  • 实验与基准:包含 benchmark、实验协议、证据文件与结果目录;
  • 自动化测试:覆盖平台检测、流式工具调用、并行工具、Ollama thinking 等关键行为。

从解析摘要看,项目默认推荐使用 Ollama;在 Linux/WSL2 + NVIDIA GPU 环境下可额外安装 vllm 依赖并显式使用 vLLM 后端。Windows 原生环境即使有 NVIDIA GPU,也明确走 Ollama 路径。

1.1 学习价值

这个项目适合作为"本地大模型 + Agent 工具调用"的入门到进阶样例,学习价值主要体现在:

  1. 理解 Agent 工程结构:不是把 prompt 写死在一个文件里,而是拆成配置、服务启动、Agent 封装、工具注册、实验运行、测试验证等模块。
  2. 掌握 OpenAI 兼容工具调用格式agent.pyollama_native.py 都围绕工具 schema、工具调用解析、工具执行与结果回填展开。
  3. 看清流式输出的工程难点:项目测试中特别覆盖了碎片化 tool call、thinking 字段、结构化流式拼接等问题。
  4. 学会跨平台后端选择main.pycheck_compatibility.py 展示了如何根据操作系统、CUDA、依赖情况选择 Ollama 或 vLLM。
  5. 建立实验可复现意识run_experiment.pyexperiment_protocol.jsonruns/ 目录体现了协议、证据、manifest 的实验留痕方式。

1.2 解决的行业痛点

本地 LLM 应用落地常见痛点包括:

  • 不同本地推理后端 API 不一致,切换成本高;
  • 工具调用在流式场景下可能被拆成多个 chunk,解析容易失败;
  • Windows、macOS、Linux/WSL 的 GPU 与依赖兼容性复杂;
  • 小模型输出工具调用 JSON 不稳定,需要容错解析;
  • 并行工具调用如果串行执行,会明显拖慢响应;
  • 本地服务性能测试缺少统一协议,结果难以复现。

本项目通过统一入口、后端适配、工具注册中心、流式解析测试和实验脚本,对这些问题给出了可运行的参考实现。

1.3 前置知识要求

建议读者具备以下基础:

  • Python 3.12 基础语法、虚拟环境与包管理;
  • 了解 OpenAI Chat Completions API 的基本概念;
  • 了解 function calling / tool calling 的消息结构;
  • 对本地模型服务有初步认识,例如 Ollama、vLLM;
  • 能使用命令行执行 pythonpipuvollama 等命令;
  • 如果要运行 vLLM,需要了解 Linux/WSL2、NVIDIA GPU、CUDA 相关基础。

如果完全没有接触过 LLM API,建议先理解三个概念:messagestoolstool_calls。本项目的核心调用链基本围绕它们展开。

2. 目录结构速览

项目根目录为 chapter2/local_llm_serving。根据解析摘要,目录结构如下:

text 复制代码
.
├── README.md
├── agent.py
├── benchmark.py
├── check_compatibility.py
├── config.py
├── demo_streaming.py
├── env.example
├── experiment_protocol.json
├── main.py
├── ollama_native.py
├── quick_test_streaming.py
├── requirements.txt
├── run_experiment.py
├── server.py
├── setup.sh
├── test_benchmark.py
├── test_code_interpreter_full.py
├── test_ollama_streaming_final.py
├── test_ollama_thinking.py
├── test_parallel_tools.py
├── test_platform_detection.py
├── test_run_experiment.py
├── test_sample_command.py
├── test_streaming.py
├── test_streaming_fix.py
├── test_vllm_structured_streaming.py
├── test_weather.py
├── tools.py
└── runs/
    ├── exp2-1-qwen3-0.6b-20260730-v1/
    │   ├── evidence.json
    │   ├── experiment_protocol.json
    │   └── manifest.json
    └── exp2-1-qwen3-0.6b-20260730-v2/
        ├── evidence.json
        ├── experiment_protocol.json
        └── manifest.json

核心文件可以按职责分组:

分组 文件 作用
统一入口 main.py 根据后端初始化 Agent,支持交互模式、单任务模式、流式输出
vLLM Agent agent.py 基于 OpenAI Python SDK 调用 vLLM 服务,实现工具调用与流式处理
Ollama Agent ollama_native.py Ollama 原生工具调用、OpenAI 兼容封装、thinking fallback
工具系统 tools.py 工具注册中心与天气、时间、汇率、PDF、代码解释器等工具
配置 config.pyenv.example 从环境变量加载配置,具体变量名未在摘要中展开
服务启动 server.py 启动和管理 vLLM 服务,支持模型下载函数
兼容性检查 check_compatibility.py 检查系统、CUDA 与后端适配建议
性能测试 benchmark.py 吞吐量、KV cache、batching 等基准场景
实验运行 run_experiment.pyexperiment_protocol.json 按协议运行完整实验并生成证据
流式演示 demo_streaming.pytest_streaming.pyquick_test_streaming.py 展示和验证流式输出
回归测试 test_*.py 覆盖平台检测、并行工具、结构化流式、benchmark 等
结果目录 runs/ 保存实验协议、证据和 manifest

需要注意:部分文件如 quick_test_streaming.pytest_ollama_streaming_final.pytest_sample_command.pytest_streaming_fix.pytest_weather.py 在解析摘要中没有模块说明,不能推断其具体实现细节。

3. 核心模块与职责

3.1 main.py:统一入口与后端选择

main.py 是项目的主入口,包含 ToolCallingAgent 类。它负责:

  • 接收 backend 参数;
  • 自动检测最佳后端;
  • 初始化 vLLM 或 Ollama;
  • 提供统一的 chat()reset_conversation() 接口;
  • 支持单任务运行和交互模式。

主要方法包括:

  • __init__(self, backend):初始化入口 Agent;
  • _detect_best_backend(self):根据平台和环境检测后端;
  • _initialize_backend(self):初始化具体后端;
  • _init_vllm(self):初始化 vLLM Agent;
  • _init_ollama(self):初始化 Ollama Agent;
  • chat(...):统一聊天接口;
  • reset_conversation(self):重置对话历史。

从 README 可知,推荐显式传入后端:

bash 复制代码
python main.py --backend ollama

Linux/WSL GPU 路径在安装 vllm extra 后可运行:

bash 复制代码
python check_compatibility.py
python main.py --backend vllm

3.2 agent.py:vLLM 工具调用 Agent

agent.py 的核心类是 VLLMToolAgent,模块说明为 "vLLM Tool Calling Agent Implementation"。它通过 openai SDK 调用 OpenAI 兼容接口,因此 vLLM 服务需要暴露兼容 OpenAI 的 API。

主要职责:

  1. 初始化 API base 与 API key;
  2. 将工具 schema 格式化到系统提示词或工具参数中;
  3. 解析模型返回的 tool calls;
  4. 并发执行多个工具调用;
  5. 将工具结果回填到对话中;
  6. 支持普通聊天和流式聊天;
  7. 支持自定义工具注册。

关键方法:

方法 职责
__init__(self, api_base, api_key) 初始化 OpenAI 客户端与工具注册中心
_format_system_prompt_with_tools(self) 格式化带工具说明的系统提示词
_parse_tool_calls(self, content) 解析模型输出中的工具调用
_execute_tool_calls(self, tool_calls) 执行多个工具调用
_execute_single_tool(self, tool_data) 执行单个工具调用
chat(...) 非流式聊天,支持工具调用循环
chat_stream(...) 流式聊天,支持实时输出和工具片段拼接
reset_conversation(self) 清空会话历史
add_custom_tool(...) 添加自定义工具

3.3 ollama_native.py:Ollama 原生与兼容封装

该文件包含两个主要类:

OllamaNativeAgent

用于 Ollama 原生工具调用,主要方法:

  • __init__(self, model):初始化模型与客户端;
  • _convert_tools_to_ollama_format(self):将内部工具 schema 转成 Ollama 格式;
  • _chat_with_think_fallback(self, **kwargs):处理 thinking 字段或 fallback;
  • _execute_tool_calls(self, tool_calls):执行工具调用;
  • chat(...):普通聊天;
  • chat_stream(...):流式聊天;
  • reset_conversation(self):重置会话。

OllamaOpenAICompatible

用于通过 OpenAI 兼容接口访问 Ollama,摘要中显示的方法包括:

  • __init__(self, model, base_url)
  • chat(...)
  • reset_conversation(self)

这说明项目同时考虑了 Ollama 原生 API 和 OpenAI 兼容 API 两种接入方式。

3.4 tools.py:工具注册与内置工具

tools.py 是工具系统的核心,包含 ToolRegistry 类。它负责注册工具、生成工具 schema、执行工具调用。

内置工具函数包括:

工具函数 作用
get_current_temperature(location, unit) 获取当前天气温度
get_current_time(timezone) 获取当前时间
convert_currency(amount, from_currency, to_currency) 汇率转换
parse_pdf(url) 解析 PDF
code_interpreter(code) Python 代码解释器

ToolRegistry 的关键方法:

  • _register_default_tools(self):注册默认工具;
  • register_tool(...):注册自定义工具;
  • get_tool_schemas(self):返回给模型使用的工具 schema;
  • execute_tool(self, name, arguments):按名称执行工具。

模块还提供 format_tool_response(tool_name, tool_result),用于把工具执行结果格式化为可回填给模型的内容。

3.5 server.py:vLLM 服务管理

server.py 包含 VLLMServer 类,用于启动、等待、停止和重启 vLLM 服务。

关键方法:

方法 职责
__init__(self, config) 读取配置并构造服务对象
_build_command(self) 构造启动 vLLM 的命令
start(self, wait_for_ready, timeout) 启动服务
_wait_for_ready(self, timeout) 轮询等待服务就绪
stop(self) 停止服务
is_running(self) 判断服务是否运行
restart(self) 重启服务

此外还有 download_model_from_modelscope() 函数,说明项目支持从 ModelScope 下载模型,但具体命令和参数未在摘要中完整展开。

3.6 benchmark.py:本地服务性能基准

benchmark.py 是实验 2-1 配套的性能基准脚本,包含:

  • build_padded_system_prompt(target_tokens):构造指定 token 长度的系统提示词;
  • make_client(base_url, api_key):构造客户端;
  • stream_once(...):执行一次流式请求;
  • scenario_throughput(...):吞吐量场景;
  • scenario_kv_cache(...):KV cache 场景;
  • scenario_batching(...):批处理场景;
  • print_report(results):打印报告;
  • parse_concurrency(value):解析并发参数;
  • build_parser():构建命令行参数;
  • main():入口函数。

摘要未给出完整命令行参数说明,因此不能编造具体参数。实际使用时应通过 python benchmark.py --help 查看。

3.7 run_experiment.py:完整实验运行器

run_experiment.py 用于运行完整的本地服务实验,包含 OllamaRawClient 类和多个实验辅助函数。

OllamaRawClient 方法:

  • __init__(self, base_url, model, timeout)
  • get_json(self, path)
  • show_model(self)
  • generate(self, prompt, num_predict, temperature)

主要函数:

函数 作用
sha256_bytes(data) 计算字节哈希
sha256_text(text) 计算文本哈希
utc_now() 获取 UTC 时间
parse_tool_calls(raw_text) 解析原始工具调用文本
normalize_tool_call(call) 规范化工具调用
execute_parallel(registry, calls) 并行执行工具
render_prompt(tokenizer, messages, tools) 使用 tokenizer 渲染 prompt
run_tool_case(...) 运行工具调用实验
run_cache_case(...) 运行缓存实验
credential_scan(path) 扫描凭据泄露风险
cfg_pairs(protocol) 读取协议配置
main() 实验入口

runs/ 下已有两个实验结果目录,每个目录包含:

  • evidence.json:实验证据;
  • experiment_protocol.json:实验协议副本;
  • manifest.json:清单文件。

摘要未展示这些 JSON 的具体字段,因此不能推断其完整格式。

3.8 测试模块:保障关键行为

项目测试文件较多,重点覆盖:

测试文件 覆盖内容
test_platform_detection.py Windows/Linux/CUDA 场景下的后端选择
test_parallel_tools.py 并行工具调用、真实 Ollama/vLLM 模型路径
test_vllm_structured_streaming.py vLLM 流式碎片化 tool call 拼接
test_ollama_thinking.py Ollama thinking 字段流式处理
test_benchmark.py benchmark 中 reasoning chunk 与 TTFT 行为
test_code_interpreter_full.py 代码解释器成功、失败、环境访问和错误传播
test_run_experiment.py 多工具调用解析、参数规范化、协议 JSON 校验

这些测试说明项目最容易出问题的地方不是"能不能调用模型",而是:

  • 流式 tool call 被拆片;
  • 小模型输出 JSON 不规范;
  • thinking 字段和普通 content 字段混杂;
  • 并行工具是否真的并发;
  • 平台后端选择是否符合预期。

3.9 核心原理通俗解读

可以把整个项目理解成一个"前台接待员 + 工具箱 + 本地模型专家"的协作系统:

  1. 用户发消息:例如"北京现在多少度?"
  2. Agent 判断是否需要工具 :模型看到工具 schema 后,决定调用 get_current_temperature
  3. 工具注册中心查找工具ToolRegistry 根据工具名找到对应 Python 函数。
  4. 执行工具:把模型给出的参数传给函数,得到天气结果。
  5. 结果回填模型:Agent 把工具结果加入消息历史。
  6. 模型生成最终回答:例如"北京当前气温为......"。
  7. 流式场景下:模型输出不是一次性返回,而是一段一段到达。工具调用 JSON 可能被拆成多个 chunk,因此需要缓存、拼接、解析和容错。

vLLM 与 Ollama 的区别主要在"本地模型专家如何上岗":

  • Ollama:跨平台、安装简单,适合 macOS、Windows 原生、无 GPU Linux;
  • vLLM:适合 Linux/WSL2 + NVIDIA GPU,强调高并发和服务化推理能力。

4. 关键数据流与调用链

4.1 普通非流式工具调用链

python main.py --backend ollama 为例,典型调用链如下:

text 复制代码
用户输入
  ↓
main.py: ToolCallingAgent.chat()
  ↓
根据 backend 选择具体 Agent
  ├─ OllamaNativeAgent.chat()
  │   ├─ _convert_tools_to_ollama_format()
  │   ├─ 调用 Ollama 模型
  │   ├─ 收到 tool_calls
  │   ├─ _execute_tool_calls()
  │   │   └─ ToolRegistry.execute_tool()
  │   └─ 将工具结果回填后继续生成最终回答
  │
  └─ VLLMToolAgent.chat()
      ├─ _format_system_prompt_with_tools()
      ├─ 调用 OpenAI 兼容接口
      ├─ _parse_tool_calls()
      ├─ _execute_tool_calls()
      │   └─ ToolRegistry.execute_tool()
      └─ 回填工具结果并生成最终回答

核心消息流可以概括为:

text 复制代码
system / developer prompt
+ user message
+ tool schemas
  → model returns tool_calls
  → tool execution results
  → model returns final answer

4.2 流式工具调用链

流式路径更复杂,因为工具调用参数可能被拆成多个 chunk:

text 复制代码
用户输入
  ↓
chat_stream()
  ↓
模型逐块返回 content / reasoning / tool_calls
  ↓
Agent 缓存并拼接片段
  ↓
判断 tool_call arguments 是否完整
  ├─ 完整:执行工具
  │   ├─ ToolRegistry.execute_tool()
  │   └─ 工具结果回填
  └─ 不完整:继续等待后续 chunk
  ↓
继续生成最终自然语言回答

从测试文件看,项目明确关注以下流式问题:

  • test_vllm_structured_streaming.py:碎片化并行 tool call 拼接;
  • test_ollama_thinking.py:Ollama thinking 字段输出;
  • test_benchmark.py:reasoning chunks 对 TTFT 的影响;
  • test_streaming.py:普通流式功能演示与对比。

4.3 并行工具调用链

agent.pyollama_native.py 都导入了 concurrent.futuresrun_experiment.py 提供 execute_parallel(registry, calls)test_parallel_tools.py 还注册了 _sleep_tool 来验证并行性。

并行调用链大致为:

text 复制代码
模型一次返回多个 tool_calls
  ↓
_execute_tool_calls()
  ↓
ThreadPoolExecutor / concurrent.futures 并发执行
  ↓
收集每个工具结果
  ↓
按调用 ID 回填到消息历史
  ↓
模型生成最终回答

这类实现的重点是:

  • 工具调用 ID 必须和结果对应;
  • 工具参数要在执行前完成 JSON 解析;
  • 单个工具失败不能让整个批处理无限挂起;
  • 测试需要用耗时工具验证"确实并发",而不是逻辑上看起来并发。

4.4 实验运行数据流

run_experiment.py 的数据流可概括为:

text 复制代码
experiment_protocol.json
  ↓
main() 读取协议
  ↓
cfg_pairs(protocol) 生成配置组合
  ↓
OllamaRawClient / 本地服务请求
  ↓
run_tool_case() / run_cache_case()
  ↓
收集指标、原始输出、哈希与时间戳
  ↓
credential_scan(path) 检查敏感信息
  ↓
写入 runs/<experiment-id>/
      ├─ evidence.json
      ├─ experiment_protocol.json
      └─ manifest.json

摘要未说明 benchmark.py 是否会自动写入文件,也未说明 run_experiment.py 的完整命令参数,因此实际运行前应查看 --help

4.5 流程易错节点标注

以下节点是本项目最容易出错的位置:

  1. 后端选择错误

    Windows 原生环境即使有 CUDA,也应使用 Ollama;vLLM 需要 Linux/WSL GPU 环境。

  2. 模型未拉取或服务未启动

    README 中 macOS 示例要求先 ollama serve,再 ollama pull qwen3:0.6b

  3. 工具 schema 与函数参数不一致

    如果 schema 中声明的参数名和 Python 函数参数不匹配,工具执行会失败。

  4. 流式 tool call JSON 不完整

    多个 chunk 到达前不能急于 json.loads()

  5. 小模型输出工具调用格式不稳定

    run_experiment.py 中存在 parse_tool_calls()normalize_tool_call(),说明需要容错和规范化。

  6. 并行工具结果回填顺序错误

    必须按 tool call ID 关联结果,不能简单按完成顺序回填。

  7. 代码解释器安全风险

    code_interpreter(code) 具备完整 Python 环境访问能力,测试中也有 test_full_environment_access,不应在不可信输入下直接暴露到生产环境。

  8. 实验结果误判

    如果协议、模型版本、并发参数不同,吞吐量和延迟不能直接横向比较。

5. 关键类/函数速查表

5.1 入口与后端类

类/函数 所在文件 作用
ToolCallingAgent main.py 统一入口,封装后端选择与聊天接口
ToolCallingAgent._detect_best_backend main.py 自动检测推荐后端
ToolCallingAgent._initialize_backend main.py 初始化具体后端
ToolCallingAgent._init_vllm main.py 初始化 vLLM Agent
ToolCallingAgent._init_ollama main.py 初始化 Ollama Agent
VLLMToolAgent agent.py vLLM/OpenAI 兼容工具调用 Agent
OllamaNativeAgent ollama_native.py Ollama 原生工具调用 Agent
OllamaOpenAICompatible ollama_native.py Ollama 的 OpenAI 兼容封装
VLLMServer server.py vLLM 服务启动与生命周期管理

5.2 工具体系

类/函数 所在文件 作用
ToolRegistry tools.py 工具注册、schema 生成、工具执行
ToolRegistry.register_tool tools.py 注册自定义工具
ToolRegistry.get_tool_schemas tools.py 获取工具 schema 列表
ToolRegistry.execute_tool tools.py 执行指定工具
get_current_temperature tools.py 天气查询工具
get_current_time tools.py 时间查询工具
convert_currency tools.py 汇率转换工具
parse_pdf tools.py PDF 解析工具
code_interpreter tools.py Python 代码解释器
format_tool_response tools.py 格式化工具返回结果

5.3 流式与工具调用处理

类/函数 所在文件 作用
VLLMToolAgent.chat agent.py 非流式聊天与工具调用循环
VLLMToolAgent.chat_stream agent.py 流式聊天与工具片段处理
VLLMToolAgent._parse_tool_calls agent.py 解析工具调用
VLLMToolAgent._execute_tool_calls agent.py 执行多个工具调用
OllamaNativeAgent.chat_stream ollama_native.py Ollama 流式输出
OllamaNativeAgent._chat_with_think_fallback ollama_native.py thinking 字段兼容处理
parse_tool_calls run_experiment.py 解析实验中的原始工具调用
normalize_tool_call run_experiment.py 规范化工具调用参数
execute_parallel run_experiment.py 并行执行工具调用

5.4 基准与实验

类/函数 所在文件 作用
build_padded_system_prompt benchmark.py 构造目标 token 数的系统提示词
stream_once benchmark.py 发起一次流式请求
scenario_throughput benchmark.py 吞吐量测试场景
scenario_kv_cache benchmark.py KV cache 测试场景
scenario_batching benchmark.py 批处理测试场景
print_report benchmark.py 打印基准报告
OllamaRawClient run_experiment.py 实验用 Ollama 原始 HTTP 客户端
run_tool_case run_experiment.py 运行工具调用实验
run_cache_case run_experiment.py 运行缓存实验
credential_scan run_experiment.py 检查结果目录中的凭据泄露
sha256_bytes / sha256_text run_experiment.py 生成哈希,用于证据留痕

5.5 平台检查

函数 所在文件 作用
check_system check_compatibility.py 检查系统兼容性
provide_recommendations check_compatibility.py 根据 CUDA 和系统给出建议
main check_compatibility.py 兼容性检查入口

6. 如何运行与调试(基于摘要推断,无法确定则说明)

本节严格依据 README 摘要与模块入口线索整理。未在摘要中发现的命令参数、环境变量和输出内容,会明确标注。

6.1 环境准备

6.1.1 安装 Python

README 要求:

  • Python 3.12;
  • 推荐从仓库根目录安装 Chapter 2 共享环境。

6.1.2 安装 Chapter 2 依赖

根据 README,应先在仓库根目录执行:

bash 复制代码
uv sync --locked --python 3.12 --extra ch2

执行目的:

  • 创建或同步 Python 3.12 虚拟环境;
  • 安装第 2 章默认依赖;
  • 默认路径使用 Ollama,不会拉取 Linux/GPU 专用的 vLLM 栈。

如果使用 macOS/Linux,激活环境:

bash 复制代码
source .venv/bin/activate

Windows PowerShell:

powershell 复制代码
.venv\Scripts\Activate.ps1

Windows cmd:

bat 复制代码
.venv\Scripts\activate.bat

如果没有安装 uv,README 给出 pip fallback:

bash 复制代码
python -m pip install -e ".[ch2]"

6.1.3 可选安装 vLLM 依赖

仅在 Linux/WSL2 + NVIDIA GPU 环境下使用:

bash 复制代码
uv sync --locked --python 3.12 --extra ch2 --extra vllm

pip fallback:

bash 复制代码
python -m pip install -e ".[ch2,vllm]"

执行目的:

  • 安装 vLLM 所需依赖;
  • 支持 python main.py --backend vllm

注意:README 明确说明 Windows 原生始终使用 Ollama;如果要在 Windows 上运行 vLLM,应使用 WSL2 或 Linux 容器。

6.1.4 进入本项目目录

bash 复制代码
cd chapter2/local_llm_serving

如果迁移过程中单项目安装方式仍需使用,README 提到:

bash 复制代码
python -m pip install -r requirements.txt

但 README 主线推荐从仓库根目录安装 ch2 extra。

6.2 安装并启动 Ollama

macOS

README 给出的步骤:

bash 复制代码
brew install ollama
ollama serve

然后在另一个终端拉取模型:

bash 复制代码
ollama pull qwen3:0.6b

执行目的:

  • brew install ollama:安装 Ollama;
  • ollama serve:启动 Ollama 服务;
  • ollama pull qwen3:0.6b:下载项目示例模型。

正常控制台输出特征:

  • ollama serve 会持续运行并输出服务日志;
  • ollama pull qwen3:0.6b 会显示模型下载进度;
  • 下载完成后命令退出。

具体日志文本未在解析摘要中发现。

Windows 原生

README 要求:

  1. ollama.com/download/windows 安装 Ollama;
  2. 执行:
bash 复制代码
ollama pull qwen3:0.6b
  1. 运行:
bash 复制代码
python main.py --backend ollama

即使 Windows 机器有 NVIDIA GPU,也使用 Ollama。

Linux 无 GPU

README 摘要未给出 Linux 无 GPU 的完整 Ollama 安装命令,但项目特性说明 Linux without GPU 使用 Ollama。可参考 macOS 的命令思路安装 Ollama、启动服务并拉取模型;具体 Linux 安装方式未在摘要中发现,建议以 Ollama 官方文档为准。

6.3 运行主程序

6.3.1 Ollama 后端

chapter2/local_llm_serving 目录执行:

bash 复制代码
python main.py --backend ollama

执行目的:

  • 启动统一入口;
  • 初始化 Ollama Agent;
  • 进入交互或任务模式。

README 未展示 main.py 的完整参数列表,因此交互命令、单任务参数、流式参数需要通过以下命令查看:

bash 复制代码
python main.py --help

正常预期:

  • 程序应能连接本地 Ollama;
  • 可输入问题;
  • 当问题需要工具时,会调用天气、时间、汇率、PDF 或代码解释器等工具;
  • 如果启用流式,应逐段输出回答或思考内容。

具体控制台提示文本未在解析摘要中发现。

6.3.2 vLLM 后端

仅在 Linux/WSL2 + NVIDIA GPU 且已安装 vllm extra 后执行:

bash 复制代码
python check_compatibility.py
python main.py --backend vllm

执行目的:

  • check_compatibility.py:检查系统是否满足 vLLM 运行条件;
  • main.py --backend vllm:显式使用 vLLM 后端。

正常预期:

  • 兼容性检查应给出系统和 CUDA 相关建议;
  • vLLM 后端应连接到本地 vLLM OpenAI 兼容服务。

摘要未明确 main.py --backend vllm 是否会自动启动 server.py 中的 VLLMServer,因此不能断言。若服务未启动,需要单独查看 server.py --help 或源码确认。

6.4 运行兼容性检查

bash 复制代码
python check_compatibility.py

执行目的:

  • 检查操作系统;
  • 检查 CUDA 是否可用;
  • 根据平台给出后端建议。

根据测试文件,预期逻辑包括:

  • Native Windows:即使 CUDA 可用,也推荐 Ollama;
  • Linux with CUDA:可使用 vLLM;
  • Linux without CUDA:使用 Ollama。

正常输出特征:

  • 应输出系统检查结果和建议;
  • 具体文案未在摘要中发现。

6.5 运行流式演示

入口线索显示 demo_streaming.py 支持:

  • demo_vllm_streaming()
  • demo_ollama_streaming()
  • demo_unified_streaming()
  • main()

可先查看帮助:

bash 复制代码
python demo_streaming.py --help

如果该脚本支持参数,按帮助选择后端。摘要未给出明确运行命令,因此不能编造。

执行目的:

  • 演示 vLLM 或 Ollama 的流式输出;
  • 展示统一流式接口;
  • 通过打字机效果观察 token 逐块输出。

print_with_typing_effect(text, delay) 表明脚本可能带有延迟打印效果。

6.6 运行测试

项目包含多个测试文件。可使用 Python 自带测试方式运行:

bash 复制代码
python -m unittest

如果希望运行某个测试文件,例如:

bash 复制代码
python -m unittest test_platform_detection
python -m unittest test_vllm_structured_streaming
python -m unittest test_ollama_thinking
python -m unittest test_code_interpreter_full

部分测试可能依赖真实 Ollama 或 vLLM 服务,例如:

  • test_parallel_tools.py 中包含 test_native_real_model()test_openai_compat_real_model()test_vllm_agent_real_model()
  • 这些测试在模型服务未启动时可能失败或跳过,具体行为未在摘要中说明。

执行目的:

  • 验证后端检测逻辑;
  • 验证流式 tool call 拼接;
  • 验证 Ollama thinking 字段;
  • 验证代码解释器错误处理;
  • 验证实验工具调用解析。

正常预期:

  • 不依赖外部服务的单元测试应通过;
  • 依赖真实模型的测试需要本地服务和模型就绪。

6.7 运行 benchmark

摘要显示 benchmark.py 使用 argparse,但未给出完整参数。建议先执行:

bash 复制代码
python benchmark.py --help

执行目的:

  • 查看吞吐量、KV cache、batching 等场景参数;
  • 确认 base URL、model、并发数、max tokens 等配置方式。

可预期该脚本会:

  • 构造 padded system prompt;
  • 发起流式请求;
  • 统计延迟、吞吐量等指标;
  • 调用 print_report(results) 打印报告。

是否写入结果文件:未在解析摘要中发现

6.8 运行实验

run_experiment.py 是完整实验运行器,支持 argparse。建议先执行:

bash 复制代码
python run_experiment.py --help

执行目的:

  • 查看实验协议路径、模型名、输出目录等参数;
  • 确认如何指定 experiment_protocol.json

从已有目录看,成功运行后可能生成或更新:

text 复制代码
runs/
└── <experiment-id>/
    ├── evidence.json
    ├── experiment_protocol.json
    └── manifest.json

已有示例目录:

  • runs/exp2-1-qwen3-0.6b-20260730-v1/
  • runs/exp2-1-qwen3-0.6b-20260730-v2/

正常输出特征:

  • 应显示实验配置、进度、指标或结果路径;
  • 具体输出格式未在解析摘要中发现。

6.9 调试建议

  1. 先跑兼容性检查

    在使用 vLLM 前先运行 python check_compatibility.py

  2. 确认 Ollama 服务可用

    先执行 ollama serve,并确认 ollama pull qwen3:0.6b 已完成。

  3. 用最小问题验证链路

    先问"你好",确认模型连通;再问"现在几点",确认工具调用链路。

  4. 开启流式观察 chunk 行为

    使用 demo_streaming.pymain.py 的流式参数观察输出是否连续。

  5. 运行定向测试

    出现工具调用异常时,优先运行:

    • test_vllm_structured_streaming.py
    • test_ollama_thinking.py
    • test_run_experiment.py
  6. 查看日志

    多个模块导入了 logging,可通过设置日志级别观察请求、工具解析和执行过程。具体日志配置入口未在摘要中发现。

7. 可扩展点与二次开发建议

7.1 新增自定义工具

项目已经提供 VLLMToolAgent.add_custom_tool(...)ToolRegistry.register_tool(...),因此扩展工具是最直接的二次开发方式。

新增工具时需要明确:

  • 工具名:模型调用时使用的名称;
  • Python 函数:实际执行逻辑;
  • 工具描述:告诉模型何时使用该工具;
  • JSON Schema:声明参数类型、字段含义、必填项。

建议遵循以下步骤:

  1. tools.py 中实现函数;
  2. ToolRegistry._register_default_tools() 中注册;
  3. 确认参数名与 schema 一致;
  4. 编写单元测试;
  5. 用真实问题验证模型是否能正确触发工具。

常见可扩展工具包括:

  • 数据库查询;
  • 企业内部 API 调用;
  • 文档检索;
  • 邮件或日历操作;
  • 代码执行沙箱;
  • 多模态文件解析。

7.2 增加新的 LLM 后端

当前已有:

  • vLLM / OpenAI-compatible;
  • Ollama native;
  • Ollama OpenAI-compatible。

如果要接入新后端,建议保持 main.py 的统一接口:

  • chat(...)
  • chat_stream(...) 或等价流式接口
  • reset_conversation()

可以新增一个后端类,例如:

python 复制代码
class CustomBackendAgent:
    def chat(self, message, use_tools=True, stream=False, **kwargs):
        ...

然后在 ToolCallingAgent._initialize_backend() 中加入分支。

需要重点补齐:

  • 工具 schema 转换;
  • tool call ID 映射;
  • 流式片段拼接;
  • 错误重试;
  • 平台兼容性说明。

7.3 强化工具调用解析

小模型输出工具调用时可能出现:

  • JSON 外层包含多余文本;
  • 单引号和双引号混用;
  • 参数字段缺失;
  • 时区、城市名等参数不规范;
  • 一次输出多个工具调用但格式不统一。

项目已有 parse_tool_calls()normalize_tool_call(),二次开发时可以:

  • 增加 JSON 修复逻辑;
  • 为特定工具增加参数校验;
  • 对城市、时区、货币代码做枚举校验;
  • 将解析失败原因写入 evidence;
  • 建立失败样本集做回归测试。

7.4 提升流式输出稳定性

流式工具调用是本项目的重点难点。建议扩展:

  • chunk 缓冲区超时机制;
  • tool call JSON 完整性检查;
  • 多个 tool call 的并行组装;
  • reasoning/content/tool_call 三类事件的统一事件模型;
  • 前端可消费的 SSE 格式。

如果要做 Web 化,可以把 chat_stream() 输出封装成:

text 复制代码
event: message
data: {"type": "content", "delta": "..."}

event: tool_call
data: {"type": "tool_call", "name": "...", "arguments": "..."}

event: final
data: {"type": "final", "content": "..."}

当前摘要未发现 Web 服务框架依赖,因此这属于二次开发建议,不是现有功能。

7.5 加强代码解释器安全

code_interpreter(code) 具备完整 Python 环境访问能力。生产化时至少应考虑:

  • 使用容器或沙箱执行;
  • 限制文件系统访问;
  • 限制网络访问;
  • 设置超时;
  • 限制内存和 CPU;
  • 禁止读取环境变量中的密钥;
  • 对用户代码做静态检查或权限隔离。

test_code_interpreter_full.py 已经覆盖成功、错误处理、环境访问和错误传播,说明安全边界是后续开发必须关注的点。

7.6 扩展实验指标

benchmark.py 已包含吞吐量、KV cache、batching 场景。可进一步增加:

  • TTFT:首 token 时间;
  • TBT:token 间时间;
  • 工具调用成功率;
  • 工具参数修复率;
  • 并行工具加速比;
  • 不同上下文长度下的延迟;
  • 不同并发数下的失败率;
  • 流式 chunk 碎片数量。

实验结果应继续写入 runs/,并保留:

  • 协议;
  • 模型版本;
  • 启动参数;
  • 原始证据;
  • 哈希;
  • 时间戳;
  • 机器信息。

7.7 方案优劣对比表格

方案 优点 缺点 适用场景
Ollama 原生 跨平台、安装简单、原生工具调用支持好 高并发和服务化能力相对有限 macOS、Windows 原生、Linux 无 GPU、本地演示
vLLM 适合高并发、GPU 推理性能强、OpenAI 兼容 依赖 Linux/WSL2 + NVIDIA GPU,安装更重 Linux/WSL GPU 服务器、性能实验、多人共享服务
单进程脚本 Agent 结构简单、易调试 难以服务化、缺少权限隔离 本地学习、实验复现
ToolRegistry 工具注册 易扩展、schema 统一 需要维护参数一致性 工具调用项目通用底座
流式工具调用 用户体验好、可实时展示思考和工具状态 解析复杂、碎片化问题多 聊天界面、可观测 Agent
实验协议 + evidence 结果可复现、可审计 前期设计成本较高 教学实验、性能对比、论文或报告

7.8 落地场景 & 面试考点提炼

落地场景

  1. 本地知识库助手

    增加检索工具,让模型查询本地文档后回答。

  2. 教学实验平台

    让学生观察工具调用、流式输出、并行工具和性能指标。

  3. 企业内网运维助手

    增加日志查询、监控告警、工单系统等内部工具。

  4. 离线数据处理助手

    通过代码解释器处理 CSV、Excel、PDF,但必须做沙箱隔离。

  5. 本地模型评测平台

    基于 run_experiment.py 扩展不同模型、提示词和工具调用成功率评测。

面试考点

  • Agent 工具调用的标准消息结构是什么?
  • tool call ID 有什么作用?
  • 流式输出中 tool call 被拆片如何处理?
  • 多个工具调用如何并行执行并保证结果回填正确?
  • Ollama 与 vLLM 的适用场景有何不同?
  • 如何设计 ToolRegistry?
  • 如何统计 TTFT、吞吐量和 KV cache 影响?
  • 代码解释器如何做安全隔离?
  • 如何保证实验结果可复现?
  • Windows 原生有 GPU 时为什么不直接选 vLLM?

8. 常见问题与排查清单

8.1 后端选择问题

【故障现象】在 Windows 上运行 vLLM 后端失败,或程序自动选择了不符合预期的后端。

【根因】README 明确说明 Native Windows always uses Ollama;vLLM 官方 GPU 执行需要 Linux。

【修复方案】在 Windows 原生环境使用:

bash 复制代码
python main.py --backend ollama

如果必须使用 vLLM,请切换到 WSL2 + CUDA 或 Linux 容器,并安装 vllm extra。

8.2 Ollama 服务未启动

【故障现象】运行 python main.py --backend ollama 后连接失败。

【根因】可能没有执行 ollama serve,或者 Ollama 服务未在默认地址运行。

【修复方案】先在单独终端启动:

bash 复制代码
ollama serve

再确认模型已拉取:

bash 复制代码
ollama pull qwen3:0.6b

8.3 模型未下载

【故障现象】Agent 初始化成功,但请求模型时报模型不存在。

【根因】本地没有 qwen3:0.6b 或代码中配置了其他未下载模型。

【修复方案】执行:

bash 复制代码
ollama pull qwen3:0.6b

如果使用自定义模型,需同步修改配置。具体配置变量名未在摘要中展开,可查看 config.pyenv.example

8.4 vLLM 依赖未安装

【故障现象】运行 python main.py --backend vllm 时报 vLLM 相关导入错误。

【根因】默认 ch2 安装不会包含 vLLM,需要显式安装 vllm extra。

【修复方案】在仓库根目录执行:

bash 复制代码
uv sync --locked --python 3.12 --extra ch2 --extra vllm

或使用 pip fallback:

bash 复制代码
python -m pip install -e ".[ch2,vllm]"

8.5 虚拟环境未激活

【故障现象】执行 python main.py 时找不到依赖,或调用了系统 Python。

【根因】安装依赖后没有激活对应虚拟环境。

【修复方案】根据系统激活环境:

macOS/Linux:

bash 复制代码
source .venv/bin/activate

Windows PowerShell:

powershell 复制代码
.venv\Scripts\Activate.ps1

Windows cmd:

bat 复制代码
.venv\Scripts\activate.bat

8.6 工具调用没有触发

【故障现象】用户询问天气或时间时,模型直接自然语言回答,没有调用工具。

【根因】可能是模型能力不足、工具描述不清晰、use_tools 未开启、后端没有正确传入 tools schema。

【修复方案】

  • 确认调用 chat() 时启用工具调用;
  • 检查 ToolRegistry.get_tool_schemas() 是否返回工具;
  • 优化工具描述和参数说明;
  • 使用更稳定的模型;
  • 运行相关测试确认工具注册链路正常。

具体 use_tools 参数默认值未在摘要中明确,需查看源码或 --help

8.7 流式工具调用解析失败

【故障现象】流式输出中途报错,提示 JSON 解析失败或 tool call arguments 不完整。

【根因】模型将工具调用参数拆成多个 chunk,程序过早解析;或模型输出了格式错误的 JSON。

【修复方案】

  • 确保流式解析器缓存完整 tool call 后再执行;
  • 参考 test_vllm_structured_streaming.py 中的碎片化测试;
  • 增加 normalize_tool_call() 容错;
  • 对解析失败情况记录原始文本;
  • 必要时切换到更稳定的模型。

8.8 Ollama thinking 字段处理异常

【故障现象】流式输出中思考内容和最终回答混在一起,或字段读取报错。

【根因】不同 Ollama 返回结构中可能存在 thinking 字段,需要 fallback 处理。

【修复方案】

  • 检查 OllamaNativeAgent._chat_with_think_fallback()
  • 运行:
bash 复制代码
python -m unittest test_ollama_thinking
  • 根据实际 Ollama 客户端返回结构调整字段读取逻辑。

8.9 并行工具没有并发执行

【故障现象】多个 sleep 工具总耗时接近各工具耗时之和,而不是最长工具耗时。

【根因】工具执行可能被串行调用,或并发池未正确使用。

【修复方案】

  • 检查 _execute_tool_calls() 是否使用 concurrent.futures
  • 参考 run_experiment.execute_parallel(registry, calls)
  • 运行 test_parallel_tools.py 中的并行验证测试;
  • 确认工具函数不会共享阻塞资源。

8.10 代码解释器执行危险操作

【故障现象】代码解释器可以访问本地文件、环境变量或执行系统命令。

【根因】code_interpreter(code) 使用完整 Python 环境,测试中也覆盖了 full environment access。

【修复方案】

  • 不要直接暴露给不可信用户;
  • 使用容器、沙箱或低权限用户执行;
  • 限制网络、文件系统和环境变量;
  • 设置执行超时;
  • 对输出做敏感信息扫描。

8.11 PDF 解析失败

【故障现象】调用 parse_pdf(url) 时无法读取 PDF。

【根因】可能是 URL 不可访问、网络问题、PDF 格式异常或 PyPDF2 解析失败。

【修复方案】

  • 确认 URL 可下载;
  • 检查网络和代理;
  • 用本地可访问 PDF 测试;
  • 查看异常信息;
  • 必要时增加其他 PDF 解析库作为 fallback。

8.12 benchmark 结果不稳定

【故障现象】多次运行 benchmark,吞吐量和延迟差异很大。

【根因】可能受到模型加载状态、KV cache 预热、并发设置、机器负载、上下文长度影响。

【修复方案】

  • 固定实验协议;
  • 运行前预热模型;
  • 记录机器信息和启动参数;
  • 多次运行取统计值;
  • 使用 run_experiment.py 保存 evidence;
  • 不要把不同配置下的结果直接比较。

8.13 实验结果目录缺少证据

【故障现象】运行实验后没有生成 evidence.jsonmanifest.json

【根因】实验可能未成功完成、输出路径参数不正确、或程序中途异常退出。

【修复方案】

  • 先运行 python run_experiment.py --help 确认参数;
  • 检查 experiment_protocol.json 是否有效;
  • 查看控制台异常;
  • 确认程序对 runs/ 目录有写权限;
  • 参考已有目录 runs/exp2-1-qwen3-0.6b-20260730-v1/ 的结构。

8.14 测试依赖真实模型导致失败

【故障现象】运行全部测试时,某些 real model 测试失败。

【根因】部分测试需要 Ollama 或 vLLM 服务在线,并且模型已准备好。

【修复方案】

  • 先启动 Ollama 并拉取模型;
  • 对 vLLM 测试,先启动兼容 OpenAI 的本地服务;
  • 只运行不依赖外部服务的测试,例如平台检测和结构化流式单测;
  • 将真实模型测试与纯单元测试分开执行。

8.15 环境变量配置不明确

【故障现象】不知道如何配置 API base、API key、模型名或服务端口。

【根因】config.pyenv.example 存在,但解析摘要未展开具体变量名。

【修复方案】

  • 打开 env.example 查看示例变量;
  • 阅读 config.py 中读取的环境变量;
  • 按需复制为 .env
  • 不要把真实密钥提交到仓库;
  • 运行实验前可使用 credential_scan(path) 思路检查结果目录是否泄露凭据。

8.16 端口或服务地址冲突

【故障现象】vLLM 或 Ollama 服务启动失败,提示端口占用或连接到错误服务。

【根因】本地已有其他服务占用端口,或客户端配置指向了错误地址。

【修复方案】

  • 检查本地服务端口占用情况;
  • 确认 config.py 中的 API base;
  • 重启本地模型服务;
  • 如使用 VLLMServer,查看 _wait_for_ready() 连接的地址是否正确。

具体端口号未在解析摘要中发现。

8.17 安装命令执行目录错误

【故障现象】安装 ch2 extra 失败,或运行时找不到 Chapter 2 依赖。

【根因】README 要求先在仓库根目录安装共享环境,再进入 chapter2/local_llm_serving

【修复方案】

  1. 回到仓库根目录;
  2. 执行:
bash 复制代码
uv sync --locked --python 3.12 --extra ch2
  1. 激活虚拟环境;
  2. 再执行:
bash 复制代码
cd chapter2/local_llm_serving
python main.py --backend ollama

8.18 无实测结果说明

解析摘要中没有提供 benchmark 的具体数值、实验图表或运行截图,因此本文不编造任何性能数据。若读者完成实测,可在以下位置补充结果对比:

模型 后端 并发数 输入长度 输出长度 TTFT 吞吐量 工具调用成功率 备注
qwen3:0.6b Ollama 未实测 未实测 未实测 未实测 未实测 未实测 待补充
qwen3:0.6b vLLM 未实测 未实测 未实测 未实测 未实测 未实测 待补充

建议运行 benchmark.pyrun_experiment.py 后,将控制台报告与 runs/ 下的证据文件一起归档。

相关推荐
Zkaisen1 小时前
第三章 · 大语言模型基础(详尽展开版)
人工智能·语言模型·自然语言处理
todoitbo1 小时前
MongoDB迁移:从烟囱式部署走向 KES-AI 时代融合数据库架构
人工智能·mongodb·数据库架构·国产数据库·kingbasees
意图共鸣1 小时前
意图共鸣科技8月6日正式发布《交互等效原理》——大模型下半场的工程哲学纲领
人工智能
nuoxin1141 小时前
BL-M8812CU3 无线 WiFi 模块-富利威
人工智能·嵌入式硬件·fpga开发·硬件工程·dsp开发
想会飞的蒲公英1 小时前
PyTorch 学习率实战:从零理解衰减策略与调度器
人工智能·pytorch·python·深度学习·机器学习
cxr8281 小时前
第四章 查询与推理能力
人工智能·架构·知识图谱·智能体
云端漫步19871 小时前
HarmonyOS NEXT AI 应用开发总结:30 篇之旅
人工智能·华为·harmonyos
confiself1 小时前
COVE:记忆-参数双通道协调自进化
人工智能
风途科技~1 小时前
土壤五参数测定仪:pH / 水分 / 温度 / 电导率 / 含盐量一体化土壤监测利器
人工智能