☰
Agent开发实战:从概念到千问本地部署与工具调用
2026/10/27 1:34:35 网站建设 项目流程

最近技术圈有个消息热度很高:前千问负责人林俊旸再次创业,新公司方向直接瞄准 Agent,腾讯跟投。虽然具体产品形态还不算清晰,但资本和顶尖 AI 从业者同时押注 Agent,本身就说明这件事到了值得认真对待的阶段。

对开发者来说,这波热度的核心其实是机会:Agent 开发正在从概念走向工程化。市面上关于 Agent 的资料很多,但大部分要么偏概念、要么只讲框架 API,真正能把原理、手写代码、模型部署、坑点串起来的教程很少。这篇文章以 Agent 开发为主线,结合千问系列开源模型的使用经验,从概念拆解到最小可运行案例,再到本地模型部署和排错清单,完整走一遍。无论你是刚接触大模型开发的学生,还是已经在做 AI 应用的后端工程师,都可以从中找到能直接上手的内容。

读完这篇文章,你会理解 Agent 为什么不是简单的提示词模板;会亲手实现一个能调用工具的 Agent;会掌握在线 API 和本地模型两种接入方式;还会知道本地部署千问这类开源模型时会踩哪些坑。

1. 为什么 Agent 突然成了大模型落地的关键方向

1.1 Agent 是什么,它和聊天机器人有什么区别

很多人刚开始接触 Agent 时,最容易把它和聊天机器人混为一谈。聊天机器人的能力边界是“对话”:用户问一句,模型答一句,即使有多轮上下文,本质上还是在生成文本。Agent 则不一样,它的目标不是“回答”,而是“完成任务”。

一个典型 Agent 的工作方式是这样的:用户提出目标,Agent 先判断需要哪些信息,然后决定调用什么工具、按什么顺序执行,最后根据工具返回结果继续推理,直到给出最终结论或执行完整套动作。比如“帮我查一下北京明后天天气,并制定一份出行计划”,聊天机器人只能根据训练数据或上下文大概说一下,Agent 却可以主动去调用天气 API、读取日历、拆分任务,最后产出一份真正有依据的计划。

所以更准确地说,Agent 是一个以 LLM 为决策核心的自主系统。它把模型的语言理解能力、推理能力和外部工具的执行能力组合在一起,形成“感知 → 决策 → 行动 → 反馈”的闭环。

1.2 Agent 的四个核心要素

一个能完成任务的 Agent,通常包含四个核心要素:

  • 规划:把复杂目标拆分成可执行的子任务,决定每一步做什么。常用方式包括思维链、任务分解、ReAct 循环。
  • 记忆:保存对话历史、任务状态和长期知识。短期记忆对应模型的上下文窗口,长期记忆通常落在向量数据库或普通数据库里。
  • 工具:让 Agent 能和外部世界交互的能力,比如查天气、搜网页、执行代码、操作数据库。工具通常以函数或 HTTP API 的形式暴露给模型。
  • 行动:把模型的决策真正执行出去,并把执行结果重新喂给模型,供下一轮决策使用。

这四个要素缺一不可。没有规划,Agent 就是一个单步问答;没有记忆,它无法处理多轮任务;没有工具,它只能纸上谈兵;没有行动闭环,所有决策都无法落地。

1.3 Agent 赛道为什么会受到资本关注

林俊旸此前负责千问相关业务,属于大模型领域非常核心的技术负责人,他再次创业选择 Agent 方向,加上腾讯跟投,说明资本市场对 Agent 的商业化路径已经有共识:大模型本身很难直接变成产品,但“大模型 + 工具 + 流程”的 Agent 可以嵌入真实业务,成为客服、运营、数据分析、代码开发等场景的自动化执行体。

从就业和技术发展角度看,Agent 也正在成为新的岗位方向。搜索热词里已经能看到大量与 agent 相关的需求,比如 agent 开发、agent 框架、agent 安全、agent 记忆、agent 面试题。这意味着市场不再只关心“会不会调 API”,而是关心“能不能用模型构建可靠的多步骤系统”。

1.4 Agent 与工作流、RAG 的边界

在 AI 应用开发中,还有两个经常和 Agent 并列的概念:工作流(Workflow)和 RAG(检索增强生成)。它们之间不是替代关系,而是互补关系。

RAG 解决的是“模型知识不够”的问题。模型训练数据有截止时间,也有领域盲区,RAG 通过引入外部知识库,让模型在回答前先检索相关资料。但 RAG 本身不会做多步决策,它只是给模型喂更多上下文。

工作流解决的是“流程固定”的问题。比如先做意图识别,再查数据库,再调用大模型生成回答,整个过程是预先编排好的,每一步都很确定。工作流适合规则清晰的业务。

Agent 的价值在于“决策不确定”。它面对的任务可能有多条路径,需要模型根据实际情况判断下一步该调用哪个工具、是否需要继续执行。在真实项目里,三者经常组合使用:用 RAG 提供知识,用工作流兜底主流程,用 Agent 处理分支和异常情况。有些框架还会把 Agent 的运行时称为 harness,本质上是把模型、工具、记忆装进一个受控执行环境,你只需要关注决策逻辑,不用关心进程调度和上下文管理。

2. Agent 的核心技术架构拆解

2.1 大模型底座:Agent 的“大脑”

Agent 的决策能力完全来自底层大模型。模型的理解能力、指令跟随能力和函数调用能力,直接决定了 Agent 的上限。

当前开发 Agent 有两种主流路线。第一种是使用在线 API,比如千问 DashScope 的 OpenAI 兼容模式,优点是开箱即用、模型能力较强、不需要自己维护显卡。第二种是本地部署开源模型,比如通过 Ollama、LM Studio、vLLM 加载千问系列模型,优点是数据不出内网、调用成本可控、可以深度定制,但需要自己处理显存、量化和性能问题。

需要特别注意的是,并不是所有模型都适合做 Agent。做 Agent 需要模型能够准确理解工具描述,并输出符合 JSON 结构或函数签名要求的调用结果。如果模型指令跟随能力较弱,经常会出现工具名写错、参数缺失、格式不合法等问题。所以在选型时,要优先选择明确支持 Function Calling 或在 Agent 场景上有过优化的模型。

2.2 规划能力:任务拆解与 ReAct 循环

Agent 最常见的规划模式是 ReAct,也就是 Reason + Act 的循环。它的核心思想是让模型交替进行推理和行动:

  1. 模型观察当前问题,给出下一步思考。
  2. 根据思考选择一个工具并给出调用参数。
  3. 程序执行工具,把结果返回给模型。
  4. 模型根据新信息继续推理,决定是再调用工具还是给出最终答案。

这种循环不需要提前写好所有分支,模型会根据实际结果动态调整策略。下面是一个简化后的循环过程:

用户:北京今天适合出门吗? 模型:需要先查北京天气。 模型:调用 get_weather(city="北京") 工具:返回“晴,15℃~27℃” 模型:天气晴且温度舒适,适合出门。 模型:适合出门,记得带件薄外套。

在代码层面,循环的终止条件通常有两类:一是模型输出最终答案,不再调用任何工具;二是程序设置了最大步数限制,防止模型陷入死循环。后文实战部分会实现这个闭环。

2.3 记忆系统:短期记忆与长期记忆

记忆是 Agent 容易被忽略、却在真实项目中非常重要的部分。短期记忆就是消息序列本身,模型每次决策都要依赖对话历史。问题是上下文窗口有限,超过窗口后最早的信息会被丢弃,Agent 就会“失忆”。

长期记忆用于解决跨会话的问题。比如 Agent 是客服助手,它需要记住用户上次报修的设备型号;Agent 是数据分析助手,它需要记住项目背景信息。长期记忆通常由向量数据库承载,把文本转成向量存储下来,使用时通过语义检索找回相关性最高的内容。

工程上还可以做记忆分层:核心任务状态放内存或 Redis,长期知识放向量库,敏感数据放权限管控的数据库。不要把全部历史都塞进上下文,否则 token 成本会不可控地增长。

2.4 工具调用:Function Calling 的原理

工具调用是 Agent 区别于普通聊天机器人的关键能力。它的原理并不神秘:模型并不会真的去执行函数,它只是根据用户问题和工具描述,输出一个“调用意图”和“参数”,真正的函数执行由外部程序完成。

如果使用原生 Function Calling,模型接口会提供tools参数,开发者把工具的名称、描述和参数结构传给模型,模型返回的tool_calls字段里会包含具体调用信息。程序拿到后执行对应函数,再把结果以tool角色的消息传回模型。

如果不使用原生 Function Calling,也可以采用文本协议:在系统提示词里告知模型所有工具及其参数格式,要求模型输出特定 JSON,比如:

{"name": "get_weather", "arguments": {"city": "北京"}}

程序负责解析 JSON、判断工具是否存在、检查参数合法性、执行函数并回填结果。这种方式兼容性更强,适合本地小模型或在线模型未开放 function calling 的场景。

2.5 行动闭环:Agent 如何与环境交互

行动层关注的是“工具执行以后会发生什么”。最简单的行动就是调用 Python 函数,但真实场景里还包括:调用第三方 HTTP 接口、读写数据库、执行 Shell 命令、操作浏览器、发送消息等。

行动层是安全风险最集中的地方。一个 Agent 如果被提示词注入恶意指令,又拥有执行命令的权限,后果会非常严重。所以生产环境的行动层一定要做权限控制:工具最小化授权、敏感操作人工确认、代码执行放在沙箱、所有行动记录日志。这些内容会在第八章展开。

3. 环境准备与版本说明

3.1 开发环境选择

本文的代码示例以 Python 为主,建议使用 Python 3.10 或更高版本。版本需要根据你的项目实际情况调整,本文示例以常见环境为例,重点演示配置思路。

除了 Python 本身,只需要两个第三方库:

  • requests:用于调用模型服务接口。
  • python-dotenv:用于读取.env配置文件。

如果你不想安装python-dotenv,也可以直接用环境变量或把配置硬编码在代码里,但生产环境不推荐硬编码密钥。

3.2 模型服务的两种接入方式

为了让实战代码既能连接在线 API,也能连接本地模型,我会使用 OpenAI 兼容接口格式。现在很多模型服务都提供这种格式,包括千问在线 API 和 Ollama 本地服务。

两种方案的对比如下:

接入方式服务地址模型名称示例适用场景
Ollama 本地http://localhost:11434/v1qwen2.5离线开发、数据敏感、成本敏感
千问在线 API以官方文档兼容模式地址为准模型名以官方列表为准需要更强模型能力、不想维护显卡

在下面的最小实战中,默认使用 Ollama 本地服务,这样代码开箱即可运行,在线接入只需要修改环境变量。

3.3 推荐项目结构

整个实战项目建议保持简洁:

agent-demo/ ├── .env ├── requirements.txt ├── tools.py └── agent.py

.env保存配置,tools.py定义工具函数,agent.py实现 Agent 主循环。这样拆分的好处是:工具函数可以独立测试,Agent 逻辑保持纯粹,后续新增工具不用频繁改动主程序。

4. 从零实现一个最小 Agent:代码实战

4.1 需求与设计

我们要实现一个能查天气的 Agent。用户会以自然语言提问,比如“北京今天适合出门吗”。Agent 需要完成以下流程:

  1. 判断是否需要查询天气。
  2. 如果需要,调用get_weather工具。
  3. 拿到工具结果后,结合结果给出最终回答。
  4. 如果用户问题不需要任何工具,直接回答。

这个需求体现了 Agent 的核心特征:工具调用、结果回填、多轮决策。虽然业务很简单,但代码框架可以复用到更复杂的场景。

4.2 定义工具函数

先创建tools.py,定义一个模拟的天气查询函数。真实项目里可以把这个函数替换成第三方天气 API,返回结构建议保持 JSON 字符串或字典。

# 文件路径:agent-demo/tools.py def get_weather(city: str) -> str: """模拟查询天气。真实项目可替换为第三方 API。""" weather_data = { "北京": "晴,15℃~27℃,西北风3级", "上海": "多云,18℃~25℃,东风2级", "广州": "雷阵雨,20℃~28℃,南风3级", } return weather_data.get(city, f"暂未收录 {city} 的天气数据")

为了让工具描述能够自动生成系统提示词,需要在 Agent 中维护一个工具注册表。注册表里包含工具名称、描述、参数格式和对应的执行函数。

4.3 实现 Agent 主循环

接下来创建agent.py,这是整个项目的核心。先看完整代码,然后逐步解释。

# 文件路径:agent-demo/agent.py import json import os import re import requests from dotenv import load_dotenv from tools import get_weather load_dotenv() # 模型服务配置 BASE_URL = os.getenv("BASE_URL", "http://localhost:11434/v1") API_KEY = os.getenv("API_KEY", "ollama") MODEL = os.getenv("MODEL", "qwen2.5") # 工具注册表 TOOLS = [ { "name": "get_weather", "description": "查询指定城市的天气情况", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名,例如北京、上海、广州", } }, "required": ["city"], }, "function": get_weather, } ] MAX_STEPS = 5 def build_system_prompt() -> str: """根据工具注册表自动生成系统提示词。""" lines = [ "你是一个能够调用工具完成任务的 AI 助手。", "如果需要调用工具,请只输出如下 JSON 格式,不要输出任何多余内容:", '{"name": "工具名", "arguments": {"参数名": "参数值"}}', "", "可用工具如下:", ] for tool in TOOLS: lines.append( f"- {tool['name']}: {tool['description']}," f"参数: {json.dumps(tool['parameters'], ensure_ascii=False)}" ) lines.append("") lines.append("拿到工具结果后,请根据结果用自然语言回答用户。") return "\n".join(lines) def extract_json(text: str) -> dict: """从模型输出中解析 JSON,兼容 markdown 代码块包裹的情况。""" text = text.strip() # 去掉可能的 markdown 代码块标记 if text.startswith("```"): text = re.sub(r"^```(?:json)?\s*", "", text) text = re.sub(r"\s*```$", "", text) start = text.find("{") end = text.rfind("}") if start == -1 or end == -1: raise ValueError("输出中没有找到 JSON 对象") return json.loads(text[start : end + 1]) def call_llm(messages: list) -> dict: """调用 OpenAI 兼容的 chat/completions 接口。""" payload = { "model": MODEL, "messages": messages, "temperature": 0.2, } resp = requests.post( f"{BASE_URL}/chat/completions", headers={"Authorization": f"Bearer {API_KEY}"}, json=payload, timeout=60, ) resp.raise_for_status() return resp.json()["choices"][0]["message"] def execute_tool(tool_call: dict) -> str: """根据模型输出的调用信息执行工具。""" name = tool_call.get("name") args = tool_call.get("arguments", {}) for tool in TOOLS: if tool["name"] == name: return str(tool["function"](**args)) return f"未知工具: {name}" def run_agent(user_input: str) -> str: """Agent 主循环。""" messages = [ {"role": "system", "content": build_system_prompt()}, {"role": "user", "content": user_input}, ] for step in range(MAX_STEPS): print(f"[step {step + 1}] 调用模型...") msg = call_llm(messages) content = msg.get("content", "") print(f"[模型输出] {content}") # 尝试解析工具调用,不是 JSON 则视为最终回答 try: tool_call = extract_json(content) except (ValueError, json.JSONDecodeError): return content # 校验工具名是否存在 tool_names = {t["name"] for t in TOOLS} if tool_call.get("name") not in tool_names: return "模型输出了不合法的工具调用:" + content # 执行工具并回填结果 result = execute_tool(tool_call) print(f"[工具结果] {result}") messages.append({"role": "assistant", "content": content}) messages.append( { "role": "user", "content": f"工具 {tool_call['name']} 返回结果:{result}\n" "请根据结果继续回答用户问题。如果信息已足够,请直接给出最终答案。", } ) return "已达到最大步骤数,未能生成最终答案。" if __name__ == "__main__": answer = run_agent("北京今天适合出门吗?") print("\n最终回答:") print(answer)

这段代码有几个设计要点:

  • 系统提示词由工具注册表自动生成,新增工具时不用手动维护提示词。
  • extract_json做了容错,兼容了模型输出 markdown 代码块的情况。
  • execute_tool通过工具名查找函数,避免直接执行任意模型输入,降低安全风险。
  • 主循环里每轮都会把模型输出和工具结果回填到消息列表,让模型在下一轮能感知到完整的执行过程。

4.4 配置环境变量并运行

创建.env文件,默认配置指向本机 Ollama:

BASE_URL=http://localhost:11434/v1 API_KEY=ollama MODEL=qwen2.5

如果你使用在线千问 API,可以把BASE_URL改成官方文档中的 OpenAI 兼容模式地址,API_KEY改成你的密钥,MODEL改成对应的模型名称。

创建requirements.txt:

requests python-dotenv

安装依赖并运行:

pip install -r requirements.txt python agent.py

注意:如果使用本地 Ollama,需要先确保模型已经拉取:

ollama pull qwen2.5 ollama serve

4.5 运行结果与原理说明

预期输出大致如下:

[step 1] 调用模型... [模型输出] {"name": "get_weather", "arguments": {"city": "北京"}} [工具结果] 晴,15℃~27℃,西北风3级 [step 2] 调用模型... [模型输出] 北京今天天气晴,气温在15℃到27℃之间,风力不大,比较舒适,适合出门。建议带一件薄外套。 最终回答: 北京今天天气晴,气温在15℃到27℃之间,风力不大,比较舒适,适合出门。建议带一件薄外套。

从结果可以看到,Agent 在第一轮没有直接回答,而是先输出了工具调用指令;程序执行工具后把结果回填给模型;模型在第二轮根据真实天气数据给出了有依据的回答。整个过程就是一个最小可用的 ReAct 闭环。

这个示例采用的是“文本 JSON 协议”约定工具调用,不属于模型原生的 function calling。它的好处是兼容各种模型服务,只要模型能输出合法 JSON 即可。生产环境如果模型服务支持原生函数调用,更推荐使用原生方式,比如 OpenAI 兼容接口的tools参数,参数校验和错误处理会更规范。

5. 用框架快速搭建 Agent:框架选型与编排思路

5.1 要不要用框架

手写最小 Agent 能帮助理解原理,但真实项目中通常不建议从零构建。原因是 Agent 涉及很多工程细节:上下文管理、工具调用异常、重试机制、成本统计、可视化调试、多 Agent 协作等,轮子已经有人造好了。

使用框架并不意味着“黑盒调用”。框架的价值在于把通用问题抽象好,让开发者把精力集中在业务工具和提示词上。不过框架 API 变化通常较快,尤其是 LangChain 这类大型框架,升级版本时经常出现接口变动。因此,选择框架时需要评估团队的维护成本,并锁定版本。

5.2 主流框架速览

框架/工具定位适用场景
LangChain通用 LLM 应用框架要灵活编排 Agent、链、RAG 的中大型项目
LlamaIndex数据与 RAG 框架知识库问答、文档分析为主,也支持 Agent
AutoGen多 Agent 对话框架需要多个 Agent 协作解决问题的研究原型
Dify开源 LLM 应用平台希望可视化编排、快速交付产品的团队

如果你还是新手,建议先用 Dify 这类带界面的平台把 Agent 跑通,观察工具调用链,再回到代码层面深入框架。

5.3 Dify 可视化编排 Agent 的关键步骤

以 Dify 这类开源编排平台为例,核心步骤通常包括:

  1. 创建应用时选择 Agent 类型,而不是简单的聊天应用。
  2. 在模型供应商中配置可用模型。因为 Dify 支持 OpenAI 兼容接口,所以本地 Ollama 和千问在线 API 都可以配置。
  3. 编写系统提示词。提示词里需要明确 Agent 的任务边界、工具使用规则和最终答案输出格式。
  4. 添加工具。平台通常内置搜索、计算等工具,也支持按 OpenAPI 规范导入自定义 HTTP 工具。
  5. 调试对话。观察模型每一步的工具调用、参数和返回结果。
  6. 发布应用。Dify 能生成 Web 页面或 API 服务,方便快速集成到业务系统。

5.4 工作流编排与自主 Agent 怎么选

在实际产品中,不要一上来就全用“自主 Agent”。判断标准很简单:任务路径是否确定性高。如果任务流程固定,比如“先鉴权,再查库存,再生成测试报告”,用工作流更稳定、成本更低。如果任务有较多分支和不确定性,比如“根据用户模糊描述判断客服工单应该转给哪个部门,并生成初步处理方案”,自主 Agent 更合适。

更常见的是混合模式:主流程用工作流控制,遇到分支和异常时调用 Agent 子任务。这样既能保证核心流程稳定,又能利用模型的灵活性处理非确定性问题。

6. 千问模型的本地部署与性能调优

6.1 本地部署三条路线

本地部署开源模型的工具很多,最常见的三条路线是:

  • Ollama:安装简单,一条命令就能拉取并启动模型,提供 OpenAI 兼容接口,适合开发调试和个人使用。
  • LM Studio:带图形界面,适合不熟悉命令行的开发者,可以直观管理 gguf 模型文件,也能暴露本地 HTTP 服务。
  • vLLM:吞吐量高,适合生产环境的模型服务,但部署复杂度也更高,通常需要更精细的显存和并发配置。

对 Agent 开发来说,开发阶段用 Ollama 或 LM Studio 就足够了。生产环境如果对延迟和吞吐有要求,可以切换到 vLLM。

6.2 Ollama 接入千问并启动服务

安装 Ollama 后,先用命令行拉取模型:

ollama pull qwen2.5

拉取完成后启动服务:

ollama serve

默认情况下,Ollama 的 OpenAI 兼容接口地址是http://localhost:11434/v1。前面章节的agent.py默认配置就是基于这个地址,所以只要模型拉取成功,代码可以直接运行。

6.3 “本地模型很慢”的排查思路

“本地模型很慢”是个高频问题,很多人一上来就以为是显卡不够,其实不一定。建议按以下顺序排查:

  1. 检查是否真的使用了 GPU。Ollama 默认会自动卸载层到 GPU,但 LM Studio 等工具可能需要手动设置 GPU Offload。如果模型完全跑在 CPU 上,速度会慢很多。
  2. 检查量化等级。同样一个模型,FP16 精度比 Q4 量化显存占用高很多,速度也更慢。本地消费级显卡建议优先使用 Q4_K_M 或 Q5_K_M 量化。
  3. 检查上下文长度。如果你把上下文设置成 32K 甚至更长,每步计算量会明显增加。Agent 场景可以先从 4K 或 8K 开始,确认效果后再逐步加长。
  4. 检查推理线程数。CPU 推理时线程数太少会拉低性能,但线程数设置超过物理核心数也没有意义。
  5. 检查是否有多进程抢占。如果同一块显卡上同时跑多个模型服务,显存和计算单元都会争抢。

如果模型仍很慢,可以考虑降低模型规模。比如 27B 量级的模型双卡跑不动时,改用 7B 或 14B 量级的量化版本,体验会流畅很多。

6.4 多卡与边缘设备部署注意事项

对于几十 B 量级的开源模型,常见方案是用多张消费级显卡并行推理。比如两张 3090 共 48GB 显存,通常可以跑 27B 量级的量化模型,但需要注意几个问题:

  • 多卡并行会引入跨卡通信开销,实际加速比并不是线性增长。
  • KV cache 会随上下文长度增长,需要预留足够显存。
  • 量化格式要统一,混合使用不同量化策略可能导致推理崩溃或结果异常。

边缘设备部署,比如 RK3588 这样的 ARM 平台,挑战更大。这类设备通常有 NPU,但大模型算子对 NPU 的适配并不完整,很多场景实际是 CPU 推理,内存带宽会成为瓶颈。如果需要边缘部署,一定要先用目标设备实测吞吐和延迟,不要只看规格参数。

6.5 gguf 模型文件选择与下载注意事项

gguf 是本地推理工具最常用的模型格式,Ollama 和 LM Studio 都能直接使用。选择 gguf 文件时要注意以下几点:

  • 看清量化等级。文件名里的Q4_K_M、Q5_K_M表示不同量化精度,精度越低占用显存越小,但效果也会有所下降。
  • 确认文件完整性。大文件下载过程中容易损坏,加载失败时可以比对 SHA256 或重新下载。
  • 注意模型来源。不要随意下载来路不明的 gguf 文件,尽量选择官方或可信渠道发布的内容,避免恶意权重或后门风险。
  • 如果使用 Ollama,不需要手动下载 gguf,直接用ollama pull拉取即可;Ollama 对模型文件有自己的管理方式。

如果在 CC Switch 等模型管理工具里看不到刚下载的模型,常见原因是模型文件没有放到工具指定的 models 目录,或者工具没有刷新模型列表。把 gguf 文件移动到目录后重启工具,或者手动刷新,通常可以解决。

7. Agent 开发中的高频问题与排查思路

Agent 开发比普通 API 调用更容易出问题,因为它是多步循环,任何一步出错都会影响最终结果。下面整理了一些高频问题。

问题现象常见原因解决思路
Agent 执行时报agent execution provider did not respond in time模型服务响应超时,或某一步工具执行时间过长检查模型 API 是否正常,调大超时时间,减少单步任务量,必要时拆分步骤
模型输出不是合法 JSON,工具调用失败模型没有严格遵循输出格式系统提示词强调格式;换用原生 function calling;加入 JSON 解析容错和重试机制
Agent 陷入重复调用同一个工具的死循环缺乏终止条件或工具结果没有让模型获得新信息设置最大步数;要求模型基于结果直接回答;在工具结果中补充更清晰的信息
多轮对话后上下文超过模型限制记忆没有做压缩或裁剪实现滑动窗口、摘要压缩、向量检索式长期记忆
本地模型回答很慢没有用 GPU、量化等级过高、上下文过长、设备带宽不足按 6.3 节的顺序逐项排查
工具执行成功但结果不理想工具描述不清晰,模型传错参数或理解错意图完善工具 description;参数尽量少并提供默认值;增加参数校验
Agent 在敏感环境执行了风险操作工具权限过大,缺少人工确认最小权限授权;敏感操作需要人工审批;代码放入沙箱执行

下面重点展开几个高频问题。

第一个是超时问题。很多 Agent 运行时会在网络层设置默认超时,比如 30 秒。如果模型本身要生成较长内容,或者工具调用链很长,单步很容易超时。解决方案是分层设置超时:模型 API 调用设置一个较宽的超时,比如 60 秒;整个 Agent 流程设置总预算时间和最大步数,超预算后主动返回部分结果给用户,而不是一直阻塞。

第二个是工具调用格式问题。小模型尤其容易出现“模型在 JSON 外面加了说明文字”“工具名拼错”“参数名和工具定义不一致”。处理方式有三层:第一层是在提示词里给出标准示例;第二层是在代码里做容错解析和自动纠错;第三层是解析失败时把错误信息回传给模型,让它自己修正后再试一次。如果模型原生支持 function calling,优先用它,格式正确率会明显更高。

第三个是死循环问题。死循环的根因通常是模型认为“我还需要执行某个工具”,但工具结果并没有带来足够的信息。解决方案是:在系统提示词里明确“当工具结果已返回,且信息足以回答用户时,必须直接输出最终答案,不要重复调用工具”;同时设置最大步数,防止异常情况拖垮整个服务。

第四个是上下文膨胀。Agent 每执行一步,都要把模型输出、工具结果、汇总消息重新塞回 messages。步数多了以后,很快会触达上下文窗口。简单粗暴的滑动窗口会丢失关键任务状态,更稳妥的做法是:关键状态单独存储,上下文只保留最近 N 轮,历史信息按轮次生成摘要后在后续对话中引用摘要。

8. Agent 工程化的最佳实践与安全建议

8.1 工具设计规范

工具是 Agent 与世界的接口,设计质量直接影响成功率。推荐遵循以下规范:

  • 命名要语义化。工具名尽量使用“动词 + 名词”的格式,比如get_weather、create_order,不要用func1这种无意义名称。
  • 描述要像写 API 文档。描述里要写清楚工具能做什么、什么场景用、需要哪些参数、参数取值范围。模型完全靠描述决定是否调用工具,描述越模糊,调用越容易出错。
  • 参数越少越好。一个工具的参数超过五个,模型传错的概率会显著上升。能合并的参数就合并,能给默认值的就给默认值。
  • 返回值要结构化。尽量返回 JSON,而不是一长串人类可读文本。结构化返回值便于模型理解,也便于程序做后续处理。
  • 工具要有错误返回。比如查不到城市时,不要抛出异常,而是返回“未查询到该城市天气”,让模型有机会追问用户或改用其他方式处理。

8.2 提示词与模型约束

Agent 的系统提示词比普通问答的提示词更关键,需要做到以下三点:

第一,明确工具调用格式。给出一个标准示例,并说明“除非调用工具,否则不要输出 JSON”。

第二,明确任务边界。说明哪些情况必须调用工具,哪些情况直接回答。比如“当用户问天气时,必须先调用 get_weather

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询