摘要

很多人学习 Agent,第一反应是记概念:

  • LLM 加上工具就是 Agent;

  • ReAct 是边想边做;

  • MCP 是 AI 世界的 USB-C;

  • Skills 是高级提示词;

  • A2A 是让多个 Agent 互相聊天。

这些说法不能算错,但只停留在这个层面,真正开始写 Agent 系统时,还是会一头雾水。

因为 Agent 最难理解的,从来不是某个框架、协议或者 API,而是一个更底层的问题:

在一个软件系统中,下一步做什么,到底由代码决定,还是由模型决定?

当我把 Agent 看成一次“软件控制权迁移”之后,Workflow、Function Call、MCP、Skills、A2A,甚至多 Agent 架构,一下子全串起来了。

这篇文章不会堆术语。我会从一个具体任务开始,逐层讲清 Agent 的运行本质、几种常见模式的真实关系,以及一个 Agent 从 Demo 走向生产环境时,必须补齐的状态管理、权限、审计、评测和人工审批机制。


一、先忘掉所有框架,只思考一个问题

假设现在有一个退款请求:

用户购买了一件商品,收到后发现存在质量问题,希望退款。

传统后端系统会怎么处理?

开发者通常会提前写好流程:

接收退款申请
    ↓
查询订单
    ↓
判断是否超过退款期限
    ↓
判断商品是否支持退款
    ↓
满足条件:调用退款接口
不满足条件:生成拒绝通知
    ↓
记录处理结果

每一步做什么、什么时候查询数据库、什么时候发送通知,全部写在代码里。

代码拥有完整的流程控制权。

即使某个节点使用了大模型,例如让模型判断用户描述是否属于“质量问题”,整体上它依然是一个 Workflow:

order = get_order(order_id)

problem_type = llm_classify(user_description)

if problem_type == "quality_issue" and order.within_refund_period:
    refund(order)
else:
    reject_refund(order)

大模型只是在流程中的某个位置工作,并没有决定整个流程。

现在换一种方式。

我们只告诉系统:

请处理这条退款申请。

系统收到目标后,自己决定:

  1. 先读取用户的退款理由;

  2. 发现需要核实订单,调用订单查询工具;

  3. 发现订单超过普通退款期限;

  4. 继续查询特殊质量问题退款政策;

  5. 判断该情况符合例外条款;

  6. 调用退款工具;

  7. 调用消息工具通知用户;

  8. 写入处理记录。

这里发生了一个关键变化:

开发者没有提前写死每一步,而是让模型根据当前信息动态决定下一步。

这才是 Agent 最值得理解的地方。


二、Agent 不是一个更聪明的模型,而是一个持续运行的系统

很多文章会把 Agent 写成一个公式:

Agent = LLM + Tools + Memory + Planning

这个公式方便记忆,却容易让人产生误解:好像把几个模块拼起来,就自动得到了 Agent。

实际上,Agent 最核心的并不是加法,而是一个循环。

目标
 ↓
读取当前状态
 ↓
判断下一步行动
 ↓
调用工具
 ↓
观察工具结果
 ↓
更新状态
 ↓
判断任务是否完成
 ↓
未完成则继续循环

可以把它抽象成下面这个过程:

action_t = Model(goal, state_t, observations_t, available_tools)

observation_t = Environment(action_t)

state_t+1 = Update(state_t, action_t, observation_t)

模型每次只负责做一件事:

根据目标、当前状态和已经获得的信息,判断下一步应该做什么。

至于工具怎么执行、权限是否允许、失败是否重试、状态如何保存,通常由 Agent Runtime,也就是智能体运行时负责。

这也是为什么我更愿意把 Agent 定义为:

Agent 是一个以模型作为动态决策器、通过循环与外部环境交互,直到目标完成或触发终止条件的运行系统。

OpenAI Agents SDK 的核心能力之一,就是内置 Agent Loop:处理工具调用,把工具结果重新交给模型,并持续运行,直到任务完成。(OpenAI)


一个最小可用的 Agent Loop

先不依赖 LangGraph、CrewAI 或任何大型框架,一个最简化的 Agent 循环,大致可以写成这样:

from typing import Any


class AgentRuntimeError(Exception):
    pass


def run_agent(goal: str, model: Any, tool_registry: dict, max_steps: int = 8):
    state = {
        "goal": goal,
        "history": [],
        "status": "running",
    }

    for step in range(max_steps):
        decision = model.decide(
            goal=state["goal"],
            history=state["history"],
            available_tools=list(tool_registry.keys()),
        )

        if decision.type == "final_answer":
            state["status"] = "completed"
            return {
                "status": "completed",
                "answer": decision.content,
                "steps": step + 1,
                "history": state["history"],
            }

        if decision.type != "tool_call":
            raise AgentRuntimeError(
                f"Unsupported decision type: {decision.type}"
            )

        tool_name = decision.tool_name
        tool_args = decision.arguments

        if tool_name not in tool_registry:
            state["history"].append({
                "type": "tool_error",
                "tool": tool_name,
                "error": "Tool not found",
            })
            continue

        try:
            validated_args = validate_tool_arguments(
                tool_name,
                tool_args,
            )

            check_permission(
                tool_name=tool_name,
                arguments=validated_args,
            )

            result = tool_registry[tool_name](**validated_args)

            state["history"].append({
                "type": "tool_result",
                "tool": tool_name,
                "arguments": validated_args,
                "result": result,
            })

        except Exception as exc:
            state["history"].append({
                "type": "tool_error",
                "tool": tool_name,
                "arguments": tool_args,
                "error": str(exc),
            })

    state["status"] = "max_steps_exceeded"

    return {
        "status": "failed",
        "reason": "Agent exceeded the maximum number of steps",
        "history": state["history"],
    }

这段代码并不复杂,但已经包含了 Agent 最核心的结构:

模型决策
→ 工具执行
→ 结果回写
→ 再次决策
→ 直到结束

真正需要重点注意的是:循环一定要有明确的终止条件。

至少应该考虑:

任务成功
任务明确失败
达到最大步数
达到最大 Token 预算
达到最大执行时间
工具连续失败
需要人工确认
发生不可恢复异常

否则,一个 Agent 很容易反复查询相同信息,或者在错误路径上不断自我循环。


三、LLM 和 Agent 的区别,关键不在“会不会调用工具”

大语言模型在推理时,本质上是根据已有上下文生成后续 Token。

这不意味着它只是低级的文字接龙。经过大规模训练之后,模型可以表现出很强的语言理解、代码生成、归纳、推理和任务分解能力。

但单独的一次模型调用,通常仍然只是:

输入上下文 → 生成输出

它没有天然拥有下面这些东西:

  • 一个持续运行的任务状态;

  • 对业务系统的真实访问权限;

  • 可重复执行的工具;

  • 对失败结果的处理机制;

  • 对任务是否完成的可靠判断;

  • 对高风险行为的审批机制。

所以 LLM 和 Agent 的关系,更准确地说是:

LLM 是决策能力,Agent 是围绕这种决策能力构建出来的执行系统。

可以类比成:

LLM:一个会判断下一步怎么走的大脑

Agent:大脑 + 状态 + 工具 + 执行环境 + 安全边界 + 循环控制

也就是说,Agent 不只是让模型“知道怎么做”,还要让系统能够:

真的执行
观察结果
修正计划
控制风险
保留状态
最终停止

四、Workflow 和 Agent 的真正区别:谁掌握下一步的控制权

这是理解 Agent 架构最重要的一道分界线。

传统 Workflow

在 Workflow 中,开发者提前定义好执行路径:

def process_refund(request):
    order = query_order(request.order_id)
    category = classify_problem(request.description)

    if category == "quality_issue":
        policy = load_quality_refund_policy()
    else:
        policy = load_standard_refund_policy()

    decision = evaluate_refund(order, policy)

    if decision.approved:
        execute_refund(order)
    else:
        send_rejection(order)

即使 classify_problem()evaluate_refund() 使用了大模型,控制流程的仍然是 Python 代码。

Agent

Agent 的代码可能只定义目标、可用工具和边界:

目标:完成退款申请处理

可用工具:
- query_order
- search_refund_policy
- request_more_information
- execute_refund
- send_message
- escalate_to_human

至于先调用哪个工具,什么时候补充信息,什么时候升级人工,由模型结合当前状态动态决定。


Workflow 和 Agent 不是非黑即白

现实中的系统通常处于一条连续谱上。

第一层:完全确定性 Workflow

A → B → C → D

每一步都由代码决定。

适合:

  • ETL;

  • 数据同步;

  • 账单计算;

  • 固定审批流程;

  • 数据库迁移。

第二层:Workflow 中包含 LLM 节点

读取文档
→ LLM 提取字段
→ 代码校验
→ 写入数据库

模型参与理解,但不拥有流程控制权。

第三层:Agentic Workflow

主流程由代码控制,但在部分复杂节点中,允许 Agent 动态决策。

接收工单
→ 固定分类流程
→ 复杂问题进入 Agent
→ Agent 自主查询和分析
→ 返回结构化建议
→ 固定审批流程

第四层:高度自主的 Agent

开发者主要定义目标、权限和工具,模型自己决定任务路径。

这类方式灵活性最高,但行为的不确定性、调试难度和运行成本也最高。


最实用的设计原则:最小必要自主性

很多团队做 Agent 时容易陷入一个误区:

既然 Agent 越自主越先进,那就把所有决策都交给模型。

这在生产环境里往往适得其反。

Anthropic 在总结实际 Agent 项目经验时强调,成功的实现往往依赖简单、可组合的模式,而不是一开始就引入复杂框架;对于路径明确的任务,应优先使用更简单的 Workflow,只在确实需要动态决策时增加 Agent 自主性。(Anthropic)

一个更稳妥的原则是:

能用代码确定的流程,不要交给模型猜;只有无法提前枚举的决策,才交给 Agent。


五、企业级 Agent 最常见的形态:外层 Workflow,内层 Agent

真正投入业务的系统,通常既不是纯 Workflow,也不是完全自由的 Agent,而是混合架构。

还是以退款系统为例。

外层 Workflow 可以负责:

接收退款申请
→ 身份验证
→ 数据脱敏
→ 启动退款分析 Agent
→ 校验 Agent 返回结果
→ 人工审批
→ 执行退款
→ 写入审计日志

退款分析 Agent 负责:

分析用户描述
→ 查询订单
→ 判断缺少哪些资料
→ 检索适用的退款政策
→ 比较订单事实和政策条款
→ 输出建议与证据

这里的边界非常清晰。

Agent 可以:

  • 查询资料;

  • 分析情况;

  • 生成建议;

  • 说明理由;

  • 请求补充信息。

但 Agent 不应该默认拥有:

  • 无条件退款权限;

  • 修改公司政策的权限;

  • 删除业务记录的权限;

  • 绕过审批的权限。

这类设计叫作受约束的自主性,Bounded Autonomy。

生产级 Agent 的目标并不是“让模型什么都能做”,而是:

在明确边界内,让模型只获得完成任务所必需的最小权限。


六、ReAct、Plan-and-Execute、Reflection、Multi-Agent,其实不是四种并列架构

很多介绍会把下面四个概念放在同一个列表中:

  • ReAct;

  • Plan-and-Execute;

  • Reflection;

  • Multi-Agent。

看上去像四选一。

实际上,它们根本不在同一个维度。

概念所属维度解决的问题
ReAct执行策略每一步如何根据环境反馈行动
Plan-and-Execute规划策略先形成计划还是边执行边规划
Reflection质量改进机制如何根据错误和反馈修正结果
Multi-Agent系统拓扑一个 Agent 工作,还是多个 Agent 协作

一个多 Agent 系统完全可能同时使用这四种机制:

Orchestrator Agent
    ↓
Planner Agent:使用 Plan-and-Execute
    ↓
Research Agent:内部使用 ReAct
    ↓
Developer Agent:内部使用 ReAct
    ↓
Reviewer Agent:使用 Reflection

所以不要问“这四种模式该选哪一种”,而要问:

我的执行过程需要实时观察吗?
我的任务适合提前规划吗?
我的结果需要怎样的反馈修正?
我的子任务是否真的需要多个独立 Agent?

七、ReAct:重点不是“多想”,而是让外部事实纠正模型

ReAct 来自 Reasoning 与 Acting 的组合。

它的典型过程是:

判断当前情况
→ 采取行动
→ 获得观察结果
→ 根据结果调整下一步

例如,用户要求 Agent 修复一个项目中的 Bug。

Agent 可能这样执行:

读取错误日志
→ 判断问题可能来自数据库连接
→ 搜索相关配置
→ 发现连接串没有问题
→ 运行测试
→ 观察到真实错误是字段类型不匹配
→ 修改代码
→ 再次运行测试
→ 测试通过

ReAct 真正有价值的地方,不是让模型凭空生成更长的推理文字,而是让推理能够不断接收环境反馈。

原始 ReAct 研究也是把推理与外部行动交替进行,让模型能够通过知识库或环境获得新信息,并据此更新计划。(arXiv)

ReAct 最常见的三个问题

1. 重复调用同一个工具

查询订单
→ 没得到想要的答案
→ 再次查询同一个订单
→ 仍然没有新信息
→ 继续查询

解决方式:

  • 最大步数;

  • 重复行动检测;

  • 工具调用指纹;

  • 连续失败终止;

  • 触发重新规划。

2. 工具结果太长

如果把整个数据库响应、网页或日志全部塞回模型,上下文会迅速膨胀。

应该先做:

字段过滤
结构化提取
长度限制
敏感数据脱敏
必要时摘要

3. 错误被不断放大

如果第一次观察结果本身不可靠,模型可能在错误方向上越走越远。

因此,工具结果应该带有:

来源
时间
置信度
错误状态
数据版本

八、Plan-and-Execute:成熟实现一定需要重新规划

Plan-and-Execute 的基本思路是:

先生成计划
→ 再按计划执行

例如:

目标:生成一份竞争对手技术分析报告

计划:
1. 确认分析对象
2. 收集公开资料
3. 提取产品能力
4. 比较技术架构
5. 分析优势和风险
6. 生成报告
7. 检查证据完整性

这个模式的好处是,模型不用每一步都重新思考整个任务。

但如果严格按照初始计划执行到底,会产生另一个问题:

初始计划是基于不完整信息形成的,执行过程中很可能已经失效。

更合理的实现是:

Plan
→ Execute
→ Observe
→ Check Plan
→ Replan if Necessary
→ Continue

也就是说,要设置重新规划检查点。

例如:

if step_count % 3 == 0:
    plan = model.replan(
        original_goal=goal,
        current_plan=plan,
        completed_steps=completed_steps,
        new_observations=observations,
    )

适合 Plan-and-Execute 的任务通常具有这些特点:

  • 步骤较多;

  • 子任务边界比较清楚;

  • 部分任务可以并行;

  • 工具调用成本较高;

  • 需要整体控制预算。

如果任务只有两三步,或者每一步结果都会完全改变后续方向,直接使用 ReAct 往往更自然。


九、Reflection:不是让模型“再看一遍”,而是引入新的反馈

很多人实现 Reflection 时,会在原始回答后追加一句:

请检查上面的答案是否有问题,并进行改进。

这并不是真正可靠的反思机制。

因为同一个模型、同一份信息、同一个判断习惯,很可能再次犯下相同错误。

有效的 Reflection 应该引入新的反馈信号。

例如:

代码生成
→ 编译器返回错误
→ 分析错误原因
→ 修改代码
→ 重新运行测试

或者:

SQL 生成
→ 数据库返回执行计划
→ 发现发生全表扫描
→ 调整索引或查询条件
→ 再次检查执行计划

又或者:

RAG 回答
→ 事实一致性评测失败
→ 找到缺少引用的句子
→ 重新检索证据
→ 重写回答

Reflexion 的核心思想也是根据环境或评测反馈形成语言化反思,并将这些经验写入记忆,用于后续尝试,而不只是简单重新生成一次。(arXiv)

所以更有效的结构是:

生成
→ 执行或评测
→ 获得具体失败信号
→ 总结失败原因
→ 修改策略
→ 再次执行

没有新的反馈,Reflection 很容易退化成“模型重新表达一遍”。


十、Multi-Agent:角色越多,不代表系统越先进

多 Agent 系统经常被设计成一个虚拟团队:

产品经理 Agent
架构师 Agent
开发 Agent
测试 Agent
安全审查 Agent
文档 Agent

看起来很完整,但每多一个 Agent,就会增加一层新的问题:

  • 上下文传递损失;

  • 重复推理;

  • 状态同步;

  • Token 消耗;

  • 错误传播;

  • 权限划分;

  • 调试难度;

  • 最终责任归属。

多 Agent 真正适合的场景,一般满足下面几个条件。

1. 子任务可以明确拆分

例如:

市场研究
技术评估
财务分析
法律审查

每个子任务有清晰输入和输出。

2. 子任务可以并行

如果所有任务必须严格串行,多 Agent 不一定带来效率提升。

3. 不同任务需要不同工具或权限

例如:

财务 Agent 只能访问财务系统
HR Agent 只能访问招聘系统
IT Agent 只能访问设备管理平台

4. 不同任务需要相互隔离的上下文

一个 Agent 不需要知道另一个 Agent 的所有内部状态。

5. 交付物可以验证

每个 Agent 的输出都应该有明确格式和验收标准。

否则,把多个 Agent 放在一起,往往只是把一个复杂问题拆成了更多难以调试的问题。


十一、别再背那些固定成本倍数

网上经常能看到类似说法:

Workflow 的 Token 成本大约是 Agent 的四分之一。

Plan-and-Execute 的成本大约是 ReAct 的五分之一。

这些比例不能当作通用技术结论。

  • 使用的是什么模型;

  • 上下文长度是多少;

  • 工具调用了几次;

  • 有没有进行重规划;

  • 是否发生错误重试;

  • 是否使用小模型执行部分步骤;

  • 任务复杂度是否相同;

  • 是否计算了工具和基础设施成本。

能够确定的只有方向:

固定流程通常比动态循环更容易控制成本。

减少高能力模型的决策次数,通常能够降低 Token 消耗。

预先规划可能减少重复思考,但也可能因为错误计划带来额外重试。

多 Agent 通常会增加通信和上下文成本。

具体成本必须用自己的任务集做评测,不能靠背一个比例。


十二、Function Call 的本质:模型提交行动申请,程序决定是否执行

Function Call 最容易被错误理解成:

大模型直接调用了一个函数。

实际上,模型通常并不执行函数。

模型只是输出一个结构化请求:

{
  "tool_name": "get_weather",
  "arguments": {
    "city": "上海",
    "date": "2026-07-17"
  }
}

真正的执行者是应用程序或 Agent Runtime。

完整过程是:

开发者定义工具
→ 模型读取工具描述
→ 模型选择工具并生成参数
→ Runtime 校验参数
→ Runtime 检查权限
→ Runtime 执行工具
→ 工具结果写回模型
→ 模型继续决策

一个工具定义示例

{
  "type": "function",
  "function": {
    "name": "query_order",
    "description": "根据订单编号查询订单状态和退款相关信息",
    "parameters": {
      "type": "object",
      "properties": {
        "order_id": {
          "type": "string",
          "description": "订单编号"
        }
      },
      "required": ["order_id"],
      "additionalProperties": false
    }
  }
}

模型看到这个描述后,可以根据用户请求决定是否调用它。

但一定要记住:

模型选择了工具,不等于系统必须执行工具。


十三、生产级工具调用,至少要补齐八件事

1. 参数校验

class RefundArguments(BaseModel):
    order_id: str
    amount: Decimal
    reason: str

不能直接相信模型生成的参数。

2. 权限校验

查询订单:允许自动执行
生成退款建议:允许自动执行
实际退款:需要人工审批
删除订单:禁止

工具可见,不代表工具可执行。

3. 幂等性

Agent 可能因为超时而重复调用工具。

对于退款、发送邮件、创建任务等有副作用的操作,应增加幂等键:

idempotency_key = f"refund:{order_id}:{request_id}"

4. 超时控制

所有外部工具都应该有明确超时。

result = call_tool(timeout_seconds=10)

5. 分类重试

网络超时:可以重试
服务暂时不可用:可以重试
参数错误:不能重试
权限不足:不能重试
业务规则拒绝:不能重试

6. 结果标准化

不要把外部系统的完整原始响应直接交给模型。

应该只返回模型完成任务所需的字段。

7. 审计日志

至少记录:

哪个用户触发
哪个 Agent 决策
调用了哪个工具
输入参数是什么
执行结果是什么
是否产生业务副作用
是否经过审批

8. 人工确认

高风险操作必须设计审批节点,例如:

退款
转账
删除数据
发送外部邮件
修改合同
修改生产环境
拒绝候选人

真正的 Agent 工程,难点往往不是让模型产生一个 Tool Call,而是让这个 Tool Call 可控、可回滚、可审计。


十四、MCP 不只是“统一版 Function Call”

很多人习惯把 MCP 比作 AI 世界的 USB-C。

这个比喻适合入门,但不够精确。

MCP,全称 Model Context Protocol,它解决的是 AI 应用与外部能力之间如何建立标准化连接的问题。

一个典型 MCP 架构包含:

MCP Host
    ↓
MCP Client
    ↓
MCP Server

MCP Host

承载 Agent 的应用,例如:

  • 桌面 AI 客户端;

  • IDE;

  • 企业 Agent 平台;

  • 自研聊天应用。

MCP Client

运行在 Host 中,负责和 MCP Server 建立连接、协商能力、发送请求和接收结果。

MCP Server

向外暴露工具、资源和提示模板。

MCP 官方架构将协议分成数据层和传输层。数据层基于 JSON-RPC,处理生命周期、能力协商、工具、资源、提示模板和通知;传输层负责具体通信机制与授权。(Model Context Protocol)


MCP 不只有 Tools

Tools:可执行动作

例如:

create_issue
send_email
query_database
update_calendar

Resources:上下文资源

例如:

项目文档
数据库 Schema
日历内容
Git 提交历史
企业政策

Prompts:可复用交互模板

例如:

代码审查模板
故障分析模板
发布说明生成模板

因此,更准确的说法是:

MCP 标准化了 AI 应用与外部工具、数据和交互模板之间的上下文交换。

官方文档也将 Tools、Resources 和 Prompts 作为 MCP Server 的核心能力。(Model Context Protocol)


十五、MCP 和 Function Call 到底是什么关系

常见但不够严谨的说法是:

MCP 建立在 Function Call 之上。

更准确的链路应该是:

MCP Server 暴露工具
→ MCP Client 发现工具
→ Host 把工具转换成模型可理解的 Schema
→ 模型选择是否调用
→ Host 通过 MCP 请求 Server
→ Server 执行并返回结果

Function Call 解决的是:

模型如何表达“我想执行哪个动作,参数是什么”。

MCP 解决的是:

AI 应用如何以统一方式发现、连接和调用外部能力。

二者经常一起使用,但不是同一个东西。


什么时候值得使用 MCP

适合:

  • 多个 Agent 应用需要连接同一批服务;

  • 多个团队需要共享工具;

  • 需要运行时发现工具;

  • 需要对接数据库、文件系统、代码仓库和企业系统;

  • 希望降低每个 AI 应用单独编写适配器的成本。

不一定需要 MCP:

  • 只有一个简单工具;

  • 工具只在当前应用内部使用;

  • 没有跨客户端复用需求;

  • 一个普通函数调用已经足够清晰。

MCP 是标准化连接协议,不是所有 Agent 项目的必选项。


十六、Skills 不是高级提示词,而是可以复用的能力包

在 Agent 的整个技术体系中,我认为 Skills 是最容易被低估的一层。

工具解决的是:

Agent 能做什么。

Skill 解决的是:

面对某类任务,Agent 应该按照什么方法做。

例如,一个 Agent 拥有下面这些工具:

读取文件
查询数据库
运行 Python
搜索文档
生成报告

这些工具只能说明 Agent 有能力操作文件、数据库和代码。

但它并不知道:

  • 做代码审查时应该检查什么;

  • 做候选人筛选时如何处理硬性条件;

  • 做 RAG 评测时应该使用哪些指标;

  • 做故障分析时应该先看日志还是先看指标;

  • 输出报告时应该遵守什么结构。

这些领域经验,才是 Skill 应该承载的内容。

当前 Agent Skills 规范将 Skill 定义为一个包含 SKILL.md 的目录,还可以附带脚本、参考资料和其他资源。(Agent Skills)


一个实际的 Skill 目录

以候选人筛选为例:

candidate-screening/
├── SKILL.md
├── scripts/
│   ├── normalize_resume.py
│   └── validate_score.py
├── references/
│   ├── scoring_rules.md
│   ├── skill_taxonomy.md
│   └── education_mapping.md
└── assets/
    └── screening_report_template.md

这里并不只有一段提示词。

SKILL.md

定义工作方法、触发条件和输出要求。

references/

存放详细的业务知识和规则。

scripts/

执行确定性计算和校验。

assets/

存放报告模板、表单或其他输出资源。


一个简化的 SKILL.md

---
name: candidate-screening
description: >
  用于分析职位描述、匹配候选人经历、识别硬性条件、
  输出带证据的候选人适配度报告。
---

# 目标

基于职位描述和候选人资料,生成可解释、可追溯的匹配结果。

# 工作流程

1. 提取职位硬性条件。
2. 区分必须条件、优先条件和普通加分项。
3. 对候选人资料进行标准化。
4. 对每一项判断寻找明确证据。
5. 信息缺失时标记未知,不允许自行推测。
6. 计算各维度评分。
7. 输出匹配理由、风险和待确认问题。

# 强制规则

- 不得根据姓名、性别、年龄等敏感信息推断能力。
- 没有证据的数据标记为 Information Not Available。
- 不得把“没有写”判断为“不具备”。
- Agent 只提供建议,不得自动拒绝候选人。
- 所有评分必须附带证据字段。

# 输出格式

{
  "candidate_id": "string",
  "overall_score": 0,
  "matched_requirements": [],
  "missing_information": [],
  "risks": [],
  "evidence": [],
  "recommendation": "review | potential_match | insufficient_information"
}

这比一个巨型 System Prompt 更容易管理,也更容易版本控制和测试。


十七、Skills 最关键的机制:渐进式加载

如果系统有 100 个 Skills,而每个 Skill 都有几千字,把所有内容一次性塞进模型上下文,成本和效果都会迅速恶化。

更合理的过程是:

第一步:只暴露 Skill 的名称和描述

第二步:模型判断当前任务是否需要某个 Skill

第三步:命中后加载对应 SKILL.md

第四步:真正需要时再读取 references

第五步:需要确定性执行时再调用 scripts

也就是:

元数据
→ 核心工作流
→ 详细领域知识
→ 可执行脚本

Agent Skills 的官方实现指导同样强调技能发现、元数据暴露、按需加载和上下文管理。(Agent Skills)

这背后的本质是:

Agent 可以拥有大量潜在能力,但不应该同时加载所有能力。


一个好的 Skill 应该怎么写

1. 只写模型原本不知道的东西

不要在 Skill 里解释什么是 HTTP、什么是数据库、什么是 Markdown。

应该重点写:

  • 企业内部规则;

  • 特定项目约定;

  • 容易犯错的边界;

  • 必须使用的工具;

  • 特定输出格式;

  • 业务领域经验。

Agent Skills 的最佳实践也建议,把上下文留给模型不知道的项目规则、专业流程和非显而易见的边界。(Agent Skills)

2. 把确定性逻辑交给脚本

例如:

金额计算
日期判断
格式校验
字段映射
统计指标
数据清洗

不要让模型反复凭语言推理计算。

3. 把输出定义成结构化格式

这样才能:

  • 自动校验;

  • 写入数据库;

  • 进行回归测试;

  • 比较不同模型效果。

4. 给 Skill 建测试集

不要只测试一个成功样例。

至少应该覆盖:

正常输入
信息缺失
字段冲突
边界条件
不应该触发 Skill 的请求
高风险请求
恶意输入

官方 Skills 文档也建议通过结构化评测比较“使用 Skill”和“不使用 Skill”的表现,而不是依赖单次主观观察。(Agent Skills)


十八、Function Call、MCP、Skills,可以放进同一张技术分层图

┌────────────────────────────────┐
│ Skills:这类任务应该按什么方法做 │
├────────────────────────────────┤
│ Agent Loop:当前下一步应该做什么  │
├────────────────────────────────┤
│ Function Call:如何表达行动请求   │
├────────────────────────────────┤
│ MCP:如何发现和连接外部能力       │
├────────────────────────────────┤
│ Runtime:权限、执行、重试、审计    │
├────────────────────────────────┤
│ External Systems:真实业务系统     │
└────────────────────────────────┘

它们分别回答不同的问题。

技术核心问题
Skills应该使用什么专业方法
Agent Loop当前下一步是什么
Function Call如何结构化描述行动
MCP如何标准化连接外部能力
Runtime是否允许执行以及如何可靠执行
External Systems在真实世界产生什么结果

这里最容易被忽略的是 Runtime。

因为 Function Call、MCP 和 Skills 都不会自动解决:

数据库事务
幂等性
权限控制
审批流程
失败补偿
服务降级
审计日志
数据隔离

这些仍然属于扎扎实实的后端工程。


十九、A2A 解决的不是工具调用,而是责任委派

MCP 解决了 Agent 如何连接工具和数据。

但如果一个独立 Agent 需要把任务交给另一个独立 Agent 呢?

例如,企业新员工入职:

入职编排 Agent
├── 委派 HR Agent 创建员工档案
├── 委派 IT Agent 创建系统账号
└── 委派 Finance Agent 配置薪资信息

这里不是简单调用三个普通函数。

每个远程 Agent 可能:

  • 由不同团队维护;

  • 使用不同模型和框架;

  • 拥有独立权限;

  • 有自己的内部工具;

  • 运行数分钟甚至数小时;

  • 需要持续返回任务进度。

这就是 A2A,也就是 Agent-to-Agent 协议要解决的问题。

截至 2026 年 7 月,A2A 官方规范的最新发布版本为 1.0.0,目标是在不同框架、语言和供应商构建的独立 Agent 之间提供统一的发现、通信和任务协作机制。(A2A Protocol)


A2A 的几个核心对象

Agent Card

可以理解成 Agent 的机器可读名片:

我是谁
我能做什么
支持哪些输入输出
需要什么认证
支持哪些协议能力

Message

Agent 之间交换的过程信息。

Task

一个具有生命周期的任务,例如:

submitted
working
input-required
completed
failed
canceled
rejected

Artifact

Agent 最终交付的结果,例如:

报告
代码
表格
文件
结构化数据

A2A 不要求一个 Agent 暴露自己的内部提示词、记忆或工具,只需要通过协议描述能力、接收任务并返回结果。(A2A Protocol)


二十、MCP 和 A2A 的准确边界

最常见的解释是:

MCP 是纵向连接
A2A 是横向连接

这有助于记忆,但我认为还有一个更准确的区分:

MCP 调用的是能力,A2A 委派的是责任。

MCP

主 Agent 调用一个工具时,仍然对整个任务负责。

主 Agent
→ 调用数据库查询工具
→ 获得查询结果
→ 主 Agent 继续判断

A2A

主 Agent 把一个完整子任务委派给远程 Agent。

主 Agent
→ 请财务 Agent 完成费用核算
→ 财务 Agent 自己规划和调用工具
→ 财务 Agent 返回最终核算结果
对比项MCPA2A
连接对象工具、数据和资源独立 Agent
任务控制权主 Agent 保留可委派给远程 Agent
远程对象是否自主规划通常不需要可以
是否需要任务生命周期不一定通常需要
典型结果工具返回值Artifact 或完整任务结果

一个典型架构可能是:

Orchestrator Agent
    │
    ├── 通过 A2A 委派给 HR Agent
    │       └── HR Agent 通过 MCP 访问招聘系统
    │
    ├── 通过 A2A 委派给 IT Agent
    │       └── IT Agent 通过 MCP 访问账号系统
    │
    └── 通过 A2A 委派给 Finance Agent
            └── Finance Agent 通过 MCP 访问财务系统

二十一、一个 Agent 从 Demo 到生产,还缺哪些东西

很多 Agent 教程写到“成功调用工具”就结束了。

但在企业环境里,这通常只是起点。

真正决定系统能不能上线的,是下面五个模块。


1. State:状态管理

Agent 的状态不只是聊天记录。

至少要区分:

Conversation State

当前对话里发生过什么。

Task State

当前任务执行到哪一步。

Working Memory

当前步骤真正需要使用的信息。

Episodic Memory

过去执行过哪些类似任务,犯过哪些错误。

Semantic Memory

知识库、业务文档、长期事实和规则。

还要特别区分三种信息:

模型推测
工具返回的事实
用户明确确认的信息

它们的可信等级不能相同。

业务数据库应该是 Source of Truth,不能让模型记忆覆盖真实业务状态。


2. Guardrails:安全约束

Guardrail 不只是检查用户输入中有没有敏感词。

至少应该覆盖:

输入阶段
模型输出阶段
工具调用阶段
最终结果阶段

例如招聘 Agent:

输入阶段:
禁止基于敏感属性进行歧视性筛选

工具阶段:
禁止未经审批自动拒绝候选人

输出阶段:
禁止生成没有证据支撑的负面判断

尤其要注意:

用户输入安全,不代表工具调用一定安全。

Agent 可能在后续循环中受到工具返回内容、外部文档或网页中的提示注入影响。


3. Human-in-the-Loop:人在回路

人工审批不是 Agent 不够先进,而是风险边界的一部分。

典型人工介入点包括:

信息不足
多个规则发生冲突
操作不可逆
涉及资金
涉及外部发送
涉及法律责任
成本超过预算
模型置信度过低

一个成熟 Agent 必须知道:

什么时候自己处理
什么时候调用工具
什么时候重新规划
什么时候请求人类
什么时候立即停止

4. Observability:可观测性

如果 Agent 最后给出了错误结果,你必须能回答:

它为什么调用这个工具?
调用参数是什么?
工具返回了什么?
在哪一步改变了计划?
为什么发生重试?
为什么最终得出这个结论?

至少需要记录:

模型调用
工具调用
工具耗时
Token 使用
状态变化
重试记录
Agent 委派
Guardrail 结果
人工审批
最终输出

OpenAI Agents SDK 的 tracing 也会记录模型生成、工具调用、handoff、guardrail 和自定义事件,用于开发及生产环境中的调试和监控。(OpenAI)

注意,可审计性不等于公开模型的全部隐藏思维过程。

生产系统应该记录的是:

可验证的行动轨迹、状态变化和证据来源。


5. Evaluation:评测体系

不能只评价最终文字“看起来写得好不好”。

Agent 至少需要四层评测。

任务结果

任务是否真正完成
结果是否正确
是否满足业务要求

执行轨迹

是否选择了正确工具
是否遗漏必要步骤
是否发生无效循环
是否违反权限限制

效率成本

执行耗时
模型调用次数
工具调用次数
Token 成本
失败重试次数

安全性

越权调用率
错误副作用率
敏感信息泄漏率
人工拦截率

对于高风险 Agent,只看最终答案,远远不够。


二十二、用一个完整案例,把这些技术真正串起来

假设我们要实现一个候选人筛选 Agent。

用户目标是:

从人才库中找出适合 Java 架构师岗位的候选人,输出匹配依据和风险,但不要自动淘汰任何人。

第一步:外层 Workflow

读取职位
→ 验证用户权限
→ 获取候选人列表
→ 数据脱敏
→ 启动匹配 Agent
→ 校验结果格式
→ 检查偏见和合规风险
→ 交给 HR 人工复核

这些步骤由代码控制。

第二步:给 Agent 定义目标

分析 JD 和候选人资料,输出有证据的匹配结果。
不得推测缺失信息。
不得基于敏感属性进行评分。
不得自动拒绝候选人。

第三步:给 Agent 提供工具

get_job_description
get_candidate_profile
search_skill_taxonomy
search_internal_job_policy
request_missing_information

第四步:加载 Candidate Screening Skill

Skill 规定:

先识别硬性条件
再识别优先条件
再分析项目经历
每一项判断必须有证据
缺失信息标记 Information Not Available
最终输出结构化 JSON

第五步:Agent Loop 运行

读取 JD
→ 提取 Java、分布式系统、团队管理等要求
→ 读取候选人资料
→ 发现候选人只写了“负责系统架构”
→ 判断证据不足
→ 查询项目经历
→ 找到微服务迁移和性能治理项目
→ 查询技能词典,确认相关技能映射
→ 生成评分和证据
→ 标记云平台经验 Information Not Available
→ 返回结构化结果

第六步:Guardrail 检查

检查:

是否使用敏感属性
是否存在无证据判断
是否自动生成拒绝建议
是否遗漏硬性条件

第七步:HR 人工确认

最终决定权仍然在人。

这个案例中:

Workflow 负责安全边界和确定性流程

Agent Loop 负责动态分析

Function Call 负责表达工具请求

MCP 可以负责连接 ATS、知识库和文档系统

Skill 负责招聘筛选方法

A2A 只有在需要把技术评估委派给独立技术面试 Agent 时才有必要

这样,整套概念就不再是零散名词,而是落在同一套系统架构中。


二十三、推荐的 Agent 学习顺序

很多人一开始就学多 Agent、MCP、复杂图编排,结果概念知道很多,却连一个可靠的 Agent Loop 都没有真正实现过。

我更推荐下面这个顺序。

第一阶段:自己写一个最小 Agent Loop

实现:

模型决策
→ 工具调用
→ 结果回写
→ 终止判断

只使用一两个无副作用的工具。

第二阶段:加入状态和错误处理

实现:

最大步数
超时
失败分类
重试
重复调用检测

第三阶段:划分 Workflow 和 Agent 边界

把系统拆成:

确定性主流程
+
少量动态决策节点

第四阶段:加入 tracing 和评测

没有可观测性,不要扩大自主权限。

第五阶段:把专业经验沉淀成 Skills

避免把所有规则都堆在一个巨型 System Prompt 中。

第六阶段:引入 MCP

当工具和数据源开始跨应用、跨团队复用时,再做标准化连接。

第七阶段:考虑 Multi-Agent 和 A2A

只有任务确实需要独立责任边界、跨系统协作或长时间运行时,再引入 Agent 间委派。


二十四、做 Agent 最容易踩的五个坑

坑一:把所有判断都交给模型

能用确定性规则解决的问题,尽量用代码。

坑二:把所有知识塞进一个 Prompt

Prompt 越长,不代表效果越稳定。

应该拆分:

系统规则
业务 Skill
按需参考资料
工具定义
当前任务上下文

坑三:模型一生成 Tool Call 就立即执行

必须经过参数、权限、风险和审批检查。

坑四:只看最终回答,不看执行轨迹

Agent 错误往往发生在中间步骤。

坑五:一开始就做多 Agent

先证明一个 Agent 无法可靠完成,再考虑拆分。


结语:Agent 工程师真正设计的是控制权边界

回头再看这些概念:

LLM
Agent
Workflow
ReAct
Plan-and-Execute
Reflection
Function Call
MCP
Skills
A2A

它们并不是一堆相互竞争的新名词。

它们分别位于不同层级,解决不同问题:

LLM 提供判断能力

Agent Loop 让判断持续运行

Workflow 控制确定性流程

ReAct 让环境反馈进入决策

Plan-and-Execute 管理复杂任务规划

Reflection 使用反馈修正失败

Function Call 表达结构化行动请求

MCP 标准化外部能力连接

Skills 沉淀领域方法和专业经验

A2A 支持独立 Agent 之间委派任务

但这些技术背后,其实只有一个核心问题:

在这个系统中,哪些决定应该交给模型,哪些决定必须留在代码、规则和人类手中?

过去的软件开发,是开发者提前写完大部分执行路径。

Agent 软件则是:

开发者定义目标
开发者提供工具
开发者设定边界
模型在边界内动态选择路径

所以,Agent 系统先进不先进,并不取决于它有多少个 Agent、接入了多少 MCP Server,也不取决于它的 Prompt 有多长。

真正重要的是:

它能不能完成真实任务
它的行为是否可控
它的结论是否有证据
它的操作是否可审计
它犯错时能否及时停止
它是否知道什么时候应该把决定交还给人

从这个角度看,Agent 工程师并不只是 Prompt 工程师。

更准确地说:

Agent 工程师是在设计一个由概率模型参与决策的受控软件系统。

而系统设计的最高水平,从来不是给模型无限自由。

是在正确的地方,给它恰到好处的控制权。


建议 CSDN 标签:

大语言模型 AI Agent MCP Function Calling Agent Skills A2A LLM 人工智能

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐