AI Agent开发指南:用Function Calling构建智能助手
普通的 LLM 调用是“一问一答”:你问它答,它不能查数据库、不能调外部 API、不能执行代码。但真实世界的任务往往需要多步操作——比如“查一下北京明天天气,如果下雨就帮我订一把伞”。这就需要 AI Agent:让模型不仅能说话,还能自主决定调用哪些工具、按什么顺序调用,直到完成任务。
本文将从 Agent 的核心概念讲起,用 Function Calling 从零实现一个能查天气、算数学、查数据库的智能助手。读完你就能理解 LangChain Agent、AutoGPT 这类框架背后的本质。
一、什么是 AI Agent
Agent 的定义有很多版本,但本质就一句话:一个以 LLM 为大脑、能调用外部工具完成多步任务的系统。它和普通聊天机器人的核心区别在于“自主决策”。
一个 Agent 通常由四个部分组成:
- 大脑(LLM):负责理解任务、规划步骤、决定调用哪个工具。
- 工具(Tools):模型可以调用的外部能力,如搜索、计算、数据库查询、发邮件。
- 记忆(Memory):保存对话历史和中间结果,让 Agent 知道之前做了什么。
- 循环(Loop):思考 → 调用工具 → 观察结果 → 再思考,直到给出最终答案。
二、Function Calling:Agent 的基石
Function Calling(函数调用)是让 LLM 能“调用工具”的标准机制。它的流程是:
- 你把可用工具的名称、描述、参数 schema 告诉模型。
- 模型判断是否需要调用工具,如果需要,返回一个结构化的工具调用请求(工具名 + 参数 JSON)。
- 你的代码执行这个工具,把结果回传给模型。
- 模型基于结果继续思考,要么再调一个工具,要么给出最终答案。
关键点:模型不会真的执行你的函数,它只是输出“我想调用这个函数,参数是这些”。真正的执行由你的代码完成。这种设计保证了安全性——模型无法直接访问你的数据库或发邮件。
三、定义工具:用 JSON Schema 描述
每个工具需要用 JSON Schema 描述清楚:名字、做什么、接受什么参数。描述越清晰,模型调用越准。
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": "calculate",
"description": "计算一个数学表达式。当需要精确数值计算时调用,不要自己心算。",
"parameters": {
"type": "object",
"properties": {
"expression": { "type": "string", "description": "合法的数学表达式,如 '12 * 8 + 5'" }
},
"required": ["expression"]
}
}
}
]
写描述的两个技巧:一是说明什么时候该用(“当用户问天气时调用”),二是说明什么时候不该用(“不要自己心算”)。这能显著减少误调用。
四、实现工具函数
import json
# 工具的实际实现
def get_weather(city, unit="celsius"):
# 实际项目里这里调用真实天气 API
weather_db = {"北京": 28, "上海": 26, "广州": 31}
temp = weather_db.get(city, 25)
if unit == "fahrenheit":
temp = temp * 9 / 5 + 32
return json.dumps({"city": city, "temp": temp, "unit": unit}, ensure_ascii=False)
def calculate(expression):
try:
return str(eval(expression))
except Exception as e:
return f"计算失败: {e}"
# 工具名到函数的映射
tool_map = {"get_weather": get_weather, "calculate": calculate}
五、Agent 的核心循环
这是 Agent 最关键的部分:一个“思考-行动-观察”的循环。模型每次回复后,我们检查它是否要求调用工具;如果是,执行工具把结果送回去,让模型继续;如果模型给出最终答案(没有工具调用),循环结束。
from openai import OpenAI
client = OpenAI(api_key="sk-your-enlyai-key", base_url="https://enlyai.com/v1")
def run_agent(user_query, model="gpt-5.5", max_steps=8):
messages = [
{"role": "system", "content": "你是一个能调用工具的智能助手。遇到需要查天气或计算的问题,请调用对应工具,不要凭空猜测。"},
{"role": "user", "content": user_query}
]
for step in range(max_steps):
resp = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
tool_choice="auto" # 让模型自己决定是否调用
)
msg = resp.choices[0].message
messages.append(msg)
# 如果模型没有调用工具,说明已经给出最终答案
if not msg.tool_calls:
return msg.content
# 执行模型要求的所有工具调用
for call in msg.tool_calls:
fn_name = call.function.name
fn_args = json.loads(call.function.arguments)
print(f"[调用工具] {fn_name}({fn_args})")
result = tool_map[fn_name](**fn_args)
# 把工具结果作为 tool 角色消息回传
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result
})
return "达到最大步数,任务未完成。"
# 测试:模型会先查天气,再综合回答
print(run_agent("北京和上海哪个更热?请给出具体温度。"))
运行这段代码,你会看到模型先调用两次 get_weather(北京、上海),拿到结果后对比给出“广州更热”的结论。这就是 Agent 的自主决策能力——你只给了任务,模型自己规划了执行路径。
六、多轮对话:让 Agent 有记忆
真实助手需要支持多轮对话,用户可能基于上一轮结果追问。只要把完整的 messages 历史保留下来传给模型即可:
conversation = [
{"role": "system", "content": "你是智能助手,可调用工具。"}
]
def chat(user_input):
conversation.append({"role": "user", "content": user_input})
# 复用 run_agent 的循环逻辑,传入已有 conversation
answer = run_agent_with_history(conversation)
return answer
# 第一轮
print(chat("北京今天多少度?"))
# 第二轮,模型能记住上文
print(chat("那换成华氏度呢?")) # 模型知道"那"指北京
注意控制历史长度:对话轮数多了,token 会膨胀。生产环境建议保留最近 10-20 轮,或用摘要压缩更早的历史。
七、ReAct 模式:思考过程可见
上面用的是原生 Function Calling。另一种经典模式是 ReAct(Reasoning + Acting):让模型在每一步先输出“Thought(思考)”,再输出“Action(行动)”。好处是推理过程透明,便于调试;缺点是更费 token。
2026 年主流模型(GPT-5.5、Claude Opus 4.8)的原生 Function Calling 已经足够稳定,新项目优先用 Function Calling;只有在模型不支持 function calling、或需要强可解释性时才用 ReAct。
八、生产环境最佳实践
- 限制最大步数:Agent 可能陷入“调用-失败-再调用”死循环,
max_steps必须设上限(通常 8-15)。 - 工具要做参数校验:模型可能传错参数类型,工具函数里要 try/except 并返回友好错误,而不是抛异常崩溃。
- 工具结果要简洁:返回大段 HTML 或超长文本会撑爆上下文,工具内部应做摘要或截断。
- 记录每一步:把 Thought、Action、Observation 全部记日志,出问题时能复盘模型为什么走偏。
- 危险工具要二次确认:发邮件、删数据、付款这类工具,不要让 Agent 自动执行,应返回“需确认”让用户拍板。
- 用便宜模型做简单决策:路由、参数提取用 GPT-5.4-mini,复杂规划才用 GPT-5.5,能省大量成本。
九、用 EnlyAI 统一接入多模型
Agent 开发中你往往要在多个模型间切换:规划用 Claude Opus 4.8(推理强),工具调用用 GPT-5.5(function calling 稳),简单判断用 GPT-5.4-mini(便宜)。如果分别对接各家平台,密钥和 SDK 管理很麻烦。通过 EnlyAI 统一接入,一个 key 调用所有模型:
from openai import OpenAI
client = OpenAI(api_key="sk-your-enlyai-key", base_url="https://enlyai.com/v1")
# 同一套 Agent 代码,只改 model 即可切换底层模型
def adaptive_agent(query):
# 简单问题用 mini 省钱,复杂问题用 GPT-5.5
if len(query) < 20:
return run_agent(query, model="gpt-5.4-mini")
return run_agent(query, model="gpt-5.5")
# 也可以用 Claude 做规划
print(run_agent("帮我分析最近一周的销售数据趋势", model="claude-opus-4-8"))
统一接入还能实现故障转移:某个模型服务波动时,代码里改一个字符串就能切到备用模型,不用改 SDK、不用换密钥。
总结
AI Agent 的本质并不神秘:LLM 当大脑,Function Calling 当手脚,一个循环把“思考-行动-观察”串起来。本文从工具定义到核心循环给出了完整可运行的代码,你已经具备了自己实现一个 LangChain Agent 的能力——因为那些框架做的,无非是把这套循环封装得更优雅。
真正决定 Agent 好坏的,是工具描述写得清不清楚、循环控制稳不稳定、错误处理健不健壮。把这些细节打磨好,再配合 EnlyAI 统一接入多模型的能力,你就能构建出既聪明又省钱的智能助手。
想用一套代码调用所有大模型构建 Agent?
EnlyAI 提供 OpenAI 兼容的统一接口,一个 key 调用 GPT-5.5、Claude Opus 4.8、Gemini 3.5 Pro,原生支持 Function Calling,注册即送免费额度。
立即注册 EnlyAI →