/* 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具备以下核心能力:
- 感知(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 循环的关键特点:
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。核心要点总结如下:
现在,你已经掌握了构建AI Agent的核心技能。尝试为你的Agent添加更多工具(如计算器、数据库查询、文件操作),让它变得更加强大吧!




