乐于分享
好东西不私藏

从零搭建AI智能体:无玄学,仅靠确定性循环

从零搭建AI智能体:无玄学,仅靠确定性循环

整理编辑|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].message        messages.append(message)        # 分支判断:输出答案 或 调用工具        if not message.tool_calls:            return message.content        # 解析并批量执行工具        for tool_call in message.tool_calls:            name = tool_call.function.name            args = 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


MTSC2026中国互联网测试开发大会
将于8月15日在深圳举行

最新议题看这里

这些议题进入评审环节,一起围观AI时代的行业关注热点!

大会火热报名中

7折票已于5月30日截止

目前购票8折优惠

时间越晚折扣越少噢~

扫描下方二维码,即可参会

开源|ARM开源Metis智能体安全框架,Agentic AI驱动更早、更大规模检测复杂漏洞

从Webpack到Rspack:构建速度提升80%!Yelp工程师总结的5个关键优化技巧,对测试开发同学有这些借鉴

智能测试进阶|大模型驱动的测试用例生成与优化:全流程实操指南

不鼓励烧Token了!大厂AI考核转向?亚马逊紧急下线AI Token排行榜

AI编码|团队新基础设施?MCP协议在AI辅助编程中的质量保障作用

AI测试|如何构建一个工程师真正会听取意见的AI代码审查工具

AI时代下,软件测试岗位正在消失吗?——全球科技公司的QA转型、裁撤与重构

大厂技术密集更新:OpenAI、Anthropic、微软等AI智能体与云原生工具重塑开发测试流程