一句话结论:提示词工程不是"调措辞",而是信息架构——把正确的信息放在正确的位置,让模型在约束条件下做出可预期的决策。
一、信息架构:Agent必须知道什么,不能编造什么
1.1 facts与推理分离
催收Agent必须知道用户的账单金额、逾期天数,但不能让LLM自己编造。
我们的做法是:把事实注入为结构化数据,与推理指令严格分离。
context = {
"user_message": "我现在没钱",
"facts": {
"due_amount": 2580, # 系统读取,禁止LLM修改
"overdue_days": 15,
"occupation": "销售",
},
"messages": [...],
}
为什么重要:如果让LLM自己"记住"金额,它会幻觉。把facts放在独立字段,并在prompt中明确要求"只能使用facts中的金额",可以显著降低幻觉概率。
1.2 信息压缩(Compaction)
简单丢弃旧消息(FIFO)会丢失关键信息。比如用户上周承诺"周五还",如果被新的对话挤掉,Agent就不知道这个承诺了。
做法:当对话历史超过30条时,保留最近5轮完整对话,更早的内容用LLM压缩为"关键事实摘要"。
class ConversationContext:
messages: list[Message]
summary: str | None # 压缩后的摘要
def compact(self):
if len(self.messages) <= 30:
return
recent = self.messages[-5:]
older = self.messages[:-5]
self.summary = await llm.summarize(
older,
instruction="提取还款承诺、争议、危机事件、协商方案等关键事实"
)
self.messages = recent
压缩后的Context结构:
System prompt
↓
Facts(系统注入的账单金额、逾期天数)
↓
Summary(压缩后的历史关键事实)
↓
Recent messages(最近5轮完整对话)
↓
Current user message
↓
输出格式要求
这样,关键事实不会因为对话轮数增加而丢失,同时prompt长度可控。
二、职责分离:不要让一个prompt做所有事
collect-agent最初把意图识别和Skill选择放在同一个200+行的system prompt里。结果:
- 意图识别准确率受Skill描述干扰
- 改一句Skill描述,意图识别也受影响
- 无法单独测试和迭代
拆分后的结构:
| 组件 | Prompt职责 | 为什么独立 |
|---|---|---|
| Decider | 只做意图识别 | 意图分类是基础,不能被策略描述污染 |
| Skill | 只做策略执行 | 策略可以频繁更新,不触碰分类逻辑 |
| Compliance | 只做输出审核 | 安全审查是独立关注点 |
好处:隔离故障、独立迭代、降低长度(减少Lost in the Middle)。
三、推理透明:让Agent"说出"它在想什么
3.1 CoT:给模型思考时间
Decider的prompt中加入了思考步骤,要求模型输出thinking字段:
思考流程(每轮必须执行):
1. 用户消息的关键词是什么?
2. 历史意图是什么?
3. 用户当前状态是什么?
4. 最匹配的意图是什么?
5. 置信度如何?
输出JSON:{"intent": "...", "confidence": 0.95, "thinking": "..."}
效果:加了thinking字段后,意图识别的准确率有明显提升。模型被迫"说出"自己的推理过程,减少了直觉性误判。
代价:增加了延迟(多了几十个输出token),生产中需要权衡。
3.2 结构化输出:JSON比自由文本更可靠
所有关键组件都要求模型输出结构化JSON:
| 组件 | 输出格式 |
|---|---|
| Decider | {"intent": "...", "confidence": 0.95} |
| Skill action | {"type": "tool_call", "name": "...", "params": {}} |
| Compliance audit | {"passed": true, "violations": [...]} |
为什么不用自由文本:
- 自由文本需要复杂的正则提取,容易出错
- JSON可以直接解析,下游处理简单
- 结构化输出更容易验证和测试
四、安全兜底:说错话怎么办
催收场景对安全性要求极高。我们采用了三层防御:
第一层:Harness(代码层,不在prompt中)
时间窗口、频次限制、DNC检查——这些不通过prompt实现,而是代码硬拦截。因为"请在白天联系用户"这种prompt,LLM可能会忽略。
第二层:Prompt中的明确约束
每个Skill的prompt中都有"禁止"列表:
禁止:
- 施压或威胁
- 承诺超出权限的减免
- 用户已明确拒绝后继续纠缠
第三层:输出审核(LLM Self-critique)
生成回复后,再用一个独立的审核prompt检查:
你是一个严格的催收合规审核员。
请审查以下回复草稿是否包含威胁/羞辱性语言?
输出JSON:{"passed": true/false, "violations": [...]}
三层的关系:代码层拦截确定性违规,prompt层约束行为边界,审核层捕获语义违规。
五、Prompt管理:让策略可迭代
collect-agent的Skills从Markdown文件加载:
name: negotiation
description: 用户表示困难,希望延期或分期
tools: [query_bill, record_promise]
max_steps: 5
你是协商专家...
好处:
- 版本可控:git管理,每次修改有记录
- 领域专家可参与:业务人员可以直接编辑Markdown
- 运行时切换:不需要重启服务,可以动态加载新策略
关联
- [[03-agent-architecture]] — Agent架构设计与实现
- [[ai-engineering-book-notes]] — AI Engineering: Building Applications with Foundation Models 章节笔记
Tags
#collection-agent #ai-engineering #prompt-engineering
Loading comments...