Agent 开发进阶(十):系统提示词不是大字符串,而是可维护的组装流水线
本文是「从零构建 Coding Agent」系列的第十篇,适合想让系统提示词更灵活、可维护的开发者。
先问一个问题
你是怎么管理系统提示词的?
- 写成一大段固定的硬编码文本?
- 每次有新工具或新技能时,手动修改提示词?
- 把所有信息都塞进一个大字符串里?
如果你的答案是肯定的,那么当系统功能越来越多时,你会遇到越来越多的麻烦。
系统提示词的「维护困境」问题
到了这一阶段,你的 Agent 已经具备了多种能力:
- 核心循环运行
- 工具使用与分发
- 会话内规划
- 子智能体机制
- 技能加载
- 上下文压缩
- 权限系统
- Hook 系统
- Memory 系统
但随着功能的增加,系统提示词变得越来越难维护:
- 工具列表会变
- skills 会变
- memory 会变
- 当前目录、日期、模式会变
- 某些提醒只在这一轮有效,不该永远塞进系统说明
所以到了这个阶段,系统提示词不能再当成一块硬编码文本。
它应该升级成:
由多个来源共同组装出来的一条流水线。
系统提示词的核心设计:组装流水线
用一个图来表示系统提示词的组装流程:
core (核心身份和规则)
+
tools (工具列表)
+
skills (技能元信息)
+
memory (记忆内容)
+
claude_md (长期规则说明)
+
dynamic (动态环境信息)
=
final system prompt
关键点只有一个:
system prompt 的关键不是「写一段很长的话」,而是「把不同来源的信息按清晰边界组装起来」。
几个必须搞懂的概念
System Prompt(系统提示词)
给模型的系统级说明,通常负责告诉模型:
- 你是谁
- 你能做什么
- 你应该遵守什么规则
- 你现在处在什么环境里
组装流水线
意思是:
- 不同信息来自不同地方
- 最后按顺序拼接成一份输入
- 它不是一个死字符串,而是一条构建过程
动态信息
有些信息经常变化,例如:
- 当前日期
- 当前工作目录
- 本轮新增的提醒
这些信息不适合和所有稳定说明混在一起。
最小实现
1. System Prompt Builder
class SystemPromptBuilder:
"""系统提示词构建器"""
def __init__(self, config=None):
self.config = config or {}
self.tools = []
self.skills = []
self.memory_manager = None
self.claude_md_path = None
def set_tools(self, tools):
"""设置工具列表"""
self.tools = tools
return self
def set_skills(self, skills):
"""设置技能列表"""
self.skills = skills
return self
def set_memory_manager(self, memory_manager):
"""设置记忆管理器"""
self.memory_manager = memory_manager
return self
def set_claude_md_path(self, path):
"""设置 CLAUDE.md 路径"""
self.claude_md_path = path
return self
def build(self):
"""构建系统提示词"""
parts = []
# 1. 核心身份和行为说明
parts.append(self._build_core())
# 2. 工具列表
parts.append(self._build_tools())
# 3. 技能元信息
parts.append(self._build_skills())
# 4. 记忆内容
parts.append(self._build_memory())
# 5. CLAUDE.md 指令链
parts.append(self._build_claude_md())
# 6. 动态环境信息
parts.append(self._build_dynamic())
# 过滤空部分并拼接
return "\n\n".join(p for p in parts if p)
def _build_core(self):
"""构建核心身份和行为说明"""
return """# 你是一个智能开发助手
## 你的角色
你是一个专业的编程助手,擅长解决各种开发问题,帮助用户完成代码相关的任务。
## 你的职责
- 理解用户需求
- 分析问题
- 提供专业的解决方案
- 执行相关工具
- 清晰地解释你的思路
## 你的规则
- 保持专业和友好
- 提供准确的信息
- 遇到不确定的问题时,先查询再回答
- 保护用户隐私
- 拒绝执行危险操作
"""
def _build_tools(self):
"""构建工具列表说明"""
if not self.tools:
return ""
tool_descriptions = []
for tool in self.tools:
name = tool.get("name")
description = tool.get("description", "")
parameters = tool.get("parameters", {})
param_str = []
for param_name, param_info in parameters.items():
param_desc = param_info.get("description", "")
param_type = param_info.get("type", "string")
param_str.append(f" - {param_name} ({param_type}): {param_desc}")
tool_descriptions.append(f"- **{name}**: {description}\n" + "\n".join(param_str))
return f"""# 可用工具
{"\n".join(tool_descriptions)}
"""
def _build_skills(self):
"""构建技能元信息"""
if not self.skills:
return ""
skill_descriptions = []
for skill in self.skills:
name = skill.get("name")
description = skill.get("description", "")
skill_descriptions.append(f"- **{name}**: {description}")
return f"""# 可用技能
{"\n".join(skill_descriptions)}
"""
def _build_memory(self):
"""构建记忆内容"""
if not self.memory_manager:
return ""
return self.memory_manager.get_all_for_context()
def _build_claude_md(self):
"""构建 CLAUDE.md 指令链"""
if not self.claude_md_path or not self.claude_md_path.exists():
return ""
try:
content = self.claude_md_path.read_text(encoding="utf-8")
return f"""# 项目规则 (CLAUDE.md)
{content}
"""
except Exception:
return ""
def _build_dynamic(self):
"""构建动态环境信息"""
import datetime
import os
dynamic_parts = [
f"**当前日期**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
f"**当前目录**: {os.getcwd()}",
]
# 添加当前模式
current_mode = self.config.get("mode", "default")
dynamic_parts.append(f"**当前模式**: {current_mode}")
# 添加本轮提醒
reminder = self.config.get("reminder", "")
if reminder:
dynamic_parts.append(f"**本轮提醒**: {reminder}")
return f"""# 动态环境信息
{"\n".join(dynamic_parts)}
"""
2. 集成到 Agent Loop
def create_system_prompt(config):
"""创建系统提示词"""
builder = SystemPromptBuilder(config)
# 设置工具
tools = [
{
"name": "read_file",
"description": "读取文件内容",
"parameters": {
"file_path": {"type": "string", "description": "文件路径"}
}
},
{
"name": "write_file",
"description": "写入文件内容",
"parameters": {
"file_path": {"type": "string", "description": "文件路径"},
"content": {"type": "string", "description": "文件内容"}
}
},
# 其他工具...
]
builder.set_tools(tools)
# 设置技能
skills = [
{"name": "code_review", "description": "代码审查技能"},
{"name": "debug", "description": "调试技能"},
# 其他技能...
]
builder.set_skills(skills)
# 设置记忆管理器
from memory_manager import MemoryManager
memory_manager = MemoryManager()
builder.set_memory_manager(memory_manager)
# 设置 CLAUDE.md 路径
from pathlib import Path
claude_md_path = Path("./CLAUDE.md")
builder.set_claude_md_path(claude_md_path)
# 构建系统提示词
return builder.build()
def agent_loop():
"""智能体主循环"""
# 配置
config = {
"mode": "default",
"reminder": "本次任务:修复认证模块的登录问题"
}
# 创建系统提示词
system_prompt = create_system_prompt(config)
# 初始化状态
state = {
"system": system_prompt,
"messages": []
}
# 主循环
while True:
# 调用模型
response = call_model(state["messages"], system=state["system"])
# 处理响应...
核心边界区分
1. 稳定说明 vs 动态提醒
| 类型 | 内容 | 特点 |
|---|---|---|
| 稳定说明 | 身份、规则、工具、技能、长期约束 | 不常变化,适合放在 system prompt 中 |
| 动态提醒 | 当前日期、工作目录、本轮任务、临时状态 | 每次都可能变化,适合作为动态部分 |
2. System Prompt vs System Reminder
| 类型 | 适合放的内容 | 特点 |
|---|---|---|
| System Prompt | 身份、规则、工具、长期约束 | 相对稳定,每轮变化不大 |
| System Reminder | 本轮临时需要的补充上下文、当前变动的状态 | 只在本轮有效,下轮可能不同 |
3. 不同信息来源的职责
| 来源 | 职责 | 特点 |
|---|---|---|
| Core | 核心身份和行为规则 | 最稳定的部分 |
| Tools | 工具列表和使用说明 | 随着工具增减而变化 |
| Skills | 技能元信息 | 随着技能加载而变化 |
| Memory | 跨会话记忆 | 随着记忆的增删而变化 |
| CLAUDE.md | 长期规则说明 | 相对稳定,项目级配置 |
| Dynamic | 动态环境信息 | 每次都可能不同 |
新手最容易犯的 4 个错
1. 把 system prompt 写成固定字符串
# ❌ 错误
system_prompt = """你是一个智能助手... 这里有很多工具... 还有很多规则..."""
# ✅ 正确
# 使用 SystemPromptBuilder 动态构建
builder = SystemPromptBuilder()
system_prompt = builder.build()
2. 把所有变化信息都塞进 system prompt
# ❌ 错误
system_prompt = f"""你是一个智能助手...
当前日期: {datetime.now()}
当前目录: {os.getcwd()}
本次任务: {current_task}
"""
# ✅ 正确
# 把动态信息放在动态部分
builder = SystemPromptBuilder(config={"reminder": "本次任务:修复登录问题"})
3. 把 CLAUDE.md、memory、skills 写成同一种东西
# ❌ 错误
system_prompt = f"""你是一个智能助手...
{load_claude_md()}
{load_memory()}
{load_skills()}
"""
# ✅ 正确
# 分开处理不同来源
builder.set_claude_md_path(Path("./CLAUDE.md"))
builder.set_memory_manager(memory_manager)
builder.set_skills(skills)
4. 不区分静态和动态部分
# ❌ 错误
system_prompt = """你是一个智能助手...
当前日期: 2024-01-01
当前目录: /home/user
"""
# ✅ 正确
# 动态部分每次都重新生成
builder = SystemPromptBuilder()
system_prompt = builder.build() # 每次都会重新生成动态部分
为什么这很重要
因为一个可维护的系统,不应该把所有信息都混在一起。
系统提示词组装流水线让你能够:
- 更好维护:每个部分职责清晰,修改方便
- 更好测试:可以单独测试每个部分的生成效果
- 更好扩展:新增工具、技能时,自动更新到系统提示词
- 更好管理:稳定部分和动态部分分开处理
推荐的实现步骤
- 第一步:创建 SystemPromptBuilder 类
- 第二步:实现各个构建方法(core、tools、skills、memory、claude_md、dynamic)
- 第三步:在 Agent Loop 中使用构建器生成系统提示词
- 第四步:根据需要调整各部分的内容和顺序
- 第五步:测试不同场景下的系统提示词效果
系统提示词与后续章节的关系
- s10 系统提示词:把前面所有功能组织成一份清楚的系统输入
- s11 错误恢复:会使用系统提示词来指导错误处理
- s12 任务系统:会在系统提示词中添加任务相关的信息
- s19 MCP 插件:会通过系统提示词向模型介绍新的能力
所以系统提示词是连接所有功能的重要环节。
下一章预告
有了系统提示词组装流水线,你的 Agent 已经具备了灵活、可维护的系统说明能力。下一章我们将探讨错误恢复机制,让 Agent 在遇到错误时能够优雅地处理并继续工作。
一句话总结:system prompt 的关键不是「写一段很长的话」,而是「把不同来源的信息按清晰边界组装起来」。
如果觉得有帮助,欢迎关注,我会持续更新「从零构建 Coding Agent」系列文章。