☰
从古法编程到AI Agent开发:范式跃迁与工程实践
2026/11/5 17:43:42 网站建设 项目流程

这次我们不看某个具体工具,而是看一个开发范式的变化:从“把每一步逻辑都写死在代码里”的古法编程,到“让模型负责判断、让代码负责执行”的 AI Agent 开发。

这两者最大的区别不是换了一个框架、多调一个 API,而是整个开发流程的思考方式变了。以前写一个日志分析工具,要先写数据接入、规则匹配、阈值判断、告警输出,每一步都要定义清楚;现在写一个 AI Agent,你只需要给它一个目标、几个工具、一套边界约束,剩下的路径规划、参数提取、结果判断,都由模型自动完成,代码负责的是把这些能力安全地接起来。

这篇文章会拆解这个跃迁到底体现在哪里:核心概念、最小可运行示例、工具调用 API 设计、批量任务编排、资源占用观察,以及最容易踩的坑。内容偏工程实践,适合后端开发、全栈开发,以及正在从传统编程转向 AI 应用开发的技术人员。

1. 核心能力速览

维度古法编程AI Agent 开发
核心资产代码逻辑、规则、数据流模型能力、工具集合、上下文管理
开发重点把逻辑写对、把性能调好把目标定清楚、把工具设计好、把边界约束住
输入输出确定输入 -> 输出目标 + 上下文 + 工具 -> 结果 + 行动轨迹
错误处理异常捕获、重试、回滚模型误判、工具调用失败、上下文丢失
调试方式断点、日志、单测逐步观察模型决策、检查工具输入输出、压缩上下文
扩展方式加代码、加模块加工具、加记忆、加评估
性能瓶颈CPU、内存、磁盘、网络Token 消耗、模型延迟、上下文长度、工具调用次数
主要风险逻辑 Bug、数据不一致幻觉、权限失控、成本不可控

对开发者的直观感受是:古法编程里 80% 的时间在研究“怎么做”,AI Agent 开发里 80% 的时间在研究“做什么、边界在哪、怎么验证”。

2. 适用场景与使用边界

AI Agent 不是银弹,它解决的问题和传统编程有明显边界。

适合的场景有这几类:

  1. 流程不确定的任务。比如“分析这几条日志,找出异常原因”,你事前无法把所有异常规则穷举出来,适合让模型来分析。
  2. 多步骤工具调用。比如“查一下这个服务状态,如果异常就拉取最近日志并给出结论”,这需要模型自己决定调用哪些工具、按什么顺序调用。
  3. 自然语言交互入口。比如内部运维助手、数据分析助手,用户用中文描述需求,Agent 帮忙翻译成 API 调用。
  4. 快速原型和内部工具。很多一次性脚本、临时分析任务,与其手写解析逻辑,不如交给 Agent。

不适合的场景也很明确:

  • 高并发、低延迟的请求路径,Agent 的推理延迟和成本无法接受。
  • 强一致性的财务、交易系统,模型输出不稳定,需要大量校验。
  • 完全确定性的规则处理,比如字符串格式化、字段映射,用传统代码更可靠。

使用边界必须提醒:如果 Agent 接入的是日志、用户数据、内部 API,一定要在授权范围内使用,数据和日志先脱敏再传给外部模型。涉及生产系统操作时,建议只给只读工具,或加入人工确认环节。

3. 从古法编程到 AI Agent 开发:三个关键差异

3.1 从“指令式”到“意图式”

古法编程是标准的指令式:告诉机器每一步做什么,最终得到结果。AI Agent 开发是意图式:告诉模型“你要解决什么问题”,模型自己拆解步骤。

举例来说,传统代码实现“查询最近的异常日志”:

def get_recent_errors(log_path, hours=24): errors = [] end_time = time.time() start_time = end_time - hours * 3600 with open(log_path, "r", encoding="utf-8") as f: for line in f: timestamp_str, level, message = parse_log_line(line) timestamp = parse_time(timestamp_str) if start_time <= timestamp <= end_time and level == "ERROR": errors.append({"time": timestamp_str, "message": message}) return errors

这段代码的逻辑是完整的,但只能做这一件事。如果要“先查服务状态,再根据状态决定是否需要查日志,然后总结原因”,逻辑会成倍增长,且每增加一个分支都要改代码。

Agent 化之后,代码里不再写“如何解析日志”,而是定义好查询工具,让模型自己决定调用什么工具来完成任务:

# 只定义工具,具体调用顺序由模型决定 tools = [ { "name": "query_logs", "description": "按时间范围查询日志,支持按级别过滤", "parameters": {...} }, { "name": "query_service_status", "description": "查询服务当前运行状态", "parameters": {...} } ]

这种转变带来一个直接后果:以前你会花大量时间写“解析逻辑”,现在把时间花在“把工具描述写清楚”上面,因为模型的工具选择准确度,直接取决于工具描述的清晰度。

3.2 从“确定性逻辑”到“工具调用循环”

传统程序是一棵树,根节点是入口,分支是条件判断,叶子是具体操作。AI Agent 是一个循环:模型读取任务 -> 判断需要什么信息 -> 调用工具 -> 观察结果 -> 再次判断,直到完成或到达最大轮次。

这个循环是 Agent 和单次模型调用最大的区别。单次调用是“你问一句,模型答一句”,Agent 则是让模型反复思考、调用工具、修正路径。

一个最小循环的伪代码是这样:

messages = [{"role": "user", "content": task}] for step in range(max_steps): response = llm.chat(messages, tools=tools) if response.finish_reason == "tool_calls": messages.append(response.message) for tool_call in response.tool_calls: result = execute_tool(tool_call) messages.append(tool_result_message(tool_call, result)) else: return response.content

这个循环看起来简单,但在工程上有大量细节:如何避免模型反复调用同一个失败工具、如何限制最大轮数、如何控制中间结果占用的上下文、如何决定哪一步该停止。

3.3 从“处理数据”到“管理上下文”

传统编程里,数据要么在内存、要么在数据库,变量作用域清晰。Agent 开发里,模型能看到的所有内容都来自上下文窗口,包括系统提示词、历史消息、工具返回结果。

上下文是最贵的资源。工具返回内容过多会挤占上下文,导致模型忽略早期指令;返回内容过少,模型信息不足又会误判。这需要开发者对工具输出做压缩。

比如查询日志时,不要把原始日志原样返回给模型,而是先在工具内部做一次聚合,只返回统计结果:

def query_logs_tool(level: str, hours: int): logs = fetch_logs(level, hours) # 聚合,减少 token 消耗 summary = { "total": len(logs), "error_count": count_by_level(logs, "ERROR"), "top_messages": Counter(logs).most_common(5) } return summary

理解这三个差异后,后面的示例和工程实践就顺理成章了。

4. 环境准备与前置条件

AI Agent 开发的基础环境比传统后端开发多两部分:模型访问凭证和 Agent 运行库。

基础检查清单如下:

检查项要求
Python 版本建议 3.10 及以上,异步编程支持更好
虚拟环境每个项目单独创建 venv,避免依赖冲突
模型 API准备好 OpenAI 兼容的 API Key,或本地部署模型服务
依赖库openai / requests / pydantic,按实际框架选择
网络能正常访问模型 API 服务即可,无需额外配置
日志目录建议单独建 logs 目录,记录 Agent 每一步决策过程

创建虚拟环境的通用命令:

python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install openai requests pydantic

环境变量示例:

export OPENAI_API_KEY="your-api-key" export OPENAI_BASE_URL="https://api.endpoint.com/v1"

这里需要注意:如果你使用本地模型部署,OpenAI Base URL 指向本地服务;如果使用第三方兼容平台,则指向对应服务地址。不要硬编码 API Key 在代码里,统一走环境变量。

5. 最小可运行的 Agent 示例

5.1 传统方式:写死逻辑

假设要完成一个任务:查询服务器磁盘使用率,如果超过 80%,返回告警,否则返回正常。

传统代码大概是这样:

def check_disk_usage(server): usage = get_disk_usage(server) # 假设已实现 if usage > 80: return {"level": "error", "message": f"{server} disk usage {usage}%"} return {"level": "ok", "message": f"{server} disk usage {usage}%"}

逻辑很直接,但新增一个检查项就要加一个函数、加一个分支。

5.2 Agent 方式:定义工具与目标

用 OpenAI 兼容接口实现一个最小 Agent:

import json import os from openai import OpenAI client = OpenAI( api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"), ) # 1. 定义工具 def get_disk_usage(host: str) -> dict: # 实际项目里替换为真实采集逻辑 demo_data = { "web-01": 82, "web-02": 45, "db-01": 91, } usage = demo_data.get(host, 0) return {"host": host, "usage_percent": usage} # 2. 工具 schema tools = [ { "type": "function", "function": { "name": "get_disk_usage", "description": "查询指定主机的磁盘使用率,返回百分比", "parameters": { "type": "object", "properties": { "host": {"type": "string", "description": "主机名"} }, "required": ["host"] } } } ] # 3. 执行循环 def run_agent(task: str, max_steps: int = 5): messages = [{"role": "user", "content": task}] for step in range(max_steps): response = client.chat.completions.create( model=os.getenv("MODEL_NAME", "gpt-4o-mini"), messages=messages, tools=tools, ) message = response.choices[0].message if not message.tool_calls: return message.content # 执行工具并将结果追加到上下文 messages.append(message) for tool_call in message.tool_calls: fn_name = tool_call.function.name fn_args = json.loads(tool_call.function.arguments) print(f"[step {step+1}] call {fn_name}({fn_args})") if fn_name == "get_disk_usage": result = get_disk_usage(**fn_args) else: result = {"error": f"unknown tool: {fn_name}"} messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) return "达到最大步数,任务未完成" if __name__ == "__main__": task = "请检查 web-01 和 db-01 的磁盘使用率,如果超过 80% 就标记为异常,并给出处理建议。" result = run_agent(task) print(result)

5.3 预期结果与判断标准

运行代码后,应看到类似输出:

[step 1] call get_disk_usage({'host': 'web-01'}) [step 2] call get_disk_usage({'host': 'db-01'}) [最终输出] web-01 磁盘使用率为 82%,超过阈值,建议清理日志;db-01 磁盘使用率为 91%,建议扩容或迁移数据。

判断 Agent 运行成功的标准有三个:

  1. 模型正确识别任务中需要查询的主机。
  2. 工具调用参数解析正确。
  3. 最终输出结合了工具结果并给出了完整结论。

如果模型在第一步就直接输出文本而不调用工具,说明工具描述不够清晰,或者模型不支持工具调用功能。这时先检查模型服务是否支持 Function Calling,再看 description 是否写得足够明确。

6. 工具调用与接口 API 设计

Agent 的工具调用本质上是给模型提供一组可调用函数,模型负责选函数、填参数,代码负责执行。因此工具的接口设计直接影响 Agent 的效果。

6.1 工具描述要写清楚

工具描述有三个关键层:

  1. name:简短、语义明确,如query_logs,不要用func1。
  2. description:说明工具能做什么、什么场景下使用,例如“按时间范围查询应用日志,支持按级别过滤,适合排障时获取详情”。
  3. parameters:参数名、类型、是否必需、含义都要完整,尤其要写清楚单位、格式。

一个典型的工具 schema 如下:

{ "name": "query_logs", "description": "查询应用日志,支持按时间范围、级别过滤,返回最近 N 条", "parameters": { "type": "object", "properties": { "start_time": { "type": "string", "description": "开始时间,ISO8601 格式,例如 2025-01-01T00:00:00Z" }, "end_time": { "type": "string", "description": "结束时间,ISO8601 格式" }, "level": { "type": "string", "enum": ["DEBUG", "INFO", "WARNING", "ERROR"], "description": "日志级别" }, "limit": { "type": "integer", "description": "最多返回条数,默认 100" } }, "required": ["start_time", "end_time"] } }

6.2 工具返回内容要精简

工具的返回结果会被直接放入模型上下文,这会影响模型后续决策和整体 token 消耗。实现工具时建议在工具内部做一次结果规整,而不是把原始数据直接抛给模型。

比如日志查询,直接返回原始日志内容可能需要几百条消息;在工具内部聚合后,只返回关键字段:

{ "total": 342, "level_counts": {"ERROR": 12, "WARNING": 45}, "top_errors": [ {"message": "Connection timeout", "count": 5}, {"message": "NullPointerException", "count": 4} ] }

这种设计能显著减少上下文长度、降低延迟。

6.3 请求与返回结构

如果 Agent 服务对外提供接口,常见做法是暴露一个 POST 接口,接受任务描述,返回最终结果和执行轨迹:

from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class AgentRequest(BaseModel): task: str max_steps: int = 5 class AgentResponse(BaseModel): result: str steps: list @app.post("/agent/run") def run(request: AgentRequest): # 实际项目里在这里调用 agent 执行函数 result, steps = execute_agent(request.task, request.max_steps) return AgentResponse(result=result, steps=steps)

调用方可以用 curl 直接测试:

curl -X POST http://127.0.0.1:8000/agent/run \ -H "Content-Type: application/json" \ -d '{"task": "检查 web-01 磁盘使用率", "max_steps": 5}'

接口返回格式:

{ "result": "web-01 磁盘使用率 82%,超过 80% 阈值,建议清理日志", "steps": [ {"tool": "get_disk_usage", "args": {"host": "web-01"}, "result": {"usage_percent": 82}} ] }

把执行轨迹一并返回,是 Agent 服务的必要设计。没有轨迹,用户无法判断结果是否可靠,也没法做排障。

6.4 用 Python 做接口调用测试

import requests url = "http://127.0.0.1:8000/agent/run" payload = {"task": "查询 db-01 的磁盘状态并给出建议", "max_steps": 5} resp = requests.post(url, json=payload, timeout=60) data = resp.json() print(data["result"]) for step in data["steps"]: print(step)

7. 批量任务与异步编排

Agent 的典型瓶颈不是工具数量,而是单次任务的串行推理延迟。以日志分析为例,分析 100 个服务的状态,如果逐个串行调用,每个任务假设需要 5 秒,总计 500 秒,用户体验不可接受。所以批量任务需要异步编排和并发控制。

7.1 异步批量处理示例

使用 asyncio 和 OpenAI 异步客户端,可以并发跑多个 Agent 任务:

import asyncio from openai import AsyncOpenAI client = AsyncOpenAI() async def run_single_agent(task: str, tools: list): messages = [{"role": "user", "content": task}] for step in range(3): response = await client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, ) message = response.choices[0].message if not message.tool_calls: return message.content messages.append(message) for tc in message.tool_calls: result = execute_tool(tc) messages.append({ "role": "tool", "tool_call_id": tc.id, "content": str(result) }) return "max_step_reached" async def run_batch(tasks: list[str], tools: list, concurrency: int = 5): semaphore = asyncio.Semaphore(concurrency) async def worker(task): async with semaphore: return await run_single_agent(task, tools) results = await asyncio.gather(*[worker(t) for t in tasks]) return results

7.2 并发度控制

并发度不要盲目开高。模型 API 通常有速率限制,并发过高会被返回 429 限流错误。推荐的策略是:

  1. 开始时并发度设置为 3 到 5,观察延迟和限流情况。
  2. 出现限流错误时,指数退避重试。
  3. 对每个任务设置超时时间,避免单个任务卡死整个队列。
  4. 记录每个任务的耗时和 token 消耗,用于后续成本分析。

7.3 失败重试与任务隔离

批量任务中,单个 Agent 失败不应影响其他任务。建议为每个任务维护独立的状态和日志:

task_status = { "task_id": "task_001", "status": "running|succeeded|failed", "retry_count": 0, "result": "", "error_message": "" }

重试策略:工具调用失败可以重试 2 次;模型 API 限流可以重试 3 次,按指数退避;任务整体失败则写入失败队列,等待人工排查。

8. 资源占用与性能观察

Agent 应用的性能观察和传统接口不同,重点看这几个指标:

指标说明
Token 消耗每次任务总 token 数,直接关联成本
首次响应延迟模型第一次返回前的等待时间
工具调用次数每个任务平均调用多少次工具,过多说明模型在试探
上下文长度每一步的上下文 token 数,是否接近模型上限
API 限流率每分钟触发限流的次数
任务成功率完成并输出有效结果的任务占比

观察工具调用次数尤其重要。如果模型反复调用同一个工具、参数变化不大,说明工具描述有歧义或上下文信息不足。常见优化方向:

  1. 工具 description 里补充使用场景和示例。
  2. 工具返回内容中加入“你已经查过哪些参数”的提示,减少重复查询。
  3. 限制最大步数,防止死循环。

如果想要降低 token 消耗,优先做三件事:

  • 压缩工具返回内容,只保留关键统计量。
  • 任务完成后把中间工具结果从消息列表移除,只保留最终结论。
  • 一个任务尽量控制工具调用次数,合并同类查询。

9. 常见问题与排查方法

问题现象可能原因排查方式解决方案
模型不调用工具,直接输出文本工具 description 不清晰,或模型不支持工具调用查看返回的 finish_reason 和 message.tool_calls优化工具描述,确认模型支持 Function Calling
工具参数解析错误工具 schema 参数描述不完整打印模型返回的 tool_call.arguments在 parameters 中补充类型、格式、取值范围说明
上下文超出模型限制工具返回内容过大,或历史消息堆积统计每次 append 的 token 数压缩工具返回内容,精简历史消息
任务运行到最大步数仍未完成任务目标不清晰,或模型在试探工具查看执行轨迹,定位反复调用的工具限制任务范围,在 system prompt 里明确终止条件
API 返回 429 限流并发过高查看服务端速率限制文档降低并发,增加指数退避重试
批量任务中单个任务卡死单个 Agent 没有设置超时检查任务状态为每个任务设置超时时间,超时后标记失败
输出结果不稳定模型本身具有随机性,或 prompt 约束不足多次运行对比输出降低 temperature,明确输出格式约束
工具执行抛出异常工具内部代码问题或参数非法捕获异常并观察参数工具内部加 try-except,返回结构化错误信息

10. 学习路线与最佳实践

10.1 学习路线

从古法编程转向 AI Agent 开发,不建议直接上手框架,建议按这个顺序走:

第一阶段:掌握 Prompt 工程基础。熟悉角色设定、上下文管理、few-shot 示例对输出的影响。

第二阶段:掌握 Function Calling。用原生 OpenAI 接口手写一个 Agent 循环,理解工具调用和上下文追加的底层逻辑。

第三阶段:使用 Agent 框架。在原生实现跑通后,再引入 LangChain、LlamaIndex 或其它框架,你会更容易理解框架封装的到底是什么。

第四阶段:构建自己的工具集。把日常开发中的日志查询、接口检查、数据统计封装成 Agent 工具,形成自己的工具库。

第五阶段:引入记忆和评估。为 Agent 增加任务级、会话级记忆,并建立评估集,用真实任务回归测试输出质量。

10.2 工程实践建议

第一,从最小可用开始。别一开始就设计复杂的多智能体协同架构。先用一个 Agent、三个工具跑通一个真实业务场景,观察效果和成本,再逐步扩展。

第二,完整记录执行轨迹。Agent 的结果必须有依据。把工具输入输出保存在日志里,出问题才能复盘。

第三,明确工具权限边界。Agent 调用的工具越多,越容易出差错。生产环境先只开放只读工具,确认稳定后再考虑写操作。

第四,先定义评估标准。传统开发有单元测试,Agent 开发至少要有评估集。准备 20 到 50 个真实任务,每次修改 prompt 或工具后,跑一遍评估集看效果是否下降。

第五,关注成本而不是只看效果。一个任务 5000 token 和 2000 token 的差距在规模放大后很明显。批量任务上线前,先跑小批量样本估算单任务平均 token 和耗时。

10.3 合规提醒

如果 Agent 接入的是内部日志、用户信息、生产系统 API,务必注意:

  • 未经授权不得采集、分析他人数据,日志内容先脱敏再处理。
  • 生产系统操作工具要设置人工审批环节。
  • 使用外部模型服务时,确认数据是否允许发送到该平台,必要时使用本地部署模型。

11. 总结

从古法编程到 AI Agent 开发,最直观的变化是工作重心从“写逻辑”变成了“定义目标、设计工具、控制边界”。模型负责执行智力工作,代码负责把模型安全地接到真实系统上。

上手第一步,建议先用原生接口写一个最小 Agent 循环,跑通“任务 -> 工具调用 -> 结果返回”的完整链路,再判断你现有的业务里,哪些任务适合交给 Agent,哪些继续用传统代码实现。最容易踩的坑是工具描述不清晰、上下文无限增长、以及不设最大步数导致模型反复试探。

下一步值得尝试的方向:把静态脚本改造成 Agent 工具、给 Agent 增加可复用的记忆模块、引入小规模评估集来做回归测试。可以把这篇文章当作一个起点,带着自己的真实业务需求去验证。建议收藏备用,后续我会继续拆 Agent 开发里更细的工程问题。

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

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

立即咨询