

整理编辑|TesterHome社区
作者|Sergey Nes
以下为作者观点:
我每天都在使用Claude、Codex、Cursor、Gemini、Copilot、Junie等各类大模型产品,却始终说不清:普通聊天机器人究竟在哪一步蜕变成了智能体,也无法界定智能体的核心特质。于是我从零手写了一个简易版智能体,一探究竟。
于我而言,吃透新概念最好的方式就是亲手实现、再转述讲解。本文兼顾项目实操与原理科普,结合落地实验过程撰写,实用性拉满。
我们从仅50行Python代码起步:先对接OpenAI云端接口,再通过Ollama切换本地大模型,搭建云端+本地混合调度模式;接着扩展工具调用、接入MCP协议,最后和Claude命令行工具做对标。读完你就能看透智能体底层运行逻辑。
全程不依赖LangChain、LangGraph、CrewAI等任何框架,只用Python、大模型与一个while循环。

一、开发需求:我们要实现的智能体规格
动手编码前,先明确智能体的定义与功能边界,AI智能体是一套具备如下能力的程序:
1. 接收用户给出的高阶任务指令
2. 自主推理下一步执行动作
3. 发起动作(调用工具、联网检索、读取本地文件等)
4. 观测工具返回结果
5. 判断继续迭代还是输出最终答案
6. 留存完整对话上下文,后续决策依托历史交互信息
常规大模型单次调用是一次性流程:传入提示词、接收回复、流程结束。而智能体的核心区别就是循环执行:接收任务→推理动作→执行操作→收集结果,循环往复直至任务闭环。
这套「思考→行动→观测→决策」的往复循环,就是把基础大模型变成智能体的关键。
当下绝大多数智能体都遵循ReAct(推理+行动)架构:大模型不会直接输出最终答案,而是先思考执行方案、再发起工具调用,拿到返回结果后继续推演后续步骤。

图1 ReAct循环流程:先推理、再执行,观测结果后再次推理,循环直至模型信息充足可直接作答。
大模型本身没有自主意识,不存在生物学意义上的自我反思。它所谓的自省纠错,本质是把全部对话历史、历次工具调用与返回结果存入上下文窗口,依靠ReAct机制模拟出自省效果,且这套方案落地可行。
单次循环执行逻辑:
1. 把系统提示词、用户指令、过往所有工具返回结果打包送入大模型;
2. 模型二选一输出:最终答案 / 待调用的工具列表;
3. 若返回答案:流程终止,输出内容;
4. 若返回工具调用指令:程序执行对应工具,将结果追加至对话记录,回到第一步继续循环。
以上便是智能体完整底层架构。
二、最简实现:依托云端API作为模型大脑
首选OpenAI接口做底层推理,其工具调用规范简洁友好;该代码同样兼容所有遵循OpenAI调用格式的接口,Gemini、Anthropic全系产品均可适配。
核心智能体主逻辑代码
def run_agent(task: str, client: OpenAI, model: str = "gpt-4o-mini") -> str:messages = [{"role": "system","content": ("你是一名智能助手,需要时调用工具;信息完备可给出最终答案时,直接回复正文,不再调用任何工具。"),},{"role": "user", "content": task},]while True:response = client.chat.completions.create(model=model,messages=messages,tools=TOOLS,tool_choice="auto",)message = response.choices[0].messagemessages.append(message)# 分支判断:输出答案 或 调用工具if not message.tool_calls:return message.content# 解析并批量执行工具for tool_call in message.tool_calls:name = tool_call.function.nameargs = json.loads(tool_call.function.arguments)print(f" > 正在调用 {name}({args})")fn = TOOL_FUNCTIONS.get(name)result = fn(**args) if fn else f"未知工具:{name}"messages.append({"role": "tool","tool_call_id": tool_call.id,"content": result,})# 单次循环结束,回到while开头新一轮请求
关键判断语句:if not message.tool_calls
• 模型无工具调用:代表信息充足,直接返回答案,智能体退出循环
• 模型携带工具调用:执行工具、结果存入上下文,重新请求模型
messages列表就是智能体的短期记忆,所有交互、工具输入输出全留存,保证模型做后续决策时能查阅全量历史。
系统提示词相当于智能体的方向盘,规定了工具启用时机、终止条件、答案输出规范;商用产品(Anthropic、苹果等泄露的配置文件)里的系统提示词往往篇幅庞大。
自定义工具:日期查询、计算器、天气查询
先用三个简易工具落地演示,天气接口预留替换为真实第三方API:
import jsonimport osfrom datetime import datetimefrom openai import OpenAI# 获取当前时间def get_current_date() -> str:return datetime.now().strftime("%Y-%m-%d %H:%M:%S")# 数学表达式计算def calculate(expression: str) -> str:try:result = eval(expression, {"__builtins__": {}}, {})return str(result)except Exception as e:return f"计算异常:{e}"# 模拟天气接口def get_weather(city: str) -> str:# 可替换为真实天气API请求return f"{city}天气:72华氏度,局部多云"# 工具函数映射字典TOOL_FUNCTIONS = {"get_current_date": get_current_date,"calculate": calculate,"get_weather": get_weather,}
# 传给大模型的工具描述JSON(模型靠此识别可用工具与入参)
TOOLS = [{"type": "function","function": {"name": "get_current_date","description": "获取当前系统日期时间","parameters": {"type": "object", "properties": {}, "required": []},},},{"type": "function","function": {"name": "calculate","description": "计算数学表达式结果","parameters": {"type": "object","properties": {"expression": {"type": "string","description": "Python格式数学式,示例:'2 + 2'、'100 * 0.15'",}},"required": ["expression"],},},},{"type": "function","function": {"name": "get_weather","description": "查询指定城市实时天气","parameters": {"type": "object","properties": {"city": {"type": "string", "description": "城市名称"}},"required": ["city"],},},},]
运行入口与输出示例
if __name__ == "__main__":client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])task = "查询今日日期,计算847的15%,再查东京天气"print(f"任务:{task}\n")answer = run_agent(task, client)print(f"\n最终回答:{answer}")
控制台输出:
任务:查询今日日期,计算847的15%,再查东京天气> 正在调用 get_current_date({})> 正在调用 calculate({'expression': '847 * 0.15'})> 正在调用 get_weather({'city': 'Tokyo'})最终回答:今日日期2026-04-30 09:14:22,847的15%为127.05;东京气温72华氏度,局部多云。
首轮交互中模型一次性识别三项所需工具,逐个调用、汇总结果后生成答案,全程无额外框架与调度中间层。
三、替换Ollama本地大模型
Ollama兼容OpenAI接口规范,仅修改客户端实例即可无缝切换本地模型,主体智能体代码完全不用改动:
ollama_client = OpenAI(base_url="http://localhost:11434/v1",api_key="ollama" # 客户端必填参数,Ollama本身不校验密钥)answer = run_agent(task, ollama_client, model="qwen2.5")Ollama部署步骤
1. 官网下载安装Ollama
2. 命令行拉取模型+启动服务
ollama pull qwen2.5
ollama serve
部署完成后智能体全离线运行,适合工具调试(节省云端API费用)、涉密本地数据处理场景。
踩坑提醒:并非所有本地模型都支持结构化工具调用
测试Mistral-7B时出现异常:模型只会用自然文本描述要调用的工具,不会生成规范结构化JSON,代码识别不到tool_calls字段直接终止返回文本。
根源:Mistral-7B训练方案不兼容OpenAI格式函数调用,只能用自然语言描述动作、无法输出结构化指令。
选型建议:Ollama环境优先选用Qwen2.5等原生支持函数调用的模型,智能体异常先排查模型兼容性而非代码。

四、混合调度架构:本地主控+云端兜底复杂推理
本地模型负责循环调度与简单工具运算,遇到超纲复杂问题时,通过自定义工具调用云端GPT-4做高阶推理,仅复杂场景消耗云端计费。
def ask_cloud_expert(question: str) -> str:"""疑难问题转交云端大模型处理"""cloud_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])res = cloud_client.chat.completions.create(model="gpt-4o",messages=[{"role": "user", "content": question}])return res.choices[0].message.content
把该函数注册进TOOL_FUNCTIONS与TOOLS工具清单,测试任务:
计算2+2,同时用哲学角度解读忒修斯之船悖论
• Qwen2.5本地计算2+2(调用计算器)
• 识别哲学问题超出能力,自动调用ask_cloud_expert请求GPT-4作答
大幅缩减云端接口调用次数,降低使用成本。
五、扩展实用工具:联网搜索、文件读写
新增网页检索、文件读取、文件写入能力,web_search预留替换为Tavily、SerpAPI等商用搜索接口:
from pathlib import Pathdef web_search(query: str) -> str:# 模拟搜索接口return (f"关键词「{query}」搜索结果:\n"f"1.维基百科综合词条\n2.五分钟科普短文\n3.官方文档")def read_file(path: str) -> str:return Path(path).read_text()def write_file(path: str, content: str) -> str:Path(path).write_text(content)return f"已向{path}写入{len(content)}个字符"# 更新工具映射TOOL_FUNCTIONS = {"get_current_date": get_current_date,"calculate": calculate,"get_weather": get_weather,"web_search": web_search,"read_file": read_file,"write_file": write_file,}
补充对应工具JSON描述后,智能体即可完成:查时间、算数、查天气、全网检索、本地文档读写全链路实操。
项目完整源码地址:github.com/sergenes/mini_agent(含文件路径安全校验、异常捕获逻辑)
当前短板:所有工具硬编码在项目内,无法跨项目复用、无法接入第三方开发的现成工具,MCP协议正是为解决工具互通而生。
六、MCP协议:跨服务发现与调用外部工具
MCP(模型上下文协议)由Anthropic在2024年11月推出,统一了智能体跨进程/跨服务器调用工具的标准:开发者把工具封装成MCP服务端,任意MCP客户端智能体都能自动发现、调用服务端工具(Github、Slack、Postgres、谷歌网盘等生态均已配套MCP服务)。

图2MCP架构:单个客户端(自研智能体)对接多台MCP服务端,各服务端挂载自有工具,客户端调用规范统一,屏蔽后端实现差异。
改造后的自研智能体作为MCP客户端:不再硬编码工具定义,运行时主动连接MCP服务端、自动拉取工具列表与描述,直接喂给大模型使用。智能体主体循环代码完全不变,仅工具来源从本地函数变成远程服务。
极简MCP服务端示例(10行实现文本工具服务)
# mcp_server.pyfrom mcp.server.fastmcp import FastMCPmcp = FastMCP("mini-tools")@mcp.tool()def to_uppercase(text: str) -> str:"""文本转大写"""return text.upper()@mcp.tool()def count_words(text: str) -> int:"""统计单词数量"""return len(text.split())if __name__ == "__main__":mcp.run()
服务端独立进程运行,不管部署在本地还是远端服务器,客户端智能体调用逻辑毫无改动;Claude桌面端、Cursor、各类自研智能体只要兼容MCP协议,均可一键接入这套工具。
生态价值:同类工具只需要一人开发一套MCP服务,全行业智能体直接复用,避免重复造轮子。
七、对标商用产品:Claude CLI与自研智能体差异
Claude Code(商用)优势
• 超大任务自动拆分子智能体,各子体上下文隔离
• 高危修改命令执行前弹窗确认
• 跨会话持久化记忆、工具调用失败自动重试、临近上下文上限时自动压缩历史消息
自研极简智能体优势
• 全量代码透明可控,故障可逐行定位
• 可全离线Ollama部署,混合模式按需付费调用云端模型
• 无固定订阅成本,不调用云端GPT则零开销
落地选型:生产级稳定业务选用Claude Code;学习底层原理、定制化原型开发优先从零手写循环。
八、各类框架适用场景
1. LangGraph:把智能体抽象为有限状态机,补充失败重试、执行断点、人工审批、子智能体并行调度、全链路观测;适合需要健壮容错的项目,基础学习无需上手。
2. CrewAI/AutoGen:主打多智能体协同,拆分研究员、文案、评审等角色分工协作,适配复杂多步骤任务。
3. Claude Agents SDK / OpenAI Assistants API:平台托管状态管理、工具路由、线程调度,开发效率高,但自定义可控度偏低。
一句话总结:学习原理手写while循环,商用落地按需选用框架。
九、项目落地感悟
从零实现这套智能体后,我建立了完整的智能体底层认知:清楚智能体卡顿诱因、工具选择逻辑、多工具冗余带来的性能损耗,看懂Claude创建子智能体、Cursor重试异常调用的底层原理。
实际项目中:复杂生产场景用LangGraph、官方Agent SDK规避重复开发;轻量化定制需求沿用50行极简框架,避免被黑盒抽象束缚修改。
智能体没有任何黑魔法:本质就是模型读取历史上下文,判断调用工具还是输出答案,循环往复。
重试机制、人工介入、长效记忆、多智能体协作全都是在这套基础循环之上做的上层封装。
先手写最简版本吃透原理,再按需引入第三方框架,是最高效的学习路径。
参考资料
项目源码
完整工程:github.com/sergenes/mini_agent
官方文档
OpenAI函数调用:platform.openai.com/docs/guides/function-calling
Ollama接口规范:github.com/ollama/ollama/blob/main/docs/api.md
MCP协议官网:modelcontextprotocol.io
FastMCP开发库:github.com/jlowin/fastmcp
主流框架地址
LangGraph:langchain-ai.github.io/langgraph
CrewAI:crewai.com
AutoGen:microsoft.github.io/autogen
Claude Agents SDK:docs.anthropic.com/en/docs/agents
OpenAI Assistants:platform.openai.com/docs/assistants
学术论文
ReAct: Synergizing Reasoning and Acting in Language Models(2022)arxiv.org/abs/2210.03629
最新议题看这里→
大会火热报名中
7折票已于5月30日截止
目前购票8折优惠
时间越晚折扣越少噢~
扫描下方二维码,即可参会


开源|ARM开源Metis智能体安全框架,Agentic AI驱动更早、更大规模检测复杂漏洞
从Webpack到Rspack:构建速度提升80%!Yelp工程师总结的5个关键优化技巧,对测试开发同学有这些借鉴
智能测试进阶|大模型驱动的测试用例生成与优化:全流程实操指南
不鼓励烧Token了!大厂AI考核转向?亚马逊紧急下线AI Token排行榜
AI编码|团队新基础设施?MCP协议在AI辅助编程中的质量保障作用
AI测试|如何构建一个工程师真正会听取意见的AI代码审查工具
夜雨聆风