欢迎光临
我们一直在努力

从0到1开发一个AI Agent:完整实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

1. 引言

下面这张图展示了 AI Agent 的整体架构,帮助你快速建立全局认知:

#mermaid-svg-yFI9AujoCoKnw1N7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yFI9AujoCoKnw1N7 .error-icon{fill:#552222;}#mermaid-svg-yFI9AujoCoKnw1N7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yFI9AujoCoKnw1N7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yFI9AujoCoKnw1N7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yFI9AujoCoKnw1N7 .marker.cross{stroke:#333333;}#mermaid-svg-yFI9AujoCoKnw1N7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yFI9AujoCoKnw1N7 p{margin:0;}#mermaid-svg-yFI9AujoCoKnw1N7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-yFI9AujoCoKnw1N7 .cluster-label text{fill:#333;}#mermaid-svg-yFI9AujoCoKnw1N7 .cluster-label span{color:#333;}#mermaid-svg-yFI9AujoCoKnw1N7 .cluster-label span p{background-color:transparent;}#mermaid-svg-yFI9AujoCoKnw1N7 .label text,#mermaid-svg-yFI9AujoCoKnw1N7 span{fill:#333;color:#333;}#mermaid-svg-yFI9AujoCoKnw1N7 .node rect,#mermaid-svg-yFI9AujoCoKnw1N7 .node circle,#mermaid-svg-yFI9AujoCoKnw1N7 .node ellipse,#mermaid-svg-yFI9AujoCoKnw1N7 .node polygon,#mermaid-svg-yFI9AujoCoKnw1N7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yFI9AujoCoKnw1N7 .rough-node .label text,#mermaid-svg-yFI9AujoCoKnw1N7 .node .label text,#mermaid-svg-yFI9AujoCoKnw1N7 .image-shape .label,#mermaid-svg-yFI9AujoCoKnw1N7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-yFI9AujoCoKnw1N7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yFI9AujoCoKnw1N7 .rough-node .label,#mermaid-svg-yFI9AujoCoKnw1N7 .node .label,#mermaid-svg-yFI9AujoCoKnw1N7 .image-shape .label,#mermaid-svg-yFI9AujoCoKnw1N7 .icon-shape .label{text-align:center;}#mermaid-svg-yFI9AujoCoKnw1N7 .node.clickable{cursor:pointer;}#mermaid-svg-yFI9AujoCoKnw1N7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yFI9AujoCoKnw1N7 .arrowheadPath{fill:#333333;}#mermaid-svg-yFI9AujoCoKnw1N7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yFI9AujoCoKnw1N7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yFI9AujoCoKnw1N7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yFI9AujoCoKnw1N7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yFI9AujoCoKnw1N7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yFI9AujoCoKnw1N7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yFI9AujoCoKnw1N7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yFI9AujoCoKnw1N7 .cluster text{fill:#333;}#mermaid-svg-yFI9AujoCoKnw1N7 .cluster span{color:#333;}#mermaid-svg-yFI9AujoCoKnw1N7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yFI9AujoCoKnw1N7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yFI9AujoCoKnw1N7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-yFI9AujoCoKnw1N7 .icon-shape,#mermaid-svg-yFI9AujoCoKnw1N7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yFI9AujoCoKnw1N7 .icon-shape p,#mermaid-svg-yFI9AujoCoKnw1N7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yFI9AujoCoKnw1N7 .icon-shape .label rect,#mermaid-svg-yFI9AujoCoKnw1N7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yFI9AujoCoKnw1N7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yFI9AujoCoKnw1N7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yFI9AujoCoKnw1N7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

需要外部信息

可以回答

👤 用户输入

🧠 大语言模型(LLM)

🤔 思考与规划

🔧 工具调用

🌐 网络搜索

💾 数据库查询

🧮 代码执行器

📁 文件操作

📥 工具结果

💬 生成最终答案

📝 记忆存储

AI Agent(智能体)是当前人工智能领域最热门的概念之一。它不再是一个简单的问答模型,而是一个能够自主理解目标、拆解任务、调用工具、并执行多步操作的智能系统。本文将带你从零开始,手把手构建一个属于自己的AI Agent,让你深入理解其核心原理与实现方式。

2. 什么是AI Agent?

下面这张图展示了 AI Agent 的五大核心能力及其协作关系:

#mermaid-svg-ytXmJuqYC5z5jUya{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ytXmJuqYC5z5jUya .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ytXmJuqYC5z5jUya .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ytXmJuqYC5z5jUya .error-icon{fill:#552222;}#mermaid-svg-ytXmJuqYC5z5jUya .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ytXmJuqYC5z5jUya .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ytXmJuqYC5z5jUya .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ytXmJuqYC5z5jUya .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ytXmJuqYC5z5jUya .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ytXmJuqYC5z5jUya .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ytXmJuqYC5z5jUya .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ytXmJuqYC5z5jUya .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ytXmJuqYC5z5jUya .marker.cross{stroke:#333333;}#mermaid-svg-ytXmJuqYC5z5jUya svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ytXmJuqYC5z5jUya p{margin:0;}#mermaid-svg-ytXmJuqYC5z5jUya .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ytXmJuqYC5z5jUya .cluster-label text{fill:#333;}#mermaid-svg-ytXmJuqYC5z5jUya .cluster-label span{color:#333;}#mermaid-svg-ytXmJuqYC5z5jUya .cluster-label span p{background-color:transparent;}#mermaid-svg-ytXmJuqYC5z5jUya .label text,#mermaid-svg-ytXmJuqYC5z5jUya span{fill:#333;color:#333;}#mermaid-svg-ytXmJuqYC5z5jUya .node rect,#mermaid-svg-ytXmJuqYC5z5jUya .node circle,#mermaid-svg-ytXmJuqYC5z5jUya .node ellipse,#mermaid-svg-ytXmJuqYC5z5jUya .node polygon,#mermaid-svg-ytXmJuqYC5z5jUya .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ytXmJuqYC5z5jUya .rough-node .label text,#mermaid-svg-ytXmJuqYC5z5jUya .node .label text,#mermaid-svg-ytXmJuqYC5z5jUya .image-shape .label,#mermaid-svg-ytXmJuqYC5z5jUya .icon-shape .label{text-anchor:middle;}#mermaid-svg-ytXmJuqYC5z5jUya .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ytXmJuqYC5z5jUya .rough-node .label,#mermaid-svg-ytXmJuqYC5z5jUya .node .label,#mermaid-svg-ytXmJuqYC5z5jUya .image-shape .label,#mermaid-svg-ytXmJuqYC5z5jUya .icon-shape .label{text-align:center;}#mermaid-svg-ytXmJuqYC5z5jUya .node.clickable{cursor:pointer;}#mermaid-svg-ytXmJuqYC5z5jUya .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ytXmJuqYC5z5jUya .arrowheadPath{fill:#333333;}#mermaid-svg-ytXmJuqYC5z5jUya .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ytXmJuqYC5z5jUya .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ytXmJuqYC5z5jUya .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ytXmJuqYC5z5jUya .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ytXmJuqYC5z5jUya .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ytXmJuqYC5z5jUya .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ytXmJuqYC5z5jUya .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ytXmJuqYC5z5jUya .cluster text{fill:#333;}#mermaid-svg-ytXmJuqYC5z5jUya .cluster span{color:#333;}#mermaid-svg-ytXmJuqYC5z5jUya div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ytXmJuqYC5z5jUya .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ytXmJuqYC5z5jUya rect.text{fill:none;stroke-width:0;}#mermaid-svg-ytXmJuqYC5z5jUya .icon-shape,#mermaid-svg-ytXmJuqYC5z5jUya .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ytXmJuqYC5z5jUya .icon-shape p,#mermaid-svg-ytXmJuqYC5z5jUya .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ytXmJuqYC5z5jUya .icon-shape .label rect,#mermaid-svg-ytXmJuqYC5z5jUya .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ytXmJuqYC5z5jUya .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ytXmJuqYC5z5jUya .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ytXmJuqYC5z5jUya :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

🤖 AI Agent 核心能力

反馈循环

👁️ 感知Perception

🧠 规划Planning

💾 记忆Memory

🔧 工具使用Tool Use

⚡ 行动Action

🌍 外部环境

👤 用户

2.1 与传统问答系统的区别

特性传统问答系统AI Agent
交互方式 单轮问答 多轮对话 + 自主行动
能力边界 仅文本生成 调用工具、执行代码、操作文件
记忆能力 无上下文记忆 短期 + 长期记忆
任务处理 一次性回答 多步规划 + 逐步执行
反馈机制 无 根据结果自动调整策略

在开始编码之前,我们先明确AI Agent的定义。一个典型的AI Agent具备以下核心能力:

  • 感知(Perception):接收并理解用户输入的指令或环境信息。
  • 规划(Planning):将复杂目标拆解为一系列可执行的子任务。
  • 记忆(Memory):存储对话历史、中间结果和关键信息。
  • 工具使用(Tool Use):调用外部API、数据库、搜索引擎或代码执行器来完成任务。
  • 行动(Action):执行具体的操作,并基于反馈调整后续行为。

简单来说,AI Agent = 大语言模型(LLM) + 规划能力 + 记忆系统 + 工具集。

3. 环境准备与项目初始化

在开始编码之前,我们先搭建好完整的开发环境。下面是整个项目的目录结构和依赖关系图:

#mermaid-svg-4sCyeB3KFDzexP6F{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4sCyeB3KFDzexP6F .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4sCyeB3KFDzexP6F .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4sCyeB3KFDzexP6F .error-icon{fill:#552222;}#mermaid-svg-4sCyeB3KFDzexP6F .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4sCyeB3KFDzexP6F .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4sCyeB3KFDzexP6F .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4sCyeB3KFDzexP6F .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4sCyeB3KFDzexP6F .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4sCyeB3KFDzexP6F .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4sCyeB3KFDzexP6F .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4sCyeB3KFDzexP6F .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4sCyeB3KFDzexP6F .marker.cross{stroke:#333333;}#mermaid-svg-4sCyeB3KFDzexP6F svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4sCyeB3KFDzexP6F p{margin:0;}#mermaid-svg-4sCyeB3KFDzexP6F .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-4sCyeB3KFDzexP6F .cluster-label text{fill:#333;}#mermaid-svg-4sCyeB3KFDzexP6F .cluster-label span{color:#333;}#mermaid-svg-4sCyeB3KFDzexP6F .cluster-label span p{background-color:transparent;}#mermaid-svg-4sCyeB3KFDzexP6F .label text,#mermaid-svg-4sCyeB3KFDzexP6F span{fill:#333;color:#333;}#mermaid-svg-4sCyeB3KFDzexP6F .node rect,#mermaid-svg-4sCyeB3KFDzexP6F .node circle,#mermaid-svg-4sCyeB3KFDzexP6F .node ellipse,#mermaid-svg-4sCyeB3KFDzexP6F .node polygon,#mermaid-svg-4sCyeB3KFDzexP6F .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4sCyeB3KFDzexP6F .rough-node .label text,#mermaid-svg-4sCyeB3KFDzexP6F .node .label text,#mermaid-svg-4sCyeB3KFDzexP6F .image-shape .label,#mermaid-svg-4sCyeB3KFDzexP6F .icon-shape .label{text-anchor:middle;}#mermaid-svg-4sCyeB3KFDzexP6F .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4sCyeB3KFDzexP6F .rough-node .label,#mermaid-svg-4sCyeB3KFDzexP6F .node .label,#mermaid-svg-4sCyeB3KFDzexP6F .image-shape .label,#mermaid-svg-4sCyeB3KFDzexP6F .icon-shape .label{text-align:center;}#mermaid-svg-4sCyeB3KFDzexP6F .node.clickable{cursor:pointer;}#mermaid-svg-4sCyeB3KFDzexP6F .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4sCyeB3KFDzexP6F .arrowheadPath{fill:#333333;}#mermaid-svg-4sCyeB3KFDzexP6F .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4sCyeB3KFDzexP6F .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4sCyeB3KFDzexP6F .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4sCyeB3KFDzexP6F .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4sCyeB3KFDzexP6F .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4sCyeB3KFDzexP6F .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4sCyeB3KFDzexP6F .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4sCyeB3KFDzexP6F .cluster text{fill:#333;}#mermaid-svg-4sCyeB3KFDzexP6F .cluster span{color:#333;}#mermaid-svg-4sCyeB3KFDzexP6F div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4sCyeB3KFDzexP6F .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4sCyeB3KFDzexP6F rect.text{fill:none;stroke-width:0;}#mermaid-svg-4sCyeB3KFDzexP6F .icon-shape,#mermaid-svg-4sCyeB3KFDzexP6F .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4sCyeB3KFDzexP6F .icon-shape p,#mermaid-svg-4sCyeB3KFDzexP6F .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4sCyeB3KFDzexP6F .icon-shape .label rect,#mermaid-svg-4sCyeB3KFDzexP6F .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4sCyeB3KFDzexP6F .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4sCyeB3KFDzexP6F .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4sCyeB3KFDzexP6F :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

📁 ai-agent-tutorial/

main.py主程序入口

agent_core.pyAgent核心逻辑

tools.py工具定义

memory.py记忆管理

.env环境变量

requirements.txt依赖清单

🐍 Python 3.10+

🔑 OpenAI API

🌐 DuckDuckGo

3.1 技术选型

我们将使用以下技术栈:

  • Python 3.10+:开发语言
  • OpenAI API:作为核心LLM(兼容任何支持Function Calling的模型)
  • LangChain:作为Agent框架(可选,但能极大简化开发)
  • DuckDuckGo Search:作为示例工具

3.2 安装依赖

mkdir ai-agent-tutorial
cd ai-agent-tutorial
python -m venv venv
source venv/bin/activate # Windows: venv\\Scripts\\activate

pip install openai langchain langchain-community duckduckgo-search python-dotenv

3.3 配置环境变量

在项目根目录创建 .env 文件:

OPENAI_API_KEY=your_openai_api_key_here

4. 核心实现:从零构建Agent

下面这张图展示了我们将要实现的三个核心模块及其演进关系:

#mermaid-svg-9RwM8pn2HdCnMnWb{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9RwM8pn2HdCnMnWb .error-icon{fill:#552222;}#mermaid-svg-9RwM8pn2HdCnMnWb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9RwM8pn2HdCnMnWb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9RwM8pn2HdCnMnWb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9RwM8pn2HdCnMnWb .marker.cross{stroke:#333333;}#mermaid-svg-9RwM8pn2HdCnMnWb svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9RwM8pn2HdCnMnWb p{margin:0;}#mermaid-svg-9RwM8pn2HdCnMnWb .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-9RwM8pn2HdCnMnWb .cluster-label text{fill:#333;}#mermaid-svg-9RwM8pn2HdCnMnWb .cluster-label span{color:#333;}#mermaid-svg-9RwM8pn2HdCnMnWb .cluster-label span p{background-color:transparent;}#mermaid-svg-9RwM8pn2HdCnMnWb .label text,#mermaid-svg-9RwM8pn2HdCnMnWb span{fill:#333;color:#333;}#mermaid-svg-9RwM8pn2HdCnMnWb .node rect,#mermaid-svg-9RwM8pn2HdCnMnWb .node circle,#mermaid-svg-9RwM8pn2HdCnMnWb .node ellipse,#mermaid-svg-9RwM8pn2HdCnMnWb .node polygon,#mermaid-svg-9RwM8pn2HdCnMnWb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9RwM8pn2HdCnMnWb .rough-node .label text,#mermaid-svg-9RwM8pn2HdCnMnWb .node .label text,#mermaid-svg-9RwM8pn2HdCnMnWb .image-shape .label,#mermaid-svg-9RwM8pn2HdCnMnWb .icon-shape .label{text-anchor:middle;}#mermaid-svg-9RwM8pn2HdCnMnWb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9RwM8pn2HdCnMnWb .rough-node .label,#mermaid-svg-9RwM8pn2HdCnMnWb .node .label,#mermaid-svg-9RwM8pn2HdCnMnWb .image-shape .label,#mermaid-svg-9RwM8pn2HdCnMnWb .icon-shape .label{text-align:center;}#mermaid-svg-9RwM8pn2HdCnMnWb .node.clickable{cursor:pointer;}#mermaid-svg-9RwM8pn2HdCnMnWb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9RwM8pn2HdCnMnWb .arrowheadPath{fill:#333333;}#mermaid-svg-9RwM8pn2HdCnMnWb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9RwM8pn2HdCnMnWb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9RwM8pn2HdCnMnWb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9RwM8pn2HdCnMnWb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9RwM8pn2HdCnMnWb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9RwM8pn2HdCnMnWb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9RwM8pn2HdCnMnWb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9RwM8pn2HdCnMnWb .cluster text{fill:#333;}#mermaid-svg-9RwM8pn2HdCnMnWb .cluster span{color:#333;}#mermaid-svg-9RwM8pn2HdCnMnWb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9RwM8pn2HdCnMnWb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9RwM8pn2HdCnMnWb rect.text{fill:none;stroke-width:0;}#mermaid-svg-9RwM8pn2HdCnMnWb .icon-shape,#mermaid-svg-9RwM8pn2HdCnMnWb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9RwM8pn2HdCnMnWb .icon-shape p,#mermaid-svg-9RwM8pn2HdCnMnWb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9RwM8pn2HdCnMnWb .icon-shape .label rect,#mermaid-svg-9RwM8pn2HdCnMnWb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9RwM8pn2HdCnMnWb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9RwM8pn2HdCnMnWb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9RwM8pn2HdCnMnWb :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

步骤三:加入记忆系统

短期记忆

长期记忆

上下文管理

步骤二:引入工具调用

Function Calling

搜索工具

计算工具

其他工具

步骤一:基础ReAct循环

思考(Reasoning)

行动(Acting)

我们将分三步实现:先实现一个基础的ReAct循环,再引入工具调用,最后加入记忆功能。

4.1 基础ReAct循环

ReAct 循环是 Agent 最核心的执行范式。下面这张图展示了它的完整执行流程:

#mermaid-svg-5v0xFc4wUkFezR9n{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5v0xFc4wUkFezR9n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5v0xFc4wUkFezR9n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5v0xFc4wUkFezR9n .error-icon{fill:#552222;}#mermaid-svg-5v0xFc4wUkFezR9n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5v0xFc4wUkFezR9n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5v0xFc4wUkFezR9n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5v0xFc4wUkFezR9n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5v0xFc4wUkFezR9n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5v0xFc4wUkFezR9n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5v0xFc4wUkFezR9n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5v0xFc4wUkFezR9n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5v0xFc4wUkFezR9n .marker.cross{stroke:#333333;}#mermaid-svg-5v0xFc4wUkFezR9n svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5v0xFc4wUkFezR9n p{margin:0;}#mermaid-svg-5v0xFc4wUkFezR9n .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-5v0xFc4wUkFezR9n .cluster-label text{fill:#333;}#mermaid-svg-5v0xFc4wUkFezR9n .cluster-label span{color:#333;}#mermaid-svg-5v0xFc4wUkFezR9n .cluster-label span p{background-color:transparent;}#mermaid-svg-5v0xFc4wUkFezR9n .label text,#mermaid-svg-5v0xFc4wUkFezR9n span{fill:#333;color:#333;}#mermaid-svg-5v0xFc4wUkFezR9n .node rect,#mermaid-svg-5v0xFc4wUkFezR9n .node circle,#mermaid-svg-5v0xFc4wUkFezR9n .node ellipse,#mermaid-svg-5v0xFc4wUkFezR9n .node polygon,#mermaid-svg-5v0xFc4wUkFezR9n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5v0xFc4wUkFezR9n .rough-node .label text,#mermaid-svg-5v0xFc4wUkFezR9n .node .label text,#mermaid-svg-5v0xFc4wUkFezR9n .image-shape .label,#mermaid-svg-5v0xFc4wUkFezR9n .icon-shape .label{text-anchor:middle;}#mermaid-svg-5v0xFc4wUkFezR9n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5v0xFc4wUkFezR9n .rough-node .label,#mermaid-svg-5v0xFc4wUkFezR9n .node .label,#mermaid-svg-5v0xFc4wUkFezR9n .image-shape .label,#mermaid-svg-5v0xFc4wUkFezR9n .icon-shape .label{text-align:center;}#mermaid-svg-5v0xFc4wUkFezR9n .node.clickable{cursor:pointer;}#mermaid-svg-5v0xFc4wUkFezR9n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5v0xFc4wUkFezR9n .arrowheadPath{fill:#333333;}#mermaid-svg-5v0xFc4wUkFezR9n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5v0xFc4wUkFezR9n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5v0xFc4wUkFezR9n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5v0xFc4wUkFezR9n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5v0xFc4wUkFezR9n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5v0xFc4wUkFezR9n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5v0xFc4wUkFezR9n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5v0xFc4wUkFezR9n .cluster text{fill:#333;}#mermaid-svg-5v0xFc4wUkFezR9n .cluster span{color:#333;}#mermaid-svg-5v0xFc4wUkFezR9n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5v0xFc4wUkFezR9n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5v0xFc4wUkFezR9n rect.text{fill:none;stroke-width:0;}#mermaid-svg-5v0xFc4wUkFezR9n .icon-shape,#mermaid-svg-5v0xFc4wUkFezR9n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5v0xFc4wUkFezR9n .icon-shape p,#mermaid-svg-5v0xFc4wUkFezR9n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5v0xFc4wUkFezR9n .icon-shape .label rect,#mermaid-svg-5v0xFc4wUkFezR9n .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5v0xFc4wUkFezR9n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5v0xFc4wUkFezR9n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5v0xFc4wUkFezR9n :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

不能,需要行动

能

🚀 开始

📝 接收用户输入

🤔 思考:分析问题确定需要什么信息

🧐 判断:能否直接回答?

⚡ 行动:执行某个操作

👀 观察:获取行动结果

💬 生成最终答案

✅ 结束

ReAct 循环的关键特点:

  • 思考(Reasoning):LLM 分析当前状态,决定下一步做什么
  • 行动(Acting):执行具体的操作(如搜索、计算)
  • 观察(Observation):获取行动结果,反馈给 LLM
  • 循环迭代:重复上述步骤,直到得出最终答案
  • ReAct(Reasoning + Acting)是Agent最核心的范式。它让LLM在“思考”和“行动”之间交替,直到得出最终答案。

    import os
    from openai import OpenAI
    from dotenv import load_dotenv

    load_dotenv()
    client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

    def simple_agent(user_input: str, max_steps: int = 5):
    messages = [
    {"role": "system", "content": "你是一个AI助手。请逐步思考并行动,最终给出答案。"},
    {"role": "user", "content": user_input}
    ]

    for step in range(max_steps):
    response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages
    )
    assistant_message = response.choices[0].message
    messages.append(assistant_message)

    # 检查是否已给出最终答案
    if assistant_message.content and "最终答案" in assistant_message.content:
    return assistant_message.content

    # 模拟思考-行动循环
    print(f"Step {step + 1}: {assistant_message.content}")

    return "已达到最大步数,未得出最终答案。"

    # 测试
    result = simple_agent("请计算 25 的平方根,并告诉我结果。")
    print(result)

    4.2 引入工具调用(Function Calling)

    真正的Agent需要能调用外部工具。OpenAI的Function Calling机制让LLM可以请求执行特定函数。

    首先,定义一个搜索工具:

    import json
    from duckduckgo_search import DDGS

    def search_web(query: str) –> str:
    """使用DuckDuckGo搜索网络信息"""
    with DDGS() as ddgs:
    results = list(ddgs.text(query, max_results=3))
    if results:
    return "\\n".join([f"{r['title']}: {r['body']}" for r in results])
    return "未找到相关结果。"

    # 定义工具描述(用于Function Calling)
    tools = [
    {
    "type": "function",
    "function": {
    "name": "search_web",
    "description": "搜索网络获取最新信息",
    "parameters": {
    "type": "object",
    "properties": {
    "query": {
    "type": "string",
    "description": "搜索关键词"
    }
    },
    "required": ["query"]
    }
    }
    }
    ]

    # 工具映射表
    tool_map = {
    "search_web": search_web
    }

    然后,实现带工具调用的Agent循环:

    def agent_with_tools(user_input: str, max_steps: int = 5):
    messages = [
    {"role": "system", "content": "你是一个能调用工具的AI助手。请根据用户需求,合理调用工具并给出最终答案。"},
    {"role": "user", "content": user_input}
    ]

    for step in range(max_steps):
    response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice="auto"
    )

    assistant_message = response.choices[0].message
    messages.append(assistant_message)

    # 检查是否有工具调用请求
    if assistant_message.tool_calls:
    for tool_call in assistant_message.tool_calls:
    function_name = tool_call.function.name
    function_args = json.loads(tool_call.function.arguments)

    print(f"🔧 调用工具: {function_name}({function_args})")

    # 执行工具
    function_response = tool_map[function_name](**function_args)

    # 将工具结果返回给LLM
    messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": function_response
    })
    else:
    # 没有工具调用,说明LLM给出了最终答案
    return assistant_message.content

    return "已达到最大步数。"

    # 测试
    result = agent_with_tools("2024年巴黎奥运会中国获得了多少枚金牌?")
    print(f"最终答案: {result}")

    4.3 加入记忆系统

    为了让Agent能记住对话上下文,我们需要实现一个简单的记忆管理:

    from typing import List, Dict

    class SimpleMemory:
    def __init__(self, max_history: int = 10):
    self.history: List[Dict] = []
    self.max_history = max_history

    def add_message(self, role: str, content: str):
    self.history.append({"role": role, "content": content})
    # 限制历史长度
    if len(self.history) > self.max_history:
    self.history = self.history[–self.max_history:]

    def get_context(self) –> List[Dict]:
    return self.history

    def clear(self):
    self.history = []

    def agent_with_memory(user_input: str, memory: SimpleMemory, max_steps: int = 5):
    # 构建消息列表:系统提示 + 历史记忆 + 当前输入
    messages = [
    {"role": "system", "content": "你是一个有记忆的AI助手。请记住对话上下文,合理调用工具。"}
    ]
    messages.extend(memory.get_context())
    messages.append({"role": "user", "content": user_input})

    for step in range(max_steps):
    response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice="auto"
    )

    assistant_message = response.choices[0].message
    messages.append(assistant_message)

    if assistant_message.tool_calls:
    for tool_call in assistant_message.tool_calls:
    function_name = tool_call.function.name
    function_args = json.loads(tool_call.function.arguments)
    function_response = tool_map[function_name](**function_args)

    messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": function_response
    })
    else:
    # 保存到记忆
    memory.add_message("user", user_input)
    memory.add_message("assistant", assistant_message.content)
    return assistant_message.content

    return "已达到最大步数。"

    # 测试多轮对话
    memory = SimpleMemory()
    print(agent_with_memory("你好,我叫小明", memory))
    print(agent_with_memory("我刚才说了什么?", memory)) # 应该记得名字

    5. 进阶:使用LangChain快速构建

    如果你不想从零实现,LangChain提供了开箱即用的Agent构建能力:

    from langchain.agents import create_react_agent, AgentExecutor
    from langchain.tools import Tool
    from langchain_openai import ChatOpenAI
    from langchain.prompts import PromptTemplate

    # 定义工具
    def search_tool(query: str) –> str:
    with DDGS() as ddgs:
    results = list(ddgs.text(query, max_results=3))
    return "\\n".join([r["body"] for r in results]) if results else "无结果"

    tools = [
    Tool(
    name="web_search",
    func=search_tool,
    description="搜索网络信息,输入为搜索关键词"
    )
    ]

    # 创建Agent
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    prompt = PromptTemplate.from_template(
    "你是一个AI助手。请使用以下工具回答问题:\\n{tools}\\n\\n"
    "工具名称: {tool_names}\\n"
    "用户问题: {input}\\n\\n"
    "请逐步思考:\\n{agent_scratchpad}"
    )

    agent = create_react_agent(llm, tools, prompt)
    agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

    # 运行
    result = agent_executor.invoke({"input": "今天比特币价格是多少?"})
    print(result["output"])

    6. 部署与优化建议

    6.1 生产环境注意事项

    • 错误处理:为每个工具调用添加try-except,防止单点故障导致整个Agent崩溃。
    • 超时控制:为LLM调用和工具执行设置超时时间。
    • 速率限制:实现令牌桶或滑动窗口算法,防止API调用超限。
    • 日志记录:记录每次思考-行动循环,便于调试和审计。

    6.2 性能优化

    • 缓存:对相同输入的LLM响应和工具结果进行缓存。
    • 并行工具调用:对于不依赖顺序的工具,可以并行执行。
    • 精简上下文:使用滑动窗口或摘要压缩历史对话,避免超出上下文窗口。

    7. 总结

    本文从零开始,带你完整实现了一个具备工具调用和记忆能力的AI Agent。核心要点总结如下:

  • ReAct循环是Agent的基础范式,让LLM在思考与行动间交替。
  • Function Calling让LLM能够调用外部工具,扩展能力边界。
  • 记忆系统使Agent能维持多轮对话的上下文。
  • LangChain等框架可以加速开发,但理解底层原理同样重要。
  • 现在,你已经掌握了构建AI Agent的核心技能。尝试为你的Agent添加更多工具(如计算器、数据库查询、文件操作),让它变得更加强大吧!

    赞(0)
    未经允许不得转载:171主机测评 » 从0到1开发一个AI Agent:完整实战指南
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址