一句话结论:提示词工程不是"调措辞",而是信息架构——把正确的信息放在正确的位置,让模型在约束条件下做出可预期的决策。

一、信息架构: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:给模型思考时间

Deciderprompt中加入了思考步骤,要求模型输出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中的明确约束

每个Skillprompt中都有"禁止"列表:

禁止:
- 施压或威胁
- 承诺超出权限的减免
- 用户已明确拒绝后继续纠缠

第三层:输出审核(LLM Self-critique)

生成回复后,再用一个独立的审核prompt检查:

你是一个严格的催收合规审核员。
请审查以下回复草稿是否包含威胁/羞辱性语言?
输出JSON:{"passed": true/false, "violations": [...]}

三层的关系:代码层拦截确定性违规,prompt层约束行为边界,审核层捕获语义违规。

五、Prompt管理:让策略可迭代

collect-agentSkillsMarkdown文件加载:

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