智谱GLM-4 接金融数据:工具描述多写三个字,模型少犯一类错
你把智谱开放平台的 Function Calling 示例从“查天气”改成“查行情”。在多次测试中GLM-4-Flash 不仅调对了工具还能把用户说的“茅台”映射成600519.SH——这是中文模型在 A 股数据上的天然优势。但当三个行情工具同时注册时同一个 query 在第三轮对话里突然调错了函数。优势区和暗坑区只隔着一套工具描述的写法。一、GLM-4 的中文红利在金融场景下是双刃剑GLM-4 对中文金融术语的理解、对 A 股代码的熟悉程度明显优于仅靠英文语料做中文适配的模型。你用中文写“查询贵州茅台和宁德时代的最新股价”它不仅能提取出两只股票还可能自动补全代码——这是训练语料里 A 股信息密度高的直接体现。但这层中文红利同时也是隐性债务。GLM-4 在金融数据场景下的表现优势面暗坑面中文名称到代码的映射A 股常见股票可自动映射开发者经验观察非官方保证港股、美股的映射准确率递减遇到“苹果”这类歧义词可能选错市场中文工具描述解析对“最新价”“成交量”等术语理解准确两个工具的中文描述高度相似时选择置信度下降免费额度零成本验证适合原型开发免费版在多工具场景下的稳定性可能弱于付费版本以智谱官网当前文档为准错误信息的中文理解能准确理解“请求超限”“Key失效”等提示可能“过度理解”——从“请求超限”推断出“服务端繁忙建议稍后重试”而不是只告知失败这些特点决定了一件事用 GLM-4 接金融数据你需要的不是“把 curl 改成 Python”而是一套专门针对中文模型行为特征的工具设计方法。为了让模型的优势不被数据源的不一致性抵消本文以 TickDB 的统一行情接口作为数据后端——跨市场一致的字段命名、错误码语义和 symbol 格式让你给 GLM-4 定义的工具只需一套字段映射和一套错误处理逻辑。如果你在 AI 编码环境中工作TickDB 也提供 MCP 端点mcp.tickdb.ai可在 Claude Code、Cursor 等工具中直接调用无需手写 HTTP 封装。二、三个设计决策决定你的 Agent 会不会“自作主张”决策一工具描述的第一句话写功能还是写边界GLM-4 的tool_choice默认为auto。模型根据function.description判断“这个工具能做什么”。当一个工具时任何合理描述都能工作当三个工具共存时描述里的每一个模糊词都是误选的种子。金融场景最小工具集通常包括工具功能如果描述写成这样模型会混淆get_ticker实时行情快照“获取股票行情数据”get_kline历史 K 线“获取股票历史数据”get_kline_latest最近一根 K 线“获取最新 K 线数据”当三个描述分别是“获取行情”“获取历史”“获取最新K线”时GLM-4 对“现在价格是多少”可能选get_ticker也可能选get_kline_latest——因为两者都能回答“现在价格”。而get_kline_latest返回的是最近一根已完成 K 线的收盘价不是实时价。正确的写法是把“不要用”写进 description 的第一句# ✅ GLM-4 能正确区分description:(获取品种实时行情快照最新价、24小时成交量。不要使用此函数获取历史K线数据——历史K线应使用 get_kline。不要使用此函数获取最近K线——最近K线应使用 get_kline_latest。)对于 GLM-4在 description 中使用中文否定句划定工具边界是一种在实践中被验证有效的做法开发者经验观察。模型不是理解不了“获取行情”和“获取K线”的区别——它是不确定在当前上下文里你更想要哪个。你把“不要用这个”写在第一句它就不再犹豫。决策二错误返回让模型自行理解还是写死它的行为金融数据接口的返回不是成功/失败二元。get_ticker可能遇到限流、Key 失效、symbol 不存在等情况。如果你把 API 返回的 raw JSON 直接丢给模型GLM-4 的中文理解能力反而会成为风险实际状态如果你把 raw JSON 直接丢给模型限流3001模型可能回复“请求频率过高建议稍后重试根据最近一次查询……”然后编一个价格Key 无效1001模型可能回复“API Key 配置有误请检查。在此期间根据公开信息……”symbol 不存在模型可能回复“该股票代码不存在您是否想查询……”然后推荐一个代码这不是 GLM-4 的 bug——它只是太想帮忙了。但在金融场景下任何“帮忙”都是不可接受的。解决方式在工具函数内部把所有错误转换为模型可以直接判断的success字段并在 system prompt 中写死它的行为。# 无论什么错误始终返回此结构{success:False,data:[],error_code:RATE_LIMITED}# system prompt 中的硬规则——不给模型留任何自行发挥的空间 工具返回 successfalse 时你只能说 当前无法获取行情数据错误原因error_code。 不要说建议稍后重试、不要猜测原因、不要提供替代方案、绝对不要编造任何数值。这条规则在 GLM-4 上需要比在其他模型上写得更“绝”——它的中文能力越强就越容易从error_code里读出额外意思然后自己扩展回复。你给它留一条缝它就敢钻进去。决策三利用中文映射优势还是禁止它GLM-4 能从“茅台”自动提取600519.SH从“宁德时代”提取300750.SZ——这是训练语料给的天然能力。但这个能力有三个边界A 股覆盖率好港股美股递减“腾讯”映射700.HK成功率较高“苹果”映射AAPL.US成功率也较高但“苹果”有歧义——模型需要判断是 AAPL 还是水果。映射结果的 symbol 格式可能不标准模型可能返回600519.SSE而非600519.SH。.SSE在 TickDB 不是有效后缀查询静默失败。你可以通过 system prompt 完全关闭这个行为——GLM-4 的指令跟随能力足够强只要 prompt 里明确写了“不要自行转换中文名称为代码”它就会照做。建议策略原型验证阶段利用自动映射快速跑通流程。生产环境中通过 system prompt 关闭这个行为改由专门的映射函数对接 TickDB 的GET /v1/symbols/available品种列表完成中文名称到标准代码的转换。这样 symbol 格式完全可控。三、完整实现以下代码将上述三个决策落实为三层封装参数校验层在请求前拦截非法格式工具执行层统一限流退避和结构化错误返回GLM-4 对话层管理完整的 Function Calling 生命周期。SDK 调用约定提示ZhipuAI类名、chat.completions.create方法签名、tool_choiceauto、role: tool回填格式及glm-4-flash模型名称均以智谱开放平台官网当前文档为准。正式接入前建议核对你所使用的 SDK 版本的实际行为。环境准备pipinstallzhipuai python-dotenv requests.env文件不要提交到版本控制ZHIPUAI_API_KEY你的智谱API Key TICKDB_API_KEY你的TickDB API Key TICKDB_REST_URLhttps://api.tickdb.ai完整代码glm4_tickdb.py# glm4_tickdb.py# 智谱 GLM-4 Function Calling 接入 TickDB 实时行情# 三层封装参数校验 → 工具执行与错误处理 → GLM-4 对话# Python 3.10 可直接运行importosimportjsonimporttimeimportreimportrequestsfromdecimalimportDecimal,InvalidOperationfromdotenvimportload_dotenvfromzhipuaiimportZhipuAI load_dotenv()# 配置 ZHIPUAI_API_KEYos.getenv(ZHIPUAI_API_KEY)TICKDB_API_KEYos.getenv(TICKDB_API_KEY)TICKDB_REST_URLos.getenv(TICKDB_REST_URL,https://api.tickdb.ai)MAX_RETRIES3# 第一层Symbol 格式校验 SYMBOL_PATTERNre.compile(r^(\d{6}\.(SH|SZ|BJ)|[1-9]\d{0,4}\.HK|[A-Z]{1,5}\.US|r[A-Z]{2,4}[A-Z0-9]{2,8}|[A-Z]{2}\d{4})$)defvalidate_symbols(symbols_str:str)-list:返回不合法的 symbol 列表ifnotsymbols_strornotsymbols_str.strip():return[]sym_list[s.strip()forsinsymbols_str.split(,)ifs.strip()]return[sforsinsym_listifnotSYMBOL_PATTERN.match(s)]# 第二层TickDB 工具执行 defget_ticker(symbols_str:str,retry_count:int0)-dict: 获取实时行情快照。 不要使用此函数获取历史K线——历史K线应使用 get_kline。 始终返回 {success: bool, data: [...], error_code: str} invalidvalidate_symbols(symbols_str)ifinvalid:return{success:False,data:[],error_code:fINVALID_SYMBOL_FORMAT:{invalid}}ifretry_countMAX_RETRIES:return{success:False,data:[],error_code:MAX_RETRIES_EXCEEDED}headers{X-API-Key:TICKDB_API_KEY}params{symbols:symbols_str}try:resprequests.get(f{TICKDB_REST_URL}/v1/market/ticker,headersheaders,paramsparams,timeout10)exceptrequests.exceptions.Timeout:return{success:False,data:[],error_code:TIMEOUT}exceptrequests.exceptions.ConnectionError:return{success:False,data:[],error_code:CONNECTION_ERROR}dataresp.json()# 限流解析 Retry-After保护非整数ifresp.status_code429ordata.get(code)3001:retry_afterresp.headers.get(Retry-After,5)try:wait_secondsfloat(retry_after)except(ValueError,TypeError):wait_seconds5time.sleep(wait_seconds)returnget_ticker(symbols_str,retry_count1)# 鉴权错误阻断不重试ifdata.get(code)1001:return{success:False,data:[],error_code:INVALID_API_KEY}ifdata.get(code)1002:return{success:False,data:[],error_code:MISSING_API_KEY}ifdata.get(code)1004:return{success:False,data:[],error_code:PERMISSION_DENIED}ifdata.get(code)2002:return{success:False,data:[],error_code:SYMBOL_NOT_FOUND}ifdata.get(code)!0:return{success:False,data:[],error_code:fAPI_ERROR_{data[code]}}# 字段映射results[]fordindata.get(data,[]):try:priceDecimal(str(d[last_price]))volDecimal(str(d.get(volume_24h,0)))tsd[timestamp]except(InvalidOperation,ValueError):continueresults.append({symbol:d[symbol],last_price:str(price),volume_24h:str(vol),timestamp_ms:ts,timestamp_note:毫秒UTC (ticker接口)})ifnotresults:return{success:False,data:[],error_code:EMPTY_DATA}return{success:True,data:results,error_code:}# GLM-4 工具定义 TOOLS[{type:function,function:{name:get_ticker,description:(获取品种实时行情快照最新价、24小时成交量、毫秒UTC时间戳。不要使用此函数获取历史K线数据——历史K线应使用 get_kline 函数。不要使用此函数获取盘口深度——盘口深度应使用 get_order_book 函数。不要使用此函数获取最近K线——最近K线应使用 get_kline_latest 函数。),parameters:{type:object,properties:{symbols:{type:string,description:(逗号分隔的品种代码例如 600519.SH,700.HK,AAPL.US。A 股格式为代码.SH/SZ/BJ如 600519.SH港股为代码.HK 无前导零如 700.HK美股为代码.US如 AAPL.US期货为代码本身无后缀如 IF2606。)}},required:[symbols]}}}]SYSTEM_PROMPT你是一个严谨的金融数据助手。你只能通过 get_ticker 工具获取实时行情。 工具使用规则 1. 工具返回 successtrue 时基于 data 中的结构化数据回答用户问题。 2. 工具返回 successfalse 时只允许回复以下固定句式 当前无法获取行情数据错误原因error_code。 不允许添加建议稍后重试、请检查网络、数据源可能不可用等任何扩展说明。 绝对不要根据 error_code 推测或编造任何价格、成交量或数值。 Symbol 规则 3. A 股格式: 6位数字.SH/.SZ/.BJ | 港股: 数字.HK (无前导零) | 美股: 字母.US | 期货: 无后缀 4. 用户用中文名称如茅台查询时回复 请提供标准品种代码例如 600519.SH贵州茅台、700.HK腾讯控股、AAPL.US苹果。 绝对不要自行将中文名称转换为代码。# 第三层GLM-4 对话管理 defchat_with_tools(user_query:str,model:strglm-4-flash)-str:单轮带工具调用的金融查询clientZhipuAI(api_keyZHIPUAI_API_KEY)messages[{role:system,content:SYSTEM_PROMPT},{role:user,content:user_query}]responseclient.chat.completions.create(modelmodel,messagesmessages,toolsTOOLS,tool_choiceauto)assistant_messageresponse.choices[0].messageifnotassistant_message.tool_calls:returnassistant_message.contentormessages.append(assistant_message)fortool_callinassistant_message.tool_calls:iftool_call.function.nameget_ticker:try:argsjson.loads(tool_call.function.arguments)exceptjson.JSONDecodeError:tool_result{success:False,data:[],error_code:INVALID_ARGUMENTS_JSON}else:tool_resultget_ticker(args.get(symbols,))messages.append({role:tool,tool_call_id:tool_call.id,content:json.dumps(tool_result,ensure_asciiFalse)})final_responseclient.chat.completions.create(modelmodel,messagesmessages)returnfinal_response.choices[0].message.content# 测试入口 if__name____main__:print( 测试1: 跨市场标准代码查询 )print(chat_with_tools(查一下 600519.SH、700.HK 和 AAPL.US 的最新价格))print(\n 测试2: 中文名称输入应引导而非映射 )print(chat_with_tools(茅台现在多少钱))print(\n 测试3: 错误 symbol 格式 )print(chat_with_tools(查询 600519.SSE 的价格))print(\n 测试4: 不存在的 symbol )print(chat_with_tools(查询 NOTEXIST.SH 的价格))关键解读工具描述description开头写功能紧接着写三个“不要用”——不是可有可无的注释而是直接决定模型选择精度的硬配置。错误返回无论底层 API 发生了什么始终返回带success字段的同一结构字典。模型的回复行为由这个字段触发不由它自己判断。system prompt对successfalse规定了固定回复句式并明文禁止“建议稍后重试”“请检查网络”等扩展——这是针对 GLM-4 “过度理解”倾向的定向约束。模型版本glm-4-flash适合原型验证。多工具≥3生产场景付费版本的工具选择精度通常更稳定。四、统一数据层在 GLM-4 场景下的价值当多个金融接口的字段名不统一时你每接入一个新数据源GLM-4 的工具函数都要重写一套字段映射和错误处理逻辑。一个统一的数据接口可以把这个复杂度压到最低。工程困境统一接口应提供什么TickDB 的实现模型分不清不同接口的成交量字段字段语义按端点严格隔离ticker 用volume_24hkline 用volume不混用限流后模型“过度理解”错误信息标准错误码 Retry-After3001 携带建议等待时间客户端据此退避中文名称映射格式不统一品种列表接口 统一后缀规范GET /v1/symbols/available可查正版 symbolFunction Calling 切换到 AI 编码助手场景MCP 端点无需手写 HTTP 代码mcp.tickdb.ai可在 Claude Code、Cursor 等工具中直接调用五、结尾给 GLM-4 接上金融数据代码层面只是注册了一个get_ticker函数。但让它不犯错靠的是三个在通用教程里不会展开的东西描述里那三句“不要用”返回结构里那个success字段system prompt 里那条把模型的嘴焊死的硬规则。一个反直觉的观察GLM-4 对中文的理解越强它在金融场景下的风险反而越大——因为强到它觉得自己可以在数据缺失时“帮用户一把”。而金融场景下任何“帮一把”都是不能接受的。你把约束写在 tool description 里它照做你不写它默认帮你——这就是中文模型的纪律边界。你在用国产模型接入业务数据时有没有遇到过模型“过度帮忙”的情况是在 prompt 里堵还是在代码里拦欢迎在评论区聊聊你的防御策略。 数据示例由 TickDB.ai 提供标签智谱 GLM / Function Calling / 金融数据接入 / 工具调用 / TickDB / GLM-4文末自检清单我要查什么怎么查每个工具的 description 第一句是否写了“不要用 X应选 Y”打开TOOLS定义逐条检查 description 开头get_ticker所有 return 分支是否都包含success字段检查函数体内每个return语句system prompt 里是否明确禁止模型在失败时扩展说明搜索 prompt 中“固定句式”和“不允许添加”成交量字段用的是int()还是Decimal()搜索int(volume有则改限流退避是否解析了Retry-After检查 3001 分支中是否调用了resp.headers.get(Retry-After)中文名称映射是由模型还是代码完成如果 prompt 写了“不要自行转换”确认代码里有替代映射函数