ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

AI Agent开发实战:从函数调用到生产化落地

AI Agent开发实战:从函数调用到生产化落地 《时代》公布2026年全球AI百大人物榜后AI 应用开发再次成为技术社区的高频话题。封面人物包括OpenAI的奥尔特曼、马斯克、阿里巴巴的吴泳铭等。这里不讨论榜单排名和人物八卦真正值得开发者关注的是AI 产业的话题重心已经从“谁的模型参数更多”转向“谁能用模型稳定地解决真实问题”。对大多数非算法岗位的开发者来说这反而是更大的机会。要在实际项目里稳定解决业务问题不能只调用大模型API还需要理解模型如何接收指令、如何调用外部工具、如何维护多轮上下文以及如何把错误处理、日志、权限、成本监控这些工程能力补齐。这些能力合在一起就是当前讨论度很高的 AI Agent 开发也就是 AI 应用开发。接下来会用一个小例子把这条链路完整跑一遍从定义工具协议、实现函数调用循环到运行验证、排查问题最后给出生产化的改进方向。这个例子虽然小但足够支撑你理解主流 Agent 框架背后的核心机制。1. 榜单背后的技术信号AI 开发重心正在转向应用落地1.1 从人物榜到工程问题《时代》公布的全球AI百大人物榜反映的是 AI 产业进入应用落地阶段的缩影。能够登上这类榜单的除了大模型研发者还有很多把模型变成产品、把AI做成业务系统的人。这个信号对普通开发者很有价值现在不需要训练大模型也能在AI技术栈里做出有实际价值的工作。但模型本身并不等于产品。大语言模型只是一个“能理解自然语言、能生成文本”的推理引擎。要让它回答实时问题需要给它接上数据库、API、搜索引擎要让它完成多步任务需要设计流程让它在多个工具之间决策要让它进入生产环境还需要考虑速度、成本、稳定性和安全性。这些内容才是 AI 应用开发的核心。换句话说AI 应用开发不是“提个需求给模型”那么轻量而是一种新的工程形态。它会复用大量传统后端知识同时引入“模型输出不确定”这个新的复杂度来源。1.2 AI应用开发需要的能力组合一个合格的 AI 应用开发者不是只会写 Prompt也不是只会写 CRUD。常见能力要求包括理解提示词工程的基础原则知道如何让模型输出结构化结果。理解函数调用Function Calling和工具协议。会设计外部工具接口并处理模型返回的调用参数。会管理多轮对话上下文避免超长和混乱。会做应用的日志、监控、限流、缓存和异常处理。有基本的成本意识能估算每次请求的 token 消耗。传统后端开发经验在中间几项上有明显优势。前端、测试、产品经历也可以从不同切入点进入。为了直观对比这里给出一张表格能力维度传统后端开发AI应用开发关键差异核心依赖数据库、消息队列、缓存大模型API、向量库、工具服务模型输出不确定需要额外校验调试方式断点、日志、异常栈需要记录完整输入输出和token用量模型结果不固定回归测试更复杂可靠性设计超时、重试、幂等增加格式校验、降级、工具重试模型可能拒绝执行或调用错误工具成本控制CPU、内存、带宽token、缓存命中率、模型版本成本与请求内容长度强相关上线周期需求、开发、测试周期固定需要评估效果经常迭代Prompt效果验证需要真实用户反馈这张表不是否定传统后端能力而是说明 AI 应用开发会在原有工程基础上增加一层“模型不确定性”的管理。带着这个视角下面开始搭环境。2. 环境准备先搭一套最小可运行的AI Agent工程2.1 技术选型为什么要用 Function Calling 而不是只写 Prompt现在要实现一个“天气助手”案例。用户问“北京今天适合穿什么”Agent 先调用天气工具拿到北京今天的天气、温度和湿度再结合这些信息给出穿衣建议。如果不用函数调用只写一句“请根据实时天气回答”模型没有天气数据来源只能凭训练知识给一个模糊答案。函数调用则是把“获取天气”定义成工具模型在需要时输出一个结构化调用请求应用层执行工具并把结果回传给模型模型再组织最终回答。这个“模型决策、程序执行、结果回传”的循环是所有 Agent 应用的核心。技术栈选择上使用 Python 3.10、OpenAI Python SDK、python-dotenv。不引入 LangChain先贴近原生机制便于理解每一步在做什么。如果团队使用 Java后续可以用 Spring AI 做类似实现但原理是一样的。这里需要提醒示例使用的接口格式基于 OpenAI 官方 SDK。如果使用其他兼容 OpenAI 协议的大模型服务只要接口格式兼容代码大体可用具体模型名、接口地址和工具协议要以服务商文档为准。2.2 创建项目并安装依赖命令如下mkdir ai-agent-demo cd ai-agent-demo python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate pip install openai python-dotenv安装完成后在项目根目录创建.env文件保存密钥和模型配置OPENAI_API_KEY你的API密钥 OPENAI_BASE_URLhttps://api.openai.com/v1 MODEL_NAMEgpt-4o-mini如果使用的是兼容接口的托管服务OPENAI_BASE_URL要换成对应服务商的接口地址。.env文件不要提交到 Git 仓库同时在.gitignore中加入.env venv/ __pycache__/这里有几个容易出错的地方python命令在部分环境是python3创建虚拟环境前先确认解释器版本。API 密钥不要直接写在代码里否则仓库一旦泄露密钥会跟着泄露。模型名要改成账号实际可以访问的模型不同服务商提供的模型名差异很大。2.3 项目目录结构最小项目只保留核心文件ai-agent-demo/ ├── .env ├── .gitignore ├── requirements.txt ├── tools.py └── main.pytools.py负责定义工具函数和工具 Schemamain.py负责 Agent 主循环。后面需要增加工具时在tools.py中扩展即可。3. 核心实现一个带工具调用的天气Agent3.1 先定义工具协议在 OpenAI Function Calling 协议中工具使用 JSON Schema 描述。模型看到的是工具名称、描述、参数结构和必填项不会直接看到 Python 代码。在tools.py中写入import json def get_weather(city: str, date: str today) - str: 获取指定城市的天气信息模拟实现。 真实项目应替换为气象服务 API并处理超时、限流、异常。 mock_db { 北京: {weather: 晴, temperature: 18, humidity: 30}, 上海: {weather: 小雨, temperature: 22, humidity: 85}, 杭州: {weather: 多云, temperature: 20, humidity: 60}, } info mock_db.get(city) if not info: return json.dumps({error: f暂不支持该城市: {city}}, ensure_asciiFalse) result {**info, city: city, date: date} return json.dumps(result, ensure_asciiFalse) WEATHER_SCHEMA { type: function, function: { name: get_weather, description: 获取指定城市的实时天气情况, parameters: { type: object, properties: { city: { type: string, description: 城市名称例如北京、上海、杭州, }, date: { type: string, description: 日期默认是今天, }, }, required: [city], }, }, } TOOLS [WEATHER_SCHEMA]这段代码有几个要点工具函数返回值必须是字符串因为后续要作为消息内容传给模型。不要返回 Python 字典否则在构造消息时需要先序列化。JSON Schema 中的description很重要模型依靠它决定何时调用以及传入什么参数。描述写得太泛模型会在不必要时调用写得太窄真实请求又匹配不上。get_weather当前是模拟数据。实际项目中可以在这里请求气象服务 API 或内部服务注意把外部调用异常转换成用户可理解的错误信息。3.2 Agent 主循环main.py的核心逻辑是循环判断模型是否需要调用工具import json import os from openai import OpenAI from dotenv import load_dotenv from tools import TOOLS, get_weather load_dotenv() client OpenAI( api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL, https://api.openai.com/v1), ) MODEL os.getenv(MODEL_NAME, gpt-4o-mini) SYSTEM_PROMPT 你是一个智能助手请使用工具获取实时信息并用中文回答用户问题。 def call_model(messages): return client.chat.completions.create( modelMODEL, messagesmessages, toolsTOOLS, ) def run_agent(user_input: str): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_input}, ] while True: response call_model(messages) message response.choices[0].message messages.append(message) # 模型没有要求调用工具说明可以输出最终回答 if not message.tool_calls: return message.content # 模型要求调用工具执行并回传结果 for tool_call in message.tool_calls: fn_name tool_call.function.name args json.loads(tool_call.function.arguments) if fn_name get_weather: tool_result get_weather(**args) else: tool_result json.dumps({error: f未知工具: {fn_name}}, ensure_asciiFalse) messages.append({ role: tool, tool_call_id: tool_call.id, content: tool_result, }) if __name__ __main__: while True: try: user_input input(你) except (EOFError, KeyboardInterrupt): break if not user_input.strip(): continue if user_input.lower() in (exit, quit): break print(AI, run_agent(user_input))运行命令python main.py这个循环是 Agent 最基础的原型。第一次请求时模型发现需要天气数据会在返回对象中携带tool_calls。程序执行对应工具后把结果以role: tool的消息追加到对话历史中再次请求模型模型基于工具结果组织最终回答。注意几个容易踩的坑messages.append(message)时message是 SDK 对象不是字典。在某些 SDK 版本中直接追加到消息列表会正常但如果后续要做序列化需要先转成message.model_dump()。tool_call.id必须与工具结果消息中的tool_call_id严格一致否则接口会校验失败。tool_call.function.arguments是一个 JSON 字符串需要先json.loads再传给 Python 函数。解析失败时要记录原字符串便于排查。3.3 关键参数说明调用模型时client.chat.completions.create还有很多参数会影响结果。下表列出常见调参项参数默认值作用调大/调小影响temperature1.0控制随机性调大回答更发散调小更确定工具调用相关任务建议 0~0.3top_p1.0核采样概率与 temperature 二选一调整不建议同时大幅修改max_tokens由模型决定限制单次回答长度太小会导致回答被截断frequency_penalty0降低重复用词调大可减少重复但可能影响连贯性presence_penalty0提高新话题出现概率调大更容易引入新内容timeoutSDK默认请求超时时间过短容易误判过长影响用户体验在工具调用型 Agent 中建议temperature设置为 0 或 0.2。工具选择和参数解析更依赖确定性随机性太大容易导致模型调用错误工具或生成非法 JSON。如果业务需要创意文案再单独把自由度调高。3.4 多轮对话的上下文管理当前示例把完整对话历史放在messages列表里。这种方式简单直接但有两个问题。第一上下文越长token 消耗越大。每次请求都会把全部历史消息发给模型成本随轮数线性增长。第二超过模型上下文窗口后请求会直接报错或被静默截断。gpt-4o-mini这类模型通常支持较大的上下文但不是无限大。常见处理策略限制对话轮数超过 N 轮后把最早的历史消息裁剪掉。对历史消息做摘要用一段摘要替代多轮完整对话。只保留最近 K 条消息和系统提示词。对工具结果做精简只保留关键字段不要把冗长 JSON 完整留在上下文里。学习阶段可以先不做裁剪但实际项目最好在进入生产前就设计好上下文策略。4. 运行验证从“能跑”到“正确”4.1 启动后的正常输出运行python main.py后输入问题一个可能的交互如下你北京今天适合穿什么 AI根据天气信息今天北京晴气温18度湿度30%。湿度较低早晚偏凉建议穿薄外套或长袖衬衫白天体感舒适。 你上海呢 AI上海今天有小雨气温22度湿度85%。湿度较大建议带伞穿防滑的鞋子并选择透气但有点防水的薄外套。第二问“上海呢”没有重复出现城市名但 Agent 能基于上文“北京”的对话状态推断出用户想查询上海天气。这依赖上下文传递。如果模型没有正确触发工具或者工具结果解析失败输出可能就会变成“我不知道实时天气请自行查询”。出现这种情况时需要回到第 5 节排查。4.2 检查模型是否真的调用了工具为了验证工具调用是否发生可以在run_agent中临时加一行日志if message.tool_calls: print(DEBUG: 模型请求调用工具, message.tool_calls)输出类似DEBUG: 模型请求调用工具 [ChatCompletionMessageToolCall(idcall_xxx, functionFunction(arguments{city: 北京, date: today}, nameget_weather), typefunction)]只要看到这一行就说明函数调用链路是通的。如果始终没有出现大概率是工具描述或系统提示词没有引导模型使用工具。4.3 用 usage 字段统计 token每次响应对象都包含usage字段包含本次请求的 token 统计print(response.usage)示例输出CompletionUsage(completion_tokens120, prompt_tokens320, total_tokens440)prompt_tokens是输入侧消耗包括系统提示词、历史消息、工具 Schema 和用户问题。completion_tokens是输出侧消耗。total_tokens是两者之和。监控这个字段可以帮助做成本预算。还可以给每个用户设置每日调用次数上限避免异常循环导致费用爆炸。5. 常见问题排查这一节总结在本地运行和项目上线时最常遇到的问题。问题现象常见原因检查方式处理建议报错The model ... does not exist模型名填错或账号没有该模型权限用官方 SDK 列出可用模型确认MODEL_NAME修改为账号可用的模型名报了鉴权或配额错误API Key 无效、过期或额度不足查看错误码和响应体更换 Key、检查账单、确认权限模型始终不接受工具调用工具 Schema 描述不清或提示词不明确打印tools参数检查描述在系统提示词中强调必须使用工具json.loads(arguments)失败模型输出了非法 JSON打印原始arguments字符串增加解析失败重试或降低 temperature请求超时网络不稳定或接口响应慢用curl -v直接测试接口配置超时和重试策略对话轮数一多就报上下文长度超限历史消息和工具结果堆积打印消息列表长度和 usage做消息裁剪、摘要或滑动窗口工具返回了错误但没有提示用户异常被工具函数吞掉检查工具函数异常处理统一转成用户可读错误信息下面展开说三个最常见的坑。5.1 坑 1模型没有按预期调用工具很多新手在天气助手上碰到的问题不是代码报错而是模型直接回答“我无法获取实时天气”。原因是模型看到工具描述后需要判断当前用户问题是否需要调用工具。如果系统提示词只写了“请用中文回答”模型可能认为“北京天气”只是常识问题不调用工具也能回答。推荐把系统提示词改得更明确你是一个智能助手。当用户询问天气、温度、湿度等实时信息时你必须调用get_weather工具获取数据不能凭记忆回答。同时检查工具描述是否包含足够触发条件。description写“获取指定城市的天气情况”已经比较明显如果还不行可以在其中补充触发示例“当用户提到天气、温度、穿衣建议时应调用该工具。”5.2 坑 2工具结果没有正确回传工具执行完成后需要按下面的格式追加到消息列表{ role: tool, tool_call_id: call_xxx, content: {\weather\: \晴\, \temperature\: 18} }新手常见错误是漏掉tool_call_id或者使用role: function。在 OpenAI 新版接口中工具结果消息必须使用role: tool并携带tool_call_id否则接口返回 400 或忽略工具结果。排查时可以先把message.tool_calls和messages完整打印出来逐项核对 ID 是否一致。5.3 坑 3上下文窗口预算没有控制随着多轮对话延长历史消息会占用越来越多的prompt_tokens。一个简单的兜底策略是保留系统提示词和最近 N 轮消息MAX_HISTORY 10 def trim_messages(messages: list) - list: head messages[:1] # system history messages[1:] if len(history) MAX_HISTORY * 2: history history[-(MAX_HISTORY * 2):] return head history这一版仍会保留用户和助手消息但对工具结果较多的场景还要考虑对工具结果做摘要。生产环境建议把上下文管理从“简单裁剪”升级为“摘要加裁剪”。6. 生产化建议与 AI 应用开发学习路径6.1 学习环境与生产环境的差异本地跑通的最小示例和生产系统之间还有不少距离。差异可以整理成一张清单维度学习环境生产环境配置.env手动读取配置中心或环境变量注入密钥托管模型地址固定服务端地址支持多环境、多模型切换错误处理让异常中断统一异常捕获、用户可读提示、告警日志命令行打印结构化日志、链路 ID、token 用量记录限流无按用户、按接口限流缓存无相同问题或同城市天气做短时缓存重试无对网络超时和 5xx 做指数退避重试监控手动看输出请求成功率、平均耗时、token 成本、模型报错这些内容不是一次全上而是根据业务重要程度逐步补齐。最优先应该做的是密钥管理和日志其次是限流和成本监控。6.2 稳定调用重试、超时和降级大模型接口不是永远稳定。网络抖动、限流、瞬时过载都可能出现。推荐用tenacity做重试from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type from openai import APITimeoutError, APIConnectionError retry( stopstop_after_attempt(3), waitwait_exponential(multiplier1, min2, max30), retryretry_if_exception_type((APITimeoutError, APIConnectionError)), ) def call_model_with_retry(messages): return client.chat.completions.create(modelMODEL, messagesmessages, toolsTOOLS)注意APITimeoutError和APIConnectionError的导入路径根据 OpenAI SDK 版本可能不同落地前先查当前 SDK 文档。如果服务不可用不要无限重试应设置最大尝试次数并返回友好提示。降级方案也很重要。例如天气服务挂了可以返回“天气服务暂时不可用请稍后再试”同时记录告警。不要让用户看到一大段异常栈。6.3 工具函数的生产化设计示例中的get_weather是模拟数据生产化时要考虑外部 API 超时和错误码转换。结果字段过滤避免把敏感或无用字段传给模型。调用鉴权不允许任意用户通过 Prompt 诱导工具执行非授权操作。对工具调用参数做白名单校验例如城市名长度、日期格式。对工具执行耗时做超时控制避免 Agent 循环长时间卡住。当工具数量超过 5 个时还要考虑工具的发现和选择。可以用工具分组、别名或索引顺序来帮助模型准确选择。6.4 AI 应用开发学习路线清单如果是从零开始接触这个方向可以按下面顺序学习提示词工程掌握角色设定、Few-shot、思维链、结构化输出。大模型 API 基础调用 Chat 接口理解 system、user、assistant 消息角色。函数调用实现一个带天气或计算器工具的 Agent。检索增强生成RAG把本地文档切分、向量化、检索后作为上下文。Agent 流程编排把工具调用、循环、终止条件、任务拆分写清楚。评估与回归准备一组测试用例验证模型回答是否稳定。可观测性记录每次请求的输入、输出、token、模型名、延迟和错误码。安全与合规输入过滤、输出审核、密钥管理和权限控制。每一步都可以配合一个小项目用函数调用实现一个计算器。用 RAG 做一个内部文档问答机器人。用工具调用做一个工时估算助手。用多轮消息管理做一个客服对话机器人。6.5 扩展方向Spring AI、多 Agent 与 AI 自动化测试如果团队主力是 Java可以关注 Spring AI。它提供ChatClient、ToolCalling、Advisor等抽象让 Java 项目也能快速接入大模型和工具调用。核心思路与前面的 Python 示例一致模型负责理解和决策业务代码负责工具执行和流程控制。再往外扩展可以研究多
返回列表