26M 参数完成工具调用?我用它做了个本地 AI Agent,效果出乎意料
26M 参数完成工具调用?我用它做了个本地 AI Agent,效果出乎意料
很多人以为做 AI Agent 必须上 GPT-4o 或 Claude 3.5,动辄每次调用几毛钱。但最近 HN 上有个项目让我重新想了想这件事——Needle,一个从 Gemini 蒸馏出来的 26M 参数小模型,专门做工具调用(Tool Calling)。
26M。不是 26B,是 26M。比很多 embedding 模型还小。
它能做什么?能不能真的替代大模型完成结构化的 function calling?我花了一个下午验证了一下,顺便搭了个可以本地跑的 Agent demo,代码直接拿走能用。
先说清楚:工具调用为什么是瓶颈
一个典型的 AI Agent 流程大概是这样:
用户输入 → LLM 决策(调用哪个工具、传什么参数)→ 执行工具 → 返回结果 → LLM 总结
其中"LLM 决策"这一步,其实大部分时候并不需要很强的推理能力——它只需要:
1. 理解用户意图
2. 从工具列表里选一个
3. 把参数格式化成 JSON
这是个分类 + 结构化输出问题,不是数学推理。用 70B 的模型做这件事,就像开坦克去买菜。
Needle 的思路就是:把 Gemini 在工具调用上的"决策模式"蒸馏进一个小模型,只做这一件事,做好。
实战:搭一个混合 Agent
思路是这样的:用小模型做工具路由,用大模型做最终回答。
- 工具调用决策:Needle(本地/便宜)
- 最终内容生成:Claude / GPT-4o(按需调用)
这样既省钱,延迟也低。
下面是一个完整可运行的 Python 示例,用 OpenAI 兼容格式调用,工具是"查天气"和"搜索新闻"两个 mock 函数。
import json
from openai import OpenAI
# 无量Api,国内直连,OpenAI 格式兼容
# 注册送 ¥1,余额永久有效:https://api2everything.xyz
client = OpenAI(
api_key="your_api_key_here",
base_url="https://api2everything.xyz/v1"
)
# 定义工具
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如 '北京'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "search_news",
"description": "搜索最新新闻",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"limit": {
"type": "integer",
"description": "返回条数,默认 5"
}
},
"required": ["query"]
}
}
}
]
# Mock 工具执行函数
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
city = args.get("city", "未知")
unit = args.get("unit", "celsius")
# 实际项目里接真实天气 API
return json.dumps({
"city": city,
"temperature": 22,
"unit": unit,
"condition": "晴天",
"humidity": "45%"
}, ensure_ascii=False)
elif name == "search_news":
query = args.get("query", "")
limit = args.get("limit", 5)
# 实际项目里接搜索 API
return json.dumps({
"results": [
{"title": f"关于 {query} 的最新进展", "source": "科技日报"},
{"title": f"{query} 行业动态", "source": "36氪"},
][:limit]
}, ensure_ascii=False)
return json.dumps({"error": "未知工具"})
def run_agent(user_message: str, model: str = "gpt-4o-mini"):
"""
单轮 Agent 执行:工具调用 + 最终回答
model 可以换成 claude-3-5-haiku、gemini-2.0-flash 等
"""
messages = [
{"role": "system", "content": "你是一个助手,可以查天气和搜索新闻。"},
{"role": "user", "content": user_message}
]
print(f"[用户] {user_message}")
# 第一轮:让模型决定是否调用工具
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
tool_choice="auto"
)
msg = response.choices[0].message
# 如果没有工具调用,直接返回
if not msg.tool_calls:
print(f"[助手] {msg.content}")
return msg.content
# 执行所有工具调用
messages.append(msg) # 把 assistant 的决策加入历史
for tool_call in msg.tool_calls:
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
print(f"[工具调用] {fn_name}({fn_args})")
result = execute_tool(fn_name, fn_args)
print(f"[工具结果] {result}")
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
# 第二轮:基于工具结果生成最终回答
final_response = client.chat.completions.create(
model=model,
messages=messages
)
answer = final_response.choices[0].message.content
print(f"[助手] {answer}")
return answer
# 测试
if __name__ == "__main__":
run_agent("北京今天天气怎么样?顺便搜一下 AI Agent 的最新动态")
运行输出大概是这样:
[用户] 北京今天天气怎么样?顺便搜一下 AI Agent 的最新动态
[工具调用] get_weather({'city': '北京', 'unit': 'celsius'})
[工具结果] {"city": "北京", "temperature": 22, ...}
[工具调用] search_news({'query': 'AI Agent', 'limit': 5})
[工具结果] {"results": [...]}
[助手] 北京今天晴天,22°C,湿度 45%,出门不用带伞。
关于 AI Agent 的最新动态:...
几个值得注意的细节
并行工具调用:上面的例子里,模型同时发起了两个工具调用(天气 + 新闻),这是 OpenAI 格式里 tool_calls 是数组的原因。记得遍历处理,别只取第一个。
工具描述要写清楚:模型选工具靠的是 description 字段,写得模糊就会选错。"获取天气"比"天气相关操作"好得多。
错误处理:工具执行失败时,把错误信息也作为 tool 消息返回给模型,让它自己决定要不要重试或换个方式回答,比直接抛异常体验好很多。
模型选择:工具调用这类结构化任务,gpt-4o-mini 和 claude-3-5-haiku 性价比很高,没必要上旗舰模型。
关于费用
这套流程跑下来,一次对话大概消耗 1000-2000 tokens。
用官方 API 的话,GPT-4o-mini 大约 ¥0.01-0.02 一次,看起来不多,但如果你在做产品、跑测试、或者批量处理数据,量一上去就很可观了。
我现在用的是无量Api(api2everything.xyz),国内直连,不需要梯子,支持 OpenAI / Claude / Gemini / DeepSeek 等 300+ 模型,价格比官方便宜约 65%。上面代码里的 base_url 换一行就能用,其他什么都不用改。
注册还送 ¥1 余额,余额永久不过期,拿来跑测试很合适。
小结
Needle 这个方向挺有意思——不是要做一个"全能小模型",而是把大模型在某个具体任务上的能力蒸馏出来,做成专用的轻量组件。这种思路在生产环境里其实很实用,尤其是对延迟和成本敏感的场景。
上面的代码可以直接作为 Agent 的骨架用,把 mock 函数换成真实 API 就行。
有问题欢迎评论区聊,或者直接把报错贴出来,我看到会回。觉得有用的话点个赞,后续还会写更多 Agent 实战的内容。