🖥️

Qwen 3 локально: AI-агент без облака

Установка, настройка, function calling

intermediate ⏱ 18 мин
💻 Ваш компьютер GPU 8+ GB VRAM RAM 16+ GB Linux / macOS / Win БЕЗ интернета 🦙 Ollama LLM-рантайм 🤖 Qwen 3 qwen3:8b / qwen3:32b 🐍 Python Agent • ollama.chat() • function calling • conversation memory • tool execution loop • streaming response 🧮 calc calculator 📁 file file ops 🐚 shell subprocess 🔒 Архитектура: Qwen 3 локальный агент — все данные на вашем компьютере

# 1. Установка Ollama и загрузка Qwen 3

Ollama — самый простой способ запустить LLM локально. Одна команда для установки, одна для загрузки модели. Qwen 3 — мощная open-source модель от Alibaba с отличной поддержкой function calling.

# Linux: установка Ollama
curl -fsSL https://ollama.com/install.sh | sh

# macOS: brew install ollama
# Windows: скачать с ollama.com/download

# Загрузка Qwen 3 (8B — оптимальный баланс скорость/качество)
ollama pull qwen3:8b

# Если мощная видеокарта — берите 32B
ollama pull qwen3:32b

# Проверяем что модель работает
ollama run qwen3:8b "Привет! Кто ты?"

# Смотрим список установленных моделей
ollama list

# 2. Базовый клиент на Python для Ollama

Устанавливаем Python-библиотеку ollama. Она общается с демоном Ollama по HTTP (localhost:11434). Пишем простой клиент для отправки сообщений и получения ответов.

# Установка библиотеки
pip install ollama

import ollama

def ask_qwen(prompt, system=""):
    """Отправить запрос к Qwen 3 через Ollama."""
    messages = []
    if system:
        messages.append({"role": "system", "content": system})
    messages.append({"role": "user", "content": prompt})

    response = ollama.chat(
        model="qwen3:8b",
        messages=messages,
        options={"temperature": 0.3}
    )
    return response["message"]["content"]

# Тестируем
answer = ask_qwen(
    "Объясни что такое function calling в трёх предложениях.",
    system="Отвечай на русском, кратко и по делу."
)
print(answer)

# 3. Function calling с Qwen 3 через Ollama

Qwen 3 нативно поддерживает function calling. Определяем схему инструментов в формате OpenAI, передаём в ollama.chat() — модель сама решит, когда вызвать инструмент и вернёт структурированный вызов.

import json

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Получить текущую погоду для города.",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "Название города"}
                },
                "required": ["city"]
            }
        }
    }
]

response = ollama.chat(
    model="qwen3:8b",
    messages=[{"role": "user", "content": "Какая погода в Берлине?"}],
    tools=tools
)

# Qwen вернёт tool_call в ответе
msg = response["message"]
if msg.get("tool_calls"):
    for tc in msg["tool_calls"]:
        name = tc["function"]["name"]
        args = tc["function"]["arguments"]
        print(f"Qwen хочет вызвать {name}({args})")
        # Вывод: Qwen хочет вызвать get_weather({"city": "Берлин"})

# 4. Полный цикл агента с инструментами

Собираем всё вместе: агент с несколькими инструментами, циклом выполнения и памятью. Это полностью автономный AI-агент, работающий на вашем компьютере без интернета.

import ollama, json, subprocess, os

def execute_tool(name, args_str):
    args = json.loads(args_str)
    if name == "calculator":
        return {"result": eval(args["expr"], {"__builtins__": {}}, {})}
    elif name == "run_shell":
        try:
            result = subprocess.run(args["command"], shell=True,
                                    capture_output=True, text=True, timeout=10)
            return {"stdout": result.stdout[:1000], "stderr": result.stderr[:500]}
        except Exception as e:
            return {"error": str(e)}
    elif name == "read_file":
        try:
            with open(os.path.expanduser(args["path"]), "r") as f:
                return {"content": f.read()[:2000]}
        except Exception as e:
            return {"error": str(e)}
    return {"error": f"Unknown tool: {name}"}

class LocalAgent:
    def __init__(self, model="qwen3:8b"):
        self.model = model
        self.messages = [{"role": "system", "content": "Ты — AI-агент с инструментами."}]

    def run(self, user_input):
        self.messages.append({"role": "user", "content": user_input})
        for _ in range(5):
            resp = ollama.chat(model=self.model, messages=self.messages, tools=tools)
            msg = resp["message"]
            if msg.get("tool_calls"):
                self.messages.append(msg)
                for tc in msg["tool_calls"]:
                    result = execute_tool(tc["function"]["name"], tc["function"]["arguments"])
                    self.messages.append({"role": "tool", "content": json.dumps(result)})
            else:
                self.messages.append(msg)
                return msg["content"]
        return "⚠️ Агент превысил лимит итераций."

agent = LocalAgent()
print(agent.run("Сосчитай (150 + 25) * 4"))
print(agent.run("Сколько файлов в /tmp?"))

# 5. Стриминг ответов в реальном времени

Добавляем стриминг — ответ от модели приходит токен за токеном, как в ChatGPT. Это особенно важно для локальных моделей, которые работают медленнее облачных API.

def stream_ask(prompt):
    """Стриминг ответа от Qwen 3 — печатаем токены по мере генерации."""
    stream = ollama.chat(
        model="qwen3:8b",
        messages=[{"role": "user", "content": prompt}],
        stream=True
    )
    full_response = ""
    for chunk in stream:
        token = chunk["message"]["content"]
        print(token, end="", flush=True)
        full_response += token
    print()
    return full_response

# Пользователь видит как текст появляется постепенно
stream_ask("Напиши короткое стихотворение про AI.")

# 6. Конфигурация через YAML: гибкая настройка агента

Выносим конфигурацию агента в YAML-файл. Модель, системный промпт, доступные инструменты — всё настраивается без изменения кода. Удобно для разных сценариев использования.

# agent_config.yaml
model: "qwen3:8b"
system_prompt: "Ты — AI-ассистент разработчика. Помогаешь с bash, Python и файлами."
temperature: 0.3
max_iterations: 5
tools:
  - calculator: true
  - run_shell: true
  - read_file: true
  - write_file: false  # безопасность: отключаем запись

# --- Python-загрузчик конфига ---
import yaml

def load_config(path="agent_config.yaml"):
    with open(path) as f:
        return yaml.safe_load(f)

config = load_config()
agent = LocalAgent(model=config["model"])
print(f"Агент запущен: {config['model']}, инструментов: {len(config['tools'])}")

# 7. Оптимизация производительности

Локальные модели требовательны к ресурсам. Вот конкретные приёмы для ускорения Qwen 3: квантование, настройка GPU-слоёв, размер контекста.

# Создаём кастомный Modelfile для Qwen 3 с оптимизациями
ollama show qwen3:8b --modelfile > Modelfile.qwen3

# Редактируем Modelfile:
FROM qwen3:8b
PARAMETER num_ctx 4096        # контекст (по умолчанию 2048)
PARAMETER num_gpu 32          # сколько слоёв на GPU
PARAMETER num_thread 8        # потоки CPU для слоёв не на GPU
PARAMETER temperature 0.3

# Создаём оптимизированную модель
ollama create qwen3-fast -f Modelfile.qwen3

# Используем в коде:
# agent = LocalAgent(model="qwen3-fast")

# Мониторинг использования GPU во время генерации
watch -n 0.5 nvidia-smi
✅ Итог

Вы развернули полностью локальный AI-агент на базе Qwen 3. Он работает без интернета, все данные остаются на вашем компьютере. Агент умеет: выполнять shell-команды, считать, читать файлы — и сам решает, какой инструмент когда использовать. Qwen 3 отлично справляется с function calling, не уступая облачным аналогам. 8B-версия работает на GPU с 8 ГБ VRAM, 32B — на 24+ ГБ. Для продакшена рекомендую добавить YAML-конфигурацию и стриминг — пользовательский опыт становится indistinguishable от ChatGPT.

🔗 Полезные ссылки

📖 Qwen 3 на Ollama 💻 GitHub Qwen 🐍 ollama-python