07. Agent
1. 如何定义 LLM Agent?
30 秒回答
LLM Agent 是以语言模型为策略或推理核心,能够维护状态、制定计划、调用工具、观察环境反馈并循环行动,直到完成目标或触发终止条件的系统。
区别于普通聊天模型的关键不是“会调用一次 API”,而是形成闭环:
\[ \text{Observation} \rightarrow \text{Reason/Plan} \rightarrow \text{Action} \rightarrow \text{Environment Feedback} \rightarrow \text{State Update} \]
核心组件
- Model/Policy:理解任务、推理、选择动作。
- Planning:任务分解、顺序安排、重规划。
- Memory/State:保存对话、工作区、历史行动和长期知识。
- Tools:搜索、代码执行、数据库、浏览器、业务 API。
- Environment:工具返回结果或可交互世界。
- Controller/Orchestrator:执行循环、超时、重试、并发和终止。
- Guardrails:权限、确认、沙箱、策略检查和审计。
- Evaluator:判断完成度、错误和成本。
1.1 Agent Harness 是什么?
30 秒回答
Agent harness 是包在 LLM 外面的执行系统。模型只负责“想”和“选动作”,harness 负责把任务真正跑起来:
- 给模型准备 prompt、工具说明和上下文。
- 维护状态、文件、记忆和中间产物。
- 执行工具调用、命令、浏览器或 API。
- 管理权限、沙箱、超时、重试和预算。
- 记录 trace,方便复盘和评估。
- 判断任务是否完成,必要时让模型继续、回退或请求人工确认。
一句话:
LLM 是大脑,harness 是操作系统 + 工作流控制器 + 安全壳。
为什么 Harness 很重要?
同一个模型,换不同 harness,效果可能差很多。原因是 agent 的表现不只取决于模型能力,还取决于:
- 工具接口是否好用。
- 文件编辑和命令执行是否可靠。
- 观察结果是否清晰。
- 错误是否能恢复。
- 是否能安全地限制危险动作。
- 是否能保存和重放完整轨迹。
比如 coding agent 不是只把 repo 塞给 LLM。好的 harness 会提供:
- 搜索、读文件、编辑、运行测试的工具。
- 隔离环境或 sandbox。
- diff 和测试结果反馈。
- 失败重试和回滚。
- 最终 patch 验证。
SWE-agent 的核心观点之一就是 Agent-Computer Interface 设计会显著影响软件工程任务表现;OpenHands 这类平台也强调 sandbox、runtime、工具、评估和人机交互,而不只是换一个更强模型。
Harness 和 Agent Framework 的区别
- Framework:开发框架,例如 LangGraph、OpenHands、AutoGen、LlamaIndex。
- Harness:你为某个任务实际搭出来的执行壳,包括 prompt、工具、状态机、权限、评估和恢复策略。
可以用框架搭 harness,但二者不是一回事。
面试怎么说?
我理解 agent harness 是模型外面的运行时系统,负责工具调用、状态管理、安全权限、沙箱、trace、重试和评估。现在很多 Agent 的差距不只是模型差距,而是 harness 差距。尤其是 coding、browser、computer-use 任务,工具接口和执行环境设计会直接影响成功率。
1.2 最近常见的 Agent Loop 设计
基础 Agent Loop
最基础的 loop 是:
\[ \text{Observe} \rightarrow \text{Think/Plan} \rightarrow \text{Act} \rightarrow \text{Observe} \rightarrow \cdots \]
每一轮模型读取当前状态,决定下一步工具调用,然后根据 observation 继续。ReAct 就是这个范式的代表。
现在为什么不只讲简单 Loop?
简单 loop 好用,但有几个问题:
- 上下文越来越长,历史越来越乱。
- 依赖关系隐含在对话里,难 debug。
- 出错后容易无限重试。
- 很难判断哪些中间产物应该保留、哪些应该重算。
- 多工具、多子任务时,单 loop 容易变成黑盒。
所以近期更常见的方向是:从隐式 loop 走向显式 state machine / graph / harness。
常见 Loop 形态
1. ReAct Loop
Thought -> Action -> Observation -> Thought -> ...
适合短任务、工具调用和快速探索。缺点是容易循环、上下文变长、状态不够结构化。
2. Plan-Execute-Verify Loop
Plan -> Execute step -> Verify -> Replan or Finish
适合 coding、RAG、多步骤业务流程。关键是每步要有 verifier,例如测试、schema check、retrieval score、规则检查。
3. Reflection / Repair Loop
Run -> Fail -> Diagnose -> Patch -> Retry
适合代码修复、数据处理、网页操作。注意:reflection 只有在有真实失败信号时才有价值;没有测试或环境反馈时,反思可能只是自我合理化。
4. Supervisor + Worker Loop
Supervisor splits task -> Workers execute -> Supervisor merges/verifies
适合任务可拆分、可并行的场景。风险是通信成本、重复劳动和 supervisor 瓶颈。
5. Graph / State-Machine Loop
把流程写成显式节点:
Retrieve -> Draft -> Check -> Revise -> Final
每个节点有明确输入、输出、失败处理和终止条件。LangGraph 这类工具适合这种模式。相比自由 loop,它更容易测试、重放和上线。
近期趋势
- Harness engineering:优化模型外部的工具、状态、权限、sandbox 和评估。
- Explicit graph over implicit chat history:把控制流从对话上下文里拿出来,写成显式图或状态机。
- Verifier-driven loop:用测试、执行结果、规则、judge 或环境状态决定是否继续。
- Human-in-the-loop:高风险动作前暂停确认。
- Parallel sub-agents:并行探索候选方案,但必须有去重、合并和最终验证。
- Long-running/background agents:支持任务挂起、恢复、定期执行和持久化状态,但更需要权限边界和审计。
面试怎么说?
早期 Agent 常被描述成一个 ReAct loop:观察、思考、行动、再观察。最近更工程化的做法是把 loop 放进 harness 里,显式管理状态、工具、权限、验证和恢复。对生产系统来说,关键不是让模型无限循环,而是限制循环、有 verifier、有终止条件,并把流程做成可重放、可调试的 graph 或 state machine。
2. ReAct 框架
ReAct 将 reasoning trace 和 action 交错:
- Thought:基于当前观察分析下一步。
- Action:按工具协议执行动作。
- Observation:环境返回结果。
- 重复直到给出 Final Answer。
为什么有效?
- 纯 CoT 只能基于模型内部知识,容易幻觉。
- 纯 action policy 缺少显式任务分解和上下文整合。
- ReAct 让推理决定何时查证,观察又能纠正后续推理。
失败模式
- 无限循环或重复搜索。
- 因早期错误观察形成错误计划。
- 把工具输出中的恶意文本当作指令,即 prompt injection。
- Thought 很长但没有提高决策质量。
- 工具参数格式错误或调用不存在的工具。
工程改进
- 限制最大步骤、时间和预算。
- 用结构化 action schema,不解析自由文本。
- 对观察做 provenance 标记和不可信内容隔离。
- 保存状态机和 error taxonomy,针对可恢复错误重试。
- 使用 verifier 判断完成,而不是让同一模型仅凭自信终止。
3. 如何赋予 Agent 规划能力?
Chain-of-Thought(CoT)
线性分解和推理。成本低,但错误会沿单路径传播。
Plan-and-Execute
先生成高层计划,再逐步执行;执行中可重规划。适合长任务,但计划可能过早固定,环境变化时需显式修订。
Tree of Thoughts(ToT)
在每一步生成多个候选 thought,评估并搜索,如 BFS/DFS/beam search。提高探索能力,但调用成本高,评估器质量决定结果。
Graph of Thoughts(GoT)
允许 thought 间合并、回边和复用,比树更适合多来源综合、迭代修订,但控制和去重更复杂。
Self-Consistency
采样多条推理链,通过多数投票或 verifier 选择。适合有确定答案的任务,成本随采样数增加。
Reflection / Reflexion
执行失败后总结原因,把反思写入短期或长期记忆,再重试。有效前提是有可靠失败信号;否则可能只是产生合理化解释。
Search / Classical Planner
让 LLM 生成动作或启发函数,使用 A*、MCTS、约束求解器或 PDDL planner 搜索。在动作空间明确、可模拟时比自由 CoT 更可控。
选型原则
- 短、低风险任务:ReAct/CoT。
- 长任务:plan-and-execute + checkpoint。
- 可验证且分支有限:ToT、beam、MCTS。
- 强约束调度:经典 planner/solver。
- 高成本工具:先规划并估算预算,再执行。
4. 短期记忆和长期记忆
短期记忆
保存当前任务所需的工作状态:
- 对话上下文。
- 当前计划、已完成步骤、工具输出。
- Scratchpad、代码 diff、临时变量。
实现可以是 context window、结构化 state object、数据库中的任务 checkpoint。长对话要做摘要,但摘要会丢信息,因此关键事实应结构化保存而不是只做自然语言压缩。
长期记忆
- Semantic memory:事实、偏好、领域知识,常用向量库/搜索索引。
- Episodic memory:过去任务、行动和结果。
- Procedural memory:成功工作流、工具使用规则和技能。
写入策略比存储介质更重要
需要回答:
- 什么信息值得写?
- 如何去重、更新和遗忘?
- 谁能读取,权限和隐私如何控制?
- 何时召回,如何避免无关记忆污染当前决策?
可用 salience、novelty、用户明确确认、任务结果和时间衰减决定写入。召回时结合语义相似度、时间、实体和任务过滤。
常见外部技术
PostgreSQL/Redis 保存结构化状态;向量数据库做语义召回;知识图谱保存实体关系;对象存储保存大文件;事件日志支持审计和重放。
5. LLM 如何学会 Tool Use / Function Calling?
数据格式
模型看到:
- 工具名称和自然语言描述。
- 参数 JSON Schema。
- 用户请求。
- 正确的 tool call。
- 工具结果。
- 基于结果生成的最终回答。
通过 SFT 学习“何时调用、选哪个工具、参数如何填”。还可用执行成功率或结果正确性做 RL。
推理流程
- 应用把工具 schema 放入模型上下文。
- 模型输出结构化工具调用,而不是直接执行。
- Orchestrator 校验权限和参数。
- 外部系统执行并返回 observation。
- 模型读取结果,继续调用或回答。
关键风险
- Schema 合法不等于语义正确。
- 工具描述过长或相似会导致选择混淆。
- 外部内容可能包含 prompt injection。
- 写操作、支付、发送消息需要用户确认、幂等键和最小权限。
- 模型不能自行决定自己是否有权限。
评价指标
Tool selection accuracy、参数正确率、执行成功率、任务成功率、无效调用数、重试次数、延迟、成本,以及未授权操作率。
6. LangChain 与 LlamaIndex
LangChain / LangGraph
重点是 LLM 应用编排:模型、工具、prompt、状态、Agent loop。LangGraph 更适合显式状态图、分支、循环、持久化和 human-in-the-loop。
LlamaIndex
起点更偏数据和知识:数据连接器、文档解析、索引、retriever、query engine、RAG workflow。也提供 Agent 能力,但核心优势常在 knowledge-centric 应用。
如何选?
- 复杂有状态工作流、多工具编排:LangGraph。
- 文档/RAG、数据连接和索引实验:LlamaIndex。
- 简单生产服务:直接使用模型 SDK + 自己的状态机可能更透明。
面试中最好说明:框架不是能力来源。关键是可观测性、可测试性、状态持久化、错误恢复、供应商锁定和团队维护成本。