第 50 期 | 从程序员到全栈掌控者:属于 Agent 开发者的十年机遇

更新于 2026/4/5

🎯 学习目标

  • 理解 Agent 驱动型开发范式如何重塑传统软件工程,并识别其带来的十年机遇。
  • 掌握构建和编排 Agent 系统的核心概念,包括工具定义、状态管理与人机协作。
  • 学会利用 Claude 等大型语言模型构建具备复杂决策和执行能力的 Agent 应用。
  • 思考在 Agent 时代,如何通过系统级设计和问题解决能力构建个人竞争壁垒。

📖 核心概念讲解

嘿,各位 Code 爱好者!欢迎来到 Claude Code 教程系列的第 50 期。这是一个里程碑式的数字,所以我们今天不谈具体的 API 调用,而是把目光放远,聊聊未来十年属于我们 Agent 开发者的机遇与挑战。副标题“终局思考:当架构不会改变但干事方式改变时,你的竞争壁垒是什么?”直指核心——基础设施可能依然是 Kubernetes、AWS、数据库,但业务逻辑的实现和任务的执行方式,将由 Agent 彻底革新。

50.1 Agent 时代的“全栈”新定义:从 CRUD 到自治系统设计

在 Web 2.0 时代,“全栈”意味着精通前端框架、后端服务、数据库和部署运维。而在 Agent 时代,这个定义正在被彻底改写。我们的关注点从实现具体的 API 接口和数据模型,转向设计、构建和编排能够自主完成复杂任务的智能实体——Agent。

传统全栈 vs. Agent 全栈:

维度 传统全栈开发者 Agent 全栈开发者
核心职责 构建和维护特定功能的应用服务 设计、实现和优化具备自主决策、规划和执行能力的 Agent 系统
技能栈 前端框架 (React/Vue)、后端语言 (Node.js/Python/Java)、数据库 (SQL/NoSQL)、DevOps (Docker/K8s) Prompt Engineering: 引导 Agent 行为
Tool Development: 为 Agent 提供能力接口
Agent Orchestration: 协调多个 Agent
State Management: 管理 Agent 的长期记忆与上下文
Human-in-the-Loop (HITL): 设计人机协作机制
Observability: 监控 Agent 行为与性能
System Design: 跨领域问题分解与解决方案设计
关注点 数据流、API 接口、UI 交互、业务逻辑实现 任务目标、Agent 行为、决策路径、工具选择、异常处理、效率与可靠性、安全与伦理
产出 Web 应用、移动应用、API 服务 自治工作流、智能助手、决策支持系统、自动化运营平台
竞争壁垒 编程效率、架构理解、特定技术栈深度 问题分解能力、抽象思维、系统设计能力、对 LLM 限制与优势的深刻理解、工具设计与集成能力、人机协作模式设计

我们的价值不再仅仅是写出“正确”的代码,而是设计出能够“正确地干事”的智能实体。这需要我们从宏观的业务目标出发,将其分解为 Agent 可执行的子任务,并为其配备合适的工具、记忆和决策机制。

50.2 构建 Agent 的核心要素与设计模式

一个成熟的 Agent 并非简单地调用 LLM API,它是一个包含多个组件的复杂系统。理解这些组件及其相互作用是构建强大 Agent 的关键。

Agent 系统构成示意图 (ASCII Art):

+-------------------------------------+
|           Agent Orchestrator        |
| (Manages overall workflow, tasking) |
+-------------------------------------+
        |
        v
+-------------------------------------+
|         Agent Core (LLM)            |
| (Reasoning, Planning, Decision-making)|
+-------------------------------------+
        |  ^
        v  |
+-------------------------------------+    +-------------------------------------+
|        Memory / State Manager       |<-->|            Tool Library             |
| (Short-term context, Long-term knowledge)|(APIs, CLI, Database access, Web search)|
+-------------------------------------+    +-------------------------------------+
        ^  |
        |  v
+-------------------------------------+
|      Human-in-the-Loop (HITL)       |
| (Confirmation, Clarification, Override)|
+-------------------------------------+
        ^
        |
+-------------------------------------+
|           Observability             |
| (Logging, Monitoring, Tracing)      |
+-------------------------------------+
  • Agent Core (LLM): 负责理解任务、进行推理、制定计划并选择合适的工具。这是 Agent 的“大脑”。
  • Tool Library: Agent 的“手脚”。一套精心设计的工具集,让 Agent 能够与外部世界互动,执行具体操作(如调用 API、查询数据库、发送邮件、执行代码等)。
  • Memory / State Manager: Agent 的“记忆”。
    • 短期记忆 (Context Window): 维持当前对话或任务的上下文,通过 Prompt 管理。
    • 长期记忆 (Knowledge Base): 存储结构化或非结构化的历史数据、用户偏好、领域知识等,通过 RAG (Retrieval Augmented Generation) 等技术实现。
  • Agent Orchestrator: 当任务复杂或需要多个 Agent 协作时,Orchestrator 负责任务分解、子任务分配、结果聚合和冲突解决。
  • Human-in-the-Loop (HITL): 关键环节的人工介入机制,确保复杂任务的准确性和安全性。这可以是确认步骤、澄清疑问或人工审核。
  • Observability: 监控 Agent 的运行状态、决策路径、工具调用情况和性能指标,以便调试、优化和确保合规。

构建竞争壁垒的思考: 在 Agent 时代,LLM 本身是商品化的。你无法通过“拥有”一个 LLM 来构建壁垒。真正的壁垒在于:

  1. 领域专业知识的封装: 将特定行业或业务的复杂逻辑和数据封装成 Agent 可用的工具和知识库。
  2. 系统级问题解决能力: 将模糊的业务需求转化为可执行的 Agent 任务流,并设计健壮的错误处理和恢复机制。
  3. 人机协作模式的创新: 如何高效、安全地让人类与 Agent 共同完成任务,发挥各自优势。
  4. 可观测性和可控性: 构建强大的监控、调试和审计系统,确保 Agent 的行为符合预期并可追溯。

这不再仅仅是编程的问题,更是系统工程、产品设计和业务理解的综合体现。


💻 模拟 Claude TUI 交互

想象一下,你正在使用一个增强型的 Claude TUI,它不仅能回答问题,还能帮助你设计和部署 Agent。

场景一:设计一个简单的“项目经理 Agent”

> Claude,我想设计一个“项目经理 Agent”。它需要能够创建 Jira 任务,更新 Confluence 文档,并给团队发送 Slack 通知。请帮我定义它的核心工具和初步工作流。

╭─ Claude ──────────────────────────────╮
│  好的,这是一个有趣且实用的 Agent 概念。为了构建一个“项目经理 Agent”,我们首先需要为其定义一套工具,│
│  使其能够与外部系统交互。以下是初步的工具清单和工作流设想:                                            │
│                                                                                                        │
│  **1. 核心工具定义 (Tools Manifest):**                                                                 │
│     *   `create_jira_issue(project_key: str, summary: str, description: str, issue_type: str)`:         │
│         用途:在 Jira 中创建新的任务、故事或缺陷。                                                     │
│         说明:需要 Jira API 凭证和项目信息。                                                            │
│     *   `update_confluence_page(page_id: str, title: str, content: str)`:                                │
│         用途:更新 Confluence 中的指定页面内容。                                                       │
│         说明:需要 Confluence API 凭证和页面 ID。                                                      │
│     *   `send_slack_message(channel: str, message: str)`:                                               │
│         用途:向指定的 Slack 频道发送消息。                                                            │
│         说明:需要 Slack Bot Token 和频道 ID。                                                         │
│                                                                                                        │
│  **2. 初步工作流设想 (Example Workflow for "New Feature Request"):**                                     │
│      1.  **接收请求:** Agent 接收到用户关于“新功能开发”的请求。                                       │
│      2.  **需求分析 (内部推理):** Agent 分析请求,识别关键信息(功能名称、描述、优先级等)。             │
│      3.  **创建 Jira 任务:** 调用 `create_jira_issue` 工具,在 Jira 中创建相应的故事或任务。            │
│          *   **人机协作点 (HITL):** 在创建前,Agent 可询问用户确认 Jira 任务的详细信息,如“您确认要创建│
│              一个名为 'XXX' 的故事,优先级为 '高' 吗?”                                                │
│      4.  **更新 Confluence 文档:** 调用 `update_confluence_page` 工具,在项目文档中添加新功能概述。    │
│      5.  **发送 Slack 通知:** 调用 `send_slack_message` 工具,通知相关团队新任务已创建,并附上 Jira 链接。│
│      6.  **记录状态:** Agent 内部更新任务状态,并可能存储到长期记忆中。                                │
│                                                                                                        │
│  这个工作流可以作为起点。接下来,我们可以深入到每个工具的具体实现,以及如何配置 Agent 的长期记忆和错误处理机制。│
╰───────────────────────────────────────╯

场景二:调试 Agent 的工具调用失败

> 我的“项目经理 Agent”在尝试创建 Jira 任务时失败了,日志显示“Jira API returned 403 Forbidden”。请帮我诊断可能的原因并提供解决方案。

╭─ Claude ──────────────────────────────╮
│  收到,Jira API 返回 403 Forbidden 通常表示认证或权限问题。让我们一步步诊断:                            │
│                                                                                                        │
│  **1. 诊断步骤:**                                                                                     │
│      *   **Agent 内部状态检查:**                                                                      │
│          *   **工具调用参数:** Agent 调用 `create_jira_issue` 时传入的 `project_key` 或其他参数是否正确?│
│              有时,API 会因为参数不符合预期而返回权限错误。                                            │
│          *   **凭证管理:** Agent 用于调用 Jira API 的凭证(API Token, 用户名/密码)是否正确配置且未过期?│
│              Claude 可以通过内部工具检查 `credentials_manager` 中的 Jira 配置。                       │
│      *   **Jira 侧检查:**                                                                             │
│          *   **API Token 权限:** 用于认证的 API Token 是否拥有在目标 Jira 项目中创建任务的权限?     │
│              这需要在 Jira 中检查该 Token 所属用户或角色的权限设置。                                   │
│          *   **项目权限:** 目标 `project_key` 是否对该用户可见且可操作?                              │
│          *   **IP 白名单:** 如果 Jira 设置了 IP 白名单,Agent 的出站 IP 是否在允许范围内?           │
│                                                                                                        │
│  **2. 解决方案建议:**                                                                                 │
│      1.  **核对凭证:** 仔细检查 `jira_api_token` 和 `jira_username` 是否与 Jira 后台配置完全一致。    │
│          如果使用环境变量,请确保环境变量已正确加载。                                                  │
│      2.  **检查 Jira 权限:** 登录 Jira 管理后台,找到用于 Agent 认证的用户,确认其在目标项目拥有 `Create Issues` 的权限。│
│          可以尝试用该用户手动创建一个任务,看是否成功。                                                │
│      3.  **更新工具定义:** 如果权限模型发生变化,可能需要更新 Agent 的 `create_jira_issue` 工具定义,│
│          例如,如果需要额外的字段或不同的认证方式。                                                    │
│      4.  **重试机制:** 确保 Agent 的工具调用包含基本的重试逻辑,以应对临时的网络或服务波动。           │
│                                                                                                        │
│  请您先从第一点开始排查。如果需要,我可以引导您检查 Agent 的配置文件或凭证存储。                         │
╰───────────────────────────────────────╯

💻 代码演示

这里我们演示如何定义一个简单的 Agent 工具清单(Tool Manifest)和一个用于 Agent 执行的 Python 伪代码片段。

Tool Manifest (YAML 格式)

# tools_manifest.yaml
version: "1.0"
tools:
  - name: create_jira_issue
    description: "在 Jira 中创建新的任务、故事或缺陷。"
    parameters:
      type: object
      properties:
        project_key:
          type: string
          description: "Jira 项目的关键标识符 (e.g., 'DEV', 'PROJ')."
        summary:
          type: string
          description: "任务的简短摘要或标题。"
        description:
          type: string
          description: "任务的详细描述。"
        issue_type:
          type: string
          description: "任务类型 (e.g., 'Story', 'Task', 'Bug')."
      required: ["project_key", "summary", "description", "issue_type"]
    implementation:
      type: "function" # 表示这是一个可调用的函数或 API
      endpoint: "https://api.internal.com/jira/create_issue" # 实际的 API 端点
      method: "POST"
      headers:
        Authorization: "Bearer ${JIRA_API_TOKEN}" # 假设从环境变量获取

  - name: update_confluence_page
    description: "更新 Confluence 中的指定页面内容。"
    parameters:
      type: object
      properties:
        page_id:
          type: string
          description: "Confluence 页面的 ID。"
        title:
          type: string
          description: "页面的新标题。"
        content:
          type: string
          description: "页面的新内容 (支持 Confluence 的存储格式或 Markdown)."
      required: ["page_id", "title", "content"]
    implementation:
      type: "function"
      endpoint: "https://api.internal.com/confluence/update_page"
      method: "PUT"
      headers:
        Authorization: "Bearer ${CONFLUENCE_API_TOKEN}"

  - name: send_slack_message
    description: "向指定的 Slack 频道发送消息。"
    parameters:
      type: object
      properties:
        channel:
          type: string
          description: "Slack 频道名称或 ID (e.g., '#general', 'C12345')."
        message:
          type: string
          description: "要发送的消息文本。"
      required: ["channel", "message"]
    implementation:
      type: "function"
      endpoint: "https://slack.com/api/chat.postMessage"
      method: "POST"
      headers:
        Authorization: "Bearer ${SLACK_BOT_TOKEN}"
        "Content-Type": "application/json"
      body:
        channel: "${channel}"
        text: "${message}"

Agent 执行逻辑(Python 伪代码)

这展示了一个简化的 Agent 循环,如何接收用户请求,利用 LLM 决策,并调用工具。

import os
import json
import requests
from typing import Dict, Any, List

# 假设这是一个简化的 LLM 交互函数
def call_llm(prompt: str, tools_manifest: List[Dict]) -> Dict:
    """
    模拟调用 Claude LLM,根据 prompt 和工具清单生成响应。
    响应可能包含文本回复或工具调用指令。
    """
    print(f"\n[Agent Core]: Calling LLM with prompt:\n{prompt[:200]}...")
    # 实际场景中,这里会调用 Anthropic API,并传入 tools 参数
    # 例如:anthropic.messages.create(model="claude-3-opus-20240229", messages=[...], tools=tools_manifest)
    # 为演示目的,我们模拟 LLM 的响应
    if "创建 Jira 任务" in prompt:
        return {
            "type": "tool_use",
            "tool_name": "create_jira_issue",
            "tool_input": {
                "project_key": "DEV",
                "summary": "Implement new user authentication flow",
                "description": "As a user, I want to be able to log in securely using OAuth.",
                "issue_type": "Story"
            }
        }
    elif "通知团队" in prompt:
        return {
            "type": "tool_use",
            "tool_name": "send_slack_message",
            "tool_input": {
                "channel": "#dev-updates",
                "message": "新的用户认证流程任务已在 Jira 创建:[链接到Jira任务]"
            }
        }
    else:
        return {"type": "text", "content": "好的,我明白了。我将根据您的指示进行操作。"}

# 工具执行器
def execute_tool(tool_name: str, tool_input: Dict, tools_manifest: List[Dict]) -> Any:
    """根据工具清单执行指定的工具。"""
    tool_config = next((t for t in tools_manifest if t['name'] == tool_name), None)
    if not tool_config:
        raise ValueError(f"Tool '{tool_name}' not found in manifest.")

    implementation = tool_config['implementation']
    if implementation['type'] == 'function':
        endpoint = implementation['endpoint']
        method = implementation['method']
        headers = {k: v.replace('${JIRA_API_TOKEN}', os.getenv('JIRA_API_TOKEN'))
                     .replace('${CONFLUENCE_API_TOKEN}', os.getenv('CONFLUENCE_API_TOKEN'))
                     .replace('${SLACK_BOT_TOKEN}', os.getenv('SLACK_BOT_TOKEN'))
                   for k, v in implementation.get('headers', {}).items()}

        # 替换 body 中的占位符
        body_template = implementation.get('body', {})
        body = {}
        for k, v in body_template.items():
            if isinstance(v, str) and v.startswith('${') and v.endswith('}'):
                # 尝试从 tool_input 获取对应的值
                key = v[2:-1] # 提取 'channel' 或 'message'
                body[k] = tool_input.get(key, v)
            else:
                body[k] = v

        print(f"[Tool Executor]: Executing {tool_name} with input: {tool_input}")
        print(f"[Tool Executor]: Calling {method} {endpoint} with headers: {headers} and body: {body}")

        try:
            if method == "POST":
                response = requests.post(endpoint, headers=headers, json=body if body else tool_input)
            elif method == "PUT":
                response = requests.put(endpoint, headers=headers, json=body if body else tool_input)
            else:
                raise NotImplementedError(f"Method {method} not supported.")

            response.raise_for_status() # 抛出 HTTP 错误
            print(f"[Tool Executor]: {tool_name} success. Response: {response.json()}")
            return {"status": "success", "result": response.json()}
        except requests.exceptions.RequestException as e:
            print(f"[Tool Executor]: {tool_name} failed. Error: {e}")
            return {"status": "error", "message": str(e)}
    else:
        raise NotImplementedError(f"Implementation type '{implementation['type']}' not supported.")

# 主 Agent 循环
def agent_loop(user_query: str, tools_manifest_path: str):
    # 加载工具清单
    with open(tools_manifest_path, 'r') as f:
        tools_data = json.load(f) # 假设 YAML 已转换为 JSON
        # 实际使用时,Anthropic SDK 直接支持 dict 格式
        manifest_tools = tools_data.get('tools', [])

    current_prompt = f"用户请求:{user_query}\n\n"
    conversation_history = [] # 用于管理上下文

    while True:
        # 将当前对话历史和用户请求发送给 LLM
        llm_response = call_llm(current_prompt, manifest_tools)

        if llm_response['type'] == 'text':
            print(f"Agent 回复: {llm_response['content']}")
            conversation_history.append({"role": "assistant", "content": llm_response['content']})
            break # 任务完成或等待用户进一步指示
        elif llm_response['type'] == 'tool_use':
            tool_name = llm_response['tool_name']
            tool_input = llm_response['tool_input']
            print(f"Agent 决定调用工具: {tool_name} with input: {tool_input}")

            try:
                tool_output = execute_tool(tool_name, tool_input, manifest_tools)
                print(f"工具 {tool_name} 执行结果: {tool_output}")
                # 将工具执行结果添加到 prompt 中,供 LLM 下一步决策
                current_prompt += f"\n\n工具 {tool_name} 执行结果: {json.dumps(tool_output)}\n"
            except Exception as e:
                print(f"工具 {tool_name} 执行失败: {e}")
                current_prompt += f"\n\n工具 {tool_name} 执行失败: {str(e)}\n"
        else:
            print("LLM 返回未知响应类型。")
            break

# 示例运行
if __name__ == "__main__":
    # 模拟设置环境变量
    os.environ['JIRA_API_TOKEN'] = 'your_jira_token_here'
    os.environ['CONFLUENCE_API_TOKEN'] = 'your_confluence_token_here'
    os.environ['SLACK_BOT_TOKEN'] = 'your_slack_token_here'

    # 为了简化,这里将 YAML 转换为 JSON 字典
    # 实际应用中,你会直接加载 YAML 或使用 Anthropic SDK 的 tool 结构
    sample_tools_manifest_json = {
        "version": "1.0",
        "tools": [
            {
                "name": "create_jira_issue",
                "description": "在 Jira 中创建新的任务、故事或缺陷。",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "project_key": {"type": "string", "description": "Jira 项目的关键标识符 (e.g., 'DEV', 'PROJ')."},
                        "summary": {"type": "string", "description": "任务的简短摘要或标题。"},
                        "description": {"type": "string", "description": "任务的详细描述。"},
                        "issue_type": {"type": "string", "description": "任务类型 (e.g., 'Story', 'Task', 'Bug')."}
                    },
                    "required": ["project_key", "summary", "description", "issue_type"]
                },
                "implementation": {
                    "type": "function",
                    "endpoint": "https://api.internal.com/jira/create_issue",
                    "method": "POST",
                    "headers": {"Authorization": "Bearer ${JIRA_API_TOKEN}"}
                }
            },
            {
                "name": "send_slack_message",
                "description": "向指定的 Slack 频道发送消息。",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "channel": {"type": "string", "description": "Slack 频道名称或 ID (e.g., '#general', 'C12345')."},
                        "message": {"type": "string", "description": "要发送的消息文本。"}
                    },
                    "required": ["channel", "message"]
                },
                "implementation": {
                    "type": "function",
                    "endpoint": "https://slack.com/api/chat.postMessage",
                    "method": "POST",
                    "headers": {
                        "Authorization": "Bearer ${SLACK_BOT_TOKEN}",
                        "Content-Type": "application/json"
                    },
                    "body": {
                        "channel": "${channel}",
                        "text": "${message}"
                    }
                }
            }
            # ... 其他工具
        ]
    }

    # 临时保存为 JSON 文件,供 Agent 循环加载
    with open('temp_tools_manifest.json', 'w') as f:
        json.dump(sample_tools_manifest_json, f, indent=2)

    print("--- 启动 Agent 模拟 ---")
    agent_loop("请为我创建一个 Jira 任务,主题是 '实现新的用户认证流程',描述为 '作为用户,我希望能够安全地使用 OAuth 登录。',类型为 'Story'。完成后请通知 #dev-updates 频道。", 'temp_tools_manifest.json')
    print("--- Agent 模拟结束 ---")

注意: 上述 Python 代码中的 call_llmexecute_tool 函数是高度简化的模拟。在实际开发中,call_llm 会使用 Anthropic SDK 调用 Claude API,并且 execute_tool 会调用实际的第三方服务 API。这里主要演示 Agent 的决策流程和工具调用模式。


🔧 涉及的 Tools / Commands

| 工具名称 / 命令 | 用途 | 说明