ChatGLM3-6B功能扩展:轻松实现外部API调用
ChatGLM3-6B功能扩展:轻松实现外部API调用
1. 为什么需要让本地大模型“走出去”?
你有没有遇到过这样的场景:
在本地跑着一个响应飞快、隐私安全的 ChatGLM3-6B,它能秒答技术问题、润色文案、解释代码——但一问“今天北京几点了?”“查下我邮箱里上周的会议纪要”“把这份PDF转成Excel”,它就只能礼貌地沉默。
不是模型不够强,而是它被“关在屋里”了。
默认状态下,本地部署的大语言模型就像一位知识渊博却从不联网的学者:记得所有公式,却不知道今天的股价;熟读万卷书,却看不到你手机里刚拍的照片。
而 Function Call(函数调用)机制,就是给这位学者配了一部可编程的电话——它不再只靠记忆回答问题,而是能主动拨号、调用天气服务、查询数据库、发送邮件、甚至控制智能设备。
本篇不讲云端 API 的复杂配置,也不堆砌抽象概念。我们将聚焦于已在 CSDN 星图镜像广场上线的 ChatGLM3-6B 镜像,手把手带你:
在已部署好的 Streamlit 界面中无缝接入自定义函数
不改一行模型代码,仅通过提示工程 + 轻量逻辑扩展能力
实现真正“本地可控、业务可用”的智能助手
全程无需重装环境、无需编译模型、无需接触 CUDA 驱动——你打开浏览器正在用的那个对话框,下一秒就能调用真实服务。
2. 先理解:ChatGLM3 的函数调用不是“插件”,而是“决策引擎”
2.1 它和传统 API 调用有本质区别
很多开发者第一反应是:“那我写个 requests.post 就行了”。但这样只是把模型当成了“输入框+输出框”,完全浪费了它的推理能力。
ChatGLM3-6B 内置的 Function Call 机制,核心在于三步闭环决策:
- 理解意图:识别用户真实需求(不只是字面意思)
→ “帮我订明天下午三点去上海的高铁票” ≠ “搜索‘高铁票’关键词” - 选择工具:从你预设的多个函数中,精准匹配最合适的那个
→ 可能是book_train_ticket(),而不是search_flights()或get_weather() - 提取参数:自动结构化提取关键信息(时间、地点、人数),并容错处理模糊表达
→ “明天下午三点” →"date": "2024-06-15", "time": "15:00"
这个过程由模型自身完成,你只需定义好“它能用什么工具”和“每个工具怎么用”,剩下的交给它判断。
2.2 为什么这个能力在本地部署时特别珍贵?
| 场景 | 云端 API 方案 | 本地 ChatGLM3-6B + Function Call |
|---|---|---|
| 查询公司内网文档 | 需打通内网代理、配置 OAuth、处理 token 过期 | 直接调用本地 Python 函数读取 \\server\docs\2024Q2.pdf |
| 控制实验室设备 | 依赖公网暴露设备接口,存在安全审计风险 | 通过串口/USB 调用 pyserial 发送指令,全程不触网 |
| 处理敏感客户数据 | 数据需上传至第三方服务器,违反 GDPR/等保要求 | 所有原始数据留在本地,仅函数返回脱敏结果 |
本地不是妥协,而是升级——它把“AI 能力”从“远程服务”变成了“可信组件”。
3. 动手实践:在现有镜像中零侵入式添加天气查询功能
重要前提:你已通过 CSDN 星图镜像广场一键启动了 ChatGLM3-6B 镜像,并可通过浏览器访问 Streamlit 页面(如
http://localhost:8501)。本文所有操作均在此基础上进行,无需重启容器、无需修改模型权重、无需重装依赖。
3.1 第一步:准备你的“工具箱”——编写可调用函数
进入镜像容器终端(或宿主机挂载的代码目录),新建文件 tools.py:
# tools.py
import requests
import json
def get_weather(region: str) -> str:
"""
获取指定城市实时天气(使用免费公开 API)
支持中英文城市名,自动做基础清洗
"""
# 简单中英映射(实际项目可对接 NLP 实体识别)
region_map = {
"北京": "beijing",
"上海": "shanghai",
"广州": "guangzhou",
"深圳": "shenzhen",
"杭州": "hangzhou"
}
city_code = region_map.get(region.strip(), region.strip().lower())
try:
# 使用 no-key 免费天气 API(测试用,生产请替换为自有服务)
url = f"http://api.openweathermap.org/data/2.5/weather?q={city_code}&appid=00000000000000000000000000000000&units=metric"
response = requests.get(url, timeout=5)
data = response.json()
if response.status_code == 200:
temp = data['main']['temp']
desc = data['weather'][0]['description']
wind = data['wind']['speed']
return f"{region}当前 {temp:.1f}℃,{desc},风速 {wind} m/s"
else:
return f"未查到{region}的天气信息,请检查城市名是否正确"
except Exception as e:
return f"获取天气时出错:{str(e)[:50]}"
# 可在此处追加其他函数,例如:
# def search_internal_knowledge(query: str) -> str: ...
# def send_notification(title: str, content: str) -> bool: ...
关键点说明:
- 函数必须有明确的类型注解(
region: str),ChatGLM3 会据此生成更准确的参数结构 - 返回值必须是
str(模型最终需将结果整合进自然语言回复) - 错误处理要友好,避免因网络异常导致整个对话中断
3.2 第二步:告诉模型“你有哪些工具可用”
在镜像的 Streamlit 应用主文件(通常是 app.py 或 streamlit_app.py)中,找到模型加载或对话逻辑部分,在其上方添加工具定义:
# 在 app.py 中合适位置(如 import 区块后、st.title() 前)
from tools import get_weather
# 定义工具描述列表 —— 模型将据此决定何时调用哪个函数
TOOLS = [
{
"name": "get_weather",
"description": "查询指定城市的实时天气情况,包括温度、天气描述和风速",
"parameters": {
"type": "object",
"properties": {
"region": {
"type": "string",
"description": "要查询天气的城市名称,支持中文或英文"
}
},
"required": ["region"]
}
}
]
注意:required 字段必须严格匹配函数参数名,否则模型可能返回空参数。
3.3 第三步:改造对话流程——插入函数调用判断逻辑
找到 Streamlit 中执行 model.chat() 的核心函数(通常名为 generate_response 或类似)。将其替换为支持 Function Call 的版本:
# 替换原 chat 调用逻辑(保留原有 history、system 等变量)
def call_with_function(model, tokenizer, query, history, system_prompt=None):
# 构建 messages(保持原有格式)
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt, "tools": TOOLS})
for user_msg, assistant_msg in history:
messages.append({"role": "user", "content": user_msg})
if assistant_msg:
messages.append({"role": "assistant", "content": assistant_msg})
messages.append({"role": "user", "content": query})
# 关键:启用 tool calling 模式
response, _ = model.chat(
tokenizer,
messages,
max_length=2048,
top_p=0.8,
temperature=0.3,
repetition_penalty=1.1,
do_sample=True
)
# 判断模型是否返回了 function call 请求
if isinstance(response, dict) and "name" in response:
func_name = response["name"]
params = response.get("parameters", {})
# 安全调用:只允许预定义函数
if func_name == "get_weather" and "region" in params:
result = get_weather(params["region"])
# 将结果喂回模型,让它生成自然语言回复
messages.append({"role": "function", "name": func_name, "content": result})
final_response, _ = model.chat(
tokenizer, messages,
max_length=1024, temperature=0.1
)
return final_response
else:
return f"暂不支持该功能:{func_name}"
else:
# 模型直接回答,无需调用函数
return response
# 在 Streamlit 的 st.chat_input() 回调中调用此函数
效果验证:
在网页对话框中输入:
“上海现在几度?穿薄外套可以吗?”
模型将:
1⃣ 识别出需调用 get_weather,提取参数 "region": "上海"
2⃣ 自动执行 get_weather("上海") → 返回 "上海当前 26.3℃,scattered clouds,风速 2.1 m/s"
3⃣ 结合上下文生成人性化回复:
“上海现在 26.3℃,多云,微风,穿薄外套正合适~不过傍晚可能有小雨,建议带把伞哦。”
4. 进阶技巧:让函数调用更稳定、更实用
4.1 参数鲁棒性增强——应对“说人话”的用户
用户不会按 JSON 格式提问。常见问题:
- “北京和上海哪个热?” → 需拆解为两次调用
- “查下我昨天看的那个杭州景点天气” → 需结合历史对话提取“杭州景点”
解决方案:在 call_with_function 中加入预处理逻辑:
def extract_regions_from_text(text: str) -> list:
"""简单规则提取城市名(生产环境建议用 spaCy 或 LTP)"""
cities = ["北京", "上海", "广州", "深圳", "杭州", "成都", "武汉"]
found = [c for c in cities if c in text or text.lower().replace(" ", "").find(c.lower()) != -1]
return found or ["北京"] # 默认 fallback
# 调用前
regions = extract_regions_from_text(query)
if len(regions) == 1:
params = {"region": regions[0]}
elif len(regions) >= 2:
# 并行调用或分步调用逻辑
pass
4.2 多函数协同——构建真实工作流
比如“会议提醒”场景:
- 用户说:“提醒我明天上午十点开项目复盘会”
- 模型调用
parse_datetime("明天上午十点")→"2024-06-15T10:00:00" - 再调用
add_calendar_event("项目复盘会", "2024-06-15T10:00:00") - 最终回复:“ 已为您创建日程:项目复盘会(2024-06-15 10:00)”
只需在 TOOLS 列表中增加对应函数描述,模型会自动规划调用顺序。
4.3 安全边界控制——防止越权操作
在函数内部加入白名单校验:
def send_email(to: str, subject: str, body: str) -> str:
# 仅允许发给公司域名邮箱
if not to.endswith("@yourcompany.com"):
return "权限拒绝:仅支持向公司邮箱发送"
# ... 实际发送逻辑
5. 总结:你刚刚完成了一次“AI 能力组装”
我们没有训练新模型,没有部署新服务,甚至没有离开浏览器——但你已经:
🔹 赋予本地大模型“行动力”:它不再只是回答问题,而是能触发真实世界动作
🔹 守住数据主权:所有敏感操作(查内网、控设备、读文件)都在本地闭环完成
🔹 获得业务级扩展性:新增一个函数 = 新增一个 AI 能力,开发成本趋近于零
这正是 ChatGLM3-6B 作为“本地智能基座”的核心价值:
它不追求参数规模上的虚高,而是以极致的稳定性、可解释的可控性、零门槛的可扩展性,成为你数字工作流中真正可靠的“AI 同事”。
下一步,你可以:
→ 把 get_weather 换成 query_sales_db("Q2华东区销售额")
→ 接入企业微信机器人,让 AI 主动推送日报
→ 给设计稿截图,调用 describe_image() + generate_prompt() 自动生成 MidJourney 提示词
能力的边界,只取决于你定义的函数。
6. 常见问题快速排查
Q:模型返回了函数名,但参数是空的?
A:检查 parameters 字段中的 required 是否与函数签名完全一致;确保 description 里明确写出参数用途(如 "region": "城市中文名,例如'北京'")
Q:调用函数后页面卡住?
A:函数内阻塞操作(如 requests.get 无 timeout)会导致 Streamlit 主线程挂起。务必添加 timeout=5 和 try-except 包裹。
Q:如何查看模型到底生成了什么结构?
A:在 call_with_function 中打印 response 变量:
print("=== Model Raw Output ===")
print(response)
print("========================")
Q:能否支持异步函数(如 asyncio)?
A:当前 ChatGLM3-6B 官方实现基于同步推理。如需异步,建议将耗时操作封装为子进程或 FastAPI 微服务,本地函数通过 subprocess.run() 或 httpx.AsyncClient 调用。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐


所有评论(0)