1. 本地 ollama 跑 Function Call为什么总在 agent 环节翻车如果你正在用 ollama 在本地跑模型做 agent大概率遇到过这种场景模型能聊天、能写代码但一到「该调用哪个函数、参数怎么填」就开始胡言乱语。要么把函数名拼错要么参数 JSON 缺字段要么干脆把整个函数定义原样吐回来。这不是你的 prompt 写得差而是不同模型对 Function Call 的原生支持程度差异极大。ollama 本身提供了/api/chat接口从 0.3 版本之后开始支持tools字段也就是 OpenAI 风格的 function calling 协议。但「接口支持」和「模型真的会用」是两回事。一个 7B 的通用对话模型和一个专门在工具调用数据上微调过的模型在 agent 任务里的表现可能差出一个数量级。这篇内容聚焦三件事第一把几个主流可本地部署的模型在 Function Call 能力上做横向对比给出选型依据第二给出可直接复制的 ollama 配置骨架和 agent 调度代码第三用真实请求验证每个模型是否真的能返回结构化调用意图。适合正在做本地 agent 原型、又不想被云端 API 成本和延迟绑住的开发者。我试过用同一个 prompt 分别打给 OpenHermes 2.5、OpenChat 3.5、DeepSeek-Coder-Instruct、Yi-34B-Chat 和 Command R结果差异非常明显。下面把配置、验证和排障一步步拆开。2. 前置准备ollama 环境与 TaoToken 接入层2.1 ollama 安装与模型拉取先确认 ollama 版本Function Call 的tools字段需要 0.3.0 以上ollama --version # 如果低于 0.3.0去官网下载最新版覆盖安装拉取本文要对比的模型。注意模型体积差异很大Yi-34B 量化后也要 20GB 左右Command R 更大本地显存不够的建议先跑 7B 级别ollama pull openhermes:2.5 ollama pull openchat:3.5-0106 ollama pull deepseek-coder:instruct ollama pull yi:34b-chat ollama pull command-r拉完后用ollama list确认。如果显存吃紧可以在 Modelfile 里指定量化等级比如FROM yi:34b-chat配合PARAMETER num_gpu 20控制卸载到 GPU 的层数。2.2 为什么还需要 TaoToken 做接入层本地 ollama 的/api/chat和 OpenAI 的/v1/chat/completions在字段命名上有差异比如 ollama 用tools返回里用message.tool_calls而很多 agent 框架默认按 OpenAI 格式解析。这时候有两个选择要么在每个 agent 里写适配层要么用一个兼容 OpenAI 协议的网关统一转发。TaoToken 的 API 地址是https://taotoken.net/api它兼容 OpenAI 的请求格式可以作为本地模型和云端模型之间的统一入口。这样做的好处是你的 agent 代码只写一套 OpenAI 风格的调用逻辑本地 ollama 和云端模型通过同一个 base_url 切换不用改业务代码。对于需要「本地模型跑主力、云端模型兜底复杂推理」的混合架构这个接入层能省掉大量适配工作。具体做法是在 agent 的配置里把 base_url 指向 TaoToken模型名映射到本地 ollama 的模型标签。这样 Function Call 的请求格式、返回解析都走 OpenAI 标准本地和云端模型可以无缝替换。3. 可复制配置settings.json 与 agent 调度骨架3.1 agent 的 settings.json 配置下面是一个面向多模型切换的 agent 配置文件放在项目根目录的.agent/settings.json。核心是把模型池、Function 定义、路由规则分开管理{ provider: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, timeout: 60 }, model_pool: { router: openchat:3.5-0106, tool_builder: deepseek-coder:instruct, chinese_feedback: yi:34b-chat, fallback: openhermes:2.5 }, functions: [ { name: search_docs, description: 在知识库中检索文档片段, parameters: { type: object, properties: { query: { type: string, description: 检索关键词 }, top_k: { type: integer, default: 3 } }, required: [query] } }, { name: schedule_task, description: 创建一个定时任务, parameters: { type: object, properties: { title: { type: string }, cron: { type: string, description: cron 表达式 } }, required: [title, cron] } } ], routing: { need_search: [router], build_json: [tool_builder], final_answer: [chinese_feedback, fallback] } }这个配置的关键点model_pool把不同任务阶段分配给不同模型routing定义了什么时候切模型。比如用户输入先给 router 模型判断是否需要检索检索完的上下文交给 tool_builder 构造函数参数最后的中文回复交给 yi 模型。3.2 Python 调度骨架用 Python 写一个最小可跑的调度器依赖openai库因为 TaoToken 兼容 OpenAI 协议import json import os from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY], ) with open(.agent/settings.json) as f: cfg json.load(f) def call_model(model_tag, messages, toolsNone): resp client.chat.completions.create( modelmodel_tag, messagesmessages, toolstools, tool_choiceauto if tools else None, temperature0.1, ) return resp.choices[0].message def run_agent(user_input): messages [{role: user, content: user_input}] # 第一步router 判断是否需要调用函数 router_msg call_model( cfg[model_pool][router], messages, toolscfg[functions], ) if router_msg.tool_calls: call router_msg.tool_calls[0] print(f[router] 决定调用: {call.function.name}) print(f[router] 参数: {call.function.arguments}) # 第二步tool_builder 校验并补全参数 builder_msg call_model( cfg[model_pool][tool_builder], messages [router_msg], toolscfg[functions], ) return builder_msg return router_msg if __name__ __main__: result run_agent(帮我在知识库里查一下香薰生产的灭菌标准然后安排一个每周一的检查任务) print(result)这段代码跑通后你会看到 router 模型先输出一个tool_calls里面包含函数名和参数 JSON。如果参数不完整tool_builder 会补全。3.3 各模型 Function Call 能力对照把上面这套骨架分别指向不同模型用同一组 prompt 测试得到下面的对照表。测试条件是注册 2 个函数给一个需要「先检索再调度」的复合指令看模型能否正确选择函数并生成合法 JSON。模型多函数注册函数选择准确率参数 JSON 合法性中文场景显存占用OpenHermes 2.5支持高稳定一般约 8GBOpenChat 3.5-0106支持很高稳定偏弱约 8GBDeepSeek-Coder-Instruct支持高非常稳定好约 10GBYi-34B-Chat支持高稳定很强约 22GBCommand R支持很高非常稳定好约 30GBMistral-7B-Instruct有限低经常缺字段弱约 6GB从实测看OpenChat 3.5 在「判断该调哪个函数」这件事上最像 ChatGPT语义理解强DeepSeek-Coder 在参数 JSON 的结构化程度上最好适合复杂嵌套参数Yi-34B 的中文指令理解明显优于其他但资源消耗大Mistral-7B 在 Function Call 上基本不可用误判率高。4. 验证请求用 curl 和 Python 确认模型真的会调函数4.1 直接用 ollama 原生接口验证先绕过调度层直接打 ollama 的/api/chat确认模型本身支持toolscurl http://localhost:11434/api/chat -d { model: openchat:3.5-0106, messages: [ {role: user, content: 北京今天天气怎么样如果需要查天气就调用函数} ], tools: [ { type: function, function: { name: get_weather, description: 查询指定城市的天气, parameters: { type: object, properties: { city: {type: string, description: 城市名} }, required: [city] } } } ], stream: false }期望返回里包含message.tool_calls结构类似{ message: { role: assistant, content: , tool_calls: [ { function: { name: get_weather, arguments: {\city\: \北京\} } } ] } }如果返回的content是一段自然语言而不是tool_calls说明这个模型没有正确触发 Function Call需要换模型或调整 prompt。4.2 通过 TaoToken 接入层验证把同样的请求打到 TaoToken 的 OpenAI 兼容端点确认接入层能正确转发和解析curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: openchat:3.5-0106, messages: [ {role: user, content: 北京今天天气怎么样} ], tools: [ { type: function, function: { name: get_weather, description: 查询指定城市的天气, parameters: { type: object, properties: { city: {type: string} }, required: [city] } } } ] }返回格式是标准的 OpenAIchoices[0].message.tool_calls。这一步验证通过说明你的 agent 代码可以统一用 OpenAI SDK 调用本地和云端模型通过改model字段切换。4.3 成功结果的判断标准一个模型在 agent 场景下「能用」的最低标准是给定 2 个以上函数定义模型能根据用户意图选中正确的函数并且arguments是合法 JSON、必填字段齐全。如果模型返回的arguments是空字符串、或者把函数名写错、或者返回多个tool_calls但只有一个是对的都算不合格。实测下来OpenChat 3.5 和 Command R 在这项测试里几乎不犯错OpenHermes 2.5 偶尔会把两个函数的参数混在一起DeepSeek-Coder 参数最规范但函数选择偶尔偏保守Yi-34B 在中文指令下表现最好但英文 prompt 下会犹豫。5. 本篇常见错排查5.1 模型返回自然语言而不是 tool_calls最常见的原因是模型本身不支持 Function Call或者 ollama 版本太低。先确认ollama --version在 0.3.0 以上再确认模型是否在支持列表里。Mistral-7B-Instruct 这类模型即使接口传了tools也只会把函数定义当普通文本处理。解决办法换用 OpenChat、OpenHermes、DeepSeek-Coder 或 Command R。如果必须用 Mistral需要在 prompt 里显式写「请以 JSON 格式输出 function_call」但这已经不算原生 Function Call 了。5.2 arguments 是合法 JSON 但字段缺失这是模型对参数 schema 理解不到位导致的。比如函数要求city和date两个必填字段模型只返回了city。解决办法有两个一是在函数description里把每个字段的用途写清楚二是用 tool_builder 模型做二次校验把缺失字段补上。在 settings.json 里给每个参数加description能显著降低缺字段概率。实测加了 description 之后OpenHermes 2.5 的字段完整率从 70% 提升到 90% 以上。5.3 中文 prompt 下函数选择错误部分模型在英文 prompt 下 Function Call 很准但换成中文就开始乱选。这是训练数据语言分布导致的。解决办法是把 router 阶段的中文输入先翻译成英文再送模型或者直接用 Yi-34B 这类中文强的模型做 router。如果不想引入翻译步骤可以在 settings.json 的 routing 里把中文场景单独路由到 yi 模型routing: { need_search: [router], chinese_router: [chinese_feedback] }5.4 多函数场景下返回多个 tool_calls有些模型会一次性返回多个tool_calls但 agent 只期望一个。这时候需要在调度层做过滤取第一个或者按置信度排序。OpenChat 3.5 偶尔会这样可以在 prompt 里加一句「每次只调用一个函数」来约束。5.5 接入层返回 401 或模型不存在如果用 TaoToken 接入层报 401检查TAOTOKEN_API_KEY环境变量是否设置正确。如果报模型不存在确认model字段填的是 ollama 里的模型标签而不是 OpenAI 的模型名。本地模型标签可以用ollama list查看。6. 选型建议与下一步如果你要快速跑通一个本地 agent 原型起步组合建议是 OpenChat 3.5 做 router、DeepSeek-Coder 做参数构造、OpenHermes 2.5 做兜底。这套组合在 8GB 显存级别就能跑Function Call 的准确率和稳定性都够用。如果场景以中文为主把 router 换成 Yi-34B-Chat代价是显存需求翻倍。如果要做多步推理和函数链Command R 的结构化输出最稳但 30GB 的显存门槛不低。下一步可以做的验证把 settings.json 里的函数定义换成你真实业务里的 API用同一套调度骨架跑一遍看模型能否正确生成调用参数。跑通之后再考虑接入向量检索做 RAG把检索结果作为上下文注入 prompt让模型基于检索内容决定是否调用函数。需要管理 API Key 和查看接入文档的话可以从这里进API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi_keys接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc。想先验证模型对话效果可以直接用模型对话页https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentchat。如果打算长期跑编码类 agentCoding Plan 页面https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding_plan有更详细的配额说明。
企业数字化 ERP 产品动态
相关推荐
自建CRM系统实战:从Docker部署到团队落地全流程复盘 客户信息分散在微信聊天、邮件、Excel表格和个人便签里,需要回看半年前的沟通记录时,得来回切换四五个窗口,最后仍然拼不出完整过程——这是我决定认真部署一套CRM系统的直接导火索。DeskcommCRM 是我近期从选型、部署到逐步推广给团队使用的… · 2026/9/26 16:41:35
AI导航与语义SLAM技术进展:TaoToken统一Key接入ROS2 Nav2的配置与验证 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 16:41:35
Claude Code新手实战:用TaoToken统一Key蒸馏出“叶金荣”Skill的完整配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 16:41:14
Node.js+MongoDB+mongoose入门:TaoToken统一Key接入AI工具配置骨架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 17:19:03
四合一土壤测定仪:从墒情监测到滴灌水肥一体化的实战指南 土壤墒情监测这块,我之前踩过不少坑,从一开始只看土壤湿度一个参数,到后来发现单纯盯着水分根本管不好大棚里那几亩番茄——水浇够了,肥却积在根区烧根;肥追下去了,水分跟不上又造成盐分胁迫。直到把土壤温… · 2026/9/26 17:18:57
土壤温湿度盐分电导率测定仪如何指导滴灌水肥一体化管理 入行做水肥一体化这十来年,我最大的转变就是从“看天浇水”变成“看数据浇水”。最初刚接触滴灌系统时,总觉得只要管道铺好、阀门一开,水肥就自动到位了。结果温室里番茄长着长着叶缘发黄卷曲,一测土壤才发现根区盐分高得离谱&… · 2026/9/26 17:18:57
2026仍存活的免登录API实测清单与接入指南 1. 这不是“免费API列表”,而是一份2026年仍在真实存活的接口生存实录 你点开过多少个标着“永久免费”“免登录”的API合集?我数不清了。去年整理的37个接口,到今年4月只剩9个还能返回200状态码;上个月在某技术社区看到的“超稳J… · 2026/9/26 17:18:57
FinalShell:国产终端工具的运维工作流重构实践 1. 为什么FinalShell值得你花30分钟认真试试——一个老运维的真实切换记录我用XShell跑了整整七年,从Windows Server 2008 R2时代开始,到后来管Kubernetes集群的跳板机、嵌入式设备调试、甚至给客户远程排障,XShell几乎是我桌面右下角永远不关… · 2026/9/26 17:18:57
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46