Ollama平台ChatGLM3-6B-128K应用:支持工具调用的Agent系统搭建

你是不是也遇到过这样的场景?想让AI帮你查一下天气,它却只会说“我无法访问实时数据”;想让AI帮你分析一个Excel文件,它却只能对着你粘贴的文本干瞪眼。传统的对话模型就像一个知识渊博但手脚被束缚的学者,知道很多,但做不了具体的事。

今天,我们要聊的ChatGLM3-6B-128K,就是一个被“松绑”的学者。它不仅能和你聊天,还能在得到你允许后,去调用外部的工具,比如搜索引擎、计算器、数据库,真正帮你“动手”解决问题。更厉害的是,它拥有处理长达128K上下文的能力,意味着你可以丢给它一整本小说或一份冗长的技术文档,它都能理清头绪。

这篇文章,我就手把手带你,在Ollama这个轻量级平台上,把ChatGLM3-6B-128K部署起来,并重点演示如何搭建一个能调用外部工具的智能体(Agent)系统。你会发现,让AI成为你的全能助手,其实并不复杂。

1. 认识我们的主角:ChatGLM3-6B-128K

在开始动手之前,我们得先搞清楚手里这把“瑞士军刀”到底有多锋利。ChatGLM3-6B-128K并非凭空出现,它是ChatGLM3系列中的“长文本特化版”。

1.1 核心特性:长文本与多功能

它的核心能力可以概括为两点:“看得长” 和 “干得多”。

  • “看得长”- 128K上下文:普通模型处理几千字就吃力了,而它能轻松应对约20万汉字(128K tokens)的文本。无论是分析长篇报告、总结学术论文,还是进行超长对话,它都能保持连贯的理解,不会“忘记”开头说了什么。官方建议,如果你的任务上下文通常超过8K,就选它;否则,标准的ChatGLM3-6B可能更高效。
  • “干得多”- 原生工具调用与Agent能力:这是ChatGLM3系列最大的升级。它不再只是一个聊天机器人,而是一个智能体(Agent) 的核心大脑。它内置了对“工具调用(Function Call)”和“代码执行(Code Interpreter)”的原生支持。这意味着你可以定义一些工具(比如“查询天气”、“计算器”),AI在对话中会判断是否需要使用这些工具,并生成规范的调用请求,由你的程序去执行,最后把结果返回给它,它再组织语言回答你。这就实现了从“知道”到“做到”的跨越。

1.2 为什么选择Ollama平台?

你可能听说过很多部署方式,比如原生的Transformers库、FastAPI封装等。Ollama的优势在于极致的简单。

  • 一键部署:无需关心复杂的Python环境、CUDA版本冲突,一条命令就能拉取和运行模型。
  • 开箱即用的API:Ollama直接提供了类OpenAI的API接口,你的应用程序可以通过简单的HTTP请求与模型交互,大大降低了集成难度。
  • 资源管理友好:方便地查看模型列表、卸载模型,管理起来非常直观。

简单来说,Ollama让部署和使用大模型变得像安装手机App一样简单。接下来,我们就进入实战环节。

2. 第一步:在Ollama中部署ChatGLM3-6B-128K

虽然官方Ollama库可能还未直接收录chatglm3-6b-128k这个模型,但社区已经贡献了优秀的版本。我们将使用一个广受好评的第三方模型文件。

打开你的终端(命令行),执行以下命令:

ollama run entropyyue/chatglm3

是的,就这么简单。这条命令会完成所有工作:

  1. 拉取模型:自动从Ollama仓库下载名为entropyyue/chatglm3的模型(这个镜像通常基于最新的ChatGLM3-6B-128K构建)。
  2. 启动交互式对话:下载完成后,你会直接进入一个对话界面,可以开始测试。

首次运行可能会看到类似这样的输出:

pulling manifest
pulling xxxxxxxxxx... 100%
pulling yyyyyyyyyy... 100%
verifying sha256 digest
writing manifest
success
>>> Send a message (/? for help)

看到 >>> 提示符,就说明模型已经加载成功,正在等待你的输入。你可以先简单测试一下:

>>> 你好,请介绍一下你自己。

如果模型流畅地回应了,恭喜你,部署成功!你可以按 Ctrl+D 退出交互模式。模型会继续在后台运行,提供服务。

3. 核心实战:构建一个能调用工具的Agent系统

现在,模型已经跑起来了,但它还只是一个“裸”的模型。我们要为它装配“手脚”(工具),并建立一个调度系统(Agent逻辑)。这里,我们使用Python和Ollama的API来实现。

3.1 设计我们的工具

我们先定义两个简单的工具,让AI学会使用:

  1. 获取天气工具:模拟查询指定城市的天气。
  2. 计算器工具:执行数学计算。
# tool_functions.py
def get_weather(city: str) -> str:
    """
    模拟获取指定城市的天气信息。
    
    参数:
        city (str): 城市名称,例如“北京”、“上海”。
    
    返回:
        str: 模拟的天气信息字符串。
    """
    # 这里模拟一个天气查询结果,真实场景可以调用天气API
    weather_data = {
        "北京": "晴,15~25℃,西北风2级",
        "上海": "多云,18~28℃,东南风3级",
        "广州": "阵雨,22~30℃,南风1级",
        "深圳": "阴,23~31℃,微风"
    }
    return weather_data.get(city, f"未找到{city}的天气信息。")

def calculator(expression: str) -> str:
    """
    执行数学表达式计算(使用eval,注意安全)。
    仅用于演示,生产环境需严格过滤输入。
    
    参数:
        expression (str): 数学表达式,如“3 + 5 * 2”。
    
    返回:
        str: 计算结果或错误信息。
    """
    try:
        # 警告:实际应用中应对expression做严格的安全检查,避免代码注入
        result = eval(expression)
        return str(result)
    except Exception as e:
        return f"计算错误:{e}"

3.2 构建Agent调度逻辑

Agent的核心是循环:理解用户请求 -> 判断是否需要调用工具 -> 执行工具 -> 将结果返回给模型 -> 生成最终回答。

# agent_system.py
import requests
import json
import re

# Ollama API的基础地址,假设Ollama在本地默认端口运行
OLLAMA_API_BASE = "http://localhost:11434/api"

def chat_with_ollama(messages, model="entropyyue/chatglm3"):
    """
    通过Ollama的API与模型对话。
    
    参数:
        messages (list): 对话历史消息列表,格式同OpenAI API。
        model (str): 模型名称。
    
    返回:
        str: 模型的回复内容。
    """
    url = f"{OLLAMA_API_BASE}/chat"
    payload = {
        "model": model,
        "messages": messages,
        "stream": False  # 为简化示例,关闭流式输出
    }
    try:
        response = requests.post(url, json=payload)
        response.raise_for_status()
        return response.json()["message"]["content"]
    except requests.exceptions.RequestException as e:
        return f"API调用失败:{e}"

def parse_tool_call(model_response):
    """
    尝试从模型回复中解析工具调用请求。
    ChatGLM3的工具调用格式通常包含特定的JSON标记,如 ```json ... ```。
    
    参数:
        model_response (str): 模型的回复文本。
    
    返回:
        dict or None: 解析出的工具调用信息(名称和参数),如果无工具调用则返回None。
    """
    # 查找JSON代码块
    pattern = r'```json\s*(.*?)\s*```'
    match = re.search(pattern, model_response, re.DOTALL)
    
    if match:
        json_str = match.group(1)
        try:
            tool_call = json.loads(json_str)
            # 检查是否符合工具调用结构
            if "name" in tool_call and "arguments" in tool_call:
                return tool_call
        except json.JSONDecodeError:
            pass
    return None

def run_agent(user_query, max_turns=5):
    """
    运行一个简单的单轮工具调用Agent。
    
    参数:
        user_query (str): 用户的初始问题。
        max_turns (int): 最大交互轮次(防止死循环)。
    
    返回:
        str: Agent的最终回答。
    """
    from tool_functions import get_weather, calculator  # 导入之前定义的工具
    
    # 定义可供模型调用的工具列表(描述很重要,模型靠这个理解工具功能)
    available_tools = [
        {
            "name": "get_weather",
            "description": "获取指定城市的当前天气信息。",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称,如‘北京’、‘上海’。"}
                },
                "required": ["city"]
            }
        },
        {
            "name": "calculator",
            "description": "执行一个数学表达式并返回计算结果。",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {"type": "string", "description": "数学表达式,如‘3 + 5 * 2’。"}
                },
                "required": ["expression"]
            }
        }
    ]
    
    # 初始化对话历史,将工具描述作为系统提示告诉模型
    system_prompt = f"""你是一个有帮助的助手,可以调用工具来解决问题。
你可以使用的工具如下:
{json.dumps(available_tools, ensure_ascii=False, indent=2)}
当你需要调用工具时,请严格按照以下格式在JSON代码块中回复:
```json
{{"name": "工具名称", "arguments": {{"参数名": "参数值"}}}}

我会执行工具并将结果告诉你。"""

messages = [{"role": "system", "content": system_prompt},
            {"role": "user", "content": user_query}]

for turn in range(max_turns):
    # 1. 将当前对话历史发送给模型,获取回复
    model_reply = chat_with_ollama(messages)
    print(f"\n[模型回复-第{turn+1}轮]:\n{model_reply}")
    
    # 2. 尝试解析模型回复中是否包含工具调用
    tool_call = parse_tool_call(model_reply)
    
    if not tool_call:
        # 如果没有工具调用,则当前回复即为最终答案
        final_answer = model_reply
        # 清理可能残留的JSON代码块标记
        final_answer = re.sub(r'```json\s*.*?\s*```', '', final_answer, flags=re.DOTALL).strip()
        return final_answer
    
    # 3. 执行工具调用
    tool_name = tool_call["name"]
    tool_args = tool_call["arguments"]
    print(f"[检测到工具调用]: {tool_name},参数:{tool_args}")
    
    tool_result = None
    if tool_name == "get_weather":
        tool_result = get_weather(**tool_args)
    elif tool_name == "calculator":
        tool_result = calculator(**tool_args)
    else:
        tool_result = f"错误:未知工具 '{tool_name}'。"
    
    print(f"[工具执行结果]: {tool_result}")
    
    # 4. 将工具执行结果作为新消息追加到对话历史,让模型进行下一步
    # 首先,将模型刚才的回复(包含工具调用)加入历史
    messages.append({"role": "assistant", "content": model_reply})
    # 然后,将工具执行结果作为“用户”消息或“工具”角色消息加入(这里简化处理)
    messages.append({"role": "user", "content": f"工具`{tool_name}`的返回结果是:{tool_result}"})
    
return "对话轮次过多,可能陷入循环。"

if name == "main": # 测试几个例子 test_queries = [ "北京今天天气怎么样?", "帮我计算一下(15 + 7) * 3 等于多少?", "先告诉我上海的天气,然后计算一下如果气温是25度,换算成华氏度是多少?(公式:F = C × 9/5 + 32)" ]

for query in test_queries:
    print(f"\n{'='*50}")
    print(f"用户问题:{query}")
    print(f"{'='*50}")
    answer = run_agent(query)
    print(f"\n[Agent最终答案]:\n{answer}")

### 3.3 运行与效果解读

运行上面的`agent_system.py`脚本。你需要确保Ollama服务正在运行(终端里执行 `ollama serve` 或模型已在后台)。

**你会看到类似这样的交互过程:**

对于问题 **“北京今天天气怎么样?”**:
1.  模型回复中会包含一个JSON代码块,请求调用 `get_weather` 工具,参数为 `{"city": "北京"}`。
2.  我们的程序捕捉到这个请求,执行 `get_weather("北京")`,得到模拟天气数据。
3.  程序将天气结果反馈给模型。
4.  模型生成最终的自然语言回答:“北京今天的天气是晴,15~25℃,西北风2级。”

对于更复杂的第三个问题,模型可能会展示**多轮工具调用**的能力:先调用天气工具获取上海温度(假设25℃),再调用计算器工具计算华氏度(25 * 9/5 + 32 = 77°F)。

## 4. 深入探索:让Agent更强大

我们搭建了一个最基础的Agent框架。要让它真正实用,还可以从以下几个方面深化:

### 4.1 集成更多真实工具

将模拟工具替换为真实的API:
*   **网络搜索**:集成SerperAPI、Google Search API。
*   **数据查询**:连接数据库(MySQL、PostgreSQL)或调用企业内部API。
*   **文件操作**:读取本地PDF、Word、Excel文件进行分析(需结合RAG技术)。
*   **软件控制**:发送邮件、生成图表、操作办公软件。

### 4.2 优化提示工程与工具描述

模型能否正确调用工具,很大程度上取决于**系统提示(System Prompt)** 中对工具的**描述是否清晰准确**。
*   **描述要具体**:明确工具的用途、输入参数格式、输出是什么。
*   **提供示例**:在系统提示中给出1-2个工具调用的例子,效果会显著提升。
*   **指定格式**:就像我们做的,严格要求模型以特定格式(如JSON代码块)返回工具调用请求。

### 4.3 处理复杂对话与长上下文

ChatGLM3-6B-128K的128K能力在此大放异彩。
*   **长文档摘要**:将整个技术手册、法律合同丢给Agent,让它先总结要点,再根据你的具体问题定位细节。
*   **多轮复杂任务**:用户的需求可能分多步。“帮我规划一个三天的北京旅游行程,查一下故宫下周一的门票价格和天气,然后估算一下总花费。” Agent需要分解任务,依次调用行程生成、票务查询、天气查询、计算器等工具,并在整个长对话中记住所有上下文。

### 4.4 错误处理与稳定性

生产级系统需要更健壮:
*   **工具调用失败**:网络超时、API限流、参数错误等,需要有重试或降级方案。
*   **模型输出解析失败**:模型可能不按预定格式回复,需要设计更鲁棒的解析器或让模型重试。
*   **超长上下文管理**:虽然支持128K,但无限堆积历史消息会降低效率。需要设计策略,选择性保留或总结关键历史信息。

## 5. 总结

通过本文的实践,我们完成了一件很酷的事:**在个人电脑上,用Ollama轻松部署了强大的ChatGLM3-6B-128K模型,并为其赋予了调用外部工具的能力,构建了一个智能体系统的雏形。**

我们回顾一下关键步骤和收获:
1.  **部署极简**:Ollama的 `ollama run` 命令让模型部署变得毫无门槛。
2.  **能力解锁**:ChatGLM3原生的工具调用功能,是构建实用AI Agent的基石。我们通过定义清晰的工具描述和解析模型响应,实现了“思考”与“行动”的闭环。
3.  **框架搭建**:我们实现了一个简单的Agent调度循环(感知->规划->行动->观察),这是所有复杂Agent系统的基本原理。
4.  **潜力巨大**:这个基础框架可以无限扩展。接入真实API、处理长文档、管理复杂对话流,就能开发出真正能解决实际问题的AI助手。

从“聊天机器人”到“智能执行体”,ChatGLM3-6B-128K与Ollama的组合,为我们打开了一扇低成本、高效率构建个性化AI应用的大门。无论是用于个人效率提升,还是作为更复杂产品的核心引擎,这都是一个绝佳的起点。

现在,你可以尝试为你的Agent添加第一个真实世界的工具了,比如查询实时股价、翻译大段文档,或者管理你的待办事项列表。动手试试看,感受AI从“知道”到“做到”的魅力吧。

---

> **获取更多AI镜像**
>
> 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

更多推荐