用AI让AI更聪明:最小Agent的四大关键工程实践
之前在做 AI 应用项目时,一个最常被问到的题目是:模型输出不稳定、上下文容易乱、Agent 工具调用总是出错,到底怎么让系统变得更“聪明”?网上资料大多只讲模型本身,很少讲完整工程链路。本文从 AI 工程实践角度出发,围绕“用 AI 让 AI 更聪明”这一主题,拆解 Prompt、记忆、工具调用、评估反馈四个关键环节,并给出一个可运行的最小 Agent 示例。适合刚接触大模型应用开发的读者,也适合准备把 AI 功能落地到业务里的后端工程师。
1. “Making AI Smarter with AI”是什么
1.1 一句话理解这句话
“Making AI Smarter with AI”(用 AI 让 AI 更聪明)听起来像是绕口令,但它描述的其实是当前大模型应用开发中非常普遍的工程模式:
- 用 AI 辅助编写 AI 代码;
- 用 AI Agent 自主调用工具完成任务;
- 用 AI 模型评估另一个 AI 模型的输出质量;
- 用运行数据回流到 Prompt 和模型选择中,持续优化系统表现。
也就是说,AI 系统不再只是一个“静态模型调用”,而是由多种 AI 能力构成的动态工程系统。开发者通过编排、评估、迭代,让整个系统在真实业务中表现得更好。
1.2 它解决什么工程问题
传统开发模式下,业务逻辑依赖硬编码规则。比如客服机器人需要人工维护大量关键词和回复模板,遇到新问题就失效。大模型出现后,这种局面发生了根本变化,但随之而来的不是“零代码”,而是新的工程问题:
- 单次模型调用的结果不稳定,同一个问题可能给出不同答案;
- 长对话场景下上下文容易丢失或超长;
- 模型只能“说”,不能“做”,无法查询数据、调用接口;
- 质量问题难以度量,不知道哪个 Prompt 版本更好;
- 线上效果缺少闭环,坏了无法及时发现。
这些问题都不是靠换一个更大参数的模型就能彻底解决的,而是需要通过工程手段,把模型能力嵌入到流程、工具、数据和反馈回路中。
1.3 常见应用场景
在实际项目中,“用 AI 让 AI 更聪明”已经有很多落地形态:
| 场景 | 说明 |
|---|---|
| AI 编程辅助 | 用代码生成模型辅助开发、生成单元测试,提升研发效率 |
| 智能客服 | 基于历史会话数据持续优化问答效果,未解决问题自动分流人工 |
| Agent 自动化 | 让模型根据用户目标自主编排任务、调用工具、汇总结果 |
| 模型路由 | 简单问题走小模型,复杂问题走大模型,兼顾成本与效果 |
| LLM 自动评估 | 用大模型对另一个模型的输出打分,替代部分人工评测 |
| 测试数据生成 | 用模型批量生成测试用例和边界场景,补充数据集 |
这些场景的共同点是:AI 不是一次性的“黑盒接口”,而是被纳入到完整工程链路中,不断被观察、评估和优化。
2. 环境准备与版本说明
2.1 运行环境
本文的实战示例以 Python 为主,建议环境如下:
- Python 3.10 或更高版本;
- 建议使用虚拟环境隔离依赖;
- 需要一个兼容 OpenAI 格式的大模型 API 服务,可以是云端服务,也可以是本地部署的模型服务;
- 操作系统不限,Windows、macOS、Linux 均可。
版本需要根据你的项目实际情况调整,本文示例以常见环境为例,重点演示配置思路。
2.2 项目依赖
# requirements.txt requests>=2.31.0这里只依赖requests,用于调用模型服务的 HTTP 接口。如果后续引入 Flask 或 FastAPI 做服务化部署,再按需要增加依赖。
2.3 示例项目结构
ai-agent-demo/ ├── agent.py # Agent 核心逻辑 ├── main.py # 演示入口 ├── judge.py # 用 AI 评估 AI 的示例脚本 └── requirements.txt # 依赖这个结构足够小,方便理解核心机制,同时也保留了后面扩展成服务的基础。
3. 核心思路:让 AI 系统“变聪明”的四大关键
在进入代码之前,先把思路理清。如果只是封装一个模型 API,那不是“AI 工程实践”,那只是 API 调用。真正让 AI 系统变得更聪明,通常要考虑四个关键点。
3.1 Prompt 工程与上下文管理
Prompt 是开发者与模型之间唯一的“编程语言”。同样的模型,不同的 Prompt,结果可能相差很远。
基础原则:
- 系统提示词中明确角色、任务、输出格式;
- 必要时给出少量示例(Few-shot),帮助模型理解格式;
- 用户输入需要做合法性检查,避免注入攻击;
- 上下文要控制长度,超长时做截断或摘要。
示例:
system_prompt = """ 你是一个智能助手。你的任务是回答用户问题。 要求: 1. 回答必须简洁,不超过 200 字; 2. 如果用户提出无法确定的问题,请直接说明;不要编造事实。 """这里的关键不是把 Prompt 写得多复杂,而是让它具备可维护性。实际项目中,Prompt 应该作为配置管理起来,而不是散落在代码里。
3.2 记忆与反思机制
模型本身没有“记忆”,每次调用都是独立计算。要让 AI 更聪明,需要在外部维护记忆结构。
记忆通常分几层:
- 短期记忆:当前对话轮次里的消息列表;
- 工作记忆:任务执行过程中产生的中间结果;
- 长期记忆:跨会话沉淀的用户偏好、历史结论。
另外,反思机制是较高级的用法。比如让模型先给出答案,再自我评估“这个答案是否可靠”,如果不可靠就重新回答。这种自我反思能力,在复杂任务中能明显提升稳定性。
3.3 工具调用与 Agent 编排
Agent 是“用 AI 让 AI 更聪明”的重要载体。模型不再只是输出文本,而是可以输出“调用某个工具”的指令。系统解析这个指令,执行工具函数,再把结果返回给模型,让模型继续推理。
一个最小 Agent 需要四个组件:
- 模型客户端:负责与大模型交互;
- 工具注册表:登记模型可以调用的函数;
- 执行循环:解析模型输出,执行工具,回填结果;
- 终止条件:完成任务或达到最大轮数。
工具调用不是无限循环。必须设置最大轮数和超时时间,否则一个失控的 Agent 可能反复调用工具,消耗大量 token 和计算资源。
3.4 评估与反馈闭环
让 AI 变聪明,最重要的一环是评估。没有评估,就不知道优化方向。
常见做法:
- 准备一个固定评测集,包含典型问题、边界问题、高风险问题;
- 每次 Prompt 或模型调整后,批量运行评测集;
- 用大模型作为“评委”,对输出质量打分,减少人工成本;
- 线上记录失败样本,定期补充到评测集中。
这里说的“用 AI 评估 AI”,不是让模型自己说自己答得好,而是设计独立的评估维度,比如准确性、完整性、格式合规性,让评审判定。
4. 完整实战案例:用 AI 辅助 AI 开发一个最小 Agent
接下来进入工程实践环节。我们要实现一个最小 Agent,它具备:
- 工具注册与调用能力;
- 上下文记忆能力;
- 任务循环处理能力;
- 可配置的模型服务地址。
这个例子会演示“用 AI 让 AI 更聪明”的核心模式:模型负责理解与规划,工具负责执行,系统负责编排。
4.1 创建项目结构
首先创建项目目录和依赖文件。
mkdir ai-agent-demo cd ai-agent-demo touch requirements.txt agent.py main.py judge.pyrequirements.txt内容如下:
requests>=2.31.0安装依赖:
pip install -r requirements.txt4.2 编写模型客户端
模型客户端的作用是统一调用大模型接口,避免在业务代码里到处写 HTTP 请求。
# agent.py 片段:LLMClient import requests from typing import List, Dict, Any class LLMClient: def __init__(self, api_key: str, base_url: str, model: str): self.api_key = api_key self.base_url = base_url self.model = model def chat( self, messages: List[Dict[str, str]], tools: List[Dict[str, Any]] = None, temperature: float = 0.3, max_tokens: int = 1024, ) -> Dict[str, Any]: url = f"{self.base_url}/chat/completions" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", } payload = { "model": self.model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens, } if tools: payload["tools"] = tools resp = requests.post(url, headers=headers, json=payload, timeout=60) resp.raise_for_status() return resp.json()这里使用 OpenAI 兼容接口,具体参数需要根据你的模型服务调整。这里的base_url通常形如http://localhost:8000/v1或云端服务地址。
4.3 编写工具注册表与基础工具
工具注册表的核心作用是让 Agent 知道“有哪些工具可用”,并按名称执行工具。
# agent.py 片段:ToolRegistry 与工具函数 class ToolRegistry: def __init__(self): self._tools = {} def register(self, name: str, description: str, func): self._tools[name] = { "description": description, "func": func, } def list_tools(self) -> List[Dict[str, str]]: return [ {"name": name, "description": info["description"]} for name, info in self._tools.items() ] def call(self, name: str, **kwargs): if name not in self._tools: raise KeyError(f"未注册的工具: {name}") return self._tools[name]["func"](**kwargs)下面注册两个示例工具。
第一个工具是计算器。这里做了一些字符白名单,避免直接执行任意表达式。生产环境应该使用真正安全的沙箱或受限计算库。
# agent.py 片段:工具函数 def calculator(expr: str) -> str: """执行简单的四则运算表达式。 注意:这里仅做演示,生产环境请使用安全的表达式求值方案。 """ allowed = set("0123456789+-*/(). ") if not all(c in allowed for c in expr): return "表达式包含非法字符" try: result = eval(expr, {"__builtins__": {}}, {}) return str(result) except Exception as exc: return f"计算失败: {exc}"第二个工具是模拟查询函数,用来模拟 Agent 调用外部数据源的场景。
# agent.py 片段:模拟数据查询 def query_stock(name: str) -> str: """模拟查询股票行情数据。""" stock_map = { "example": "100.50", } return stock_map.get(name, "未查询到该股票数据")4.4 编写 Agent 核心循环
Agent 核心循环是整个示例的重点。它做的事情是:
- 把用户消息、系统提示词、历史记录发给模型;
- 如果模型返回工具调用请求,执行工具;
- 把工具执行结果追加到消息列表;
- 把新消息再次发给模型;
- 重复上述过程,直到模型给出最终答案或达到最大轮数。
# agent.py 片段:Agent 核心逻辑 class Agent: def __init__(self, llm_client: LLMClient, system_prompt: str, max_rounds: int = 5): self.llm_client = llm_client self.system_prompt = system_prompt self.max_rounds = max_rounds self.registry = ToolRegistry() self.messages = [ {"role": "system", "content": system_prompt}, ] def add_tool(self, name: str, description: str, func): self.registry.register(name, description, func) def _build_tools_schema(self) -> List[Dict[str, Any]]: schema = [] for tool in self.registry.list_tools(): schema.append({ "type": "function", "function": { "name": tool["name"], "description": tool["description"], "parameters": { "type": "object", "properties": { "expr": {"type": "string", "description": "输入表达式"}, "name": {"type": "string", "description": "查询名称"}, }, }, }, }) return schema def run(self, user_message: str) -> str: self.messages.append({"role": "user", "content": user_message}) for _ in range(self.max_rounds): tools_schema = self._build_tools_schema() response = self.llm_client.chat( messages=self.messages, tools=tools_schema, ) choice = response["choices"][0] message = choice["message"] self.messages.append(message) tool_calls = message.get("tool_calls") if not tool_calls: return message.get("content", "") for tool_call in tool_calls: function = tool_call["function"] func_name = function["name"] arguments = function.get("arguments", "{}") try: import json args = json.loads(arguments) except json.JSONDecodeError: args = {} result = self.registry.call(func_name, **args) tool_message = { "role": "tool", "tool_call_id": tool_call["id"], "content": str(result), } self.messages.append(tool_message) return "已达到最大轮数,任务未完成"这里的关键点是:
tool_calls是模型返回的工具调用指令;- 每次工具执行结果都要以
role: "tool"的消息回填; - 必须校验工具调用参数,不能直接信任模型输出;
- 最大轮数是必要的安全边界。
4.5 编写演示入口
main.py用来组装整个 Agent,并演示一个多步骤任务:既需要查询数据,又需要做计算。
# main.py from agent import Agent, LLMClient, calculator, query_stock SYSTEM_PROMPT = """ 你是一个智能助手。你可以使用工具来获取信息或计算结果。 当用户的问题需要工具时,请先选择合适的工具,再根据工具结果回答。 回答要简洁。 """ def main(): llm_client = LLMClient( api_key="your-api-key", base_url="your-base-url", model="your-model-name", ) agent = Agent(llm_client=llm_client, system_prompt=SYSTEM_PROMPT) agent.add_tool("calculator", "计算四则运算表达式", calculator) agent.add_tool("query_stock", "查询股票行情", query_stock) result = agent.run("请查询 example 股票的当前价格,并计算 100 股的总价。") print("最终回答:", result) if __name__ == "__main__": main()运行前,需要把api_key、base_url、model换成你自己的配置。
python main.py预期结果是:模型先调用query_stock查询股票价格,再调用calculator计算总价,最后给出类似“example 股票当前价格为 100.50,100 股总价为 10050.00”的回答。
4.6 用 AI 评估 AI:自动评测脚本
有了 Agent 还不够,还要回答“它表现得好不好”。这里演示一个简单的自动评估脚本:让大模型扮演评委,对一组答案打分。
# judge.py import requests from typing import List, Dict def judge_answers( api_key: str, base_url: str, model: str, question: str, answers: List[str], ) -> List[Dict[str, str]]: results = [] for answer in answers: messages = [ { "role": "system", "content": "你是一个严格的质量评估专家。请从准确性、完整性、可读性三个维度对模型回答打分,输出 1 到 10 的整数分数,并说明理由。", }, { "role": "user", "content": f"问题:{question}\n模型回答:{answer}", }, ] payload = { "model": model, "messages": messages, "temperature": 0, } resp = requests.post( f"{base_url}/chat/completions", headers={"Authorization": f"Bearer {api_key}"}, json=payload, timeout=60, ) resp.raise_for_status() content = resp.json()["choices"][0]["message"]["content"] results.append({"answer": answer, "judgement": content}) return results if __name__ == "__main__": question = "请解释什么是 AI Agent?" answers = [ "AI Agent 是一种能自主完成任务的程序。", "AI Agent 是使用大模型进行推理、规划并调用工具完成任务的智能体系统。", ] for item in judge_answers( api_key="your-api-key", base_url="your-base-url", model="your-model-name", question=question, answers=answers, ): print("回答:", item["answer"]) print("评估:", item["judgement"]) print("---")评估脚本的效果取决于评估维度设计。分数不是目的,目的是在版本迭代时,能在同一个评测集上对比不同 Prompt 的效果。
5. 常见问题与排查思路
在实际运行 AI 项目时,很容易遇到下面这些问题。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型返回的不是合法 JSON | 输出格式不稳定,或模型指令理解错误 | 在 Prompt 中给出 JSON 示例,或使用更严格的解析器,并增加重试 |
| 上下文过长,调用报错 | 对话轮次过多,历史消息累积 | 做消息截断、摘要压缩,或使用滑动窗口 |
| 工具调用参数错误 | 模型猜测了错误的参数名 | 在 tools schema 中写清楚参数说明,并做好入参校验 |
| Agent 进入死循环 | 缺少最大轮数限制,或工具始终失败 | 设置最大轮数,工具异常时返回错误文本让模型改道 |
| 回答质量不稳定 | Prompt 不清晰,或评测方式主观 | 固定评测集,多轮采样,使用独立评委模型打分 |
| 调用成本过高 | 模型参数过大,或单轮 token 太多 | 设置 max_tokens,采用小模型优先的路由策略 |
排查时建议按以下顺序进行:
- 先看模型原始输出,确认是解析问题还是生成问题;
- 再看 Prompt 和 tools schema,确认指令是否明确;
- 再看工具函数本身,确认是否有异常或返回格式问题;
- 最后看上下文长度和调用参数,确认是否超过模型限制。
很多时候,问题不在模型,而在工程链路中的某个环节。打印关键日志,比反复调整 Prompt 更有效。
6. 最佳实践与工程建议
6.1 安全边界设计
AI 系统接入生产环境时,安全是第一优先级。以下几点非常重要:
- 工具权限最小化,Agent 只能调用真正需要的工具;
- 禁止在 Agent 中执行未经过沙箱验证的代码;
- 对大模型返回的内容做输出过滤,尤其是面向用户的场景;
- 对用户输入做注入防护,防止恶意 Prompt 引导模型输出违规内容;
- 所有敏感操作都要人工确认后才能执行。
6.2 可观测性建设
AI 应用的调试比传统应用更复杂,可观测性必不可少。
建议每个请求至少记录:
- 输入的 messages 列表;
- Prompt 版本号;
- 模型名称与参数;
- 工具调用过程与结果;
- 耗时与 token 消耗;
- 最终输出内容。
有了这些日志,线上出问题时才能快速定位是模型问题还是工程问题。
6.3 评估先行的迭代机制
在优化 AI 系统时,最怕“凭感觉调 Prompt”。更好的做法是:
- 先建立一个小而稳的评测集,覆盖正常、边界、危险三类问题;
- 每次修改 Prompt 或 Agent 逻辑,都跑一遍评测集;
- 记录每次调整的得分变化,保留历史版本;
- 线上收集失败样本,定期补充到评测集。
这种评估机制让优化过程可量化、可回滚、可对比。
6.4 配置与版本管理
Prompt、模型参数、工具列表都应该被视为代码的一部分,纳入版本管理。不要让 Prompt 只存在于开发者的本地文件中。
推荐做法:
- 使用配置文件或配置中心管理 Prompt;
- 每次修改都记录变更原因;
- 使用独立环境验证后再发布;
- 关键业务保留回滚能力。
7. 实战总结与学习路线
通过本文的实战,你已经掌握了一个最小 AI Agent 的完整链路:模型客户端、工具注册、Agent 循环、自动评估。这套模式不是只适用于演示,而是很多真实 AI 应用的核心骨架。
下一步可以继续深入的方向包括:
- 学习更成熟的 Agent 框架,比如 LangChain、Spring AI 或官方 Function Calling 最佳实践;
- 研究 RAG(检索增强生成),让 AI 系统拥有私有知识库查询能力;
- 尝试把 Agent 服务化,接入消息队列、数据库和外部业务系统;
- 研究模型部署与性能优化,比如模型量化、推理加速、多模型路由;
- 建立完整的评测平台,把人工评估和机器评估结合起来。
比起追求“更强大的模型”,我更建议你在实际项目中先建立一套“能跑、能看、能量化、能回滚”的 AI 工程链路。真正的智能,不是来自某一次惊艳的回答,而是来自一次次失败样本的沉淀和系统化的迭代。
如果本文对你有帮助,可以收藏备用。也建议你从最简单的单工具 Agent 开始,把链路跑通,再逐步加入记忆、反思、多工具编排等能力。动手实践,比停留在概念上有用得多。
