按照故障所传授的顺序学习智能体AI工程
进入智能体工程的系统化路径:智能体表现出的故障模式、核心技术栈、五个有序推进的项目,以及保障其安全的状态管理、审查机制与安全模式。
那些转而从事智能体工程的开发者常常试图一次性掌握所有框架,会在一周内轮流使用LangChain、CrewAI、AutoGen和LangGraph,却始终无法产出任何实际成果。问题在于学习顺序:他们在尚未理解这些工具旨在避免的失败情形之前就先去研究它们。本指南按照技能之间实际的递进关系,设计了14步学习路径,从基础Python开始,直至实现可无人值守运行的智能体。在这段学习过程中,你将了解影响每一个设计决策的三种失败模式、能够覆盖大多数生产场景的简易技术组合,以及那些能将演示版本与可立即投入使用的可靠系统区分开来的结构化模式(状态文件、创建者-审核者审查机制、分层评估与权限控制)。
第一部分:思维模型
1. 智能体工程并非只是给提示工程换个新名称
提示词工程旨在设计用于向模型输入的内容。智能体工程则着眼于构建能够决定模型应处理什么任务、何时停止以及在其答案出错时如何反应的系统。
其具体定义很明确:你需要开发这样的软件,让大语言模型自行选择下一步操作,调用工具执行该操作,检查结果,并不断重复直至任务完成,整个过程无需人工干预。聊天机器人是对消息作出回应,而智能体则是选择操作、执行它们、检查结果并不断迭代。这种差异就是两者工作的核心区别。
这带来了提示词工程从未要求过的三项责任:
- 将错误处理作为核心问题。智能体总会出错:API超时、返回的JSON格式错误、模型编造了工具调用,以及工具输出不符合预设结构。那些假设一切都会成功的代码往往会在最糟糕的时刻崩溃,通常就是在演示过程中。
- 状态管理。单次LLM调用不会保留任何信息。而需要执行十步工具调用、多次重试并使用子智能体的智能体,则需要结构化且持久的状态,以便在单个上下文窗口之外依然能够继续工作。
- 将评估机制融入基础设施中。没有直观方式可以判断智能体是否正确。因此需要自动化检测机制,比如测试、评分标准或评估模型,以便在无需人工逐一检查的情况下就能剔除错误输出。
这些职位的描述往往像产品目录一样。编排框架(LangGraph、LangChain、LlamaIndex)、协议(MCP、A2A)、模型功能(函数调用、结构化输出、提示词缓存)、检索技术(RAG、RAGAS、混合搜索、重排序、嵌入模型、向量和图数据库)以及操作技能(沙箱执行、可观测性、评估)都会出现,通常还会要求候选人具备快速迭代的能力。这份清单看起来令人望而生畏,但实际上大多数内容都是不同名称下的几项核心理念。掌握了这些理念,各种产品名称就容易理解了。
2. 三种故障模式解释了大部分工作内容
在编写代码之前,先要明白代理系统为何会出故障。该领域的几乎所有工具和模式都是为了解决三种特定行为问题而存在的。
代理惰性。面对漫长且分多阶段的任务时,模型会提前停止并在完成部分工作后报告成功。它处理了50个待办任务中的20个,并称其余的也已处理完毕。相应的对策是设定明确的停止条件,由模型之外的其他机制来进行检查。
自我偏好偏差。当被要求审核自己的输出时,模型总会给予肯定评价。而对结果有既得利益关系的审核者则无法做到公正评判。解决此问题的办法是采用结构化设计:负责生成内容的代理不能同时担任审核角色。
目标偏移。在经过大量步骤处理后,尤其是在上下文被总结或压缩之后,智能体会逐渐忘记最初的目标。诸如“不要触碰支付模块”这样的约束可能在第47步时就悄然消失。解决办法是使用一个持久化的规范文件,在每次运行时重新读取,从而保留模型否则会丢失的约束条件。
当生态系统显得过于复杂时,可以询问任何新工具或模式能解决这三种问题中的哪一种。这个问题就能帮助过滤掉大部分无关信息。
3. 简洁的核心技术栈以及四件应推迟处理的事
需求清单很长,但实际智能体工作的核心仍集中在四个层面,建议按以下顺序学习:
Core stack (learn these, in this order):
1. Python + async : the bedrock; everything else builds on it
2. LLM APIs : Anthropic, OpenAI; understand tokens, context, costs
3. Tool use / MCP : function calling; how models act on the world
4. LangGraph : stateful orchestration for multi-step, multi-agent work
在至少开发出一个可用的智能体之前,先推迟处理以下内容:
- 微调。早期的项目几乎不需要这样做。一个功能强大的基础模型加上设计良好的提示词,通常比经过微调但提示词不佳的模型效果更好。
- 纠结于向量数据库。像Chroma这样的工具在本地使用完全没问题,而Pinecone这类托管服务则适合生产环境。只有在构建的项目中检索功能真正成为瓶颈时,再考虑选择哪种数据库。
- 更换框架。先选定一个编排框架(LangGraph是个不错的默认选择),完成一个项目后再去探索其他选项。如果每周都因为某个工具号称更简单就更换,那就永远无法完成任何项目。
- 语音与浏览器智能体。这些都是建立在相同基础之上的特殊化应用。先掌握文本智能体,其工作模式可以迁移到其他类型上。
第二部分:构建模块
4. Python与异步代码
无需精通Python,但至少要具备排查故障的能力,因为智能体经常会出错。重点关注以下内容:
- 类与数据模型。智能体会在各个步骤之间传递结构化数据,因此需要对其进行建模。Pydantic模式可作为工具调用与智能体逻辑之间的契约;应将其视为必需项,而非可选项。
- 使用
asyncio实现异步处理。智能体的大部分时间都用于等待工具响应:数据库查询、HTTP请求或子进程执行。同步代码在每次等待时都会暂停,而异步代码则可以继续执行其他任务。智能体代码运行缓慢往往是因为存在大量串行等待的同步代码。
try/except结构中。智能体是在无人监督的情况下运行的,若出现未处理的异常且仅打印堆栈跟踪后就终止运行,那么在深夜时根本无法解决问题。一个实用的衡量标准:如果你能够通过检查清单将任务交给初级工程师,并相信测试套件能发现他们的错误,那就说明你已经掌握了足够的Python知识可以开始学习了。后续还可以进一步深入学习。
5. 大语言模型基础:标记、上下文与成本
Claude、GPT和Gemini等模型虽然功能强大,但需要明确的指导方向,而你无法对不了解的事物进行指导。
分词。模型读取的是分词而非单词,且同一个术语会根据分词器的不同拆分成多个分词。以英语为例,100,000个分词的上下文大约对应75,000个单词。超出这个范围的内容,无论是上周的对话还是被遗忘未包含的文件,对模型而言都不存在。如果某内容很重要,它必须包含在上下文中。
上下文限制与检索。模型不会记忆;每个会话都从空白状态开始。将所有内容都放入提示词中成本高昂,且随着内容增多质量会下降。检索增强生成技术的作用就是仅获取相关内容。
推理而非训练。你几乎从不需要训练模型。只需调用他人提供的模型进行推理,并按每个标记付费。成本等于输入标记数乘以输入价格,再加上输出标记数乘以输出价格,因此在一个上下文长度为20,000个标记的循环中进行50次调用时,会产生相当可观的账单。
智能体提示词设计。智能体提示词与普通聊天提示词有所不同。其中三种模式最为重要:思维链,即模型在采取行动前先明确进行推理;ReAct,即循环执行推理、行动和观察的流程;以及反思,即模型在返回结果前先对自己的初稿进行评估。其他大多数提示词技巧都是这些模式的变体。如需更深入了解ReAct循环,可参阅ReAct智能体如何将推理与现实世界行动相结合。
6. 工具使用与MCP将聊天机器人转变为智能体
仅能生成文本的模型就是聊天机器人。而能够调用函数、查看结果并决定下一步行动的模型则是智能体,工具使用正是实现这一功能的机制。
从技术层面来看,你需要为每个函数指定名称、自然语言描述以及参数的JSON架构,然后将这些定义与用户的消息一同发送。模型会判断是否需要使用工具,如果需要,则会返回包含参数的结构化工具调用信息而非纯文本。你的代码负责执行该函数并将结果传回,模型再以此为起点继续处理。描述与架构同样重要,因为模型正是依据描述来判断何时该使用工具的。
大多数实用的智能体工具可归为四类。下方的示例说明了这四类工具:用于读取(观察世界)的工具、用于写入(改变状态)的工具、用于执行代码的工具,以及用于验证工作的工具:
# Category 1: Read (agent observes the world)
def search_codebase(query: str, path: str) -> list[str]: ...
def fetch_url(url: str) -> str: ...
def read_file(path: str) -> str: ...
# Category 2: Write (agent changes state)
def create_file(path: str, content: str) -> None: ...
def open_pull_request(title: str, body: str, branch: str) -> str: ...
def send_slack_message(channel: str, text: str) -> None: ...
# Category 3: Execute (agent runs code)
def run_tests(test_path: str) -> dict: ...
def execute_sql(query: str, db: str) -> list[dict]: ...
# Category 4: Verify (agent checks its own work)
def lint_code(file_path: str) -> list[str]: ...
def run_type_checker(path: str) -> bool: ...
这些分类也是评估风险的有用视角。用于读取和验证的工具通常可以安全地自由调用,而用于写入和执行的工具会改变系统状态,因此需要更严格的权限控制,这一主题在安全步骤中也会再次提及。
模型上下文协议(MCP)是一种新兴标准,它用协议替代了自定义的集成代码。一个常见的类比是AI领域的USB-C:每当智能体需要访问GitHub、Slack或数据库时,无需每次都编写专用的适配器,只需连接现有的MCP服务器,主机应用即可发现该服务器的功能并直接使用,无需额外的衔接代码。
最能快速见到成效的集成包括:用于分支、拉取请求和问题的 GitHub;用于通知与摘要的 Slack;用于查询和受控写入的数据库;以及团队的问题追踪工具。将这四者连接起来,智能体便能处理大部分工程工作流程中的任务。
7. 数据检索,因为上下文存在限制
基于检索的生成技术能为智能体提供超出其上下文范围的知识。这是对现实限制的应对,而非一时潮流:上下文窗口是有限的,而代码库和文档则并非如此。
检索系统由四个主要部分组成:
- 分块,这是初学者最常出错的地方。过大的分块会包含过多无关内容;而过小的分块则会导致意义丧失。合适的分块大小取决于具体内容,通常代码需要以函数整体等作为分界,而文档则有所不同。
- 嵌入,它使得相似性搜索成为可能。嵌入模型将文本转换为数值向量,从而使内容相似的段落产生相近的向量。
- 搜索,该功能会找出与嵌入查询最接近的存储向量,并返回对应的分块内容。
成熟的检索过程很少是直接从查询到答案的简单流程。实际系统通常会在搜索前重新表述问题,搜索后再对结果进行重排序,并通过评估步骤来判断检索到的材料是否真正能回答问题。实际上,模型会思考应该获取什么内容以及获取是否成功。
8. 使用LangGraph实现有状态编排
单次大语言模型调用并不等同于一个智能体。智能体会执行多个步骤,在这些步骤之间保持状态,根据观察结果做出决策,并从故障中恢复。LangGraph正好为这类功能提供了相应的结构。
从结构上看,LangGraph应用是一个有向图,其节点为各种函数,如智能体、工具或处理步骤。边则决定了控制流在节点之间的传递方式。每个节点都会读取并更新一个共享的、有类型的状态对象。
下面的示意图定义了一种状态,该状态包含任务、计划、结果、错误以及完成标志,随后会注册四个节点:负责分解工作的规划器、执行单一步骤的执行器、检查结果的验证器,以及负责重试或上报错误的错误处理器。验证器之后的条件边是循环的核心:当状态表示任务已完成时则结束循环,存在错误时转交给错误处理器,否则执行下一步。需要注意的是,这只是一个片段;一个可运行的图结构还需要入口点、其余的边以及一次compile()调用。
from langgraph.graph import StateGraph, END
from typing import TypedDict
class AgentState(TypedDict):
task: str
plan: list[str]
results: list[str]
errors: list[str]
done: bool
graph = StateGraph(AgentState)
graph.add_node("planner", plan_task) # breaks work into steps
graph.add_node("executor", execute_step) # runs one step
graph.add_node("verifier", verify_output) # checks the result
graph.add_node("handler", handle_error) # retries or escalates
graph.add_conditional_edges(
"verifier",
lambda state: END if state["done"] else
"handler" if state["errors"] else
"executor"
)
与手写的Python循环相比,该框架增加了三项功能:
- 检查点机制。使用检查点工具编译图结构时,每执行一步都会保存当前状态,这样即使运行被中断(如笔记本死机、会话重启),也能从上次停止的位置继续,而无需重新开始。
- 人工干预暂停功能。为高风险节点设置
interrupt_before参数后,图结构会暂停并显示建议的操作,等待人工确认后再继续执行。这也是演示用智能体与实际应用型智能体之间的重要区别所在。 - 并行分支处理。框架可同时运行多个独立步骤,并自动将它们的结果合并到状态中,因此用户只需描述结构即可,无需编写同步代码。
一个合理的准则是:当智能体需要处理超过三步的流程、工具输出的分支情况,或需循环直到满足特定条件时,应使用图框架。若仅为没有分支的线性链结构,则用普通Python即可。相关权衡细节可在选择线性链与带状态图一文中进一步了解。
第三部分:正确构建智能体
9. 五个依次进行的项目
了解智能体与实际构建它们是不同的技能,只有通过动手实践才能真正掌握。这五个按顺序完成的项目涵盖了项目开发所需的全部概念。
- 仅使用一个工具的智能体。选择某个单一的API,比如GitHub或天气服务,然后编写一个能够判断是否需要该API、调用它并将响应整合到回复中的智能体。直接使用Anthropic或OpenAI的原始API而不借助任何框架,这样就能看到工具使用流程,而不会有任何抽象层将其隐藏。
- 拥有三个工具的ReAct智能体。加入网络搜索、计算器和代码执行器功能,然后自行实现“推理-行动-观察”的循环。通常在这种架构中,智能体才会首次意识到并纠正自己的错误。
- 基于已知代码库的检索功能。对真实的代码仓库进行索引,构建相应的检索系统,然后提出需要理解多个文件的内容的问题。评估检索质量并修复那些表现不佳的片段。这个项目展示了为什么分块处理比其他任何因素都更为重要。
10. 状态文件:智能体会遗忘,文件却不会
这听起来过于简单而不起眼,但实际上却是每个可靠自主智能体的核心:一个 Markdown 文件、一份 JSON 文档或数据库记录,它们存在于对话之外,用于记载已完成的任务以及后续需要处理的内容。
模型在会话之间不会保留任何信息。智能体在一次运行中所学到的内容除非被记录下来,否则就会消失,因此没有持久状态的循环每次都得从零开始,而带有状态存储的循环则可以接续上一次的工作。下面的示例会记录上次运行时间、已处理和剩余任务的数量、正在进行中的工作、已完成的工作、需转交给人处理的任务,以及诸如需要避免的界面问题之类的经验教训及其发生时间:
// STATE.md: what every working autonomous agent needs
{
"last_run": "2026-07-01 03:00 UTC",
"items_processed": 47,
"items_remaining": 12,
"in_progress": [
"fix/auth-token-refresh: tests passing, awaiting CI"
],
"completed": [
"fix/null-check-in-billing: merged, CI green"
],
"escalated_to_human": [
"src/payments/refund.ts: root cause unclear after 3 theories"
],
"lessons": [
"2026-06-30: E2E tests require Stripe webhook secret in env. Skip if missing.",
"2026-06-29: Windows runner has TLS 1.2 issue. Use bash, not PowerShell."
]
}
课程列表值得重视。它决定了循环如何避免重复同样的错误,同时也能持续记录以防止目标偏移。常见的格式有两种:存入代码仓库的 Markdown 文件具有版本控制功能,便于差异对比且简单易用,适合个人或小型团队使用;而对于需要多人共同查看的正式循环流程,则更适合使用 Linear 等问题追踪工具或数据库等外部系统。其原理很简单:智能体会遗忘,而代码仓库会记住,因此所有重要信息都应存储在上下文窗口之外。
11. 制作者与审核者分离:让编写者和审查者各司其职
一个智能体负责生成内容,另一个具有不同上下文的智能体则对其进行检查。这就是对自我偏好偏差的结构化解决方案,而始终如一地应用这一方法则是成熟智能体设计的最明显标志之一。
让模型对自己的输出进行评分会使其过于宽容。询问负责修改内容的智能体该修改是否正确,它总会找到理由说是的。而将修改内容及评分标准交给另一位不知其作者身份和修改原因的审核者,就能发现真正的缺陷。
代码中的差异在于:错误版本要求单个智能体修复漏洞并确认自己的修复结果。而正确版本则先对一个模型应用修复工具,然后将生成的代码及特定的评估标准交给审核者,同时要求审核者忽略代码的作者身份和编写意图,只需根据理由给出通过判定或标注出问题所在行号并给出失败判定。由于判断更为困难,审核者会使用更强大的模型:
# Wrong: one agent does both
result = await agent("Fix the auth bug and verify your fix is correct")
# Right: maker and checker are separate agents, separate contexts
fix = await agent(
"Fix the auth bug in src/auth/middleware.ts",
model="sonnet"
)
review = await agent(
f"""Review this fix against the rubric below.
Do not consider who wrote it or their intent.
Fix:
{fix.code}
Rubric:
- Does it handle the null case on line 47?
- Does it preserve the existing token expiry logic?
- Does the test cover the regression case?
Return: PASS with reasoning, or FAIL with specific line references.""",
model="opus" # harder model for the harder judgment task
)
配对规则规定,审核者仅接收两项输入——评估标准和代码结果,绝不能看到作者身份、修改背后的理由或产生该修改的对话内容。任何这些信息都可能通过特定的表述方式引入主观偏好。评估标准也很重要;像上面那样具体且可核查的问题,远比单纯判断修改是否良好更为有效。
这种分工不仅适用于代码领域:作者与审稿人、撰稿人与事实核查员、生成器与评判者皆是如此。一旦注意到这一点,你就会发现常见的工具往往是如何悄悄地将这两种角色合二为一的。
12. 评估:让循环结果值得信赖的关卡
没有验证功能的智能体只不过是反复被调用的聊天机器人而已。评估则决定了某个结果是否足够可靠,从而可以据此采取行动、进行合并或发布。可采用三个层级,其成本及所能做出的判断类型逐级提升:
- 确定性检查。测试、代码检查工具、类型检查器以及构建过程都会给出非黑即白的结论,不涉及任何主观判断。它们是最早出现且成本最低的关卡;只要确定性检查能够排除错误输出,就应优先使用。
interrupt_before功能可用于实现这一暂停机制。该功能应仅用于那些撤销成本较高的操作,而非用来限制所有操作。要判断评估是否有效,可追踪被接受的修改率。如果某个用于修复失败测试的智能体能够通过持续集成和人工审核的修改来解决70%的问题,那么其修改率即为70%。若该比例低于50%,则意味着人工需要花费时间来完成智能体已经开始的工作,这样一来带来的成本反而高于节省的成本。
13. 安全性:无人监管的智能体即无人监管的攻击面
任何接触实际基础设施的自主智能体都构成了在无监督状态下运行的安全漏洞。风险是实实在在的:通过间接提示注入手段,读取恶意邮件或网页的智能体可能会被操控来执行攻击者的命令。主要威胁包括:
- 通过工具输出进行注入。网页、GitHub问题报告及支持工单可能将指令隐藏在普通内容中,例如要求代理忽略之前的指令并删除测试文件的命令。隔离措施是有效的防御手段:任何接触到不可信内容的代理都只能以只读方式访问。应将持续读取数据的代理与执行操作的代理分开。
- 权限逐步扩大。原本只有只读权限的代理“为方便起见”被赋予了一个写入权限,之后却无人再对此进行审核。应定期重新审查权限(每月一次较为合适),并且只授予任务所需的最低限度权限。
- 日志中的敏感信息。在长时间运行的循环中开启详细日志记录会导致凭证散布在无人监控的输出结果中。在生产环境中的循环中应关闭详细日志记录,并对剩余内容进行净化处理。
权限模型能让这些规则更加明确。下面的示例会自动批准仅用于观察的操作,如读取文件、运行测试以及查看git状态或差异,而对于推送代码、编辑环境配置文件、修改支付相关代码以及任何带有强制标志的操作,则需要人工审批:
# Safe agent permission model
permissions = {
"auto_approve": [
"Read(*)", # read anything
"Bash(npm test)", # run tests
"Bash(git status)", # observe state
"Bash(git diff*)", # observe diffs
],
"require_human": [
"Bash(git push*)", # never push without approval
"Edit(.env*)", # never touch secrets
"Edit(src/payments/*)", # never touch payments code
"Bash(*--force*)", # never force anything
]
}
每条规则的测试都只有一个问题:如果该操作出错,撤销它的成本是多少?如果撤销成本较低,则自动批准;如果成本较高,则由人工决定。在过程中逐个案例决策正是权限滥用现象的起源。
14. 将技能转化为职业发展
学习路径应当有明确的方向。以下是这些技能实际应用场景的详细分析。
应展示的内容。避免使用简单的教程示例,三个能够解决实际问题的真实项目更具说服力:
- 一个在实践中会被依赖其输出结果的定时任务代理,比如第9步中实现的循环结构。
- 一个多智能体系统,其中至少有两个智能体承担不同角色,从结构上避免单个模型实例同时承担两种功能,类似第11步中的制造者-检查者模式。
- 一个带有明确评估指标的检索系统,展示检索功能改进前后的对比情况,而不仅仅是证明其能够正常工作。
所需时间。粗略估计,那些已经具备扎实的Python编程能力且每周学习10到15小时的人,完成这条学习路径大约需要八个月时间。此数值仅作为规划参考,并非绝对承诺。
从何处开始。不同职位的入门难度差异很大:
- 在非人工智能为主营业务的公司担任AI自动化工程师。这类岗位需要的是能够快速构建用于自动修复测试问题的脚本的人,掌握LangGraph、MCP以及基本的CI知识即可,无需熟悉数十种框架。
- 在以智能体产品为业务方向的初创公司担任AI工程师。这类岗位要求具备检索、评估、多智能体设计及部署等全套技能,对能力的要求更高,发展空间也更大。
大多数学习计划都忽视了一个要点:开始之前不必掌握所有知识。重要的是有一个能够解决实际问题的已部署代理,有办法量化其成效,并能说明其设计可防范哪些故障模式。很少有候选人同时具备这三点,也没有任何证书可以替代它们。
总结
有一段时间,应用人工智能领域的大部分优势都体现在提示词上:更优的措辞、更好的上下文以及更出色的单次输出效果。随着模型具备了实际执行任务的能力,这种优势又上升到了另一个层面,即决定智能体处理什么任务、何时验证其输出结果、如何记录其行为以及失败时该如何处理的系统。
- 先学习概念再掌握框架,通过判断每个工具能防止哪种失败模式——懒惰、自我偏好或偏离目标——来评估其价值。
- 将状态信息存储在模型之外,放在智能体每次运行时都会重新读取的文件或数据库中。
- 绝不能让某项变更的提出者同时担任其审核者;只需将相关成果及具体的评估标准交给审核者即可。
- 采用从确定性检查到人工评判再到最终人类确认的多层评估机制,并统计被接受的变更比例。
这一切都不需要研究背景或微调专长。只需要扎实的 Python 功能、对大语言模型出错方式的清晰认知,以及在循环开始前就设置验证机制的习惯。先构建第一个智能体,让它运行一整夜,然后早上查看其生成的差异。
相关阅读
- 从单节点聊天机器人到 LangGraph 中基于 MCP 的智能体 — 逐步构建 LangGraph 应用:状态与还原器、边、工具循环、检查点线程、三种流式模式,以及通过 MCP 提供的工具。
- 利用 LangGraph 和 Amazon Bedrock 设计四层代理内存 — 学习如何在 Bedrock 和 LangGraph 上为大型语言模型代理赋予工作记忆、情景记忆、语义记忆和程序记忆功能,同时防范数据污染、个人身份信息泄露以及租户间数据交叉污染的问题。