进阶 20 分钟Python

使用 Python、LangChain 和 Ollama 构建本地 AI 智能体

一个基于 Python、LangChain 和 Ollama 的本地 AI Agent,不仅仅是一个聊天机器人:它能够自主决定何时调用函数、读取文件或串联多个步骤来生成响应。本指南将指导您在约二十分钟内逐步构建一个功能完整的 Agent,使用完全运行在您本地设备上的 Qwen 3.5 9B 模型。无需 API 密钥,无需向第三方发送任何数据。

作者: Mohamed Meguedmi·更新于 2026-08-27·已在 Windows、macOS 和 Linux 上测试

#为什么用 Python 构建本地 AI 智能体?

在 LangChain 的语境中,智能体就是一个简单的循环:LLM 接收一个问题及其可用工具列表,选择调用一个工具(或不调用),读取结果,然后重复这一过程,直到能够回答。整个“决策”机制都依赖于模型发出结构化工具调用的能力。

使用 Ollama 在本地完成这件事,会带来两个具体变化:您的数据永远不会离开机器,每次调用的费用都是零欧元。这就是两种做法的区别:用 OpenAI 开发原型,一周结束时收到 50 欧元的账单;或者不断迭代,无需计算调用费用。

隐私
智能体读取的文件(合同、专有代码、医疗笔记)不会离开本机。无需签署 DPA,也不会向欧盟境外传输数据。
零边际成本
模型下载完成后,您每天可以迭代数百次,而账单不会随之增加。
可复现性
您将锁定模型的精确版本(如 qwen3.5:9b、granite4.2:8b 等)。与 gpt-4o-2024-11-20 不同,后者一个月后会悄然发生变化。
可预测延迟
无网络往返。在性能不错的 GPU 上,首个 token 的生成时间少于一秒。
i
它也不是什么魔法
本地 9B 模型在非常复杂的任务上仍弱于 GPT-5 或 Claude 4.7。对于 80% 的实用智能体(读取文件、调用内部 API、进行计算、给邮件分类),这样的模型已绰绰有余。对于其余情况,它也是一个极佳的学习平台,可以先在这里学习,再付费使用 token。

#先决条件

本地副驾驶套件

本指南带你上手模型。工具包则帮你用上能在你的编辑器中编写代码的编程助手。

  • 在线空间,终身可用
  • PDF + 文件
  • 30 天内退款
Python 3.10+
LangChain 已不再针对 Python 3.9 进行测试。请使用 python --version 检查版本。
Ollama已安装并启动
它应在 http://localhost:11434 上监听。若尚未安装并启动,请参阅 Ollama 安装指南(Windows、macOS、Linux)。
能够调用工具的模型
并非所有大语言模型都具备此能力。Qwen 3.5、Granite 4.2、Gemma 4、Devstral 以及 GLM 4.7 Flash 原生支持工具调用功能。请避免使用已过时的模型(如 Llama 2/3、Qwen 2.5、Mistral 7B)。
硬件
Qwen 3.5 9B Q4 版本约占用 6.6 GB 显存。8 GB 显存的 GPU(RTX 3060、4060)就够用,12 GB 显存的 GPU(4070)则能留出余量。在 Mac 上,建议配备 16 GB 统一内存,以留出充足的空间。
→
模型选择至关重要
如果模型无法正确调用工具,您的智能体就会编造参数,或以自由文本作答,而不是生成工具调用。如果您刚入门,请先继续使用 qwen3.5:9b——这是 2026 年质量与显存需求之间的最佳平衡点。

#1. 初始化 Python 项目

一个虚拟环境,三个包,就足够了。避免在系统Python中安装LangChain——它更新频繁且容易造成污染。

创建并激活 venv
mkdir agent-local && cd agent-local
python -m venv .venv

# macOS / Linux
source .venv/bin/activate

# Windows PowerShell
# .venv\Scripts\Activate.ps1
安装依赖项
pip install --upgrade pip
pip install langchain langchain-ollama langgraph
langchain
核心:提示词的抽象、工具和消息。
langchain-ollama
Ollama 的官方集成。自 2024 年起由 LangChain 团队维护。
langgraph
用于智能体循环。这是目前推荐的引擎,比旧版 AgentExecutor 更稳定。
i
为何选择 langgraph 而非 AgentExecutor?
早期的 LangChain 教程使用 AgentExecutor + create_react_agent(来自 langchain.agents)。该 API 已进入维护模式。官方文档如今指向 langgraph.prebuilt.create_react_agent——本文将使用这一 API。它更简单,类型支持更完善,还自带流式输出功能。

#2. 从Python连接Ollama

在搭建智能体之前,先确认确实能与模型通信。如果尚未下载模型,请先下载,然后测试尽可能简单的调用。

下载 Qwen 3.5 9B
ollama pull qwen3.5:9b

Q4_K_M 量化版本的下载大小约为 6.6 GB(这是 Ollama 默认使用的量化方式)。准备就绪后,请创建第一个脚本:

test_ollama.py
from langchain_ollama import ChatOllama

llm = ChatOllama(
    model="qwen3.5:9b",
    temperature=0,
    # base_url="http://localhost:11434",  # par défaut, à changer si Ollama est ailleurs
)

reponse = llm.invoke("En une phrase : qu'est-ce qu'un agent IA ?")
print(reponse.content)
开始测试
python test_ollama.py

如果看到一条连贯的语句,Python ↔ Ollama 的连接正常。若出现 ConnectionError,请检查 Ollama 是否正在运行(ollama ps 命令应显示一个活跃的服务)。

→
为智能体设置 temperature=0
当模型选择工具时,需要确定性行为。较高的温度会导致不同运行之间工具调用的差异——这会带来难以调试的问题。对于创造性回答,稍后可将温度调至0.7。

#3. 定义智能体的工具

LangChain工具本质上只是带有@tool装饰的Python函数。docstring会成为LLM看到的描述,LLM会据此判断何时调用该函数。请务必精确:模糊的docstring会导致随机调用。

我们将创建两个代表性工具:一个算术表达式求值器,一个文件读取器。

tools.py
from pathlib import Path
from langchain_core.tools import tool


@tool
def calculer(expression: str) -> str:
    """Évalue une expression arithmétique simple.

    Args:
        expression: une expression contenant uniquement des chiffres,
                    des espaces et les opérateurs + - * / ( ).

    Returns:
        Le résultat numérique sous forme de chaîne, ou un message d'erreur.
    """
    autorise = set("0123456789+-*/(). ")
    if not all(c in autorise for c in expression):
        return "Erreur : caractère non autorisé. Seuls 0-9 et + - * / ( ) sont permis."
    try:
        resultat = eval(expression, {"__builtins__": {}}, {})
        return str(resultat)
    except Exception as e:
        return f"Erreur de calcul : {e}"


@tool
def lire_fichier(chemin: str) -> str:
    """Lit le contenu d'un fichier texte du répertoire courant.

    Args:
        chemin: chemin relatif ou absolu vers un fichier texte (.txt, .md, .py, etc.).

    Returns:
        Le contenu du fichier, ou un message d'erreur si introuvable.
    """
    p = Path(chemin)
    if not p.exists():
        return f"Fichier introuvable : {chemin}"
    if not p.is_file():
        return f"Ce n'est pas un fichier : {chemin}"
    try:
        return p.read_text(encoding="utf-8")
    except UnicodeDecodeError:
        return "Fichier binaire ou encodage non UTF-8."
    except Exception as e:
        return f"Erreur de lecture : {e}"
!
在生产环境中使用 eval() 很危险
即使清空 __builtins__,使用 eval() 也并非真正的沙箱环境。对于运行在您本地并由您直接控制的代理而言,这是可以接受的。对于任何面向第三方用户暴露的内容,应使用 ast.parse 并配合操作符白名单,或采用 simpleeval 库。

要让模型正确使用工具,需要遵循以下三条规则:

明确名称
使用 calculer 而不是 process,使用 lire_fichier 而不是 get。LLM 首先根据名称进行选择。
详细文档字符串
描述该工具的功能、输入要求以及输出内容。Python类型的注解会被LangChain读取并暴露给模型。
返回字符串
始终应返回字符串。如果函数返回 dict 或对象,LangChain 会将其序列化,但这会降低内容对模型而言的可读性。

#4. 组装智能体

我们有了 LLM,也有了工具。langgraph 的 create_react_agent 函数将两者连接起来,并管理循环:只要模型还想调用工具,就继续;当它以文本作答时,就停止。

agent.py
from langchain_ollama import ChatOllama
from langgraph.prebuilt import create_react_agent
from tools import calculer, lire_fichier

llm = ChatOllama(model="qwen3.5:9b", temperature=0)

SYSTEM_PROMPT = (
    "Tu es un assistant en français. Tu disposes d'outils pour calculer "
    "et lire des fichiers. Utilise-les dès que c'est pertinent, sans jamais "
    "inventer un résultat. Réponds toujours en français."
)

agent = create_react_agent(
    model=llm,
    tools=[calculer, lire_fichier],
    prompt=SYSTEM_PROMPT,
)

if __name__ == "__main__":
    question = (
        "Combien fait 1234 * 5678 ? "
        "Ensuite, lis le fichier notes.txt et résume-le en deux phrases."
    )
    reponse = agent.invoke({"messages": [("user", question)]})

    # Le dernier message est la réponse finale du modèle
    print(reponse["messages"][-1].content)

请在旁边创建一个 notes.txt 小文件进行测试:

测试文件
echo "Réunion projet Hermes : on garde Ollama comme runtime principal, on évalue vLLM pour la prod, RAG sur ChromaDB. Décision : POC en 2 semaines." > notes.txt

#5. 执行并观察循环

启动智能体
python agent.py

您应该看到一个包含计算结果(7 006 652)和文件摘要的回复。但更值得一看的是执行过程。添加详细模式以逐步跟踪循环:

详细流式输出模式
for evenement in agent.stream(
    {"messages": [("user", question)]},
    stream_mode="values",
):
    dernier = evenement["messages"][-1]
    dernier.pretty_print()
    print("---")

您将观察到智能体的典型执行流程:模型先发起对 calculer 的调用,接收结果,再发起对 lire_fichier 的调用,接收内容,最后生成最终回答。一个用户问题要经过三轮迭代。

i
如果模型未调用工具
两个常见原因:(1) 模型在 Ollama 端未启用工具调用——重新运行 ollama pull qwen3.5:9b,以获取最新版本。(2) 系统提示词过于模糊。请明确写出“使用工具进行计算”,而不是期待模型自己猜到。

#技巧与故障排除

上下文过短
默认情况下,Ollama 会将上下文截断至 2048 个 token。如果您的智能体连续调用多个工具,很快就会超出这个范围。请在 ChatOllama(model="...", num_ctx=8192) 中设置 num_ctx=8192。
模型凭空编造工具
如果智能体编造函数名,请将温度降至 0,并改写系统提示词,明确列出可用工具。
无限循环
设置限制:create_react_agent(..., recursion_limit=10)。超过此限制,代理将正常终止。
延迟过高
在 CPU 上,9B 模型的速度为每秒 5–10 个 token。如果 qwen3.5:4b 的质量仍能满足您的使用需求,可以改用它(需要 3.4 GB 显存,在入门级 GPU 上可达到每秒 30 个以上的 token)。
出现“context length exceeded”错误
长文件的摘要超出 num_ctx 限制。请添加一个分块工具对文件进行切分,或将 num_ctx 增加到 32768,前提是您的 VRAM 足够。
→
使用 LangSmith 追踪您的智能体
为深入调试,LangSmith 会追踪每一次调用、每一个 token 以及每一个工具。开发环境免费使用。请在环境变量中设置 LANGSMITH_TRACING=true 和 LANGSMITH_API_KEY,即可获得完整的执行时间线。若未设置密钥,则不会发送任何数据。

#深入了解

您已经有了一个能在本地计算、读取和推理的智能体。接下来可以顺着三个方向深入探索:

授予其访问您的文档的权限
将智能体与向量数据库连接,使其能够基于内部语料库回答问题——这正是本地 RAG 入门指南的主题。
在命令行中开展编程工作
Aider 是一款开发智能体,可直接通过终端编辑您的文件。您可以将它连接到同一个 Ollama,利用 Qwen3-Coder 30B 或 Devstral 进行辅助编辑。
调整模型量化
如果您发现 Qwen 3.5 9B Q4 过慢或质量不足,量化指南会说明何时切换到 Q5_K_M 或减小模型规模。
这份指南对您有帮助吗?

有反馈、发现了错误,或想补充说明?请告诉我们,让这份指南对每个人都更有帮助。