大模型产品越来越普及,但绝大多数用户的日常使用方式,仍然停留在打开一个聊天框,输入一句话,等待一段文本回复。Agent 的概念被反复提起,企业也在讨论智能体、工作流、自动化,真正动手把 Agent 落地的人却不多。造成这种反差的原因并不复杂:聊天框接住的是模型的文本生成能力,而 Agent 需要使用模型去做规划、调用工具、观察结果、修正动作,直到完成任务。下面先从两者的本质差异讲起,再结合一个最小可运行的 Agent 开发案例,说明从聊天框走向 Agent 到底需要补哪些能力,最后给出框架选型、常见坑和学习路线。
1. 聊天框和 Agent 之间,差的不是模型而是执行闭环
1.1 聊天框的本质是一次性推理
聊天框的交互模式可以用一句话概括:用户输入,模型输出。即使支持多轮对话,模型内部处理的也只是上下文里的历史消息,并没有真正"做事"的能力。它给出的是建议、文案、代码片段或分析结果,最终执行动作的仍然是人。
这种模式适合信息咨询、内容生成、代码辅助和知识问答。它的优点是把使用门槛降到最低,缺点是任务一旦需要外部数据、需要操作业务系统、需要多步骤判断,模型的单次输出就不够用了。你让聊天框里的模型"帮我查一下本月的订单量",模型如果没有数据库连接、没有 API 调用能力,就只能回答"我无法直接查询",或者根据训练记忆编一个数字。
1.2 Agent 的本质是感知-规划-行动-反馈闭环
Agent(智能体)在工程上的定义并不神秘:它是一个能够在目标驱动下,自主决定调用哪一类工具、按什么顺序执行、如何根据中间结果调整下一步的程序。核心结构包含四个部分:
- 感知:获取用户目标,必要时读取外部状态、环境信息或工具返回结果。
- 规划:把任务拆成步骤,决定先做什么、后做什么。
- 行动:调用函数、API、数据库或命令行等工具。
- 反馈:观察工具执行结果,判断是否完成目标,未完成就继续下一轮。
聊天框之所以让人感觉"不够聪明",不是模型变笨了,而是它缺少后面这半条链路。把文本生成模型接上工具调用和循环控制,才算真正进入 Agent 的使用方式。
1.3 为什么 Agent 更有价值,也更难做好
单纯让模型输出一段文字,价值取决于模型的文字能力;让模型完成任务,价值取决于任务完成的质量和可靠性。这也是企业愿意为 Agent 付钱的原因:它可以自动完成报表生成、工单处理、客服回访、数据清洗等重复流程。
但"更难做好"也是事实。Agent 引入了三个新的复杂度:
- 工具是否真的可用:参数格式、鉴权、超时、错误码都需要处理。
- 模型的规划是否靠谱:模型可能拆错步骤、漏掉分支、陷入死循环。
- 结果是否可验证:工具执行成功不等于任务完成,需要在业务层面校验最终输出。
所以在学习 Agent 之前,先理解这一点:Agent 不是"更聪明的聊天框",而是一个需要设计状态流转和错误处理的工程系统。
2. 大多数人卡在聊天框,问题出在哪里
2.1 只用了对话接口,没有用工具调用接口
现在主流大模型厂商基本都提供了两类接口:一类是纯文本对话接口,传入消息数组,返回文本;另一类是工具调用(Function Calling / Tool Use)接口,模型可以在回答中提出"我需要调用某个函数,参数是什么",由你的代码来真正执行。
很多人只用过第一类接口。即使开发了应用,也只是把用户问题转发给模型,再把模型回复原样展示。这类应用本质上还是聊天框的 Web 化,并没有进入 Agent 范畴。判断一个应用是不是 Agent 应用,最简单的标准就看一条:程序里是否存在"模型建议动作、代码执行动作、结果回传模型"的循环。
2.2 习惯了"一问一答",缺少任务拆解意识
人使用聊天框的习惯是"把完整问题扔给模型",期望模型一次给出完整答案。但 Agent 的常见工作方式是先拆解,再执行。比如"分析这份销售数据并生成周报",聊天框思维是让模型直接输出周报;Agent 思维是:先找数据文件,再用代码读取和聚合,再判断数据异常,再调用文档生成接口输出周报。
缺乏拆解意识的人,即使拿到 Agent 框架,也不知道该怎么给模型定义工具、怎么设计步骤。从聊天框到 Agent,第一步是改变提问方式,改成"把任务拆成可执行的动作序列"。
2.3 低估了调试成本,也高估了接入门槛
实际接触 Agent 开发的人会体会到,真正的成本不在模型调用,而在调试。模型是概率系统,同样的输入可能给出不同的工具调用计划。一次工具调用失败后,模型能不能根据错误信息修正,直接决定任务是否可完成。
很多人以为装了 Agent 框架就等于有了 Agent,实际只接入了框架外壳,没有设计好工具描述、结果反馈和终止条件。反过来,也有人以为要自己实现全套多智能体架构才能开始,其实从单 Agent、单工具开始完全够用。这两种认知偏差,让很多人在门口转了很长时间。
3. 从聊天框到 Agent:以天气助手为例做最小可运行案例
这一节用一个常见场景说明完整思路。目标:用户输入"北京明天适合出门跑步吗",Agent 自动调用天气查询工具,根据返回结果再决定是否直接回答。
3.1 环境准备和项目结构
先准备一个 Python 3.10 以上环境,安装 OpenAI 兼容 SDK 和一个用于环境变量的库:
python -m venv venv source venv/bin/activate pip install openai python-dotenv如果使用国内可访问的大模型平台,只要它提供 OpenAI 兼容的/v1/chat/completions接口,代码基本可以复用,只需修改base_url和模型名。项目结构保持最小:
agent_demo/ ├── .env ├── main.py └── tools.py.env里写入:
API_BASE_URL=https://your-model-endpoint.example.com/v1 API_KEY=your_api_key MODEL_NAME=your_model_name这里不要直接把 Key 写死在代码里。学习阶段用环境变量,生产环境要用密钥管理服务,并严格控制读写权限。
3.2 定义一个可被模型调用的工具
工具的本质是一个普通函数,加上一段描述性的 JSON Schema。模型负责看懂描述,你的代码负责执行函数。
# tools.py import json import random def get_weather(city: str, date: str = "today") -> str: """查询指定城市天气的模拟工具。 实际项目中应替换为真实天气 API,这里用随机数据演示流程。 """ conditions = ["晴", "多云", "小雨", "阴"] result = { "city": city, "date": date, "condition": random.choice(conditions), "temperature_c": round(random.uniform(5, 30), 1), "wind_level": random.randint(1, 5), "source": "mock", } return json.dumps(result, ensure_ascii=False)工具函数本身不需要任何 Agent 框架知识。它的输入参数名、类型和 docstring 会提供给模型,模型依据这些信息决定要不要调用、传什么参数。
3.3 把工具描述传给模型
在主程序中,把工具以 JSON Schema 形式声明:
# main.py import json import os from dotenv import load_dotenv from openai import OpenAI from tools import get_weather load_dotenv() client = OpenAI( api_key=os.getenv("API_KEY"), base_url=os.getenv("API_BASE_URL"), ) TOOLS = [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市、指定日期的天气情况", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,例如 北京、上海", }, "date": { "type": "string", "description": "日期,例如 2025-06-01,默认 today", }, }, "required": ["city"], }, }, } ]工具描述写得越清楚,模型正确调用的概率越高。常见错误是 Description 太简短,或者参数名与函数签名不一致,导致模型传错参数。
3.4 用循环实现模型-工具-模型闭环
关键逻辑是这样:第一次调用模型,模型返回文本,或者返回一个工具调用请求。如果返回工具调用请求,你的代码执行对应函数,把结果作为新的消息返回给模型,模型再基于工具的结果继续回答。
def chat_with_agent(user_message: str) -> str: messages = [ {"role": "system", "content": "你是一个乐于助人的助手,需要查询天气时使用工具。"}, {"role": "user", "content": user_message}, ] max_rounds = 5 for _ in range(max_rounds): response = client.chat.completions.create( model=os.getenv("MODEL_NAME"), messages=messages, tools=TOOLS, ) message = response.choices[0].message if message.tool_calls: messages.append(message) for tool_call in message.tool_calls: if tool_call.function.name == "get_weather": args = json.loads(tool_call.function.arguments) tool_result = get_weather( city=args["city"], date=args.get("date", "today"), ) messages.append( { "role": "tool", "tool_call_id": tool_call.id, "content": tool_result, } ) continue return message.content or "" return "达到最大轮数,任务未完成。" if __name__ == "__main__": print(chat_with_agent("北京明天适合出门跑步吗?"))这段代码里最容易被忽略的是tool_call_id。模型发出多个工具调用时,每个工具结果消息必须绑定对应的tool_call_id,否则接口会报错。max_rounds是防线,防止模型或工具无限循环。
3.5 运行和验证
在agent_demo目录下执行:
python main.py正常输出类似:
明天北京多云,气温 18 度左右,风力 2 级。如果不下雨,可以考虑下午出门跑步,早晚降温记得加外套。判断 Agent 是否真正工作,不能只看最后这段文字,要看日志里是否存在这两个关键步骤:
- 模型先返回了
tool_calls,而不是直接输出文本。 - 工具执行后,模型基于工具结果再次生成回答。
建议在代码里打印消息轨迹,例如:
print("[Tool Call]", tool_call.function.name, args) print("[Tool Result]", tool_result)如果模型始终直接回答"我无法查询天气",说明模型不支持工具调用,或者工具描述格式有问题。这时先换成官方示例工具再测试,排除自身代码问题。
4. Agent 框架选型与 harness、agent 的关系
4.1 主流框架都在解决同一类问题
当工具数量和任务复杂度上去后,手写消息循环会越来越难维护。主流 Agent 框架做的事情可以归纳为:组织模型调用、工具执行、状态管理、记忆存储和任务编排。
下面用一张表梳理常见框架的关注点,具体版本和接口要以你选择的框架官方文档为准:
| 框架类型 | 解决的问题 | 适合场景 | 学习成本 |
|---|---|---|---|
| 轻量工具调用封装 | 简化 Function Calling 消息拼接和参数解析 | 单 Agent、少量工具 | 低 |
| 工作流编排框架 | 固定流程,节点可触发模型或工具 | 业务流程稳定、要求可控 | 中 |
| 通用 Agent 框架 | 规划、反思、工具选择、记忆管理 | 复杂任务、多步推理 | 高 |
| 多智能体框架 | 多个 Agent 分工协作、消息通信 | 角色分工明显的大型任务 | 高 |
不要一上来就选最重的框架。先用原生 Function Calling 跑通一个工具,再根据痛点选择框架,是成本最低的路径。
4.2 harness 和 agent 到底有什么区别
"Harness" 这个词在 Agent 开发中经常出现。简单理解,harness 是夹住模型的运行框架:它负责在模型与外部世界之间建立安全边界,管理工具注册、参数校验、上下文长度、循环终止条件、日志追踪。Agent 则是业务层面的智能体:它包含目标、工具集合、决策策略和记忆。
可以这样记:
- Agent 决定"要做什么"。
- Harness 负责"怎么安全地做"。
实际开发中,大多数通用 Agent 框架已经内置了 harness。你可以只关注 Agent 的业务逻辑。但如果你要对执行过程做严格审计、限制模型可用工具范围、控制每一步的最大 token 消耗,需要理解 harness 层的能力,而不是只在业务代码里打补丁。
4.3 学习环境和生产环境要分开对待
学习阶段,用模拟工具、本地文件、有限 API 就够了,核心是理解闭环机制。生产环境至少还要补这些能力:
- 工具鉴权与白名单,不让模型随意调用危险操作。
- 超时控制和轮次上限,防止费用失控和死循环。
- 全链路日志,记录每次模型输入、工具参数、返回结果和最终答案。
- 人工确认节点,高影响操作必须由用户确认后再执行。
- 版本回滚,模型提示词和工具描述变更要能快速回退。
5. 常见坑与排查路径
5.1 三个最容易踩的坑
第一个坑:模型不支持或未启用工具调用。表现是模型忽略tools参数,直接回复文本。检查模型名是否支持 Function Calling,查看平台文档确认是否需要额外启用开关。
第二个坑:工具结果格式不干净。工具返回的是普通字符串而不是结构化的 JSON,模型在解析时会出错或答非所问。工具返回结果尽量使用 JSON,并包含成功与否、错误原因等字段。
第三个坑:死循环和重复调用。模型反复调用同一个工具,或在一个失败结果上反复重试。原因是缺少终止条件、工具错误信息不明确、没有对相同错误做去重。解决方法是设置最大轮数,并在工具结果中给出可执行的修正建议,比如"参数 city 不能为空,请传入合法城市名"。
5.2 按现象定位问题的排查表
| 现象 | 可能原因 | 优先检查 | 处理方向 |
|---|---|---|---|
| 模型从不调用工具 | 模型不支持工具调用、tools 格式错误 | 打印请求参数,对照官方示例 | 更换模型、修正 Schema |
| 工具调用后报错 | tool_call_id 不匹配、参数缺失 | 检查消息列表中的 tool 消息 | 每个工具结果绑定正确 id |
| 回答内容与工具结果不一致 | 系统提示词与工具结果矛盾、模型幻觉 | 打印最终 messages | 把工具结果显式放入上下文 |
| 任务跑到 max_rounds | 规划失败、工具返回错误无法恢复 | 查看每一轮 tool result | 优化工具描述和错误提示 |
| 接口返回 400 | 消息格式不符合接口规范 | 保存完整请求体 | 按官方 schema 逐字段核对 |
| 费用异常增长 | 循环过长、重复调用 | 看日志中调用次数 | 加轮次限制、缓存相似结果 |
| 框架报错 agent execution terminated due to error | 中间节点异常或超过终止条件 | 查看节点级日志和上一轮结果 | 定位失败节点,补错误处理和重试 |
排查时遵循一个原则:先看输入输出,再看中间消息。把每轮的模型输出和工具返回值打印出来,绝大多数问题就清晰了。
6. 从聊天框到 Agent 的行动路线和最佳实践
6.1 按这个顺序学习,而不是直接追新技术
如果现在完全没接触过 Agent,推荐按下面顺序推进:
- 用脚本完成一次带 Function Calling 的模型调用,理解消息数组结构。
- 实现一个单工具闭环,比如查天气、查数据库、执行计算器。
- 增加两个以上工具,让模型根据任务选择不同工具。
- 增加错误处理:工具失败后把错误信息回传模型,观察模型能否重新规划。
- 使用一个轻量框架重构代码,比较手写与框架的差异。
- 再考虑记忆、多 Agent 协作、流程编排等复杂能力。
每一步都要留下一个可运行脚本和一个验证结果。比如第 2 步的验证结果是模型正确调用工具并引用结果回答,第 4 步的验证结果是工具故意返回错误时模型能说明原因并尝试换一种方式。
这里还要区分三条不同的增强路线。大模型微调、RAG(检索增强生成)、Agent 解决的是不同问题:微调改变模型本身的知识和行为,RAG 让模型接入外部知识库,Agent 让模型接入外部动作能力。很多人把三件事混在一起理解,结果既没学好 Agent,也没搞清 RAG 的边界。建议先做 Agent 工具调用闭环,再根据实际瓶颈决定是否需要另外两条路线。
6.2 设计工具和提示词时遵守几条可执行原则
工具描述用动词开头,说明工具能完成什么,同时说明边界。比如"删除用户的订单记录(不可恢复),调用前需二次确认"。
- 每个工具只做一件事,参数控制在 5 个以内。
- 返回结果统一为 JSON,包含
success、data、error字段,方便模型判断。 - 系统提示词里明确告诉模型:没有确切依据时不要编造结果,工具不可用时要说明限制。
- 高影响操作不要自动执行,设置人工确认开关。
- 生产环境记录每次工具调用的入参和出参,便于审计和复盘。
6.3 判断自己是否真的需要 Agent
最后回到标题的疑问。聊天框不是过时产物,它依然是信息获取和内容生成的低成本入口。只有在满足下面任意一个条件时,才值得投入精力做 Agent:
- 任务需要调用外部系统或数据源,无法靠模型记忆完成。
- 任务包含多步骤,且步骤之间依赖中间结果。
- 任务需要自动执行,不能每次都靠人工复制粘贴。
- 同一流程需要反复执行,需要标准化和可复用。
如果你的需求只是偶尔问答、写文案、查资料,深入使用好聊天框本身也是一种合理选择。Agent 的价值在于把模型从"回答问题的人"变成"完成任务的人",这个转变需要补工程能力,但不需要等到理解了所有框架之后才动手。先写一个最小的工具调用闭环,剩下的问题会在真实运行中逐渐浮出水面,那也正是技术成长最快的地方。