7.5 KiB
7.5 KiB
上下文组件:技术参考
本文档提供代理系统中每个上下文组件的详细技术参考。
系统提示词工程
章节结构
将系统提示词组织成具有清晰边界的独立章节。推荐的结构如下:
<BACKGROUND_INFORMATION>
关于领域、用户偏好或项目特定细节的上下文
</BACKGROUND_INFORMATION>
<INSTRUCTIONS>
核心行为准则和任务指令
</INSTRUCTIONS>
<TOOL_GUIDANCE>
何时以及如何使用可用工具
</TOOL_GUIDANCE>
<OUTPUT_DESCRIPTION>
预期的输出格式和质量标准
</OUTPUT_DESCRIPTION>
这种结构使代理能够快速定位相关信息,并在高级实现中支持选择性上下文加载。
抽象层级校准
指令的"抽象层级"指的是抽象的层次。请参考以下示例:
过低(脆弱):
如果用户询问定价,请查看 docs/pricing.md 中的定价表。
如果表格显示的是美元,则使用 config/exchange_rates.json 中的
汇率转换为欧元。如果用户位于欧盟,则按 config/vat_rates.json
中适用的税率添加增值税。使用货币符号、两位小数以及关于增值税的
说明来格式化回复。
过高(模糊):
帮助用户解决定价问题。要乐于助人且准确。
最优(启发式驱动):
对于定价咨询:
1. 从 docs/pricing.md 获取当前费率
2. 应用用户所在地调整(参见 config/location_defaults.json)
3. 使用适当的货币和税务考虑进行格式化
优先使用精确数字而非估算值。当费率不可用时,
明确说明,而不是进行推测。
最优的抽象层级在提供明确步骤的同时,允许在执行过程中保持灵活性。
工具定义规范
Schema 结构
每个工具应定义如下内容:
{
"name": "tool_function_name",
"description": "清晰说明工具的用途及使用时机",
"parameters": {
"type": "object",
"properties": {
"param_name": {
"type": "string",
"description": "该参数控制的内容",
"default": "reasonable_default_value"
}
},
"required": ["param_name"]
},
"returns": {
"type": "object",
"description": "工具的返回值及其结构"
}
}
描述工程
工具描述应回答以下问题:该工具做什么、何时使用它、以及它产生什么。应包含使用上下文、示例和边界情况。
较弱的描述:
搜索数据库以获取客户信息。
较强的描述:
通过 ID 或邮箱检索客户信息。
使用时机:
- 用户询问特定客户的详细信息、历史记录或状态时
- 用户提供了客户标识符并需要相关信息时
返回客户对象,包含:
- 基本信息(姓名、邮箱、账户状态)
- 订单历史摘要
- 支持工单数量
如果未找到客户则返回 null。如果数据库不可达则返回错误。
检索文档管理
标识符设计
设计能够传达含义并支持高效检索的标识符:
较差的标识符:
data/file1.jsonref/ref.md2024/q3/report
较强的标识符:
customer_pricing_rates.jsonengineering_onboarding_checklist.md2024_q3_revenue_report.pdf
即使没有搜索工具,较强的标识符也能让代理定位到相关文件。
文档分块策略
对于大型文档,应策略性地分块以保持语义连贯性:
# 语义分块的伪代码
def chunk_document(content):
"""在自然的语义边界处拆分文档。"""
boundaries = find_section_headers(content)
boundaries += find_paragraph_breaks(content)
boundaries += find_logical_breaks(content)
chunks = []
for i in range(len(boundaries) - 1):
chunk = content[boundaries[i]:boundaries[i+1]]
if len(chunk) > MIN_CHUNK_SIZE and len(chunk) < MAX_CHUNK_SIZE:
chunks.append(chunk)
return chunks
避免使用会在句子中间或概念中间截断的任意字符长度限制。
消息历史管理
Turn 表示
结构化消息历史以保留关键信息:
{
"role": "user" | "assistant" | "tool",
"content": "消息文本",
"reasoning": "可选的思维链",
"tool_calls": [如果 role 为 "assistant" 则为列表],
"tool_output": "如果 role 为 "tool" 则为输出",
"summary": "如果对话较长则为紧凑摘要"
}
摘要注入模式
对于长对话,按间隔注入摘要:
def inject_summaries(messages, summary_interval=20):
"""按固定间隔注入摘要以保留上下文。"""
summarized = []
for i, msg in enumerate(messages):
summarized.append(msg)
if i > 0 and i % summary_interval == 0:
summary = generate_summary(summarized[-summary_interval:])
summarized.append({
"role": "system",
"content": f"对话摘要:{summary}",
"is_summary": True
})
return summarized
工具输出优化
响应格式
提供响应格式选项以控制 token 用量:
def get_customer_response_format():
return {
"format": "concise | detailed",
"fields": ["id", "name", "email", "status", "history_summary"]
}
简洁格式仅返回必要字段;详细格式返回完整对象。
观察结果屏蔽
对于冗长的工具输出,可考虑使用屏蔽模式:
def mask_observation(output, max_length=500):
"""用紧凑引用替换长观察结果。"""
if len(output) <= max_length:
return output
reference_id = store_observation(output)
return f"[之前的观察结果已省略。完整内容存储于引用 {reference_id}]"
这样在减少 token 用量的同时保留了信息访问能力。
上下文预算估算
Token 计数近似
在规划时,对于英文文本,可按大约每 4 个字符约等于 1 个 token 进行估算:
1000 个单词 ≈ 7500 个字符 ≈ 1800-2000 个 token
这是一个粗略估算;实际分词因模型和内容类型而异。
上下文预算分配
在不同组件之间分配上下文预算:
| 组件 | 典型范围 | 说明 |
|---|---|---|
| 系统提示词 | 500-2000 tokens | 整个会话中保持稳定 |
| 工具定义 | 每个工具 100-500 tokens | 随工具数量增加而增长 |
| 检索文档 | 可变 | 通常是最大的消费者 |
| 消息历史 | 可变 | 随对话进行而增长 |
| 工具输出 | 可变 | 可能占据大部分上下文 |
在开发过程中监控实际使用情况,以建立基线分配。
渐进式披露实现
技能激活模式
def activate_skill_context(skill_name, task_description):
"""当任务匹配技能描述时加载技能上下文。"""
skill_metadata = load_all_skill_metadata()
relevant_skills = []
for skill in skill_metadata:
if skill_matches_task(skill, task_description):
relevant_skills.append(skill)
# 仅加载最相关技能的完整内容
for skill in relevant_skills[:MAX_CONCURRENT_SKILLS]:
skill_context = load_skill_content(skill)
inject_into_context(skill_context)
引用加载模式
def get_reference(file_reference):
"""仅在明确需要时加载引用文件。"""
if not file_reference.is_loaded:
file_reference.content = read_file(file_reference.path)
file_reference.is_loaded = True
return file_reference.content
这种模式确保文件只加载一次并在整个会话中缓存。