大清已经亡了,但是八股文该背还是要背啊,别的不说,可以在别人面前好好装杯不是。


在这里插入图片描述

Agent 八股专题第二期:Agent 核心范式 10 连问

面向:Agent 工程师、大模型应用开发、RAG/Agent 平台开发、AI Infra 应用层岗位
风格:面试可讲,项目可用,代码能落地


目录

  1. 什么是 Agent?和普通 LLM Chatbot 有什么区别?
  2. Workflow 和 Agent 的边界是什么?
  3. ReAct 是什么?为什么它适合工具调用?
  4. ReAct 最大的问题是什么?
  5. Plan-and-Execute 是什么?比 ReAct 好在哪里?
  6. Plan-and-Execute 一定比 ReAct 更强吗?
  7. CodeAct 是什么?为什么软件工程 Agent 喜欢它?
  8. Agent 如何做 Task Decomposition?
  9. Agent Memory 到底解决什么问题?
  10. Agent 为什么必须有状态机和终止条件?

1. 什么是 Agent?和普通 LLM Chatbot 有什么区别?

一句话定义

Agent 不是“会聊天的大模型”。

Agent 更准确的定义是:

一个能基于目标,感知上下文,规划步骤,调用工具,根据反馈继续调整,并在满足终止条件后交付结果的系统。

普通 Chatbot 通常是:

用户输入 -> LLM 生成回答 -> 结束

Agent 更像是:

用户目标
-> 理解任务
-> 规划步骤
-> 选择工具
-> 执行动作
-> 观察结果
-> 更新状态
-> 继续执行或终止

普通 LLM 应用 vs Agent

维度 普通 LLM Chatbot Agent
核心能力 生成回答 完成任务
是否多步 通常单轮或短多轮 经常多步循环
是否调用工具 可选 通常是核心能力
是否维护状态 简单上下文 显式任务状态
是否有终止条件 通常没有复杂终止 必须设计终止条件
典型场景 FAQ、闲聊、文本生成 数据分析、代码修复、搜索调研、自动化流程

面试回答模板

可以这样答:

普通 Chatbot 更像一个文本生成接口,而 Agent 是围绕目标执行的任务系统。它不仅调用 LLM,还需要工具、状态、观察、计划、记忆和终止条件。工程上,Agent 的难点不是让模型说得像人,而是让它在多步任务里可控、可恢复、可观测,并且不会无限循环或乱调用工具。

这句话要背下来。
别再说“Agent 就是大模型加工具”。这个回答太低级。


最小 Agent Loop 伪代码

def agent_loop(user_goal, tools, max_steps=8):
    state = {
        "goal": user_goal,
        "steps": [],
        "observations": [],
        "final_answer": None
    }

    for step in range(max_steps):
        action = llm_decide_next_action(state, tools)

        if action["type"] == "final":
            state["final_answer"] = action["answer"]
            break

        if action["type"] == "tool_call":
            result = execute_tool(action["tool_name"], action["arguments"])
            state["observations"].append(result)
            state["steps"].append(action)

    return state["final_answer"]

这只是最小模型。真实生产系统还要加:

权限校验
参数校验
工具超时
失败重试
幂等控制
状态持久化
人工审批
trace 日志
终止条件

2. Workflow 和 Agent 的边界是什么?

核心区别

Workflow 是确定性流程。

Agent 是不确定性决策。

Workflow 更像:

A -> B -> C -> D

Agent 更像:

当前状态 -> 模型判断下一步 -> 执行 -> 根据结果继续判断

对比表

维度 Workflow Agent
路径 预先定义 运行时动态决定
控制权 工程师 LLM + Runtime
稳定性 较低,需要治理
可解释性 依赖 trace
适合场景 固定业务流程 开放任务、多步探索
风险 灵活性不足 不可控、循环、误调用

面试官最想听的一句话

能用 Workflow 解决的,不要强行 Agent 化;只有当任务路径不固定、需要动态决策、需要根据观察结果调整策略时,才值得引入 Agent。

材料里也提到,Workflow 和 Agent 的边界是核心面试点:简单工作流能解决时,不要过度 Agent 化;复杂任务则需要把 Agent 和工作流编排结合起来。


真实业务例子

适合 Workflow 的任务

用户提交报销单
-> OCR 识别发票
-> 校验金额
-> 匹配审批人
-> 发送审批
-> 归档

这个流程很固定,不需要 Agent 自由发挥。


适合 Agent 的任务

帮我分析这批用户投诉,找出主要原因,并给出整改建议。

这个任务路径不固定:

可能要读文件
可能要分类
可能要聚类
可能要查历史工单
可能要生成统计图
可能要调用数据库
可能要写报告

这时 Agent 才有意义。


工程上更成熟的设计

生产系统经常不是二选一,而是:

外层 Workflow 管可靠流程
内层 Agent 处理不确定步骤

例如:

Workflow:
  1. 接收任务
  2. 文件解析
  3. Agent 分析
  4. 人工确认
  5. 生成报告
  6. 归档

Agent:
  在第 3 步内部动态检索、调用工具、分析、反思

3. ReAct 是什么?为什么它适合工具调用?

ReAct 的核心

ReAct = Reasoning + Acting。

它的基本循环是:

Thought -> Action -> Observation -> Thought -> Action -> Observation ...

也就是:

想一下
-> 做一个动作
-> 看动作结果
-> 再决定下一步

材料中对 ReAct 的描述也是:每一步交替进行 Reasoning 和 Acting,并利用 Observation 继续推进任务。


ReAct 示例

用户问:

帮我查一下杭州明天是否下雨,如果下雨,提醒我带伞。

ReAct 过程可能是:

Thought: 我需要知道杭州明天的天气。
Action: call_weather_api(city="Hangzhou", date="tomorrow")
Observation: 明天杭州小雨,降水概率 70%。

Thought: 用户需要的是判断和提醒。
Final: 明天杭州大概率有小雨,建议带伞。

简化实现

def react_agent(query, tools):
    state = {
        "query": query,
        "history": []
    }

    while True:
        model_output = llm_generate_react_step(state, tools)

        if model_output["type"] == "final":
            return model_output["answer"]

        if model_output["type"] == "action":
            tool_result = execute_tool(
                model_output["tool_name"],
                model_output["arguments"]
            )

            state["history"].append({
                "thought": model_output.get("thought"),
                "action": model_output,
                "observation": tool_result
            })

为什么适合工具调用?

因为工具调用天然需要反馈:

模型不知道数据库结果
-> 调工具
-> 工具返回 Observation
-> 模型基于结果继续判断

ReAct 刚好提供了这个结构。


面试表达

可以这样说:

ReAct 适合需要边探索边决策的任务。它的优势是简单、灵活,能把工具返回结果纳入下一步推理。但它的问题是容易局部贪心、循环调用工具,且缺少全局计划,所以长任务里通常要结合 planner、状态机和终止条件。


4. ReAct 最大的问题是什么?

核心问题

ReAct 的最大问题不是“不够聪明”,而是:

局部贪心
容易循环
缺少全局计划
工具调用成本不可控
状态容易变脏

材料里也总结得很直接:ReAct 的痛点是局部贪心和循环。


典型失败案例

用户说:

帮我总结这个项目最近三个月的技术风险。

ReAct 可能这样跑:

Step 1: 搜索项目文档
Step 2: 看到一个日志错误,开始查日志
Step 3: 查到一个模块,继续查模块
Step 4: 发现另一个错误,继续查
Step 5: 跑偏,忘了用户要的是“三个月技术风险总结”

这就是局部贪心。

它每一步看起来都合理,但整体偏离目标。


防止 ReAct 失控的工程手段

1. 最大步数

MAX_STEPS = 8

但只靠 max_steps 很粗糙。


2. 工具调用预算

budget = {
    "search": 5,
    "database_query": 3,
    "write_file": 1
}

3. 重复动作检测

def is_repeated_action(action, history):
    recent_actions = history[-3:]
    return any(
        action["tool_name"] == old["tool_name"] and
        action["arguments"] == old["arguments"]
        for old in recent_actions
    )

4. 目标一致性检查

def check_goal_alignment(goal, current_step):
    prompt = f"""
    Goal: {goal}
    Current step: {current_step}

    Is the current step still directly useful for the goal?
    Answer only YES or NO.
    """
    return llm(prompt)

5. 显式终止条件

任务完成
信息不足
工具失败
预算耗尽
需要人工审批
风险过高

面试回答模板

ReAct 的问题是每一步基于当前 observation 做局部决策,缺少全局任务视角。它适合短链路、反馈驱动的任务,但长任务容易循环、跑偏或过度调用工具。工程上要用 max steps、预算、重复检测、状态管理、目标对齐检查和 planner 来约束。


5. Plan-and-Execute 是什么?比 ReAct 好在哪里?

核心思想

Plan-and-Execute 是:

先整体规划,再逐步执行

不是每一步都临时想,而是先得到一个全局路线。


基本结构

User Goal
-> Planner 生成计划
-> Executor 执行每一步
-> 每步记录状态
-> 必要时 Replan
-> Final Answer

示例

用户任务:

帮我分析一个 GitHub 项目的代码质量,并给出改进建议。

Plan 可能是:

1. 读取项目目录结构
2. 识别核心模块
3. 检查依赖和配置
4. 扫描常见代码坏味道
5. 运行测试
6. 汇总风险
7. 输出改进建议

Executor 再一步步做。


简化代码

def plan_and_execute(goal):
    plan = planner_llm(goal)

    state = {
        "goal": goal,
        "plan": plan,
        "completed_steps": [],
        "artifacts": {}
    }

    for step in plan["steps"]:
        result = execute_step(step, state)

        state["completed_steps"].append({
            "step": step,
            "result": result
        })

        if result.get("need_replan"):
            plan = replan_llm(state)

    return final_summarize(state)

相比 ReAct 的优势

维度 ReAct Plan-and-Execute
决策方式 每步临时判断 先有全局计划
适合任务 短任务、探索任务 长任务、阶段明确任务
风险 容易跑偏 计划可能过时
控制性 中等 更强
中间产物管理 更强

材料也明确指出:Plan-and-Execute 适合长链任务和阶段化管理。


面试回答模板

Plan-and-Execute 更适合长链任务,因为它先把目标拆成阶段,能更好管理中间产物、依赖关系和执行进度。相比 ReAct 的边走边看,Plan-and-Execute 有更强全局视角。但它不是万能的,因为计划可能随着新 observation 失效,所以通常需要动态 replan。


6. Plan-and-Execute 一定比 ReAct 更强吗?

不一定

这是一个很容易暴露水平的问题。

低水平回答:

Plan-and-Execute 更高级,所以更强。

错。

正确回答:

Plan-and-Execute 适合长任务,但会带来额外规划成本,并且计划可能过时。ReAct 适合短任务和强反馈任务。工程里通常混合使用。

材料中也总结:Plan-and-Execute 的痛点是计划失真和额外开销,工程里常见的是混合,而不是单选。


什么时候 ReAct 更合适?

任务短
反馈强
环境变化快
步骤不明确
试探成本低

例如:

查一个订单状态
根据搜索结果回答一个问题
查询天气
根据数据库结果补充解释

什么时候 Plan-and-Execute 更合适?

任务长
阶段清晰
中间产物多
需要全局路线
需要进度管理

例如:

写一份行业调研报告
修复一个代码仓库里的 bug
分析一批日志并定位根因
生成完整项目方案

混合模式

最常见的生产模式是:

先 Plan
每个 Step 内部用 ReAct
遇到复杂计算/代码任务用 CodeAct
高风险动作进入 Human-in-the-Loop

伪代码:

def hybrid_agent(goal):
    plan = create_plan(goal)

    for step in plan:
        if step["type"] == "simple_tool_task":
            result = react_execute(step)

        elif step["type"] == "code_task":
            result = codeact_execute(step)

        elif step["risk"] == "high":
            approval = request_human_approval(step)
            if not approval:
                return "Stopped by human approval gate"
            result = execute_step(step)

        if result.get("plan_invalid"):
            plan = replan(goal, current_state=result)

    return summarize_results()

7. CodeAct 是什么?为什么软件工程 Agent 喜欢它?

CodeAct 的核心

CodeAct 是把 Agent 的动作写成代码,而不是自然语言 tool call。

普通工具调用可能是:

{
  "tool_name": "read_file",
  "arguments": {
    "path": "app.py"
  }
}

CodeAct 更像:

content = read_file("app.py")
print(content[:1000])

为什么代码动作更强?

因为代码天然适合表达:

循环
条件判断
变量复用
文件处理
批量操作
复杂计算
异常捕获

自然语言动作表达复杂逻辑时很容易啰嗦、模糊、不稳定。

材料中也提到:CodeAct 的动作以代码表达,适合精确执行与软件/数据任务,但痛点是执行安全与运行环境治理。


示例:自然语言工具调用很笨

任务:

读取 logs 目录下所有 .log 文件,统计 ERROR 出现次数最多的前 5 个文件。

普通工具调用可能要多轮:

list_files
read_file
read_file
read_file
count
sort
...

CodeAct 一段代码就可以:

from pathlib import Path
from collections import Counter

counter = Counter()

for file in Path("logs").glob("*.log"):
    text = file.read_text(encoding="utf-8", errors="ignore")
    counter[file.name] = text.count("ERROR")

print(counter.most_common(5))

CodeAct 的风险

CodeAct 最大的问题不是能力,而是安全。

必须限制:

文件访问范围
网络访问权限
系统命令权限
执行时间
内存使用
敏感环境变量
危险 API

简化沙箱策略

SAFE_BUILTINS = {
    "len": len,
    "range": range,
    "print": print,
    "sum": sum,
    "min": min,
    "max": max,
}

def safe_exec(code: str, sandbox_globals=None):
    sandbox_globals = sandbox_globals or {}
    sandbox_globals["__builtins__"] = SAFE_BUILTINS

    exec(code, sandbox_globals)

这个只是演示。生产环境不能这么简单,真实要用容器、权限隔离、资源限制和审计日志。


面试回答模板

CodeAct 不是 ReAct 的替代,而是动作表达形式的增强。对于代码修改、数据处理、文件批量操作、复杂计算,代码比自然语言 tool call 更精确。但 CodeAct 一定要配沙箱、权限、超时、审计和回滚,否则风险非常大。


8. Agent 如何做 Task Decomposition?

不要把任务拆解理解成“让模型列步骤”

这是新手最大误区。

真正的 Task Decomposition 至少要拆出:

子任务
依赖关系
输入输出
工具需求
成功标准
风险等级
是否需要人工审批

材料也提醒,planning 不是一句“先让模型列个步骤”,而是结构化系统能力。


差的计划

1. 分析需求
2. 查资料
3. 写结果

废话,没有执行价值。


好的计划

{
  "goal": "分析近三个月用户投诉并输出整改建议",
  "steps": [
    {
      "id": "step_1",
      "name": "加载投诉数据",
      "tool": "query_database",
      "input": {
        "table": "complaints",
        "date_range": "last_3_months"
      },
      "output": "complaint_records",
      "success_criteria": "records_count > 0",
      "risk": "low"
    },
    {
      "id": "step_2",
      "name": "投诉主题聚类",
      "tool": "cluster_text",
      "input": {
        "source": "complaint_records"
      },
      "output": "topic_clusters",
      "success_criteria": "at least 3 clusters with examples",
      "risk": "medium"
    },
    {
      "id": "step_3",
      "name": "生成整改建议",
      "tool": "llm_generate",
      "input": {
        "source": "topic_clusters"
      },
      "output": "improvement_report",
      "success_criteria": "each suggestion maps to evidence",
      "risk": "medium"
    }
  ]
}

Planner 输出结构建议

from pydantic import BaseModel
from typing import List, Optional

class PlanStep(BaseModel):
    id: str
    name: str
    description: str
    tool: Optional[str]
    input_keys: List[str]
    output_key: str
    success_criteria: str
    risk_level: str

class Plan(BaseModel):
    goal: str
    steps: List[PlanStep]

面试回答模板

Task Decomposition 不是让模型随便列步骤,而是把目标拆成可执行、可验证、可恢复的子任务。每个子任务要有输入、输出、工具、依赖和成功标准。否则计划只是文本,看起来完整,实际上无法驱动系统执行。

这句话很关键。


9. Agent Memory 到底解决什么问题?

先说结论

Memory 不是把所有聊天记录永久塞回 prompt。

这是很多人最蠢的理解。

Agent Memory 解决的是:

跨轮次保留重要状态
减少重复询问
支持个性化
支持长期任务
保留任务进度
记录用户偏好
保存可复用经验

Memory 和 Context Window 的区别

概念 作用
Context Window 当前请求能看到什么
Memory 系统长期保存什么
State 当前任务执行到哪一步
Chat History 原始聊天记录
Summary 压缩后的历史摘要

不要混在一起讲。

材料后面关于 Session-State 和 Context 生命周期也强调:长会话关键不是全保留,而是分层保存、按需注入、持续压缩;可靠 Agent 恢复执行依赖的是结构化状态,不只是聊天记录。


Memory 类型

1. Short-term Memory

当前任务内的上下文,例如:

用户这次要分析哪个文件
已经调用过哪些工具
当前执行到第几步

2. Long-term Memory

跨会话信息,例如:

用户偏好 Markdown 输出
用户常用 Python
用户项目技术栈是 LangGraph + vLLM

3. Episodic Memory

历史经验,例如:

上次处理类似日志问题时,是 Redis 超时导致的

4. Semantic Memory

结构化知识,例如:

业务术语
组织架构
项目文档
API 说明

Memory 注入策略

错误做法:

prompt = all_chat_history + all_user_memory + current_query

这会让上下文越来越脏。

正确做法:

def build_context(query, task_state, memory_store):
    relevant_memories = memory_store.search(query, top_k=5)

    context = {
        "current_query": query,
        "task_state": task_state,
        "relevant_memories": relevant_memories
    }

    return context

面试回答模板

Memory 不是简单保存聊天记录,而是把对未来任务有价值的信息结构化保存,并在合适时机按需注入上下文。工程上要区分 session state、task state、user memory、chat history 和 external knowledge,否则 memory 会变成上下文污染源。


10. Agent 为什么必须有状态机和终止条件?

这是区分 Demo 和生产系统的核心

没有状态机的 Agent,通常是:

while True:
    action = llm(...)
    result = tool(action)

这就是玩具。

生产系统必须知道:

现在处于什么阶段
下一步允许做什么
什么时候暂停
什么时候恢复
什么时候人工审批
什么时候重试
什么时候终止

材料里也明确强调:Agent 一旦多步运行,就必须显式管理状态;终止条件应是多维的,不只是 max_steps;状态机是 HITL、重试、回滚、审批和幂等的共同基础。


一个简单状态机

CREATED
-> PLANNING
-> EXECUTING
-> WAITING_HUMAN_APPROVAL
-> COMPLETED

异常路径:
EXECUTING -> FAILED
EXECUTING -> NEED_RETRY
EXECUTING -> CANCELLED

Python 示例

from enum import Enum

class AgentStatus(str, Enum):
    CREATED = "created"
    PLANNING = "planning"
    EXECUTING = "executing"
    WAITING_APPROVAL = "waiting_approval"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"

class AgentState:
    def __init__(self, goal: str):
        self.goal = goal
        self.status = AgentStatus.CREATED
        self.current_step = None
        self.completed_steps = []
        self.error = None
        self.tool_calls = []
        self.budget_used = 0

状态转移控制

VALID_TRANSITIONS = {
    AgentStatus.CREATED: [AgentStatus.PLANNING],
    AgentStatus.PLANNING: [AgentStatus.EXECUTING, AgentStatus.FAILED],
    AgentStatus.EXECUTING: [
        AgentStatus.WAITING_APPROVAL,
        AgentStatus.COMPLETED,
        AgentStatus.FAILED,
        AgentStatus.CANCELLED
    ],
    AgentStatus.WAITING_APPROVAL: [
        AgentStatus.EXECUTING,
        AgentStatus.CANCELLED
    ]
}

def transition(state: AgentState, next_status: AgentStatus):
    allowed = VALID_TRANSITIONS.get(state.status, [])

    if next_status not in allowed:
        raise ValueError(
            f"Invalid transition: {state.status} -> {next_status}"
        )

    state.status = next_status

终止条件不能只有 max_steps

低级终止条件:

if step_count > 10:
    stop()

这只是保险丝,不是完整终止设计。


更完整的终止条件

1. 成功完成
2. 达到最大步数
3. 工具调用预算耗尽
4. 连续 N 次失败
5. 重复调用相同工具
6. 缺少必要信息
7. 需要人工审批
8. 检测到高风险动作
9. 用户取消任务
10. 当前目标无法完成

终止判断示例

def should_stop(state):
    if state.status in [
        AgentStatus.COMPLETED,
        AgentStatus.FAILED,
        AgentStatus.CANCELLED
    ]:
        return True

    if len(state.completed_steps) >= 10:
        return True

    if state.budget_used > 100:
        return True

    if has_repeated_tool_calls(state.tool_calls):
        return True

    if state.error and state.error.get("retry_count", 0) >= 3:
        return True

    return False

面试回答模板

Agent 必须有状态机和终止条件,因为多步执行不是一次模型调用,而是一个可中断、可恢复、可审批、可观测的流程。状态机解决当前任务处于什么阶段、允许什么转移;终止条件解决什么时候成功、失败、暂停或交给人工。没有这些,Agent 很容易死循环、重复调用工具、产生副作用或无法恢复。


第二期总结:Agent 核心范式的主线

这 10 题的底层主线是:

Agent 不是聊天机器人
-> Agent 是目标驱动的任务执行系统
-> Workflow 管确定流程
-> Agent 管不确定决策
-> ReAct 适合边想边做
-> Plan-and-Execute 适合长链任务
-> CodeAct 适合代码/数据/文件操作
-> Task Decomposition 要结构化
-> Memory 要按需注入
-> 状态机和终止条件保证可控

真正的工程认知是:

Agent 的难点不在于“让模型会调用工具”,而在于让整个多步执行过程可控、可恢复、可观测、可治理。


面试速记版

1. Agent = LLM + Goal + Tool + State + Observation + Control Loop。
2. Workflow 适合确定流程,Agent 适合不确定决策。
3. 能用 Workflow 解决的,不要强行 Agent 化。
4. ReAct = Thought + Action + Observation 循环。
5. ReAct 灵活,但容易局部贪心和死循环。
6. Plan-and-Execute 适合长链任务,但计划可能过时。
7. CodeAct 用代码表达动作,适合软件工程和数据处理。
8. Task Decomposition 要有输入、输出、依赖、工具和成功标准。
9. Memory 不是全量聊天记录,而是按需注入的长期状态。
10. 状态机和终止条件是 Agent 从 demo 走向生产的分水岭。

第三期建议题目:RAG / Memory / Agentic RAG 方向

下一批 内容(还是再次求求各位高抬贵手点个赞点个转发,评论区写一个字就更好了,爱你们,比心!):

1. RAG 是什么?为什么不是简单向量搜索?
2. Chunking 为什么是 RAG 的核心难点?
3. 固定 token 切分有什么问题?
4. Embedding 和 Rerank 分别解决什么问题?
5. Hybrid Retrieval 为什么常比纯向量检索稳?
6. Query Rewrite 在 RAG 里有什么用?
7. RAG 和 Memory 有什么区别?
8. 长期记忆如何设计?
9. Agentic RAG 和普通 RAG 有什么区别?
10. GraphRAG 适合什么场景?
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐