一、什么是 Agent
先说几个核心判断。Agent 通俗点说,就是一个能独立替你跑腿、干活的系统。

工作流(workflow)嘛,就是为达成某个用户目标而需要执行的一系列步骤。比如处理客服问题、预订餐厅、提交代码变更或者生成报告。这里需要划个重点:如果只是集成了大语言模型(LLM),但并不用它来控制工作流的执行,比如一个简单的聊天机器人、单轮LLM调用、或者情感分类器,这些都不算 Agent。
Agent 的核心特征其实就两条:
- 它用LLM来管理工作流的执行与决策——能识别工作流什么时候算完成,必要时还能主动纠错;要是搞不定了,会暂停下来,把控制权交还给用户。
- 它能访问各种工具——跟外部系统打交道,要么获取上下文信息,要么直接采取行动。具体用哪个工具,看当前状态动态选择,不过始终在明确的规则范围内运行。
二、何时该构建 Agent
常规的规则引擎,就像一张清单,按预设条件一个个打勾。而LLM Agent 更像一位资深的调查员,会评估上下文,能识别出规则没覆盖到的可疑模式。Agent 最适合那些传统确定性方案搞不定的场景。具体来说,可以考虑从下面这些曾经很难自动化的工作流入手:
- 复杂决策:需要细腻的判断、处理例外情况、或者对上下文很敏感的决策,比如客服退款审批。
- 难维护的规则:规则集太庞杂,更新成本高还容易出错,比如供应商安全审查。
- 重度依赖非结构化数据:需要解读自然语言、从文档里提取含义、或者进行对话式交互,比如家庭保险理赔处理。
不过,在动手构建之前,必须验证你的用例是否清晰满足上面这些条件。如果确定性方案就能搞定,那就别费劲上Agent了。
三、Agent 设计基础
一个 Agent 由三个核心组件构成:模型、工具、指令。
weather_agent = Agent(name="Weather agent",instructions="You are a helpful agent who can talk to users about the weather",tools=[get_weather],)
1. 选择模型
不同的LLM在任务复杂度、延迟、成本上各有取舍。一个有意思的做法是,工作流中不同的任务,可以选用不同的模型。比如,简单的检索或意图分类,用更小更快的模型就行;而像退款审批这种比较难的任务,就得用更强悍的模型。
推荐的做法是:
- 先用最强模型搭个原型,建好性能基线;
- 然后尝试换成小模型,看看性能是否还能达标。这样就能定位出小模型能做什么、不能做什么。
原则总结下来就是:
- 先建立评估体系(evals),设定性能基线;
- 用最强模型达到准确率目标;
- 在可行的地方,换用小模型来优化成本和延迟。
2. 定义工具
工具通过底层应用或系统的 API 来扩展Agent的能力。对于没有API的遗留系统,可以用计算机使用模型,像人一样直接操作UI。每个工具都应该有标准化的定义,方便工具和Agent之间灵活地多对多组合。文档完善、充分测试、可复用的工具,能大大提升可发现性、简化版本管理、避免重复定义。
工具大致可以分为三类:
| 类型 | 说明 | 示例 |
|---|---|---|
| Data(数据型) | 获取执行工作流所需的上下文与信息 | 查询交易数据库或CRM、读PDF、搜索网页 |
| Action(动作型) | 与系统交互执行动作,比如新增/更新记录、发消息 | 发邮件信息、更新CRM、把客服工单转人工 |
| Orchestration(编排型) | Agent本身作为其他Agent的工具(参考Manager模式) | 退款Agent、研究Agent、写作Agent |
from agents import Agent, WebSearchTool, function_tool
import datetime
@function_tool
def sa ve_results(output):
db.insert({
"output": output,
"timestamp": datetime.datetime.now(),
})
return "File sa ved"
search_agent = Agent(
name="Search agent",
instructions="Help the user search the internet and sa ve results if asked.",
tools=[WebSearchTool(), sa ve_results],
)
3. 配置指令
高质量的指令对Agent至关重要,能减少歧义、改善决策、让工作流跑得更顺畅。那么,好指令该怎么写?
- 复用现有文档:把操作流程、支持话术、政策文档转化为LLM友好的指令。在客服场景下,一个指令大致对应知识库里的一篇文章。
- 引导拆解任务:把密集的资源拆成更小更清晰的步骤,减少歧义。
- 明确动作:每一步都要对应具体的动作或输出,比如“让用户提供订单号”、“调用API取账户详情”。连用户可见消息的措辞都要明确,减少解释偏差。
- 覆盖边缘情况:预判常见的变体,比如信息不全、用户有意外提问,用条件步骤或分支来处理。
更高效的方法是,可以用 o1/o3-mini 这类模型,自动从现有文档生成指令:
You are an expert in writing instructions for an LLM agent.
Convert the following help center document into a clear set of instructions,
written in a numbered list.
The document will be a policy followed by an LLM.
Ensure that there is no ambiguity, and that the instructions are written as directions for an agent.
The help center document to convert is the following {{help_center_doc}}
四、编排(Orchestration)
一个常见的误区是,上来就想建一个完全自主的复杂架构。实际上,客户通常用增量方式更容易成功。编排主要分两类:单Agent系统、多Agent系统。
1. 单 Agent 系统
单个Agent通过逐步增加工具,就能承担很多任务。这种方式的复杂度可控,评估和维护也更简单。每加一个新工具,能力就扩展一点,没必要过早引入多Agent。
任何编排都需要一个「run」的概念——通常是一个循环,让Agent运行,直到满足退出条件。这些条件包括:触发了工具调用、产生了特定结构化输出、遇到了错误、或者达到了最大轮数。
在 Agents SDK 里,Agent通过 Runner.run 启动,循环直到:
- 调用了定义了特定输出类型的 final-output 工具;
- 模型返回了一个不带工具调用的响应,比如直接回复用户。
Agents.run(agent, [UserMessage("What's the capital of the USA")])
这个while循环是Agent运行的核心。在多Agent系统中,也允许模型跑多步,直到满足退出条件。
一个管理复杂度的有效策略是使用提示词模板。用一个灵活的基础提示词,接受策略变量,而不是为每个场景维护多个提示词。新场景来了,只更新变量,不用重写整个工作流。
"""
You are a call center agent. You are interacting with
{{user_first_name}} who has been a member for {{user_tenure}}. The user's
most common complains are about {{user_complaint_categories}}. Greet the
user, thank them for being a loyal customer, and answer any questions the
user may ha ve!
那么,什么时候要考虑拆分成多Agent?核心原则是:先最大化单Agent的能力。多Agent能直观地分隔概念,但也带来了额外的复杂度和开销。很多时候,单Agent加工具就足够了。只有当Agent跟不上复杂指令,或者持续选错工具时,才考虑拆分。
具体的拆分指引:
- 复杂逻辑:提示词里包含了大量的条件分支(if-then-else),模板很难扩展时,按逻辑段拆分。
- 工具过载:问题不在于工具的数量,而在于工具之间过于相似或重叠。有的人能管理15+个清晰独立的工具,有的人不到10个重叠的工具就搞不定了。如果改进命名、参数、描述还是不行,就试试多Agent。
2. 多 Agent 系统
常见的模式有两种:
- Manager(Agent作为工具):一个中心的「manager」Agent通过工具调用,协调多个专门的Agent,每个Agent处理特定的任务或领域。
- Decentralized(Agent间handoff):多个Agent对等协作,按各自的专长把任务转交给彼此。
可以把多Agent系统建模成一张图。在Manager模式中,边是工具调用;在Decentralized模式中,边是handoff(转交执行权)。无论哪种模式,都应该保持组件灵活、可组合、由清晰的结构化提示词驱动。
Manager 模式
中心的LLM(manager)通过工具调用,编排一个专门的Agent网络。它按需委派任务,并综合结果,提供统一的用户体验。这种方式适合需要一个Agent来控制工作流执行,并面向用户的场景。
from agents import Agent, Runner
manager_agent = Agent(
name="manager_agent",
instructions=(
"You are a translation agent. You use tools given to you to translate. "
"If asked for multiple translations, you call the relevant tools."
),
tools=[
spanish_agent.as_tool(
tool_name="translate_to_spanish",
tool_description="Translate the user's message to Spanish",
),
french_agent.as_tool(
tool_name="translate_to_french",
tool_description="Translate the user's message to French",
),
italian_agent.as_tool(
tool_name="translate_to_italian",
tool_description="Translate the user's message to Italian",
),
],
)
async def main():
msg = input("Translate 'hello' to Spanish, French and Italian for me!")
orchestrator_output = await Runner.run(manager_agent, msg)
for message in orchestrator_output.new_messages:
print(f"- Translation step: {message.content}")
这里顺便提一下声明式图和非声明式图的区别。声明式框架要求预先显式定义每个分支、循环、条件。可视化清晰,但随着工作流变复杂,会变得很繁琐,还需要学专门的DSL(领域特定语言)。Agents SDK采用代码优先的方式,直接用熟悉的编程结构(比如if、for循环)来表达工作流逻辑,不需要预定义整张图,更动态、更灵活。
Decentralized 模式
在这种模式里,Agent之间可以互相handoff执行权。Handoff是单向的转交,调用handoff函数后,会立即在目标Agent上开始执行,并传递最新的会话状态。这种方式适合不需要单一Agent维持中央控制或综合的场景。每个Agent接管执行,并按需与用户交互。
from agents import Agent, Runner
technical_support_agent = Agent(
name="Technical Support Agent",
instructions=(
"You provide expert assistance with resolving technical issues, "
"system outages, or product troubleshooting."
),
tools=[search_knowledge_base],
)
sales_assistant_agent = Agent(
name="Sales Assistant Agent",
instructions=(
"You help enterprise clients browse the product catalog, "
"recommend suitable solutions, and facilitate purchase transactions."
),
tools=[initiate_purchase_order],
)
order_management_agent = Agent(
name="Order Management Agent",
instructions=(
"You assist clients with inquiries regarding order tracking, "
"delivery schedules, and processing returns or refunds."
),
tools=[track_order_status, initiate_refund_process],
)
triage_agent = Agent(
name="Triage Agent",
instructions=(
"You act as the first point of contact, assessing customer queries "
"and directing them promptly to the correct specialized agent."
),
handoffs=[
technical_support_agent,
sales_assistant_agent,
order_management_agent,
],
)
result = await Runner.run(
triage_agent,
input("Could you please provide an update on the delivery timeline for our recent purchase?")
)
在这个例子里,初始消息发给 triage_agent。它识别到问题跟近期采购相关后,就把控制权 handoff 给了 order_management_agent。这个模式特别适合会话分流,或者希望专门Agent完全接管某些任务,而原Agent不再需要继续参与的场景。当然,也可以给第二个Agent配置handoff回原Agent,必要时再转交回来。
五、护栏(Guardrails)
设计良好的护栏,能帮助管理数据隐私风险(比如防止系统提示泄露)或声誉风险(比如强制品牌一致的行为)。做法是:先针对已经识别出的风险建护栏,发现新漏洞再加一层。护栏是任何LLM部署的关键组件,但需要跟强认证授权、严格访问控制、标准软件安全措施配合使用。
记住,护栏是分层防御。单个护栏通常不足以提供充分的保护,多个专门的护栏组合起来,才能更坚韧。
1. 护栏类型
- 相关性分类(Relevance classifier):标记越界查询,确保响应在预期范围内。比如问「帝国大厦多高」就属于越界。
- 安全分类(Safety classifier):检测越狱或提示注入等不安全输入。比如试图套出系统指令的消息,会被标记为不安全。
- PII 过滤:审查模型输出,避免不必要地暴露个人身份信息。
- 内容审核(Moderation):标记仇恨、骚扰、暴力等有害或不当的输入。
- 工具风险分级(Tool safeguards):按只读/写、可逆性、所需权限、财务影响,给每个工具评低、中、高风险。据此触发自动动作——比如高风险函数执行前,暂停做护栏检查,或者升级到人工处理。
- 规则防护(Rules-based):黑名单、输入长度限制、正则过滤等确定性措施,用来防御已知威胁,比如禁用词或SQL注入。
- 输出校验(Output validation):通过提示工程与内容检查,确保响应符合品牌价值观,防止损害品牌。
2. 构建护栏
几条有效的经验法则:
- 聚焦数据隐私与内容安全;
- 根据真实遇到的边缘情况和失败案例,来新增护栏;
- 兼顾安全与用户体验,并随着Agent的演进,不断调整护栏。
from agents import (
Agent, GuardrailFunctionOutput, InputGuardrailTripwireTriggered,
RunContextWrapper, Runner, TResponseInputItem, input_guardrail,
Guardrail, GuardrailTripwireTriggered,
)
from pydantic import BaseModel
class ChurnDetectionOutput(BaseModel):
is_churn_risk: bool
reasoning: str
churn_detection_agent = Agent(
name="Churn Detection Agent",
instructions="Identify if the user message indicates a potential customer churn risk.",
output_type=ChurnDetectionOutput,
)
@input_guardrail
async def churn_detection_tripwire(
ctx: RunContextWrapper[None],
agent: Agent,
input: str | list[TResponseInputItem],
) -> GuardrailFunctionOutput:
result = await Runner.run(churn_detection_agent, input, context=ctx.context)
return GuardrailFunctionOutput(
output_info=result.final_output,
tripwire_triggered=result.final_output.is_churn_risk,
)
customer_support_agent = Agent(
name="Customer Support Agent",
instructions="You are a customer support agent. You help customers with their questions.",
input_guardrails=[Guardrail(guardrail_function=churn_detection_tripwire)],
)
async def main():
await Runner.run(customer_support_agent, "Hello!")
print("Hello message passed")
try:
await Runner.run(customer_support_agent, "I think I might cancel my subscription")
print("Guardrail didn't trip - this is unexpected")
except GuardrailTripwireTriggered:
print("Churn detection guardrail tripped")
Agents SDK把护栏作为一等概念。它默认乐观执行:主Agent主动产出,护栏并发运行,一旦违规就抛出异常。护栏可以是函数,也可以是Agent,用于强制防越狱、相关性校验、关键词过滤、黑名单、安全分类等策略。
3. 人工干预
人工干预是关键保障,尤其在部署早期。它能帮助识别失败、发现边缘案例、建立稳健的评估周期。当Agent无法完成任务时,它能优雅地转交控制权——客服场景升级给人工,编码场景交回用户。
常见的触发场景有两类:
- 超失败阈值:限制Agent的重试或动作次数。一旦超限(比如多次未能理解用户意图),就升级人工。
- 高风险动作:敏感、不可逆或高 stakes 的动作,在Agent的可靠性建立之前,应该触发人工监督。比如取消用户订单、授权大额退款、付款等。
六、结论
Agent的出现,标志着工作流自动化进入了一个新时代。系统能在歧义中推理、跨工具行动、以高度自主性处理多步任务。它特别适合复杂决策、非结构化数据或脆弱的规则系统。
构建可靠Agent的几个要点:
- 打好基础——强模型 + 定义良好的工具 + 清晰的结构化指令;
- 编排匹配复杂度——从单Agent起步,只在需要时才演进到多Agent;
- 全程护栏——从输入过滤、工具使用到人工干预,确保安全可预测。
最后,部署路径不是全有或全无的选择。从小处起步、用真实用户验证、逐步扩展能力,这才是更稳妥的方式。
