AI Agent理论提升与体系构建
AI Agent(Artificial Intelligence Agent) 称为智能体,本质是自动执行任务的程序,核心在于让模型不只回答问题,而是按步骤完成动作。一个能够感知环境、进行决策并执行行动,以达成特定目标的智能软件实体,它不仅仅是回答问题的聊天机器人,更是能够动手做事的智能执行者。Agent = LLM (大脑) + Planning (规划) + Tool use (执行) + Memory (记忆)。传统的软件程序遵循固定的指令流程:输入 → 处理 → 输出,而 AI Agent 则更像一个有自主性的员工,它能够:
- 理解任务目标:明白你想要什么结果
- 制定计划:思考如何达成目标
- 使用工具:调用各种资源和 API
- 自我调整:根据反馈优化策略
- 持续执行:直到完成任务或遇到无法解决的问题
普通的 LLM 只是 One-shot(一次性) 的响应,而 Agent 的核心在于 Iterative(迭代)。ReAct 模式 (Reason + Act) 是目前最主流的 Agent 推理逻辑:
- Thought (思考): 模型描述当前要做什么,为什么要这么做。
- Action (行动): 模型选择一个工具(如:
Google Search)。 - Observation (观察): 模型读取工具返回的结果。
- Repeat (循环): 重复上述步骤,直到得出最终答案。
一个合格的 AI Agent 通常具备以下特征:
1. 自主性(Autonomy):无需人类逐步指导,能够独立运作,自己决定下一步该做什么。示例:你说"帮我订明天去上海的机票",Agent 会自动查询航班、比较价格、选择合适选项
2. 反应性(Reactivity):能够感知环境变化并及时响应,根据新信息调整行为。示例:订票时发现航班取消,自动寻找替代方案
3. 主动性(Proactivity):不仅被动响应,还能主动采取行动,有目标导向的行为。示例:发现机票价格波动,主动提醒用户最佳购买时机
4. 社交能力(Social Ability):能与人类或其他 Agent 交互,理解自然语言,进行多轮对话。示例:在订票过程中询问用户偏好(靠窗/靠走廊)
5. 学习能力(Learning):从历史交互中学习,记住用户偏好和上下文。示例:记住你喜欢早班飞机和靠窗座位
**函数调用(Function Calling):**现代大模型通过"函数调用"机制来使用工具。开发者预先定义工具的名称与参数说明,模型在推理时会以结构化 JSON 的形式输出"我要调用哪个工具、传什么参数",由外部程序负责真正执行并把结果返回给模型。
规划策略决定了 Agent 如何"思考"再"行动",不同策略的推理深度与适用场景不同:
| 策略 | 全称 | 核心思路 | 适用场景 |
|---|---|---|---|
| CoT | Chain-of-Thought | 在给出答案前,先一步步写出推理过程 | 数学推理、逻辑分析 |
| ReAct | Reasoning + Acting | 交替进行"推理"与"行动",每次行动后根据结果再推理 | 需要工具调用的动态任务 |
| ToT | Tree-of-Thoughts | 同时探索多条推理分支,从中选择最优路径 | 复杂决策、创意任务 |
| Reflection | 自我反思 | 任务完成后,Agent 对自身输出进行批判性审查并修正 | 代码生成、长文写作 |
| 术语 | 中文 | 核心含义 | 备注 |
|---|---|---|---|
| LLM(Large Language Model) | 大语言模型 | 基于海量文本训练的语言预测模型 | GPT、Claude、Gemini 都是 LLM |
| GPT | 生成式预训练 Transformer | OpenAI 的模型架构范式 | Generative Pre-trained Transformer |
| Token | 词元 | 模型处理文本的最小单位(约 ¾ 个英文单词) | 计费和上下文长度的计量单位 |
| Context Window | 上下文窗口 | 模型一次能"看到"的最大 token 数 | 窗口越大,记得越多 |
| Inference | 推理 | 模型生成输出的过程 | 区别于训练 |
| Hallucination | 幻觉 | 模型一本正经地编造不存在的信息 | 生成与事实、上下文或目标不一致内容 |
| Temperature | 温度 | 控制采样概率分布,高值更发散,低值更稳定 | 写代码建议调低 |
| Top-p / Top-k | 采样参数 | 控制候选词的采样范围 | 影响输出多样性 |
| Embedding | 向量嵌入 | 把文本/图片转成数字向量,用于相似度计算 | RAG 的基础 |
| Fine-tuning | 微调 | 在通用模型上用特定数据继续训练 | 让模型更懂某个领域 |
| RLHF | 基于人类反馈的强化学习 | 用人类偏好对齐模型行为 | 让 AI “听话” |
| MoE(Mixture of Experts) | 混合专家 | 每次只激活部分参数,提升效率 | 用更少算力跑更强模型 |
| Multimodal | 多模态 | 同时处理文本、图像、音频、视频 | GPT-4o、Gemini 都是 |
| Transformer | Transformer 架构 | 现代 LLM 的底层神经网络结构 | 注意力机制是核心 |
| KV Cache | 键值缓存 | 缓存上下文计算结果提升推理速度 | 避免重复翻菜谱 |
| Latency | 延迟 | 模型响应耗时 | 影响用户体验 |
| Throughput | 吞吐量 | 单位时间可处理任务数 | 影响并发能力 |
| 术语 | 中文 | 核心含义 |
|---|---|---|
| Harness | 线束 / 驾驭框架 | 承载 Agent 执行、上下文管理与工具编排的运行框架 |
| Skills | 技能 | Agent 可调用的专项能力模块 |
| Context | 上下文 | 当前任务可获取的信息范围 |
| MCP(Model Context Protocol) | 模型上下文协议 | Agent 连接外部工具/数据源的标准化协议 |
| Permission | 权限控制 | 控制 Agent 能做/不能做的安全机制 |
| RAG(Retrieval-Augmented Generation) | 检索增强生成 | 先从知识库检索,再让模型生成,减少幻觉 |
| Tool Registry | 工具注册中心 | 统一管理 Agent 可调用工具 |
| Session | 会话 | 一次任务生命周期 |
| Knowledge Base | 知识库 | 供 Agent 查询的外部知识集合 |
| 术语 | 中文 | 核心含义 |
|---|---|---|
| /loop | 循环指令 | 让 Agent 持续循环执行 |
| /goal | 目标指令 | 设定目标驱动 Agent 自主达成 |
| Cron | 定时任务 | 按时间计划自动触发 |
| Worktree | 工作树 | Git 多分支并行工作区 |
| Workflow | 工作流 | 预定义的多步骤自动化流程 |
| Scheduler | 调度器 | 协调多个任务执行顺序 |
| Checkpoint | 检查点 | 保存执行状态用于恢复 |
| Human-in-the-loop | 人在回路 | 关键步骤允许人工干预 |
| 层级 | 核心组件 | 核心作用 | 典型能力 |
|---|---|---|---|
| 基础层(模型) | LLM & Token、Transformer 架构、Token 化、注意力机制 | AI 的底层计算核心;负责文本理解、Token 预测、语言生成 | 自然语言理解、文本生成、上下文建模、概率预测 |
| 上下文层(记忆) | Context Window、Prompt、Memory、RAG | 管理模型输入上下文;负责短期记忆、长期记忆、外部知识注入 | Prompt 控制、会话记忆、知识检索、上下文增强 |
| 能力扩展层(工具) | MCP、Tool Calling、API、Database | 让 AI 不止聊天;通过工具调用扩展真实世界操作能力 | 联网搜索、代码执行、数据库查询、API 调用 |
| 智能体层(决策) | Agent、Explore、Plan、Act | AI 自主决策大脑;负责目标理解、任务拆解、规划与闭环执行 | 任务规划、多步骤推理、自主决策、闭环执行 |
| 应用层(行动) | Agent Skill、Workflow、Automation | 面向具体业务场景;将 Agent 能力封装为可落地产品 | 自动化工作流、行业AI助手、企业智能系统、AI SaaS应用 |
尽管 LLM 很强大,但它也有明确的局限性:
| 能力 | 说明 | 局限性 |
|---|---|---|
| 知识截止 | 训练数据有截止日期 | 无法获知训练后的新信息 |
| 数学计算 | 能做简单计算 | 复杂计算容易出错 |
| 实时信息 | 需要外部工具辅助 | 本身无法获取实时数据 |
| 事实准确性 | 可能生成错误信息 | 需要事实核查 |
| 长文本处理 | 上下文长度有限制 | 超长文本会丢失信息 |
| 逻辑一致性 | 可能前后矛盾 | 需要仔细设计和验证 |
**Prompt(提示词)**是你给 LLM 的输入,它告诉模型你想要什么,就像给助理下达指令——指令越清晰,结果越好。Prompt 的质量直接决定了回答的质量。一个好的 Prompt 通常由以下四个部分组成:
- 明确具体:避免模糊表达。不要说写点关于狗的东西,而应该说用生动活泼的语言,为 6-8 岁儿童写一段 100 字左右的关于金毛寻回犬性格特点的简短介绍。
- 提供上下文:告诉模型你的身份、背景和目标。例如:你是一位经验丰富的 Python 编程导师。请向一个刚学完基本语法的初学者解释什么是列表推导式,并提供一个简单的例子。
- 指定格式:如果需要特定格式的输出,请明确说明,例如:请将以下要点总结为三个 bullet points 或 请以 JSON 格式输出。
- 分步思考(Chain-of-Thought):对于复杂问题,可以在 Prompt 中引导模型逐步推理,例如:请一步一步地分析这个问题,先列出已知条件,再推导中间步骤,最后给出结论。 这种方式能显著提升复杂推理任务的准确率。
模态(Modality)就是信息的表现形式。模型支持的模态越多,能力就越接近人,这也是为什么所有头部实验室都在把文字模型升级为多模态模型。不同的模态对应不同的输入与输出,下表列出常见模态及其典型应用:
| 模态 | 输入示例 | 输出示例 | 典型应用 |
|---|---|---|---|
| Text(文本) | 小说、聊天记录 | 回答、文章 | 问答、写作、翻译 |
| Image(图像) | 照片、截图 | 图片理解、生成图 | OCR、视觉问答 |
| Audio(音频) | 语音、音乐 | 转写文字、合成语音 | 会议摘要、语音助手 |
| Video(视频) | 视频流 | 视频分析、时间轴 | 教学总结、内容检索 |
| Sensor(传感器) | GPS、温度 | 控制信号 | 机器人、自动驾驶 |
| Action(动作) | 鼠标点击、键盘输入 | 执行动作 | GUI Agent、自动化 |
多模态模型的内部工作可以概括为一句话:把所有数据转成统一向量空间。
把最重要的指令放在提示词的开头或结尾,中间位置的内容在长上下文中容易被模型"忽视"——这是大模型的已知特性,称为"迷失在中间(Lost in the Middle)"现象。Token 意识对提示词设计的影响
| 场景 | Token 建议 |
|---|---|
| System Prompt | 精炼优先,去掉重复说明,核心规则控制在 500 Token 以内 |
| 输入长文档 | 先摘要再输入,或使用 RAG(检索增强)方式只传入相关片段 |
| 多轮对话 | 历史消息会累积消耗 Token,长对话要注意定期"重置"或压缩历史 |
| API 开发 | 输入 Token + 输出 Token 都计费,输出通常比输入贵 2–3 倍 |
重要陷阱: 一定要让 AI 先分析,再下结论。如果先让它说结论,再让它解释,它会反过来为已有结论找理由——而不是真正在推理。顺序非常关键。有时候,你想要的效果很难用文字描述清楚——比如一种特定的语气、一种独特的格式风格。这时候,直接给例子比反复描述更有效。这种方法叫做少样本学习(Few-Shot Learning):给 AI 看 2-3 个"输入→输出"的例子,它就能学会你想要的模式。
幻觉(Hallucination)是指 AI 自信地输出了错误的、不存在的,或者凭空捏造的信息。这是大语言模型的固有局限,但通过提示词设计,可以大幅降低它的发生率。语言模型的本质是预测接下来最可能出现的词。当它不知道某个信息时,不会像人一样说我不知道——而是会生成一个听起来合理的回答。这就像一个努力想表现好的实习生,宁可给出一个听起来专业的猜测,也不愿承认自己不知道。
策略 1:明确允许 AI 说我不知道(最简单有效)
System Prompt 中加入:
如果你不确定某个信息,请直接说"我没有关于这个问题的可靠信息",
不要猜测或编造答案。不确定 ≠ 失败,诚实才是好助手。
策略 2:限制 AI 只使用你提供的信息
请请只根据 <reference> 标签中的内容回答问题。
如果参考资料中没有足够的信息,请回答:"根据提供的资料,无法回答这个问题。"
<reference>
[你提供的文档内容]
</reference>
<question>
[用户的问题]
</question>
策略 3:先找证据,再给结论
把思维链技巧用在防幻觉上:
在回答之前,请先在 <evidence> 中找出文档里
直接支持你结论的句子或段落,再在 <answer> 中给出结论。
如果找不到支持性证据,就说找不到。
策略 4:要求标注置信度
对于你回答中的每个关键信息,请在括号内标注置信度:
(高置信度)= 你非常确定
(中置信度)= 你有一定把握但不完全确定
(低置信度)= 你只是猜测,建议用户自行核实
策略 5:降低随机性(API 开发者)
在 API 调用中将 temperature 设为 0,让模型的输出更保守、更确定,减少"创意性"发挥带来的错误,适合事实性任务。
防幻觉 System Prompt 模板
你是一位严谨的研究助手。你必须遵守以下规则:
1. 只基于用户提供的文档内容回答问题。
2. 如果文档中没有足够信息,请明确说明: "根据提供的资料,无法回答这个问题。"
3. 引用具体信息时,指出它来自哪个段落。
4. 不要用你自己的训练知识来"补充"文档之外的内容。
5. 对于数字、日期、专有名词,格外谨慎,宁可说不确定也不要猜。
专业的 AI 应用提示词通常包含以下五个部分,每部分各司其职:
════════════════════════════════
第 1 段:角色与目标
════════════════════════════════
你是谁?你的核心任务是什么?
════════════════════════════════
第 2 段:背景知识与数据
════════════════════════════════
AI 需要知道哪些背景信息?
(用 XML 标签包裹)
════════════════════════════════
第 3 段:行为规则
════════════════════════════════
必须做什么?不能做什么?
边界条件是什么?
════════════════════════════════
第 4 段:输出格式
════════════════════════════════
以什么格式输出?包含哪些字段?
════════════════════════════════
第 5 段:示例
════════════════════════════════
给 1-2 个完整的输入→输出示例
当一个任务过于复杂,单条提示词无法可靠完成时,可以把它拆分成多个子任务,依次执行,前一步的输出作为下一步的输入——这就是提示词链(Prompt Chaining)。提示词链把复杂任务分而治之,每一步都能独立验证质量,整体可靠性大幅提升。把所有要求塞进一个超长提示词,会导致以下问题:
- AI 容易遗漏某些子任务
- 前后步骤的逻辑相互干扰
- 出错时难以定位问题在哪一步
- Token 消耗高,成本上升
Token (词元) = AI 能理解的最小文本单位。可以把它理解成:AI 世界里的文字碎片或者 AI 世界的燃料。*Token 比单词更细,比字母更粗,是一种灵活的中间单位。*Token 的划分遵循一套特殊的算法(比如 BPE,字节对编码),结果有时候很直觉,有时候却出人意料:
| 文本 | Token 数量 | 说明 |
|---|---|---|
cat | 1 | 常见词,直接一个 Token |
unbelievable | 4 | un + believ + able + … |
ChatGPT | 3 | Chat + G + PT |
你好 | 约 2~3 | 中文通常比英文消耗更多 Token |
每个 AI 模型都有一个 上下文窗口(Context Window),也就是它一次能处理的最大 Token 数量。超过这个限制,AI 就会记不住之前说的话,就像一个人的短期记忆装满了一样。比如:
- GPT-3.5:约 4,000 Token
- GPT-4 Turbo:约 128,000 Token
- Claude 3.5:约 200,000 Token
调用 AI 接口(API)时,费用通常按 Token 数量计费。输入的文字 + AI 回复的文字,都会消耗 Token,所以写得越长,花费越多。AI 生成文字时,是一个 Token 一个 Token 地输出的,所以回复越长,等待时间越久。
中文、日文、韩文等亚洲语言通常比英文消耗更多 Token,因为这些字符在编码上更复杂。空格和标点也算 Token!代码的 Token 消耗一般比自然语言少,因为编程语言结构紧凑。在构建自主 AI Agent 的过程中,如果说大语言模型(LLM)是 Agent 的大脑,工具调用(Tool Use)是手脚,那么**推理与规划(Reasoning & Planning)**就是将其从简单的问答机升级为自主问题解决者的核心引擎。复杂的现实任务往往无法通过一次生成(One-pass generation)完成。AI 需要具备拆解目标、逻辑推演、探索路径、自我修正以及调度工具的能力。
思维链(CoT)的核心思想是:强制要求模型在输出最终答案前,先显式地输出中间的推理步骤(Let’s think step by step)。这种做法能显著激活模型在复杂数学、逻辑推理和常识问答中的潜力。CoT 不仅让模型有了更多的计算时间(token 数量代表计算量),还让后续的生成能建立在前面正确的逻辑基础上。
如果说 CoT 只是在模型内部闭门造车,那么 ReAct(Reason + Act) 则是让模型睁开眼睛看世界。它将内部逻辑推理(Thought)与外部工具交互(Action)交织在一起,形成一个动态的闭环反馈系统。在 ReAct 范式下,Agent 遵循 Thought(思考) -> Action(行动) -> Observation(观察) 的循环,直到得出最终结论。ReAct 在短期的、步骤清晰的任务中表现优异。但由于整个思维和动作历史都积压在同一个上下文窗口中,当任务链条过长时,极易陷入死循环或因为上下文超载而遗忘初始目标。
为了解决 ReAct 在长线任务中的疲软,Plan-and-Execute 将思考和行动进行了解耦,采用了类似人类做大型项目的策略:先出排期表,再挨个干活。系统通常分为两个独立的角色:
- Planner(规划者):负责接收大目标,生成详细的 Step-by-Step 子任务列表。
- Executor(执行者):负责按顺序执行这些子任务。执行器通常就是一个小型的 ReAct Agent,每次只专注完成当前的一个小目标。
无论是 CoT 还是 Plan-and-Execute,本质上都是线性的路径探索。但在写代码、解数学题或创意写作时,人类往往会设想多种方案,评估后选择最佳的,甚至在发现错误时回溯。ToT(思维树) 将推理过程建模为一棵树:节点是当前的思维状态。模型会在每一个分支点生成多个候选 Thought,然后通过内部的 Evaluator(评估器)对这些节点进行打分(如:可行、可能有风险、不可行)。结合 BFS(广度优先搜索) 或 DFS(深度优先搜索) 算法,决定是继续深入还是回溯重试。
人类在执行任务时,如果第一次失败了,会总结经验教训并在下一次尝试中规避错误。Reflexion 框架赋予了 Agent 类似的能力。在 Reflexion 闭环中,当 Agent 的输出被判定为失败(例如:测试用例未通过、API 报错)时,会触发一个 Reviewer 机制。LLM 被要求根据历史动作和失败的反馈写一段口语化的反思(Reflection),例如:“我刚才使用了错误的 API 参数格式,下一次我应该查阅文档后再传递 JSON”。这段反思会被存入情景记忆(Episodic Memory)中,作为下一次尝试的上下文提示,从而大幅提升 Agent 的自愈合能力。
-
reflection_prompt = """ 你是一个正在尝试编写 Python 爬虫的 AI 助手。 这是你刚才执行的代码:{previous_code} 这是运行环境返回的错误信息:{error_traceback} 请深刻反思: 1. 错误发生的根本原因是什么? 2. 在下一次尝试中,你具体的修改策略是什么? 请将反思记录下来,以指导后续的行动。 """
| 模式 | 核心机制 | 优点 | 缺点 |
|---|---|---|---|
| CoT | Step-by-Step 线性推理 | 实现极简,显著提升基础推理准确度 | 无法调用外部工具,容易一条道走到黑 |
| ReAct | 交替思考与行动闭环 | 动态适应环境,能通过观测实时调整 | 上下文容易随步骤累积而爆炸,迷失初衷 |
| Plan-and-Execute | 先拆解为子任务,再隔离执行 | 极其适合长线复杂任务,上下文清晰 | 面对突发变化(规划本身出错时)不够灵活 |
| ToT / MCTS | 树状搜索,评估回溯 | 能解决最高难度的复杂逻辑问题 | 计算成本极其高昂,Token 消耗呈指数级 |
| Reflexion | 基于失败反馈生成反思记忆 | 具备自我纠错和持续进化的能力 | 依赖明确的反馈信号(如代码编译器报错) |
向量数据库(Vector Database)是一种专门用于存储、索引和检索高维向量数据的数据库系统。把意思相近的东西存在一起,并能快速找到和这个最像的那些东西。传统关系型数据库(MySQL、PostgreSQL)非常擅长处理结构化数据,但在面对以下需求时力不从心:
- 图片搜索(找出视觉相似的图片)
- 语义搜索(用户搜"苹果手机",能找到"iPhone"的相关内容)
- 推荐系统(找到"和你喜欢的歌曲风格类似的歌")
- 异常检测(找到"和正常行为差异最大的日志")
这些问题的共同特征是:需要理解内容的"含义",而不是做字面匹配。
在数学上,向量就是一组有序的数字。
[0.12, -0.54, 0.87, 0.03, ..., 0.61] ← 这就是一个向量
在机器学习中,这组数字代表某个对象的语义特征,维度通常在 128 到 4096 之间。嵌入(Embedding)是将现实世界的对象(文字、图片、音频等)转换成向量的过程和结果。这个转换由嵌入模型完成,其核心思想是:语义相近的对象,其向量在空间中的距离也更近。向量空间中距离近的两个向量,其原始内容在语义上也更相近。这是向量数据库所有能力的基础。
找到"最相似的向量"的核心是计算两个向量的距离或相似度。以下是三种最常用的方法。
余弦相似度(Cosine Similarity),余弦相似度衡量两个向量的方向角,忽略长度。这是最常用的方法,尤其适合文本场景。结果范围:-1 到 1,值越大越相似;适用场景:文本语义搜索、文档相似度。公式:
CosineSimilarity(A,B)=A⋅B∥A∥∥B∥=∑i=1nAiBi∑i=1nAi2∑i=1nBi2CosineSimilarity(A,B)=\frac{A⋅B}{∥A∥∥B∥}=\frac{∑_{i=1}^nA_iB_i}{\sqrt{∑_{i=1}^nA_i^2}\sqrt{∑_{i=1}^nB_i^2}}CosineSimilarity(A,B)=∥A∥∥B∥A⋅B=∑i=1nAi2∑i=1nBi2∑i=1nAiBi
欧氏距离(Euclidean Distance):欧氏距离衡量两点之间的直线距离,距离越小越相似。结果范围:0 到 ∞,值越小越相似;适用场景:图像检索、地理位置相关应用。公式:d(A,B)=∑i=1n(Ai−Bi)2d(A,B)=\sqrt{∑_{i=1}^n(A_i−B_i)^2}d(A,B)=∑i=1n(Ai−Bi)2
点积(Dot Product):点积是向量相乘求和,结合了方向和长度信息。适用场景:推荐系统(向量已归一化时等价于余弦相似度)公式:A⋅B=∑i=1nAiBiA⋅B=∑_{i=1}^nA_iB_iA⋅B=∑i=1nAiBi
import numpy as np
# 余弦相似度:衡量方向相似性
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# 欧氏距离:衡量绝对位置差异
def euclidean_distance(a, b):
return np.linalg.norm(a - b)
# 点积:结合方向与长度
def dot_product(a, b):
return np.dot(a, b)
# 示例向量
v1 = np.array([0.12, -0.54, 0.87, 0.03])
v2 = np.array([0.10, -0.50, 0.90, 0.05])
v3 = np.array([-0.80, 0.20, -0.30, 0.70])
print(f"v1 vs v2 余弦相似度: {cosine_similarity(v1, v2):.4f}") # 约 0.9997(非常相似)
print(f"v1 vs v3 余弦相似度: {cosine_similarity(v1, v3):.4f}") # 约 -0.55(不相似)
RAG 的核心思想是:让 LLM 在回答问题时,先从外部知识库中检索相关内容,再基于检索结果生成回答,而不是仅依赖模型训练时记住的知识。这解决了 LLM 的两个核心痛点:知识截止日期(模型不知道训练后发生的事)和幻觉问题(模型在不确定时会编造答案)。
一个完整的 RAG 系统由两条流水线组成:离线索引流水线(将文档预处理存入向量库)和在线查询流水线(接收用户问题、检索、生成)。离线阶段将原始文档切分成小块,通过 Embedding 模型转换为向量,存入向量数据库。在线阶段将用户问题同样转换为向量,从数据库中找到最相近的文档块,拼接成上下文交给 LLM 生成答案。
$folderA = "F:\AnnotationTeam\0610_train_scene_data"
$folderB = "F:\AnnotationTeam\0620_self_ann_ok"
# 获取相对文件名列表
$filesA = Get-ChildItem -Path $folderA -Recurse -File | ForEach-Object { $_.FullName.Substring($folderA.Length) }
$filesB = Get-ChildItem -Path $folderB -Recurse -File | ForEach-Object { $_.FullName.Substring($folderB.Length) }
# 对比并输出结果
$onlyInA = Compare-Object $filesA $filesB | Where-Object { $_.SideIndicator -eq '<=' }
$onlyInB = Compare-Object $filesA $filesB | Where-Object { $_.SideIndicator -eq '=>' }
$common = Compare-Object $filesA $filesB -IncludeEqual -ExcludeDifferent
Write-Host "`n===== 对比结果 =====" -ForegroundColor Cyan
Write-Host "相同文件数: $($common.Count)" -ForegroundColor Green
Write-Host "仅在 FolderA 中: $($onlyInA.Count)" -ForegroundColor Yellow
Write-Host "仅在 FolderB 中: $($onlyInB.Count)" -ForegroundColor Red
# 可选:列出差异文件名
if ($onlyInA.Count -gt 0) {
Write-Host "`n--- 仅在 FolderA ---" -ForegroundColor Yellow
$onlyInA | ForEach-Object { Write-Host $_.InputObject }
}
if ($onlyInB.Count -gt 0) {
Write-Host "`n--- 仅在 FolderB ---" -ForegroundColor Red
$onlyInB | ForEach-Object { Write-Host $_.InputObject }
}
在进行切分前,RAG 往往面临着格式解析的挑战。特别是 PDF、Word 或扫描件中的表格、图片和多栏排版,普通的文本提取极易造成语义错乱。目前行业主流方案是引入 文档解析引擎(如 LlamaParse、Unstructured)或多模态大模型,将复杂图文转换为结构化的 Markdown,为后续高质量切分打下基础。文档切分是 RAG 效果的基础,切分粒度直接影响检索质量。块太大会引入噪声,块太小会丢失上下文。常用策略如下:
| 切分策略 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 固定大小切分 | 通用文本 | 实现简单,速度快 | 可能切断语义完整的句子 |
| 递归字符切分 | 结构化文本(Markdown、代码) | 优先按段落、句子等语义边界切分 | 实现略复杂,需设定合理的分隔符列表 |
| 语义切分 (Semantic) | 长文档、书籍 | 利用 Embedding 计算相邻句子的相似度,自动寻找语义转折点切分 | 计算成本高,预处理速度慢 |
| 父子文档检索 (Small-to-Big) | 全面覆盖场景 | 用"小块"进行高精度向量检索,命中后返回对应的"大块"(父文档)给 LLM,兼顾了检索精度和上下文完整性。 | 数据库设计和维护成本翻倍 |
实践中常在切分时加入 重叠(overlap),即相邻块之间共享若干字符,防止重要信息在边界处被截断。典型配置:块大小 512 tokens,重叠 50~100 tokens。
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=512, # 每块最大 token 数
chunk_overlap=50, # 相邻块的重叠 token 数,防止信息在边界处丢失
separators=["\n\n", "\n", "。", ".", " ", ""] # 优先按段落、句子切分
)
chunks = splitter.split_text(document_text)
print(f"切分为 {len(chunks)} 个文档块")
Embedding 模型负责将文本转换为稠密向量(通常是 768 或 1536 维的浮点数数组)。语义相近的文本在向量空间中距离更近,这正是相似度检索的数学基础。
| 模型 | 维度 | 适用语言 | 特点 |
|---|---|---|---|
text-embedding-3-small(OpenAI) | 1536 | 多语言 | 性价比高,适合大规模索引 |
text-embedding-3-large(OpenAI) | 3072 | 多语言 | 精度最高,成本较高 |
BAAI/bge-m3 | 1024 | 中英文 | 开源,中文效果优秀,支持多语言 |
sentence-transformers/all-MiniLM-L6-v2 | 384 | 英文 | 体积小,速度快,适合本地极轻量部署 |
检索的核心是度量距离。最常用的是余弦相似度(Cosine Similarity),它计算两个向量的夹角余弦值,值域 [-1, 1],越接近 1 越相似。此外还有点积(Dot Product)和欧氏距离(L2 Distance)。为了在百万级向量中实现毫秒级检索,数据库通常采用近似最近邻(ANN)算法(如 HNSW、IVF)。HNSW 是目前最主流的算法,它通过构建多层跳跃图网络,牺牲极少的精度换取了数量级的搜索速度提升。
Advanced RAG 通过预检索优化 → 检索融合 → 后检索优化的三段式架构予以解决。
预检索:查询优化 ; 用户的原始问题往往表达不够精确:
- 查询改写(Query Rewriting):用 LLM 将口语化提问改写为规范化的检索词。
- HyDE(Hypothetical Document Embedding):让 LLM 先"盲猜"一个假设性答案,由于生成的答案通常比原问题包含更多行业术语,用这个假设答案的向量去检索,往往能召回更高质量的文档。
混合检索(Hybrid Search): 将向量检索(懂语义,容错率高)与关键词检索(BM25,匹配度高)的结果按权重融合。这在遇到专有名词、产品型号、代码片段时尤为重要,因为传统的向量检索容易在特定的专有名词上"翻车"。
后检索优化:重排序(Reranking)。这是一个粗排 → 精排的两阶段设计。向量检索虽然快,但打分不够精确。重排序(Reranking)会引入 Cross-Encoder 模型(如 bge-reranker),将"问题"和"文档"成对输入模型进行联合推理打分。它的运算量大,只负责精选 Top-20 到 Top-5。
from sentence_transformers import CrossEncoder
reranker = CrossEncoder("BAAI/bge-reranker-v2-m3")
# 1. 粗排:向量检索极速召回 Top-50
candidates = vector_store.similarity_search(query, k=50)
# 2. 精排:构建 [问题, 文档] 对进行精确打分
pairs = [[query, doc.page_content] for doc in candidates]
scores = reranker.predict(pairs)
# 3. 筛选最终传入 LLM 的 Top-5
ranked_docs = sorted(zip(scores, candidates), reverse=True)
final_docs = [doc for _, doc in ranked_docs[:5]]
Self-RAG 与 CRAG(修正式 RAG)加入自我反思机制。例如 CRAG(Corrective RAG)在拿到检索结果后,先由 LLM 充当"评委"打分。如果本地知识库查无此文或质量极低,系统会自动触发 Web Search(如 Google API)作为补充,大幅降低幻觉。RAG 系统的评估不能仅凭直觉,主流使用 RAGAS 框架,从"检索"和"生成"两个维度进行自动化量化测试:
- Context Recall(检索召回率):标准答案中的信息有多少比例能被检索到。
- Context Precision(检索精确率):检索到的文档中有多少比例是真正相关的。
- Faithfulness(忠实度/幻觉指标):生成的答案是否都有检索出的文档支撑。
- Answer Relevance(答案相关性):生成的答案是否真正回答了用户的问题,避免答非所问。
Agent 上下文工程(Agent Context Engineering)是系统化设计和优化传递给 AI Agent 的上下文信息的技术实践,它的目标是让 Agent 在有限的上下文窗口内获得最有效的信息,从而提升任务执行的准确性、效率和可靠性。AI Agent 不像传统程序那样有固定的执行逻辑,它的行为完全取决于接收到的上下文——包括系统提示、工具描述、历史对话和外部检索到的信息。上下文工程不是一次性的提示词编写,而是贯穿 Agent 系统开发、测试和运维全生命周期的持续优化过程。
| 层次 | 内容 | 特点 |
|---|---|---|
| 系统提示(System Prompt) | 角色定义、行为规则、输出格式要求 | 每次调用都会携带,相对稳定 |
| 工具定义(Tool Definitions) | 可用工具的名称、参数和功能描述 | 占用大量 token,需要精简 |
| 历史记录(History) | 当前会话的对话和工具调用记录 | 持续增长,需要截断或摘要策略 |
| 检索上下文(Retrieved Context) | 从外部知识库或代码库中检索的内容 | 按需注入,需要相关性排序 |
| 用户输入(User Input) | 用户当前的指令或问题 | 不可控,但可以通过澄清来优化 |
上下文窗口不是越大越好。过多的上下文会导致模型在关键信息上的注意力被稀释,反而降低输出质量。盲目增加规则可能让系统提示变得臃肿且自相矛盾。每新增一条规则,都需要审查是否与已有规则冲突。
Agent 的工作方式本质上是一个循环(Loop)——感知当前状态,推理下一步,执行行动,再次感知……直到任务完成。不同架构的差异,就在于如何组织和扩展这个基本循环。
- **感知:**读取当前状态——文件内容、环境变量、之前步骤的输出结果,整合成当前上下文。
- **推理:**LLM 根据上下文决定下一步动作——调用哪个工具、传入什么参数,或者判断任务是否已完成。
- **行动:**执行工具调用,例如读写文件、搜索网络。工具的执行结果会被追加到上下文中,进入下一轮循环。
# 单 Agent 循环的简化实现 —— 展示 ReAct 模式的核心逻辑
class SimpleAgent:
"""单 Agent 循环的基本结构"""
def __init__(self, model, tools, max_turns=10):
self.model = model # 大语言模型
self.tools = tools # 可用工具列表
self.max_turns = max_turns # 最大循环轮次,防止无限循环
def run(self, task: str) -> str:
"""执行任务的主循环"""
context = f"用户任务:{task}"
for turn in range(self.max_turns):
# 第一步:思考 —— 让模型决定下一步
response = self.model.think(context)
# 如果模型认为任务完成,返回最终答案
if response.is_final():
return response.content
# 第二步:行动 —— 调用模型选择的工具
tool_name = response.tool_name
tool_args = response.tool_args
tool_result = self.tools[tool_name](**tool_args)
# 第三步:将工具结果反馈给模型,进入下一轮
context += f"\n工具 {tool_name} 返回:{tool_result}"
return "达到最大轮次,任务未完成"
# 使用示例
agent = SimpleAgent(model=llm, tools={
"read_file": read_file,
"search_code": search_code,
"run_test": run_test
})
result = agent.run("修复 runoob 项目中 user.py 的类型错误")
规划 + 执行架构将 Agent 的工作拆分为两个明确阶段:先规划(Plan),再执行(Execute)。在规划阶段,模型不执行任何操作,只生成一份详细的执行步骤列表。在执行阶段,系统依次完成每个步骤。这种分离让用户可以在执行前审查计划,就像 Claude Code 的 Plan Mode 一样。
| 变体 | 行为 | 典型场景 |
|---|---|---|
| 静态规划 | 计划一次性生成,按顺序线性执行,不中途调整 | 流程固定、步骤明确的任务,如数据迁移脚本 |
| 动态规划 | 每执行一步后重新评估,根据结果调整后续计划 | 结果不确定的任务,如调试、探索性数据分析 |
# Plan & Execute 架构的简化实现
class PlanExecuteAgent:
"""先规划、后执行的 Agent"""
def plan(self, task: str) -> list:
"""阶段一:生成执行计划"""
plan = self.model.generate(f"""
请将以下任务拆解为可执行的步骤列表:
任务:{task}
返回 JSON 格式的步骤列表,每步包含:
- step_id: 步骤编号
- description: 步骤描述
- tool: 需要调用的工具名
""")
return plan
def execute(self, plan: list, dynamic: bool = False) -> str:
"""阶段二:逐步执行计划"""
results = []
remaining_plan = plan.copy()
while remaining_plan:
step = remaining_plan.pop(0)
output = self.tools[step["tool"]](step["description"])
results.append({"step": step["step_id"], "output": output})
if dynamic and remaining_plan:
# 动态规划:根据当前结果重新评估后续计划
remaining_plan = self.replan(remaining_plan, results)
return self.summarize(results)
# 使用示例
agent = PlanExecuteAgent()
plan = agent.plan("为 runoob 项目添加用户认证功能")
# 人类可以先审查 plan,确认合理后再执行
result = agent.execute(plan, dynamic=True)
Plan & Execute 的代价是增加了推理轮次,对于简单任务反而是一种浪费。如果一个任务可以在 3 步内完成,直接用单 Agent 循环更高效。
当单个 Agent 面临上下文窗口不足或任务过于复杂时,多 Agent 架构提供了一个优雅的解决方案:让多个专门化的子 Agent 并行工作,由一个 Orchestrator(协调者)统筹全局。一个 Orchestrator(协调者)负责任务拆解和调度,多个 Subagent 各司其职,并行或串行地完成子任务,结果汇聚回 Orchestrator 做综合。每个子 Agent 拥有独立的上下文窗口。代码审查 Agent 深度阅读 auth.py 不会影响性能分析 Agent 的判断;安全检测 Agent 产生的大量中间输出不会挤占其他 Agent 的空间。子 Agent(Subagent)是短暂的、隔离的——完成一个任务后即销毁。Agent 团队(Agent Teams)则是多个独立 Agent 实例长时间协作、互相发消息,更像一个真实的团队。
# 多 Agent 协作的简化实现
class Orchestrator:
"""编排器:负责任务拆解、分发和结果汇总"""
def __init__(self):
self.subagents = {
"code_review": Subagent(
name="代码审查",
tools=["read_file", "static_analysis"],
system_prompt="你是代码审查专家..."
),
"security": Subagent(
name="安全检测",
tools=["scan_vulnerability", "check_deps"],
system_prompt="你是安全检测专家..."
),
"performance": Subagent(
name="性能分析",
tools=["profile_code", "analyze_complexity"],
system_prompt="你是性能分析专家..."
)
}
def handle_task(self, task: str) -> dict:
# 第一步:分析任务,决定需要哪些 Subagent
needed = self.plan(task)
# 第二步:并行分发(各 Subagent 同时工作,独立上下文)
results = {}
for agent_name in needed:
sub_task = self.decompose(task, agent_name)
results[agent_name] = self.subagents[agent_name].run(sub_task)
# 第三步:汇总各 Subagent 的结果,综合输出
return self.synthesize(task, results)
# 使用示例:一次运行,三个维度并行分析
orch = Orchestrator()
report = orch.handle_task("审查 runoob 项目 PR #42")
反思架构为 Agent 增加了一个"质检环节":每次生成输出后,都由一个**评判者(Critic)**来评估质量,如果不达标则要求修正,直到输出满足标准。这就像开发者写完代码后自己跑一遍测试——在交付之前先自查一遍。
| 方式 | 机制 | 优点 | 缺点 |
|---|---|---|---|
| 自我反思 | 同一个模型先执行再评估自己的输出 | 实现简单,无额外模型成本 | 模型可能对自己的错误"视而不见" |
| Critic 模型 | 用独立的评判模型评估执行模型的输出 | 更客观,能发现执行模型盲区 | 增加模型调用成本和延迟 |
# 反思架构的简化实现
class ReflectiveAgent:
"""带有自我反思能力的 Agent"""
def __init__(self, model, tools, max_reflections=3):
self.model = model
self.tools = tools
self.max_reflections = max_reflections # 最多修正次数,防止死循环
def run(self, task: str) -> str:
# 第一步:正常执行,产生初始输出
output = self.model.generate(task)
for i in range(self.max_reflections):
# 第二步:反思 —— 评估输出质量
critique = self.model.generate(f"""
请严格评估以下输出:
原始任务:{task}
当前输出:{output}
检查:事实错误?逻辑漏洞?遗漏信息?格式问题?
如果输出完美无缺,请回复 "PASS"。
""")
if "PASS" in critique:
break # 输出通过审查
# 第三步:修正 —— 根据批评意见改进
output = self.model.generate(f"""
原始任务:{task}
上次输出:{output}
问题反馈:{critique}
请根据反馈修正输出。
""")
return output
# 使用示例
agent = ReflectiveAgent(model=llm, tools={})
code = agent.run("编写一个 Python 函数,实现 RUNOOB 字符串的 AES 加密")
# Agent 生成代码后自我检查加密实现、密钥处理,
# 发现漏洞后自动修正,确保输出安全可靠
- 优点在于突破上下文窗口限制;输出有据可查,减少幻觉;知识库可独立更新
工作流编排(Workflow / DAG) : 把 Agent 行为固化为一张有向无环图(DAG),每个节点是一个 LLM 调用或工具调用,边表示数据依赖关系,由框架驱动执行。这是最接近传统软件工程的一种 Agent 架构。与前面几种架构的最大区别在于:Agent 的自主决策空间被限制在单个节点内部,节点之间的流转是预先定义好的,不可更改。
| 特性 | 纯 Agent | DAG 工作流 |
|---|---|---|
| 流程控制 | 模型自主决定下一步 | 预定义的 DAG 图决定 |
| 可预测性 | 低,每次运行路径可能不同 | 高,运行路径确定 |
| 可调试性 | 难,依赖日志追踪 | 易,每个节点输入输出明确 |
| 容错性 | 依赖模型自行恢复 | 框架提供重试、断点续跑 |
| 灵活性 | 高,可应对意外情况 | 低,只能走预定义路径 |
DAG 的 “无环”(Acyclic)特性意味着工作流是确定性的——没有无限循环,执行路径可以完全预测,失败的节点可以单独重试。DAG 是"低自主性、高可预测性"的极端。你需要预先设计好整个流程。这不是缺点,而是刻意的设计取舍——生产环境中有时候确定性比灵活性更重要。
# DAG 工作流的简化定义(类似 LangGraph 风格)
from langgraph import StateGraph
# 定义工作流状态 —— 节点间传递的数据对象
class PipelineState:
raw_data: str = "" # 原始输入数据
cleaned_data: str = "" # 清洗后的数据
analysis_result: dict = {} # 分析结果
final_report: str = "" # 最终报告
# 定义 DAG 节点 —— 每个节点是独立的处理单元
def extract_data(state: PipelineState) -> PipelineState:
"""节点1:从 runoob 数据库中提取原始数据"""
state.raw_data = query_database("SELECT * FROM logs")
return state
def clean_data(state: PipelineState) -> PipelineState:
"""节点2:清洗数据(去重、标准化格式)"""
state.cleaned_data = preprocess(state.raw_data)
return state
def analyze_data(state: PipelineState) -> PipelineState:
"""节点3:统计分析"""
state.analysis_result = statistical_analysis(state.cleaned_data)
return state
def generate_report(state: PipelineState) -> PipelineState:
"""节点4:使用 LLM 生成报告"""
state.final_report = llm.generate(
f"基于以下分析结果生成报告:{state.analysis_result}"
)
return state
# 构建 DAG:定义节点和边(数据流向)
workflow = StateGraph(PipelineState)
workflow.add_node("extract", extract_data)
workflow.add_node("clean", clean_data)
workflow.add_node("analyze", analyze_data)
workflow.add_node("report", generate_report)
# 定义边:extract → clean → analyze → report
workflow.add_edge("extract", "clean")
workflow.add_edge("clean", "analyze")
workflow.add_edge("analyze", "report")
workflow.set_entry_point("extract")
workflow.set_finish_point("report")
# 编译并运行
app = workflow.compile()
result = app.invoke(PipelineState())
print(result.final_report)
从多个维度对比六种架构,帮助你快速定位适合的选项。
| 架构 | 自主性 | 可预测性 | 并行能力 | 适合任务复杂度 | 典型实现 |
|---|---|---|---|---|---|
| 单 Agent 循环 | 高 | 低 | 无 | 中低 | Claude Code 默认模式 |
| 规划 + 执行 | 中 | 中 | 部分 | 中高 | Claude Code Plan Mode |
| 多 Agent 协作 | 高 | 低 | 强 | 高 | AutoGen, CrewAI |
| 反思 / 自我修正 | 中 | 中 | 无 | 中 | Reflexion, Self-Refine |
| RAG + Agent | 高 | 中 | 无 | 中高 | LangChain RAG Agent |
| 工作流编排 | 低 | 高 | 强 | 高(固定流程) | LangGraph, Prefect |
如果你不确定从哪里开始,从单 Agent 循环开始。它最容易实现和调试。当你发现上下文窗口不够用时,考虑多 Agent;当你需要质量保证时,加入反思层;当流程趋于稳定时,重构为 DAG 以提升可靠性。
即使模型支持 1M token 的上下文窗口,把所有文档塞进去仍然不是最优方案。RAG 的价值不仅在于"装得下",更在于精准检索——减少噪音、降低推理成本、提高答案准确性。DAG 定义了流程骨架,但每个节点内部仍然可以是 Agent 调用。工作流编排和 Agent 能力不是互斥的,而是互补的——DAG 提供可靠性,Agent 提供灵活性。多 Agent 协作看起来很强大,但如果你的任务用单 Agent 循环在 5 步内就能完成,引入编排开销反而降低效率。原则:用能满足需求的最简架构。选择架构时,核心考量只有两个:你需要多大的灵活性来应对意外情况,以及你需要多大的确定性来保证结果可靠。从简单开始,在确实需要时才增加复杂度,这是 Agent 架构选型的第一原则。
LangChain 是一个用于构建 LLM 应用的框架,可以把模型调用升级为可组合、可控制、可扩展的应用系统。LangChain 解决的不是怎么调模型,而是:
- 多步骤推理如何组织
- 外部数据如何接入
- 工具如何被模型安全调用
- 上下文如何被长期管理
LangChain 就是这样一个框架,它充当了连接器和协调者的角色。LangChain 将强大的语言模型(如 GPT-4、DeepSeek)与外部数据源、计算工具以及记忆系统巧妙地连接起来,构建出功能强大、可实际应用的 AI 应用程序。LangChain 通过一系列标准化的链(Chains)和组件(Components)来组织这些功能,让开发者能够像搭积木一样,快速构建复杂的 AI 应用。简单来说,LangChain 的核心价值在于:让语言模型变得有用,解决了大语言模型(LLM)的几个关键限制:
- 知识实时性:LLM 的训练数据有截止日期,无法获取最新信息。
- 领域专精性:通用 LLM 缺乏特定行业或公司的私有知识。
- 可操作性:LLM 本身无法执行如计算、查询数据库、调用 API 等动作。
- 对话连贯性:在多轮对话中,LLM 需要记住之前的聊天历史。
LangChain 模块总览:
- LLMs / ChatModels:模型接口
- Prompt Templates:Prompt 结构化
- Chains:流程编排
- Memory:上下文管理
- Retrievers / VectorStores:知识检索
- Agents & Tools:自动决策与执行
LangGraph 是由 LangChain 团队开发的一个低层级 Agent 编排框架,专为构建有状态(Stateful)、长时运行的 AI 工作流而设计。与传统的线性 LLM 调用链不同,LangGraph 将工作流建模为有向图(Directed Graph):
- 节点(Node):执行具体操作的函数(如调用 LLM、执行工具、处理数据)
- 边(Edge):定义节点之间的流转路径,支持条件分支
- 状态(State):在整个工作流中共享并传递的数据
想象你正在指挥一场交响乐演出:传统的 LLM Chain 就像演奏一首从头到尾的曲子,只能顺序播放;而 LangGraph 则像一位指挥家,可以根据现场观众的反应随时调整演奏顺序,让某个乐章重复,或者跳转到特定段落。它让 AI 工作流拥有了"指挥"的智慧——能够循环、分支、回溯,真正实现复杂的自主决策。
| 特性 | 传统 LLM Chain | LangGraph |
|---|---|---|
| 工作流结构 | 线性,单向执行 | 图结构,支持循环 |
| 状态管理 | 需手动管理 | 内置状态持久化 |
| 条件路由 | 实现复杂 | 原生支持 |
| 人机协作 | 需要额外开发 | 内置支持 interrupt |
| 多 Agent 协调 | 实现困难 | 一流支持 |
| 调试工具 | 有限 | LangGraph Studio |
Graph 是整个工作流的蓝图,定义了 Agent 的完整逻辑结构。它由节点(Nodes)和边(Edges)组成:
StateGraph
|-- Nodes(节点)
| |-- node_a
| |-- node_b
| +-- node_c
+-- Edges(边)
|-- START -> node_a
|-- node_a -> node_b(条件边)
|-- node_a -> node_c(条件边)
+-- node_b -> END
State 是贯穿整个图的共享数据结构。每个节点可以读取和更新 State,更新后的 State 会传递给下一个节点。
from typing import TypedDict, Annotated
from langgraph.graph import add_messages
class MyState(TypedDict):
messages: Annotated[list, add_messages] # 消息列表(自动追加)
user_name: str # 用户名称
step_count: int # 步骤计数
节点是普通的 Python 函数,接收当前 State,返回更新后的 State(部分字段)。
def my_node(state: MyState) -> dict:
# 读取状态
messages = state["messages"]
# 执行操作...
result = "处理结果"
# 返回更新的字段(不需要返回所有字段)
return {"messages": [{"role": "ai", "content": result}]}
边定义节点之间的流转方式:
- 普通边:固定路径,
node_a -> node_b - 条件边:根据 State 动态路由,
node_a -> node_b 或 node_c - 起始边:
START -> 第一个节点 - 结束边:
某节点 -> END
from langgraph.graph import StateGraph, START, END
from typing import TypedDict
# Step 1: 定义 State
class SimpleState(TypedDict):
message: str
processed: bool
# Step 2: 定义节点函数
def greet_node(state: SimpleState) -> dict:
"""欢迎节点:生成问候语"""
print(f"[greet_node] 收到消息: {state['message']}")
return {"message": f"你好!{state['message']}"}
def process_node(state: SimpleState) -> dict:
"""处理节点:标记为已处理"""
print(f"[process_node] 处理消息: {state['message']}")
return {"processed": True}
# Step 3: 构建图
builder = StateGraph(SimpleState)
# 添加节点
builder.add_node("greet", greet_node)
builder.add_node("process", process_node)
# 添加边
builder.add_edge(START, "greet")
builder.add_edge("greet", "process")
builder.add_edge("process", END)
# Step 4: 编译图
graph = builder.compile()
# Step 5: 运行
result = graph.invoke({
"message": "世界",
"processed": False
})
print(f"\n最终结果: {result}")
State 状态管理
使用 TypedDict 定义状态
from typing import TypedDict, Annotated, Optional
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
# 消息历史(add_messages reducer 自动追加而非覆盖)
messages: Annotated[list, add_messages]
# 普通字段(直接覆盖)
user_id: str
session_id: str
# 可选字段
error: Optional[str]
# 计数器(使用 operator.add 作为 reducer)
retry_count: Annotated[int, lambda x, y: x + y]
使用 Pydantic 定义状态(推荐用于生产)
from pydantic import BaseModel, Field
from typing import Annotated
from langgraph.graph.message import add_messages
class ProductionState(BaseModel):
messages: Annotated[list, add_messages] = Field(default_factory=list)
user_id: str = ""
confidence_score: float = 0.0
class Config:
arbitrary_types_allowed = True
MessagesState(内置快捷状态)LangGraph 提供了内置的 MessagesState,专为对话场景设计:
from langgraph.graph import MessagesState
# MessagesState 等价于:
# class MessagesState(TypedDict):
# messages: Annotated[list[AnyMessage], add_messages]
# 直接使用,无需自定义
builder = StateGraph(MessagesState)
Edges 边与条件路由
普通边
# 固定路径:node_a 完成后始终执行 node_b
builder.add_edge("node_a", "node_b")
# 结束:node_a 完成后图结束
builder.add_edge("node_a", END)
条件边 条件边是 LangGraph 的核心功能,根据当前 State 动态决定下一步。
def route_after_llm(state: AgentState) -> str:
"""
路由函数:根据 LLM 的最新输出决定走哪条路径
返回值必须是已注册节点名称或 END
"""
last_message = state["messages"][-1]
# 如果 LLM 请求使用工具
if hasattr(last_message, "tool_calls") and last_message.tool_calls:
return "tools"
# 否则结束
return END
# 添加条件边
builder.add_conditional_edges(
"llm", # 源节点
route_after_llm, # 路由函数
{
"tools": "tool_executor", # 返回 "tools" 时 -> tool_executor 节点
END: END # 返回 END 时 -> 结束
}
)
并行执行(Fan-out)
# 从一个节点并行分叉到多个节点
builder.add_edge("start_node", "branch_a")
builder.add_edge("start_node", "branch_b")
builder.add_edge("start_node", "branch_c")
# 多个节点汇聚到一个节点(Fan-in)
builder.add_edge("branch_a", "merge_node")
builder.add_edge("branch_b", "merge_node")
builder.add_edge("branch_c", "merge_node")
让 Agent 具备使用外部工具的能力是 LangGraph 最强大的特性之一。ReAct(Reason + Act)是最常见的 Agent 模式:LLM 思考 -> 选择工具 -> 执行工具 -> 观察结果 -> 继续思考。
首先定义 Agent 可以使用的工具:
from langchain_core.tools import tool
@tool
def search_web(query: str) -> str:
"""搜索网络获取最新信息。
Args:
query: 搜索关键词
Returns:
搜索结果摘要
"""
# 实际项目中替换为真实搜索 API
return f"关于 '{query}' 的搜索结果:这是模拟的搜索结果..."
@tool
def calculate(expression: str) -> str:
"""计算数学表达式。
Args:
expression: 数学表达式,如 '2 + 2' 或 '100 * 0.8'
Returns:
计算结果
"""
import ast
import operator
# 安全的运算符映射
ops = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Pow: operator.pow,
ast.USub: operator.neg,
}
def safe_eval(node):
if isinstance(node, ast.Expression):
return safe_eval(node.body)
elif isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.BinOp):
left = safe_eval(node.left)
right = safe_eval(node.right)
return ops[type(node.op)](left, right)
elif isinstance(node, ast.UnaryOp):
operand = safe_eval(node.operand)
return ops[type(node.op)](operand)
else:
raise ValueError(f"不支持的表达式类型: {type(node)}")
try:
tree = ast.parse(expression, mode='eval')
result = safe_eval(tree)
return f"计算结果: {expression} = {result}"
except Exception as e:
return f"计算错误: {str(e)}"
@tool
def get_weather(city: str) -> str:
"""获取指定城市的天气信息。
Args:
city: 城市名称
Returns:
天气信息
"""
# 实际项目中替换为真实天气 API
return f"{city} 今日天气:晴,温度 22C,湿度 60%"
tools = [search_web, calculate, get_weather]
持久化内存:LangGraph 提供了内置的状态持久化机制,让 Agent 能够跨会话记住对话历史。
内存存储(适合开发测试)
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
graph = builder.compile(checkpointer=checkpointer)
# 使用 thread_id 区分不同会话
config_user_a = {"configurable": {"thread_id": "user-alice"}}
config_user_b = {"configurable": {"thread_id": "user-bob"}}
# Alice 的对话
graph.invoke({"messages": [HumanMessage(content="我叫 Alice")]}, config=config_user_a)
graph.invoke({"messages": [HumanMessage(content="我叫什么名字?")]}, config=config_user_a)
# Agent 能记住:你叫 Alice
# Bob 的对话完全独立
graph.invoke({"messages": [HumanMessage(content="我叫什么名字?")]}, config=config_user_b)
# Agent 不知道 Bob 的名字(不同 thread_id)
SQLite 持久化存储(适合本地项目)
# 安装依赖
# pip install langgraph-checkpoint-sqlite
from langgraph.checkpoint.sqlite import SqliteSaver
# 数据持久化到文件,程序重启后对话历史仍存在
with SqliteSaver.from_conn_string("./chat_memory.db") as checkpointer:
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "persistent-chat"}}
# 第一次运行
graph.invoke({"messages": [HumanMessage(content="我叫张三")]}, config=config)
# 程序重启后再次运行,记忆仍然存在
result = graph.invoke(
{"messages": [HumanMessage(content="你还记得我叫什么吗?")]},
config=config
)
查看对话历史
# 获取某个 thread 的完整状态历史
history = list(graph.get_state_history(config))
for snapshot in history:
print(f"时间: {snapshot.created_at}")
print(f"消息数: {len(snapshot.values['messages'])}")
print("---")
# 获取当前状态
current_state = graph.get_state(config)
print(f"当前消息数: {len(current_state.values['messages'])}")
LangGraph 擅长协调多个专门化的 Agent 协同工作。通过将复杂任务分解给不同的专家 Agent,可以实现更强大的问题解决能力。主从架构(Supervisor Pattern)
import os
from dotenv import load_dotenv
from langgraph.graph import StateGraph, MessagesState, START, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
load_dotenv()
# 初始化 LLM
llm = ChatOpenAI(
model=os.getenv('DEEPSEEK_MODEL', 'deepseek-v4-pro'),
openai_api_key=os.getenv('DEEPSEEK_API_KEY'),
openai_api_base=os.getenv('DEEPSEEK_BASE_URL', 'https://api.deepseek.com'),
temperature=0
)
# 定义专家 Agent
def research_agent(state: MessagesState) -> dict:
"""研究 Agent:负责信息收集"""
system = SystemMessage(content="你是一个专业的研究员,负责收集和整理信息。请简洁地总结关键信息。")
response = llm.invoke([system] + state["messages"])
return {"messages": [response]}
def writing_agent(state: MessagesState) -> dict:
"""写作 Agent:负责内容创作"""
system = SystemMessage(content="你是一个专业的写作者,负责根据已有信息撰写内容。请保持内容清晰流畅。")
response = llm.invoke([system] + state["messages"])
return {"messages": [response]}
def review_agent(state: MessagesState) -> dict:
"""审校 Agent:负责质量控制"""
system = SystemMessage(content="你是一个专业的编辑,负责审核和改进内容质量。请指出问题并给出改进建议。")
response = llm.invoke([system] + state["messages"])
return {"messages": [response]}
# 主管 Agent 决定流程
def supervisor_node(state: MessagesState) -> dict:
"""主管:协调各专家 Agent 的工作"""
system = SystemMessage(content="""你是一个工作流主管。
根据任务进度决定下一步应该由哪个 Agent 处理。
分析对话历史,只返回以下之一:RESEARCH、WRITING、REVIEW、FINISH
- RESEARCH:需要收集更多信息
- WRITING:信息充足,可以开始写作
- REVIEW:写作完成,需要审核
- FINISH:任务已完成
""")
response = llm.invoke([system] + state["messages"])
return {"messages": [response]}
def route_by_supervisor(state: MessagesState) -> str:
"""根据主管决策路由"""
last_msg = state["messages"][-1].content.strip().upper()
if "RESEARCH" in last_msg:
return "research"
elif "WRITING" in last_msg:
return "writing"
elif "REVIEW" in last_msg:
return "review"
else:
return END
# 构建多 Agent 图
builder = StateGraph(MessagesState)
builder.add_node("supervisor", supervisor_node)
builder.add_node("research", research_agent)
builder.add_node("writing", writing_agent)
builder.add_node("review", review_agent)
builder.add_edge(START, "supervisor")
builder.add_conditional_edges("supervisor", route_by_supervisor)
# 每个专家完成后返回主管
for agent in ["research", "writing", "review"]:
builder.add_edge(agent, "supervisor")
graph = builder.compile()
# 测试多 Agent 协作
result = graph.invoke({
"messages": [HumanMessage(content="请帮我写一篇关于 Python 装饰器的简短介绍文章")]
})
print("=== 多 Agent 协作完成 ===")
for i, msg in enumerate(result["messages"]):
print(f"\n[{i+1}] {msg.type}: {msg.content[:150]}...")
子图(Subgraph) 将复杂子流程封装为子图,在主图中复用:
# 将复杂子流程封装为子图,在主图中复用
sub_builder = StateGraph(MessagesState)
sub_builder.add_node("step1", step1_node)
sub_builder.add_node("step2", step2_node)
sub_builder.add_edge(START, "step1")
sub_builder.add_edge("step1", "step2")
sub_builder.add_edge("step2", END)
sub_graph = sub_builder.compile()
# 在主图中使用子图
main_builder = StateGraph(MessagesState)
main_builder.add_node("preprocessing", preprocess_node)
main_builder.add_node("sub_workflow", sub_graph) # 直接使用编译好的子图
main_builder.add_node("postprocessing", postprocess_node)
main_builder.add_edge(START, "preprocessing")
main_builder.add_edge("preprocessing", "sub_workflow")
main_builder.add_edge("sub_workflow", "postprocessing")
main_builder.add_edge("postprocessing", END)
main_graph = main_builder.compile()
LangGraph 通过图结构的工作流编排,让开发者能够构建具备循环、分支、状态持久化能力的复杂 AI Agent。相比传统的线性 LLM Chain,LangGraph 在处理需要多步推理、人机协作、多 Agent 协同的场景时具有显著优势。
| 概念 | 说明 | 关键代码 |
|---|---|---|
| StateGraph | 有向图工作流引擎,LangGraph 的核心 | StateGraph(MyState) |
| State | 节点间共享的状态数据结构 | TypedDict + Annotated |
| Nodes | 执行具体操作的函数节点 | builder.add_node() |
| Edges | 节点间的流转路径,支持条件分支 | add_edge() / add_conditional_edges() |
| ReAct Agent | 推理+行动的循环模式 | ToolNode + tools_condition |
| Human-in-Loop | 人工审批与介入机制 | interrupt() + Command(resume=) |
| 持久化 | 会话记忆与状态保存 | MemorySaver / SqliteSaver |
| 多 Agent | 多专家协作系统 | Supervisor Pattern |
AI 开发的重点正在不断变化:从研究如何写好提示词(Prompt),逐步发展到组织上下文(Context)、编排工具与流程(Harness),再到构建能够自主运行、持续交付结果的循环系统(Loop)。
Prompt:怎么问 AI
↓
Context:给 AI 什么信息
↓
Harness:如何组织 AI 的能力
↓
Loop:如何让 AI 持续创造结果
| 工程阶段 | 核心思想 | 关注点 | 输入内容 | AI 能力 | 人的角色 | 典型场景 |
|---|---|---|---|---|---|---|
| Prompt Engineering(提示词工程) | 通过设计提示词获得更好的输出 | 怎么问问题 | Prompt / 指令 | 单轮生成 | 提问者 | 聊天、写作、代码生成 |
| Context Engineering(上下文工程) | 组织并提供完整背景信息 | 给 AI 什么信息 | 知识库、历史记录、约束条件、上下文 | 上下文理解 | 信息组织者 | RAG、AI 搜索、代码助手 |
| Harness Engineering(编排工程) | 连接模型、工具、数据形成工作流 | 如何调用能力 | 上下文 + API + 工具链 | 执行任务 | 系统设计者 | Agent、自动化流程、多工具协同 |
| Loop Engineering(循环工程) | 构建目标驱动的自主闭环系统 | 如何持续完成目标 | 目标、状态、记忆、验证机制 | 规划 → 执行 → 验证 → 修复 → 持续运行 | 规则制定者 | Claude Code、AI 编程、自动运营、AI 员工 |
一个 Loop 是一个递归目标系统:你定义一个目的,Agent 不断迭代,直到工作真正完成。每个 Agent 在执行任务时已经内置了一个"内循环":感知(Perceive)→ 推理(Reason)→ 行动(Act)→ 观察(Observe),然后再次循环。Loop Engineering 工作在这个内循环的上一层:
| 层级 | 谁在驱动 | 做什么 |
|---|---|---|
| 内循环(Agent 内置) | Agent 自身 | 读文件 → 修改代码 → 运行测试 → 读错误 → 再修改 |
| 外循环(你来设计) | 你设计的系统 | 按计划发现任务 → 分派 Agent → 验证结果 → 记录状态 → 开启下一轮 |
Prompt Engineering 并没有消亡。一个 Loop 是由多个 Prompt 组成的,写得差的 Prompt 放进 Loop 里只会让糟糕的工作以更快的速度产出。Loop Engineering 是在 Prompt Engineering 之上的层次,而不是替代它。
一个 Agent Loop 的基础结构由五个阶段构成,它们首尾相连,不断迭代。
| 阶段 | 英文名 | 做什么 | 典型信号来源 |
|---|---|---|---|
| 意图 | Intent | 定义目标结果:成功是什么样子,约束是什么 | 开发者或外部系统(Issue、CI 报告) |
| 上下文 | Context | 收集相关代码、文档、报错日志、约定规范 | 代码库、测试输出、历史对话 |
| 行动 | Action | 编辑文件、运行命令、调用工具、草拟方案 | Agent 自主执行 |
| 观察 | Observation | 获取测试结果、编译错误、运行时输出、代码 Diff | 测试框架、类型检查、CI、人工 Review |
| 调整 | Adjustment | 根据观察更新计划,重复循环直到任务完成或被阻塞 | 下一轮内循环 |
Loop 的力量不在于任何单独的步骤,而在于闭环*。测试失败不只是一条错误消息,它是新的上下文;类型错误不只是阻断,它是一个关于错误假设的信号;Code Review 评论不只是反馈,它是驱动下一步行动的新观察。*
一个能够真正独立运行的 Loop 需要五个核心组件,加上一个贯穿始终的记忆系统,缺一不可。
要素一:自动触发器(Automations)
自动触发器是 Loop 的心跳。没有自动触发,Loop 就只是"你做了一次的操作",而不是真正意义上的循环。触发器定义了:什么时候?做什么? 在 Claude Code 中,使用 /loop 命令创建定时触发的 Loop:
# 每天工作日早上 9 点运行:读取前一天的 CI 失败和 Issue,
# 将发现写入 TODO.md,并为标记为 quick-win 的问题起草修复方案
/loop "Read yesterday's CI failures and open issues, write findings \
to TODO.md, and draft fixes for anything labeled quick-win" \
--schedule "0 9 * * 1-5"
# /goal:运行直到一个可验证的条件成立
# 下面的命令会持续执行,直到认证模块的所有测试通过且 lint 干净
/goal "All tests in test/auth pass and lint is clean"
在 OpenAI Codex 中,Automations 有专属的 UI 面板,你可以设置项目、Prompt、节奏(cadence),以及是在本地检出还是后台 Worktree 中运行。发现内容的运行会进入 Triage 收件箱,未发现内容的会自动归档。
**Token 成本警告:**带验证子 Agent 的定时 Loop 每次触发都会消耗 Token,且消耗量因任务复杂度变化显著。建议先设置较慢的节奏(如每天一次),观察几天成本后再加快频率。
要素二:并行隔离(Worktrees)
当你同时运行多个 Agent 时,文件冲突是最容易出问题的地方。两个 Agent 同时写同一个文件,就像两个工程师同时提交到同一行代码,结果是灾难性的。Git Worktree 是解决方案:为每个 Agent 提供独立的工作目录,各自在独立的分支上操作,共享同一个 Git 历史,但文件改动完全隔离。
# 手动创建 worktree(Claude Code 和 Codex 都支持自动管理)
git worktree add ../agent-fix-auth feature/fix-auth-tests
git worktree add ../agent-upgrade-deps feature/upgrade-axios
# 在 Claude Code 中,为子 Agent 配置 worktree 隔离
# 在 .claude/agents/reviewer.md 的 frontmatter 中添加:
# isolation: worktree → 每个 Agent 获得独立的检出,完成后自动清理
Worktree 消除了机械性的文件冲突,但不能消除审查瓶颈。你处理和批准代码变更的速度,才是决定你能并行运行多少个 Agent 的真正上限,而不是工具能开多少个 Worktree。
要素三:技能文件(Skills)
Skills(技能文件)解决的是一个每次都在浪费的成本:每次新对话,Agent 都要从零推断你的项目规范。Skill 是一个包含 SKILL.md 文件的文件夹,写明了项目约定、构建步骤、"我们不这样做是因为那次事故"等知识。Agent 在每次会话开始时加载 Skill,而不是每次都重新猜测。
<!-- 文件路径:.claude/skills/project-conventions/SKILL.md -->
---
name: project-conventions
description: 项目编码规范和构建步骤。凡是涉及代码修改的任务都应加载此技能。
---
## 技术栈
- 后端:Node.js 20 + TypeScript 5.4 + Fastify
- 数据库:PostgreSQL 16,ORM 使用 Drizzle
- 测试:Vitest,测试文件放在 src/ 同级的 __tests__/ 下
## 构建命令
- 安装依赖:pnpm install
- 运行测试:pnpm test
- 类型检查:pnpm typecheck
- 构建产物:pnpm build
## 核心约定
- 所有数据库查询必须经过 src/db/queries/ 中的封装函数,禁止在业务层直接写 SQL
- 错误统一使用 AppError 类(src/errors/AppError.ts),禁止 throw 裸字符串
- API 路由文件命名:{resource}.routes.ts,放在 src/routes/
- 新增 API 必须同时更新 docs/api.md
## 禁止事项
- 不得直接修改 migrations/ 目录下的历史迁移文件
- 不得在 .env 文件中提交真实密钥,使用 .env.example 占位
要素四:连接器(Connectors / MCP)
一个只能看到本地文件系统的 Loop 能做的事情非常有限。连接器(基于 MCP——模型上下文协议)让 Agent 能够读取 Issue 追踪、查询数据库、调用 API、在 Slack 发消息。这是"Agent 说’这里是修复方案’"和"Loop 自动开 PR、关联 Ticket、CI 通过后通知频道"之间的核心差异。Claude Code 和 OpenAI Codex 均原生支持 MCP 协议,为一个工具编写的连接器通常可以在两者中通用。
// 文件路径:.claude/mcp.json
// 配置 MCP 连接器,让 Agent 可以操作 GitHub 和发送 Slack 通知
{
"connectors": [
{
"name": "github",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
},
{
"name": "slack",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": {
"SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}"
}
}
]
}
给 Agent 接入连接器意味着它可以在真实环境中采取真实行动。必须为每个连接器配置最小权限,高风险操作(推送代码、合并 PR、发送外部通知)应当要求人工审批,不能全自动执行。
要素五:子 Agent(Sub-Agents)
Loop 中最重要的架构决策之一:把写代码的 Agent 和检查代码的 Agent 分开。写了代码的模型在评分自己的作业时会过于宽容。一个有不同指令的独立检查器——有时还使用不同的模型——能够抓住第一个 Agent 自圆其说忽略的问题。这种"制作者-检查者"(Maker-Checker)模式也被应用到了 Loop 的停止条件上:Claude Code 的 /goal 命令在每次迭代后,会用一个单独的模型来判断是否"完成",而不是让做了工作的那个模型来判断。
<!-- 文件路径:.claude/agents/spec-reviewer.md -->
---
name: spec-reviewer
description: 对完成的代码变更进行对抗性审查,验证其符合规范和测试要求。
model: opus # 使用更强的模型作为验证者
isolation: worktree # 独立检出,避免污染制作者的工作区
---
你是一个对抗性代码审查员。你的工作不是认可,而是质疑。
收到一个 diff 后,你需要:
1. 运行完整测试套件(pnpm test),记录失败项
2. 运行类型检查(pnpm typecheck)
3. 对照 SKILL.md 中的项目规范检查 diff
4. 验证用户可见的行为变化是否符合原始需求
只有当所有测试通过、类型检查干净、规范无违反时,才输出 APPROVED。
否则输出具体的拒绝理由,不要给出模糊评价。只有当所有测试通过、类型检查干净、规范无违反时,才输出 APPROVED。
否则输出具体的拒绝理由,不要给出模糊评价。
要素六:持久记忆(Memory)
记忆是所有能跨对话持续运行的 Loop 的核心支柱。模型在每次对话之间会完全遗忘。如果没有外部记忆,每次 Loop 触发时 Agent 都从零开始,不知道昨天做了什么、哪些修复已经合并、哪些任务还在开放。解决方案极其简单:把状态写在文件里,文件放在仓库里。仓库记得,即使模型不记得。
<!-- 文件路径:TODO.md(Loop 的状态文件,随代码一起提交) -->
# Loop 任务状态
最后更新:2026-06-14 09:03 UTC(由自动 Loop 更新)
## 进行中
- [ ] test/auth/login.spec.ts 中的 flaky test(CI Run #4821,失败 3 次)
- 假设:并发测试之间的 session 状态泄漏
- 已尝试:隔离 test 数据库连接 → 无效
- 下一步:检查 beforeEach 中的 cleanup 逻辑
## 待处理
- [ ] 将 axios 升级到 1.7.x(安全漏洞 CVE-2026-xxxxx)
- [ ] API 文档更新(PR #308 合并后落后于代码)
## 已完成
- [x] 修复 billing 模块中含单引号公司名称导致的 500 错误(PR #312,已合并)
- [x] 将 Node.js 版本升级到 20.x(PR #307,已合并)
五种常见 Loop 模式 : 不同类型的工作任务需要不同的反馈信号和停止条件,因此发展出了几种经典的 Loop 模式。
| 模式 | 核心观察信号 | 停止条件 | 典型场景 |
|---|---|---|---|
| 测试驱动 Loop | 测试通过 / 失败 | 目标测试全部通过 | Bug 修复、回归测试、数据转换逻辑 |
| 编译器驱动 Loop | 类型错误、编译错误列表 | 类型检查零错误 | TypeScript 迁移、依赖升级、重构 |
| Review 驱动 Loop | 人工 Review 评论 | 所有评论被处理或有据可查地忽略 | PR Review 的机械性跟进 |
| 运行时调试 Loop | 日志、堆栈跟踪、HTTP 响应 | 问题可复现 → 提出假设 → 验证修复 | 生产 Bug、性能问题、接口异常 |
| 产品迭代 Loop | 截图、浏览器检查、可访问性报告 | 与设计稿对齐、响应式正常、规范无违反 | 落地页、UI 调整、营销组件 |
Skills 本质上就是教 AI 按固定流程做事的操作说明书,一旦写好,就能像函数一样反复调用。我们可以把 Skills 看成把 某类事情应该怎么专业做 这件事,封装成一个可复用、可自动触发的能力模块。Skills 以 Markdown 文件形式存在,不执行功能,而是通过按需、渐进式加载,实现高效且可复用的经验传递。Skills 和传统 Prompt 最大的区别是:按需加载 + 渐进式披露(只在需要时才把厚厚的 SOP 塞进上下文,极大节省 token)。
| 对比项 | 普通 Prompt | Skills 机制 |
|---|---|---|
| 每次都要重新描述 | 是 | 否(只描述一次) |
| 上下文长度占用 | 每次全量塞入 | 渐进式加载(只在触发时才读完整内容) |
| 一致性 | 依赖每次 prompt 质量 | 高(固定 SOP + 模板) |
| 复用性 | 手动复制粘贴 | 自动匹配 / slash 命令 / 项目共享 |
| 维护方式 | 改一次 prompt 就要重新发 | 修改 SKILL.md 文件,全局/项目生效 |
Skills 知识复用
- 知识分享:经验、最佳实践、工作流程
- 基于简单的 Markdown 文件,任何人都可以创建
- 渐进式加载,Token 使用效率高
- 无需服务器或后端设置
- 适用于 Web / Desktop / CLI
MCP 能力扩展
- 功能扩展:连接 API、数据库、外部工具
- 需要编码能力和服务器端配置
- 启动时加载全部工具定义
- 对外部系统集成能力强
- 更高的 Token 消耗与复杂度
Skills 的核心就是:一个文件夹 + 一个 SKILL.md 文件。SKILL.md 文件包含:
- 元数据(至少要有名称和描述)
- 告诉 AI 如何完成某一特定任务的指令
| 字段 | 必需 | 说明 |
|---|---|---|
| name | 是 | Skill 名称,最长 64 字符,只能使用小写字母、数字和 -,且不能以 - 开头或结尾 |
| description | 是 | 功能与使用场景说明,最长 1024 字符,不能为空 |
| license | 否 | 许可证名称或指向随 Skill 附带的许可证文件 |
| compatibility | 否 | 环境与依赖说明(产品、系统包、网络权限等),最长 500 字符 |
| metadata | 否 | 自定义键值对,用于扩展元数据(如作者、版本号) |
| allowed-tools | 否 | 允许使用的工具列表(空格分隔,实验性功能) |
如果你需要一些参考资料,参考实例,执行脚本,可以使用更复杂 Skill 的目录结构:
my-skill/
├── SKILL.md # 必需:指令 + 元数据
├── scripts/ # 可选:可执行代码
├── references/ # 可选:文档资料
└── assets/ # 可选:模板、资源
技能用渐进式加载来高效管理上下文:
- **发现:**启动时,AI 只加载每个技能的名称和描述,只保留最基本的识别信息。
- **激活:**当任务匹配某个技能的描述时,AI 才把完整的 SKILL.md 指令读入上下文。
- **执行:**AI 按照指令执行,按需加载参考文件或运行代码。
SKILL.md 完整格式:
--- # YAML frontmatter 开始(顶格)
name: code-comment-expert # 必填:技能名(也是 /slash 命令名)
description: >- # 必填:最关键一行!Claude 靠它判断是否加载
为代码添加专业、清晰的中英双语注释。
适合缺少文档、可读性差、需要分享审查的代码。
常见触发场景:加注释、注释一下、加文档、explain this、improve readability
trigger_keywords: # 强烈推荐(大幅提升自动触发率)
- 加注释
- 注释
- 加文档
- explain code
- document
- comment this
- readability
version: 1.0 # 可选
author: yourname # 可选
--- # ← YAML 结束
# 这里开始是正文(Markdown)—— Claude 真正执行时的指令
你现在是「专业代码注释专家」。
## 核心原则
- 只在缺少注释或可读性明显不足处添加
- 优先使用英文 JSDoc / TSDoc 风格
- 复杂逻辑 / 非明显意图处额外加一行中文解释
- 注释精炼,每行不超过 80 字符
- 绝不修改原有逻辑
## 输出格式(严格遵守)
1. 先输出完整修改后的代码块(用 ```语言 包裹)
2. 再用 diff 形式展示只改动注释的部分
3. 最后说明加了哪些注释、理由
现在直接开始处理用户提供的代码,不要闲聊。
当技能超过 500–800 行,或需要模板/脚本/参考资料时,推荐以下组织方式:
~/.claude/skills/react-component-review/
├── SKILL.md # 核心指令 + 元数据(建议控制在 400 行内)
│
├── templates/ # 常用模板(Claude 按需读取)
│ ├── functional.tsx.md
│ └── class-component.md
│
├── examples/ # 优秀/反例(给 Claude 看标准)
│ ├── good.md
│ └── anti-pattern.md
│
├── references/ # 规范、规则、禁用词表
│ ├── hooks-rules.md
│ └── naming-convention.md
│
└── scripts/ # 可执行脚本(需开启 code execution)
├── validate-props.py
└── check-cycle-deps.sh
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)