第 50 期 | 从程序员到全栈掌控者:属于 Agent 开发者的十年机遇
🎯 学习目标
- 理解 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 来构建壁垒。真正的壁垒在于:
- 领域专业知识的封装: 将特定行业或业务的复杂逻辑和数据封装成 Agent 可用的工具和知识库。
- 系统级问题解决能力: 将模糊的业务需求转化为可执行的 Agent 任务流,并设计健壮的错误处理和恢复机制。
- 人机协作模式的创新: 如何高效、安全地让人类与 Agent 共同完成任务,发挥各自优势。
- 可观测性和可控性: 构建强大的监控、调试和审计系统,确保 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_llm 和 execute_tool 函数是高度简化的模拟。在实际开发中,call_llm 会使用 Anthropic SDK 调用 Claude API,并且 execute_tool 会调用实际的第三方服务 API。这里主要演示 Agent 的决策流程和工具调用模式。
🔧 涉及的 Tools / Commands
| 工具名称 / 命令 | 用途 | 说明