系统提示 vs 代理技能
本文在系统提示词和代理技能之间划清了界限。理解这种区别是你在代理架构中能做出的最高杠杆决策之一。
微信 ezpoda免费咨询:AI编程 | AI模型微调| AI私有化部署
AI模型价格对比 | AI工具导航 | ONNX模型库 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo
当开发者第一次构建 AI 代理时,他们倾向于将系统提示词当作设置文件。把所有东西都塞进去,期望模型自己搞清楚。代理的身份、能力、动态用户数据、工具指令、行为规则,全部塞进一大段文本中。
它有效,直到失效。然后调试开始了。为什么代理使用了过时的数据?为什么它忽略了工具?为什么它在应该查找的事实时产生幻觉?为什么随着上下文增长性能下降?
几乎总是同样的答案。错误的东西放在了错误的位置。
本文在系统提示词和代理技能之间划清了界限。理解这种区别是你在代理架构中能做出的最高杠杆决策之一。大多数开发者做错了,不是因为这很难,而是因为没有人告诉他们这很重要。
1、心智模型
系统提示词是代理的宪法。它定义了代理是谁以及它如何推理。代理技能是代理的双手。它们定义了代理能伸手做什么。
这就是全部。其他一切都由此衍生。
系统提示词在每次请求时都加载,始终如此。它是稳定的。它很少变化。它塑造思维。代理技能按需加载,当相关时才加载。它们不断变化。它们塑造行动。
如果你内化了这一点,剩下的只是应用。
2、什么属于系统提示词
身份和角色。系统提示词是你回答这个代理是谁这个问题的地方。不是能力的罗列——那是另一个错误——而是一个清晰的角色声明,为所有后续行为定调。
You are a customer support specialist trained in Acme Corp's support protocols.
Your job is to help customers resolve issues empathetically and efficiently,
escalating to human agents when situations require it.
这种身份不是装饰性的。它影响代理尝试任务的意愿、默认语气以及它如何解决模糊情况。一个"支持专家"会在行动前提出澄清问题。一个"脚本执行器"只会直接运行命令。同样的底层模型,不同的行为,因为身份以几乎令人惊讶的方式塑造推理,直到你接受这完全说得通。
行为约束和护栏。系统提示词编码的是策略,而非流程。策略说的是应该发生什么。流程说的是如何让它发生。这些是根本不同的事情,它们属于不同的地方。
<constraints>
Verify customer identity before accessing account details.
Escalate frustrated customers to human agents immediately.
Never promise refunds you cannot guarantee via tool.
Handle billing, account, and product issues only.
</constraints>
这里有一点值得明确说明。安全关键的护栏,比如"不要查询个人信息列"之类的东西,不应仅存在于提示词窗口中。它们应该存在于身份和访问管理策略以及工具级别的强制执行中。系统提示词陈述策略。工具执行它。不要依赖文本指令来保护生产环境中真正重要的安全属性。提示词可以被覆盖、越狱,或者简单地被误解。工具边界不能。
推理风格和任务流程。这通常是任何系统提示词中最重要的部分。不是代理知道什么,而是它如何思考问题。
<task_flow>
1. Classify the customer issue type and sentiment
2. Retrieve account information if the request requires it
3. Identify the resolution path
4. If sentiment is negative, escalate before attempting resolution
5. After resolution, offer a satisfaction survey
</task_flow>
这是高层工作流逻辑。推理步骤的顺序,不是任何单个步骤的实现细节。"检索账户信息"的实现存在于工具描述中,不在这里。这个区别比听起来更重要。
适用于每个请求的稳定上下文。有些信息无论用户问什么都始终相关。领域术语、组织惯例、输出格式要求。如果在特定代码库中工作的代理总是需要知道你的命名约定,那属于系统提示词。如果代理总是需要以特定结构化格式响应,就在那里编码。
实际测试很简单。如果信息在每一次对话中都有用,它属于系统提示词。如果它的相关性取决于用户碰巧问的是什么,它不属于。
这里还有一个真实的成本考量。从不变化的系统提示词内容应该位于提示词的顶部。缓存的 token 处理成本大约比未缓存的便宜 75%。将稳定内容移动到可缓存位置可以显著降低大规模运行代理的每次请求成本。
3、什么属于代理技能
有副作用的操作。每当代理伸手改变世界中的某些东西——调用 API、写入数据库、发送消息、执行代码——那就是一个技能。这种分离很重要,因为系统提示词告诉代理何时采取行动。技能处理如何做。
@tool
def create_support_ticket(
customer_id: str,
issue_type: Literal["billing", "technical", "account", "general"],
urgency: Literal["low", "medium", "high"]
) -> dict:
"""
Creates a new support ticket for a customer.
Returns a dict with ticket_id, status ("created" or "failed"),
and queue_position.
This tool does NOT notify the customer. Use send_customer_email()
separately for that.
"""
动态上下文检索。这是大多数团队首先出错的地方。他们将实时数据直接嵌入系统提示词中。用户的账户状态。当前库存。今天的定价。今天的策略。这些会变化。如果它们在系统提示词中,它们会变得过时。它们还会用对大多数请求无关的数据膨胀缓存上下文。
正确的模式是即时检索。代理根据特定请求,在需要的时候准确地获取所需内容,而不是在系统提示词初始化时。
@tool
def get_customer_account(identifier: str) -> dict:
"""
Retrieves customer account information by email, phone, or account ID.
Returns name, email, account_status, plan_tier, and created_date.
Does NOT return billing history. Use get_billing_history() for that.
"""
这保持了系统提示词的干净和检索数据的时效性。在各个维度上这都是更好的设计。
只在某些时候适用的可选能力。如果一项能力只与某些请求相关,它就是一个技能。将其嵌入系统提示词会迫使代理在每次请求时都思考它,即使是不相关的。一个研究代理可能有网页搜索、PDF 提取、引用追踪和数据可视化的技能。不是每个查询都需要全部四个。将它们定义为技能让代理选择相关的,保持系统提示词专注于如何编排它们而不是它们内部做什么。
流程细节和工具特定指令。系统提示词建立策略。工具描述编码流程。混淆这些是最常见也最损害性的错误之一。
以下是错误版本,流程细节最终出现在系统提示词中:
"使用 search_database 工具时,你必须首先检查用户是否有权限访问那些列。将日期格式化为 ISO 8601 字符串。该工具返回结果数组或 null 如果未找到。"
以下是正确版本,它存在于工具描述中它应该属于的地方:
@tool
def search_database(
table: str,
filters: dict,
date_range: Optional[str] = None
) -> List[dict] | None:
"""
Searches the customer database. Access control is enforced automatically.
date_range accepts ISO 8601 interval format. Example: "2024-01-01/2024-12-31"
Returns a list of matching records, or null if no results found.
Never returns records the authenticated user lacks permission to see.
Use search_database_advanced() for fuzzy matching or complex joins.
"""
Anthropic 在他们的工程文档中说得好。你应该在工具配置——名称、描述和 schema——上投入与编写提示词一样多的精力。把 LLM 想象成你团队中的一名开发者。你对工具的文档写得越好,它就越容易被正确使用。
工具描述不仅仅是文档。它们被加载到代理的上下文中并积极塑造其行为。模糊的描述会导致不正确的工具使用、错误的参数格式和混乱的回退行为。如果你想要可靠的代理,仔细编写它们不是可选的。
3、两种出错的方式
所有东西都在系统提示词中。工具文档。动态用户数据。每种可能场景的指令。边缘情况。例外的例外。这造成了注意力稀释。随着上下文增长,准确性下降。代理开始忽略早期指令,因为有太多内容在争夺它的注意力。调试变得几乎不可能,因为你无法隔离什么改变了。添加一个新能力意味着编辑一大段文档并希望你没有破坏任何东西。
Anthropic 自己的指导很明确,正确的起点是一个最小化的系统提示词,用你最好的模型测试,然后基于观察到的失败模式逐步添加指令。大多数开发者做了相反的事。他们先写了长提示词,然后花几个月想知道为什么代理不可靠。
模糊的工具加上稀疏的提示词。代理有工具但不知道如何正确使用它们,何时应该优先选择一个而不是另一个,或者如何解释它们返回的内容。这导致不正确的工具使用、幻觉参数、错误工具选择和脆弱的输出解析。修复几乎从来不是更多的系统提示词。而是更好的工具描述。
工具 schema 优化对代理性能有超大的影响,通常比你能添加到系统提示词中的任何东西都大。这违反直觉,这可能就是它被忽视的原因。
3、一个完整的例子
以下是一个架构良好的客户支持代理如何分离这些关注点的:
系统提示词:
<identity>
You are a customer support specialist for Acme Corp. Your role is to resolve
customer issues empathetically, efficiently, and within company policy.
</identity>
<constraints>
Verify identity before accessing account details.
Escalate frustrated customers to human agents immediately.
Never promise refunds you cannot guarantee via tool.
Handle billing, account, and product issues only.
</constraints>
<task_flow>
1. Classify the customer issue type and sentiment
2. Retrieve account information if relevant
3. Identify the resolution path
4. If sentiment is negative, escalate before resolving
5. After resolution, offer a satisfaction survey
</task_flow>
技能:
classify_message(text) returns issue type, sentiment, urgency
get_customer_account(identifier) returns name, plan, status
create_support_ticket(...) returns ticket id
process_refund(...) returns status, confirmation id
escalate_to_human(...) returns queue id, eta in minutes
send_survey(...) returns sent confirmation
系统提示词说明何时升级。工具处理升级实际如何工作。系统提示词说"如果相关"就检索账户信息。工具精确地定义了检索意味着什么以及它返回什么。这些是真正的独立关注点,保持它们分离使整个系统更容易推理、更容易测试、在出问题时更容易修复。
4、为什么这种分离不仅仅是整洁
这里有一个真正的经济论点。技能按需加载。系统提示词被缓存。将稳定内容保留在系统提示词中,动态内容保留在工具中,可以最小化每次请求成本同时最大化缓存利用率。一旦你冻结了提示词,工具 schema 大约可以占请求总成本的 50%。把这个架构搞对既是财务决策也是工程决策。
还有一个安全论点。系统提示词包含来自你的可信指令。工具输出包含来自外部 API、用户输入和网页结果的潜在不可信数据。将它们保持在不同的位置使提示词注入更难利用。通过工具输出到达的注入内容明显是工具输出,不是系统指令。边界本身就提供了一些保护。
还有可维护性的论点,这通常是最终让开发者陷入困境的那个。添加新工具不需要编辑系统提示词。更新工具描述不需要重新测试代理的核心行为。每个关注点都有清晰归属的系统在调试时明显更容易。当东西坏了,你真的能弄清楚为什么。
可组合性的观点也被低估了。同一个系统提示词可以与许多不同的工具集配合使用。同一个工具可以被具有不同系统提示词的多个代理使用。如果你从一开始就构建了这种模块化,它基本上是免费的,但一旦你有了一个单体结构,基本上就不可能再改造了。
5、决策
当你不确定某样东西应该放在哪里时,有一个简单的测试。
问它是否定义了代理是谁以及它如何推理,是否无一例外地适用于每个请求,是否稳定且很少变化,以及它是否是策略的陈述而非流程。如果所有这些都为真,它属于系统提示词。
问它是否是一个有副作用的操作,是否检索动态或实时的上下文,是否只适用于某些请求,以及它是否描述了流程而非策略。如果这些为真,它属于技能。
最尖锐版本的规则是这样的。如果它是代理是什么,它是系统提示词。如果它是代理做什么,它是技能。
6、生产中好的表现是什么样的
在生产中经得起考验的代理不是那些有最精巧系统提示词的。而是那些关注点清晰分离的,身份和推理存在于提示词中,动态能力存在于技能中,它们之间的接口是明确的。
当东西坏了——总会有东西坏的——这种架构让根因变得明显。代理推理不正确?那是系统提示词的问题。工具返回了坏数据?那是技能的问题。代理调用了错误的工具?那是工具描述的问题。这些都是可回答的问题。用单体结构,它们不是。
构建这些有明确答案的问题的代理。你会花更少的时间调试,更多的时间发布真正有效的东西。
原文链接:System Prompt vs Agent Skills. The Architecture Decision That Makes or Breaks Your AI Agent
汇智网翻译整理,转载请标明出处