万字长文讲透 AI Agent 架构设计:从 ReAct 到多 Agent 协作,附完整 Python 代码

2026 年最火的技术词是 Agent,但中文圈真正讲「怎么设计一个生产可用的 Agent 系统」的文章几乎没有。看完这篇,你会对 Agent 架构有一个完整的认知框架,末尾的 3-Agent 代码助手可以直接跑。


一、为什么你的 Agent 总是「跑偏」

用过 Agent 的开发者几乎都遇到过:

  • Agent 执行了第一步就忘了目标,开始胡言乱语
  • 工具随便乱调,明明该查数据库却去搜网页
  • 上下文越跑越长,Token 费用直线上升
  • 多个 Agent 之间互相等待、死锁、重复工作

问题不在模型,在架构。 本文把 Agent 架构从头到尾讲清楚------四种架构模式、工具调用设计、三层记忆系统、多 Agent 协作,每种都配了可运行的 Python 代码。


二、Agent 核心架构模式

2.1 ReAct(Reasoning + Acting)--- 最经典

ReAct 是所有 Agent 架构的起点:思考 → 行动 → 观察 → 再思考 → 直到目标达成

python 复制代码
class ReActAgent:
    def __init__(self, llm, tools: dict):
        self.llm = llm
        self.tools = tools          # {"tool_name": callable}
        self.max_steps = 10

    def run(self, goal: str) -> str:
        context = [{"role": "user", "content": goal}]

        for step in range(self.max_steps):
            # 1. 思考 + 决策
            response = self.llm.chat(context, tools_schema=self._tool_schemas())

            # 2. 模型直接回复 → 结束
            if response.content and not response.tool_calls:
                return response.content

            # 3. 执行工具调用
            for tool_call in response.tool_calls:
                tool_name = tool_call.name
                tool_args = json.loads(tool_call.arguments)
                result = self.tools[tool_name](**tool_args)

                # 4. 观察结果加入上下文
                context.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": str(result)
                })

            context.append(response.message)

        return "达到最大步数,任务未完成"

适用场景:多步推理(代码审查、故障排查)、工具调用结果不确定(搜索、数据分析)

局限:没有全局规划,容易「走一步看一步」失去方向

2.2 Plan-Execute --- 先规划再执行

先让 LLM 制定完整计划,再逐步执行。某一步失败时自动重新规划。

python 复制代码
class PlanExecuteAgent:
    def __init__(self, llm, tools: dict):
        self.llm = llm
        self.tools = tools
        self.executor = ReActAgent(llm, tools)

    def run(self, goal: str) -> str:
        # 1. 规划阶段
        plan_prompt = f"""
        为完成以下目标,制定详细步骤计划。
        目标:{goal}
        可用工具:{', '.join(self.tools.keys())}
        返回 JSON:{{"steps": ["步骤1", "步骤2", ...]}}
        """
        plan_response = self.llm.chat([{"role": "user", "content": plan_prompt}])
        plan = json.loads(plan_response.content)

        # 2. 逐步执行
        results = []
        for i, step in enumerate(plan["steps"]):
            step_result = self.executor.run(step)
            results.append({"step": step, "result": step_result})

            # 某步失败?重新规划剩余步骤
            if "失败" in step_result or "错误" in step_result:
                remaining = plan["steps"][i+1:]
                replan = self._replan(goal, step, step_result, remaining)
                plan["steps"] = plan["steps"][:i+1] + replan

        return self._summarize(goal, results)

适用场景:需求明确的开发任务、部署流水线、数据分析工作流

局限:初始规划可能不准,动态环境不适合静态规划

2.3 Router Agent --- 按任务类型路由

一个主 Agent 分类任务,分发给专业 Agent 处理:

markdown 复制代码
         ┌──────────┐
         │  Router  │
         │  Agent   │
         └────┬─────┘
     ┌────────┼────────┐
     ↓        ↓        ↓
┌─────────┐ ┌──────┐ ┌────────┐
│ Coder   │ │Search│ │ Devops │
│ Agent   │ │Agent │ │ Agent  │
└─────────┘ └──────┘ └────────┘

关键:路由 Agent 本身可以是极轻量的(用 Haiku 甚至传统分类器),只在分发任务时调用一次,成本极低。

2.4 Multi-Agent Orchestra --- 多 Agent 编排

最复杂也最强大的模式。多个 Agent 串行/并行协作,由 Orchestrator 调度:

markdown 复制代码
              ┌──────────────┐
              │ Orchestrator │
              └──────┬───────┘
    ┌────────────────┼────────────────┐
    ↓                ↓                ↓
┌──────────┐  ┌──────────┐  ┌──────────┐
│Architect │  │  Coder   │  │ Reviewer │
│  Agent   │  │  Agent   │  │  Agent   │
└──────────┘  └──────────┘  └──────────┘

具体实现见第五节。

四种模式选型建议

场景 推荐模式 原因
简单单步任务 直接 Function Calling Agent 反而是过度设计
需要多步推理 ReAct 最灵活,最通用
步骤明确可规划 Plan-Execute 更可控,更适合生产
多种任务类型 Router 减少单个 Agent 的复杂度
复杂完整流程 Multi-Agent 各司其职,可独立优化

三、工具调用系统:让 Agent 知道该用什么

3.1 工具描述工程 --- 比代码更重要

LLM 只能通过你的工具描述来决定何时调用、传什么参数。描述质量 = 调用准确率

python 复制代码
# ❌ 差
def search(query: str) -> list:
    """搜索"""

# ✅ 好
def search_knowledge_base(query: str, top_k: int = 5, filters: dict = None) -> list:
    """在内部知识库中搜索与 query 语义相关的内容。
    返回 top_k 条最相关的结果,每项包含 {title, content, score, url}。
    支持按 filters={"category": "技术文档", "date_range": "2026-01-01,2026-06-01"} 过滤。
    当用户问到公司内部政策、技术方案或历史决策时优先使用此工具。
    """

三条黄金法则

  1. 说清楚何时使用 --- 比「做什么」更重要,直接告诉 LLM 什么场景该调用
  2. 给参数示例和默认值 --- 减少 LLM 的决策负担
  3. 写明限制条件 --- 超时、最大返回数、权限要求

3.2 工具分组与权限控制

python 复制代码
class ToolRegistry:
    def __init__(self):
        self._tools = {}

    def register(self, name: str, func, group: str, risk_level: str):
        self._tools[name] = {
            "func": func,
            "group": group,
            "risk_level": risk_level,  # "safe" | "write" | "dangerous"
        }

    def get_safe_tools(self) -> list:
        """只读操作,可以自动执行"""
        return [t for t in self._tools.values() if t["risk_level"] == "safe"]

    def get_dangerous_tools(self) -> list:
        """高危操作,需要额外审批"""
        return [t for t in self._tools.values() if t["risk_level"] == "dangerous"]

生产环境必须分级 :读操作自动执行,写操作需要确认,危险操作(如 execute_sql)需要人工审批。

3.3 Function Calling vs MCP --- 什么时候用哪个

维度 Function Calling MCP
标准化 厂商各自定义 开放协议,跨厂商通用
可移植性 绑定特定 LLM 一次实现,所有 MCP 客户端可用
部署 LLM 内部 独立进程,可远程
安全 依赖 LLM 厂商 进程隔离 + OAuth 2.1

建议:个人项目用 Function Calling 快速验证,团队项目用 MCP。


四、记忆系统:让 Agent 拥有「长期记忆」

4.1 三层记忆架构

scss 复制代码
短期记忆 (对话上下文) ── 容量 ~100K tokens,生命周期:单次会话
        ↕
工作记忆 (Scratchpad) ── 容量 ~10K tokens,生命周期:单次任务
        ↕
长期记忆 (向量数据库) ── 容量无限,生命周期:永久

4.2 长期记忆 --- pgvector 实现

python 复制代码
import psycopg2
from pgvector.psycopg2 import register_vector

class LongTermMemory:
    def __init__(self, conn_string: str, embedding_model):
        self.conn = psycopg2.connect(conn_string)
        register_vector(self.conn)
        self.embed = embedding_model
        self._create_table()

    def _create_table(self):
        with self.conn.cursor() as cur:
            cur.execute("""
                CREATE TABLE IF NOT EXISTS agent_memory (
                    id SERIAL PRIMARY KEY,
                    content TEXT NOT NULL,
                    embedding vector(1536),
                    memory_type TEXT DEFAULT 'fact',
                    importance FLOAT DEFAULT 0.5,
                    created_at TIMESTAMP DEFAULT NOW(),
                    last_accessed TIMESTAMP DEFAULT NOW(),
                    access_count INT DEFAULT 0
                );
                CREATE INDEX IF NOT EXISTS agent_memory_embedding_idx
                    ON agent_memory USING ivfflat (embedding vector_cosine_ops);
            """)
        self.conn.commit()

    def store(self, content: str, memory_type: str = "fact", importance: float = 0.5):
        """存储一条记忆"""
        embedding = self.embed(content)
        with self.conn.cursor() as cur:
            cur.execute(
                "INSERT INTO agent_memory (content, embedding, memory_type, importance) VALUES (%s, %s, %s, %s)",
                (content, embedding, memory_type, importance)
            )
        self.conn.commit()

    def recall(self, query: str, top_k: int = 5) -> list[str]:
        """语义检索相关记忆"""
        query_embedding = self.embed(query)
        with self.conn.cursor() as cur:
            cur.execute("""
                SELECT content, 1 - (embedding <=> %s) AS similarity
                FROM agent_memory
                ORDER BY embedding <=> %s
                LIMIT %s
            """, (query_embedding, query_embedding, top_k))
            return [r[0] for r in cur.fetchall()]

    def forget(self, days_inactive: int = 30):
        """遗忘不活跃且不重要的记忆"""
        with self.conn.cursor() as cur:
            cur.execute("""
                DELETE FROM agent_memory
                WHERE last_accessed < NOW() - INTERVAL '%s days'
                AND importance < 0.3
            """, (days_inactive,))
        self.conn.commit()

关键设计:记忆不是越多越好------不重要的记忆需要「遗忘」,否则检索质量会下降。


五、从零构建多 Agent 系统:AI 代码助手

三个 Agent 协作完成代码任务:

markdown 复制代码
用户需求
    ↓
Architect Agent → 分析需求,输出技术方案
    ↓
Coder Agent → 根据方案编写代码
    ↓
Reviewer Agent → 审查代码,提出修改意见
    ↓ (最多 3 轮修改)
最终结果

完整实现

python 复制代码
import json
import asyncio
from dataclasses import dataclass

@dataclass
class AgentConfig:
    name: str
    role: str
    model: str
    temperature: float = 0.3

class BaseAgent:
    def __init__(self, config: AgentConfig, llm, tools: dict = None):
        self.config = config
        self.llm = llm
        self.tools = tools or {}

    async def think(self, task: str) -> str:
        system_prompt = f"你是 {self.config.name},{self.config.role}。请根据任务要求,输出工作结果。"
        response = await self.llm.chat([
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": task}
        ])
        return response.content


class ArchitectAgent(BaseAgent):
    """需求分析 Agent"""
    def __init__(self, llm):
        super().__init__(AgentConfig(
            name="Architect",
            role="技术架构师,负责分析需求并输出技术方案",
            model="claude-sonnet-4-6"
        ), llm)

    async def design(self, requirement: str) -> dict:
        prompt = f"""
        请分析以下需求,输出技术方案。

        需求:{requirement}

        输出 JSON:
        {{
            "summary": "需求概述",
            "architecture": "架构方案",
            "tech_stack": {{"frontend": "...", "backend": "...", "database": "..."}},
            "api_design": ["端点1", "端点2"],
            "components": ["组件1", "组件2"],
            "risks": ["风险1", "风险2"],
            "implementation_steps": ["步骤1", "步骤2"]
        }}
        """
        result = await self.think(prompt)
        return json.loads(result)


class CoderAgent(BaseAgent):
    """编码 Agent"""
    def __init__(self, llm, tools: dict):
        super().__init__(AgentConfig(
            name="Coder",
            role="高级软件工程师,根据技术方案编写代码",
            model="claude-sonnet-4-6"
        ), llm, tools)

    async def implement(self, design: dict) -> str:
        prompt = f"""
        根据技术方案编写完整代码:

        架构:{design.get('architecture')}
        技术栈:{json.dumps(design.get('tech_stack', {}), ensure_ascii=False)}
        实施步骤:{json.dumps(design.get('implementation_steps', []), ensure_ascii=False)}

        要求:编写完整可运行代码,包含类型注解和注释。
        """
        return await self.think(prompt)


class ReviewerAgent(BaseAgent):
    """代码审查 Agent"""
    def __init__(self, llm):
        super().__init__(AgentConfig(
            name="Reviewer",
            role="资深代码审查者,检查 Bug、安全问题和规范",
            model="claude-sonnet-4-6"
        ), llm)

    async def review(self, code: str, design: dict) -> dict:
        prompt = f"""
        审查以下代码:

        原始需求:{json.dumps(design, ensure_ascii=False)[:2000]}
        代码:{code[:8000]}

        输出 JSON:
        {{
            "approved": true/false,
            "score": 1-10,
            "issues": [{{"severity": "critical|major|minor", "description": "..."}}],
            "suggestions": ["建议1", "建议2"]
        }}
        """
        result = await self.think(prompt)
        return json.loads(result)


class CodeAssistantOrchestrator:
    """编排器:协调三个 Agent"""
    def __init__(self, llm, tools: dict = None):
        self.architect = ArchitectAgent(llm)
        self.coder = CoderAgent(llm, tools)
        self.reviewer = ReviewerAgent(llm)
        self.max_review_rounds = 3

    async def run(self, requirement: str) -> dict:
        print(f"📋 需求: {requirement}\n")

        # 1. 架构设计
        print("🏗️  Architect Agent 分析需求...")
        design = await self.architect.design(requirement)

        # 2. 编码
        print("💻 Coder Agent 编写代码...")
        code = await self.coder.implement(design)

        # 3. 审查(最多 3 轮)
        for round_num in range(self.max_review_rounds):
            print(f"🔍 Reviewer Agent 第 {round_num+1} 轮审查...")
            review = await self.reviewer.review(code, design)

            if review["approved"]:
                print(f"✅ 通过!评分: {review['score']}/10")
                return {
                    "design": design, "code": code,
                    "review": review, "status": "approved"
                }

            print(f"⚠️ 发现 {len(review['issues'])} 个问题,Coder 修复中...")
            fix_prompt = f"""
            根据审查意见修改代码:
            问题:{json.dumps(review['issues'], ensure_ascii=False)}
            建议:{json.dumps(review.get('suggestions', []), ensure_ascii=False)}
            原代码:{code[:8000]}
            """
            code = await self.coder.think(fix_prompt)

        return {"design": design, "code": code, "review": review, "status": "max_rounds_exceeded"}


# 使用
async def main():
    from anthropic import AsyncAnthropic
    llm = AsyncAnthropic()
    assistant = CodeAssistantOrchestrator(llm)
    result = await assistant.run("实现一个用户注册和登录的 REST API,支持 JWT 认证")
    if result["status"] == "approved":
        with open("generated_code.txt", "w") as f:
            f.write(result["code"])

if __name__ == "__main__":
    asyncio.run(main())

六、生产环境考量

6.1 成本控制:模型分层策略

不要所有 Agent 都用最贵的模型:

python 复制代码
class CostTracker:
    def __init__(self, budget: float):
        self.budget = budget
        self.spent = 0.0
        self.pricing = {
            "claude-sonnet-4-6":  {"input": 3.0, "output": 15.0},
            "claude-haiku-4-5":  {"input": 0.8, "output": 4.0},
            "deepseek-v4-pro":   {"input": 0.55, "output": 2.19},
        }

    def suggest_model(self, task_complexity: str) -> str:
        """根据任务复杂度和预算推荐模型"""
        if self.spent > self.budget * 0.7:
            return "claude-haiku-4-5"      # 预算紧张
        if task_complexity == "complex":
            return "claude-sonnet-4-6"
        return "claude-haiku-4-5"

策略:路由分派用 Haiku,核心推理用 Sonnet,简单文本处理用 DeepSeek。

6.2 安全

层面 措施
工具权限 三级分级(safe/write/dangerous)
执行沙箱 Docker 容器隔离:docker run --read-only --network=none
Prompt 注入防护 输入清洗 + 输出结构校验
审批流 危险工具调用前暂停等待人工确认

6.3 监控

python 复制代码
class AgentMetrics:
    def __init__(self):
        self.tool_calls = []
        self.llm_calls = []

    def report(self) -> dict:
        return {
            "total_llm_calls": len(self.llm_calls),
            "total_tool_calls": len(self.tool_calls),
            "tool_success_rate": sum(
                1 for t in self.tool_calls if t["status"] == "success"
            ) / max(len(self.tool_calls), 1),
        }

七、框架选型

框架 理念 适合
LangGraph 状态图驱动 复杂工作流,需要精细控制
CrewAI 角色扮演式 快速原型,几行代码跑起来
AutoGen 对话驱动(微软) 微软/Azure 生态
自研 完全定制 特殊需求,极致性能

建议:先用 CrewAI 或 LangGraph 验证想法,确认设计合理后再决定是否自研。不要一开始就自研------框架已经解决了 80% 的工程问题。


八、未来趋势

趋势 时间窗口
MCP + A2A 深度融合 2026 H2
Agent UI(AUI)替代 Chat UI 2026-2027
Docker/WASM 安全沙箱标准化 2027 H1
Agent 市场(类似 App Store) 2027

写在最后

Agent 架构不是什么魔法------它是 LLM、工具调用、记忆系统和多 Agent 协作的工程组合。

最重要的是想清楚三件事:

  1. Agent 在你的产品中解决什么问题?
  2. 它的失败模式是什么?(调错工具、忘记目标、死循环)
  3. 你怎么优雅地降级?(超时、预算耗尽、工具不可用)

回答好这三个问题,你就是 Agent 时代的合格架构师。


首发于 志趣 ZhiQu --- 一个 AI 开发者知识社区,欢迎来交流。

相关推荐
Hector_zh1 小时前
实战·第八篇:当模型陷入死循环——FACA破解JSON生成的架构陷阱
人工智能·agent·vibecoding
魏祖潇1 小时前
AI 能记住了,但能自己干活吗?——看懂执行系统,你就知道它怎么完成复杂任务
人工智能·ai编程
Lkstar1 小时前
Function Calling 原理深度拆解:让 LLM 调用外部工具的机制与工具设计原则
人工智能·llm
IT_陈寒2 小时前
Vue的响应式真把我坑惨了,原来问题出在这
前端·人工智能·后端
武子康2 小时前
调查研究-190 Continue.dev 被 Cursor 收购:AI 编程工具正从“插件竞争“迈入“平台整合“阶段
人工智能·ai编程·cursor
武子康2 小时前
调查研究-189 Kronos 调研:金融 K 线基础模型,是真突破,还是量化圈的新玩具?
人工智能·深度学习·openai
东坡肘子3 小时前
Swift 还让你 Excited 吗?-- 肘子的 Swift 周报 #141
人工智能·swiftui·swift
nujnewnehc3 小时前
不会 py, 用 ai 写了个游戏辅助的感受
人工智能·游戏
ZhengEnCi12 小时前
09c-斯坦福CS336作业二:系统与分布式训练
人工智能