根据对代码的全面分析,我将系统梳理硬编码规则、LLM判断的规则以及系统是否遵循prompt.yaml中的SOP流程。
一、硬编码规则(在Java代码中写死的逻辑)
1.流程控制与默认行为
| 位置 | 硬编码内容 |
|---|---|
AgentOrchestrator.process() | 最大循环次数maxLoops = 5,超限后发送固定兜底消息。 |
AgentState | 历史记录最多保留50条(if (history.size() > 50) { history.remove(0); })。 |
AgentOrchestrator | 解析LLM响应失败时降级消息:"抱歉,我没理解您的意思。"或"抱歉,系统暂时无法处理,请稍后再试。"。 |
ToolRegistry | 工具名称硬编码:tools.put("sales", new SalesTool())。 |
SalesTool(旧实现) | 状态转换映射硬编码(如"greet_gift_intro"→"GIFT_CLAIM_GUIDE")。 |
RedisSessionManager | TTL固定为7天、键名前缀硬编码。 |
AgentFlowEngine.evaluateCondition() | 使用LLM判断条件,但prompt为硬编码字符串。 |
2.业务逻辑中的固定阈值与概率
| 位置 | 硬编码内容 |
|---|---|
ConversationDecisionEngine | 判断是否主动跟进:minutesSinceLastActivity >= 3;消息长度阈值(100、50)决定回复数量;购买意愿阈值0.7。 |
MessageGenerator | 添加思考痕迹的概率0.1;消息相似度阈值0.8;微思考响应截断长度30。 |
HumanBehaviorEngine | 大量概率和阈值(如random.nextDouble() < 0.3),设备类型因子、时间段因子等有默认值。 |
ProactiveConversationService | 响应概率阈值0.6。 |
KnowledgeService | 检索结果默认限制topK=3。 |
CustomerServiceAgent | 阶段完成条件的描述文本硬编码在buildConversationReplyPrompt中。 |
3.Prompt构建中的固定文本
许多buildXXXPrompt方法中使用String.format或字符串拼接,包含了大量固定引导语、案例、规则说明,例如:
MessageGenerator.buildMessagePrompt()中的系统角色设定、案例。StrictSalesEngine.buildStateTransitionPrompt()中的“强制规则”、“皮肤问题处理规则”。ConversationOrchestrator.buildSystemPrompt()中的工作时间、称呼、策略提示等。AgentThinkingEngine.think()中的输出格式说明。
这些固定文本虽然在代码中,但本质是用于引导LLM,并非业务逻辑硬编码,但它们作为字符串嵌入代码,不利于灵活修改。
4.枚举与状态映射
StrictSalesState枚举定义所有阶段,阶段间的流转逻辑未硬编码(由LLM决定),但状态值本身固定。StagePlan在StageGoalResolver中硬编码了默认阶段计划,但从prompt.yaml加载的配置会覆盖。
5.工具类中的简单规则
OrderStatusTool:简单查询订单并返回固定模板键。SalesTool(旧)硬编码了输入指令到状态的映射。
二、通过LLM判断的规则(由LLM动态决策)
1.核心对话决策
| 组件 | LLM决策内容 |
|---|---|
AgentOrchestrator | 调用LLM生成ThoughtResult,决定动作(SPEAK/TOOL/WAIT/END)、消息内容、工具调用、是否更新阶段。 |
StrictSalesEngine | 调用LLM生成StateMachineDecision,决定下一状态、动作、消息列表、是否完成阶段、是否介绍自己等。 |
StreamingThinkEngine | 调用LLM生成StreamThought,决定意图、消息、等待时间、后续想法等,用于持续思考。 |
MessageGenerator | 所有生成回复的方法均调用LLM,包括:普通回复、主动跟进、异议处理、产品介绍、情绪安抚等。 |
EnhancedDecisionEngine/ProactiveDecisionService | 使用LLM判断是否主动跟进及跟进内容。 |
ConversationDecisionService | 使用LLM决定是否说话及消息内容。 |
DecisionModelService | 使用LLM做是否回应、回应类型等决策。 |
IntentEvaluatorService | 使用LLM评估意图、是否主动跟进等。 |
2.认知与情感分析
| 组件 | LLM分析内容 |
|---|---|
CognitiveEngine | 使用LLM分析意图、情绪、实体、核心需求、购买意愿、风险等级(通过analyzeWithDashScope)。 |
EmotionAnalyzerLLM | 使用LLM分析情绪维度(愤怒、焦虑、怀疑等)。 |
EnhancedEmotionAnalyzer | 使用LLM进行细粒度情绪分析,返回情绪类型、强度、子情绪等。 |
BeautyIntentClassifier | 使用LLM进行意图分类(多意图)。 |
3.条件判断与规则评估
| 组件 | LLM判断内容 |
|---|---|
AgentFlowEngine.evaluateCondition() | 使用LLM判断边缘条件(如是否满足跳转条件)。 |
StrictSalesEngine.isDuplicateByLLM() | 使用LLM判断消息是否为重复消息。 |
StrictSalesEngine.violateSop() | 使用LLM判断回复是否违反SOP。 |
StrictSalesEngine.mustFollow() | 使用LLM判断当前是否必须严格遵循SOP。 |
PolicyEngine中的部分决策 | 使用LLM处理异议、价值主张应用等(但部分为硬编码规则)。 |
4.内容生成与优化
LLMRAGService:使用LLM生成高质量回复、处理异议、情绪安抚、产品介绍。PersonalizedPlanService:使用LLM生成个性化护肤方案(optimizePlanWithLLM)。SalesChampionImitationService:使用LLM生成模仿销冠风格的回复。AgentLearningService:使用LLM分析对话、提取经验、生成改进策略。
三、系统是否按照prompt.yaml中的SOP流程执行?
1.配置加载与使用
PromptProperties加载prompt.yaml,PromptService提供访问接口。阶段配置:
stageConfigs被StrictSalesEngine.init()加载并存入stageConfigsMap,在构建LLM Prompt时动态注入。完成条件与禁止话题:在
CustomerServiceAgent.buildConversationReplyPrompt()和StrictSalesEngine.buildStateTransitionPrompt()中,通过promptService.getStageGoal()、getStageCompletionCondition()、getForbiddenTopics()获取,并放入Prompt中,引导LLM遵循。话术模板:
stageStateMachine中的标准话术在StrictSalesEngine.getStateTemplate()中被使用,当LLM未提供消息时作为兜底。在MessageGenerator中,也通过promptService.get(key)获取各种模板(如greetGiftIntro),用于构建Prompt或直接使用。异议处理流程:
objectionHandlingFlow通过PromptService被ObjectionHandlingFlow.buildFromConfig()加载,并在SalesPolicyEngine.buildObjectionHandlingPrompt()中作为参考注入Prompt。
2.执行机制
决策依赖LLM:所有状态推进、是否完成阶段、是否发送消息等核心决策,均由LLM根据Prompt中的SOP描述做出。
引导而非强制:系统将SOP的目标、完成条件、禁止话题等作为“知识”提供给LLM,但LLM的最终输出可能偏离SOP(例如未达到完成条件却推进阶段)。此时系统会接受LLM的决策(除非解析失败则降级),没有强制校验或修正。
兜底措施:当LLM未提供消息时,会使用
getStateTemplate()返回的预设话术;当解析失败时,会返回默认回复或等待。但这些兜底不能保证完全符合SOP。
3.验证
在
StrictSalesEngine的parseStateMachineDecision()中,会解析LLM返回的nextState、stageComplete等字段,并直接设置状态。没有额外的SOP合规校验。虽然存在
violateSop()方法,但它仅在ReplyValidator.validateAndRepair()中被调用(该验证器在AgentRouter中被使用),用于修复违反SOP的回复,但该验证是在回复生成后,且修复也依赖LLM,并非严格拦截。在
ConversationPolicyEngine中,mustFollowSop标志由LLM判断,但后续执行仍由StrictSalesEngine处理。
4.结论
系统会参考prompt.yaml中的SOP流程,但并非硬性执行。SOP的描述(目标、完成条件、禁止话题、话术模板)被注入到LLM的Prompt中,由LLM自主决定是否遵守。由于LLM可能产生偏离,实际执行效果依赖于LLM的语义理解能力和Prompt设计的有效性。
四、改进建议
1.减少硬编码
将
AgentOrchestrator中的循环次数、兜底消息、历史长度等配置化到application.yml或prompt.yaml。将
MessageGenerator中的思考标记、案例文本等抽取为配置,通过PromptService加载。将各类阈值(如主动跟进时间、参与度阈值)移到配置文件中。
将
SalesTool中的状态映射改为配置或完全由LLM决策。
2.增强SOP合规性
在
StrictSalesEngine中增加后置校验:LLM返回的nextState是否与当前阶段允许的下一阶段列表匹配(可从配置读取)。增加
stageComplete的校验:若LLM认为阶段完成,但实际用户未满足完成条件(可通过规则检查),则强制设置stageComplete=false并重新生成。在回复发送前,用
violateSop方法做快速校验,若违反则使用默认话术覆盖。为每个阶段配置允许的下一阶段列表,在状态更新时进行合法性检查。
3.优化LLM决策质量
在Prompt中更明确地强调SOP的权威性,使用类似“你必须严格遵守以下规则”的强约束语句。
使用Few-shot示例展示正确的阶段推进场景。
对阶段完成条件进行更详细的描述,并提示LLM如果未满足条件,不能推进。
通过以上措施,可以在保持LLM灵活性的同时,增强系统对SOP的执行力,减少偏差。
我们被要求分析代码中哪些规则是硬编码的,哪些是通过LLM判断的,以及是否按照prompt.yaml中的SOP流程执行。我们需要基于提供的代码进行全面分析。代码规模很大,我们需要系统地梳理。
首先,理解项目:AI Agent系统,核心是对话流程。主要组件包括:AgentOrchestrator, AgentState, StrictSalesEngine, StreamingThinkEngine, MessageGenerator, PromptService等。系统通过LLM决策,但也有一些硬编码逻辑。
我们要从代码中提取硬编码规则和LLM判断的地方,并验证是否遵循prompt.yaml中的SOP。
一、硬编码规则
硬编码规则指在Java代码中直接写死的逻辑,不依赖LLM或配置文件。
AgentOrchestrator中的循环和默认处理:
maxLoops = 5:最多循环5次。当LLM响应解析失败时,降级发送固定消息:"抱歉,我没理解您的意思。" 或 "抱歉,系统暂时无法处理,请稍后再试。"
在
process方法中,根据ThoughtResult的action执行不同逻辑:SPEAK、TOOL、WAIT、END。这是基于JSON解析的,但具体流程控制是硬编码的。
AgentState中的历史长度限制:
if (history.size() > 50) { history.remove(0); }固定50条历史。
ToolRegistry:
注册工具时硬编码了工具名称映射。例如
tools.put("sales", new SalesTool());。但SalesTool本身逻辑也是硬编码的(在tools/SalesTool.java中)。
SalesTool(工具实现):
SalesTool.execute中有switch-case根据input执行不同的阶段转移。例如:"greet_gift_intro"-> 状态设为GIFT_CLAIM_GUIDE"gift_claim_guide"-> 状态设为WAITING_FOR_GIFT_CONFIRMATION"ask_photo"-> 状态设为ASKING_FOR_PHOTO
这些状态名和转换是硬编码的。但是注意,在StrictSalesEngine中也有类似的决策,可能SalesTool已弃用?实际分析,ToolRegistry中使用了OrderStatusTool,但SalesTool似乎用于辅助状态转换,而主要状态机在StrictSalesEngine中。
CustomerServiceAgent中的阶段完成条件:
在
buildConversationReplyPrompt中,有对阶段完成条件的描述,但这些描述是写在Java字符串中的,而不是完全从配置读取。虽然这些条件文本是硬编码的,但它们被注入到prompt中,由LLM判断是否完成。但硬编码了条件文本。
ConversationDecisionEngine中的决策逻辑:
shouldSpeak、shouldProactiveFollowUp、shouldBeSilent等方法中有硬编码的时间判断(如3分钟、10秒)、概率随机等。determineMessageCount中硬编码了根据消息长度返回1-3条消息。determineStrategy根据购买意愿阈值0.7决定策略。
MessageGenerator中的硬编码:
大量硬编码的prompt字符串,例如在
generateWithFallback、generate、buildMessagePrompt等方法中,使用String.format构造prompt,其中包含了很多固定的文本描述。在
addHumanElements中,有硬编码的思考标记数组和概率0.1。在
processMicroThinkingResponse中,有截断消息长度、添加标点等硬编码逻辑。在
generateWithDiversity中,硬编码了相似度阈值0.8和重试次数3。在
generateWithTemplate中,硬编码了根据策略类型返回的默认兜底。
HumanBehaviorEngine:
有大量硬编码的概率和阈值,例如
random.nextDouble() < 0.3、设备类型因子、时间段因子等,虽然有从配置读取,但默认值硬编码。
RedisSessionManager中的TTL和常量:
DEFAULT_TTL = Duration.ofDays(7)硬编码。一些键名前缀硬编码,如
session:%s:epoch等。
AgentFlowEngine:
evaluateCondition中直接调用LLM判断,但prompt是硬编码的字符串。
ConversationOrchestrator:
在
buildSystemPrompt方法中,有大量硬编码的规则文本,例如“工作时间:10:00~19:00”、“称呼客户为“亲爱的”或“姐妹””、“如果客户情绪负面(愤怒、失望),先道歉安抚”等。这些虽然是用于prompt的,但内容是硬编码的,不是从配置读取。
StrictSalesEngine中的硬编码:
getStageGoal方法中有switch-case,硬编码了阶段目标字符串。buildStateTransitionPrompt中,硬编码了“强制规则”等文本,但也是用于prompt。在
parseStateMachineDecision中,当nextState无效时,默认设置为StrictSalesState.GREETING_GIFT_INTRO,并且有硬编码的默认话术。getStateTemplate中,从配置读取,但若读取不到,有硬编码的兜底。isDuplicateByLLM中,如果LLM调用失败,返回false,没有重试等。
其他服务中的硬编码:
例如在
CognitiveEngine中,有硬编码的意图映射(switch(intent))。EmotionAnalyzerLLM中有硬编码的默认值。KnowledgeService中retrieveRelevantDocs默认limit为3,硬编码。ProactiveConversationService中阈值0.6硬编码。
二、通过LLM判断的规则
这部分是指决策由LLM完成,系统将上下文组织成prompt,调用LLM,解析返回的JSON来驱动行为。
AgentOrchestrator的思考循环:
核心:调用
LLMClient.call生成ThoughtResult,包含action、message、toolName等,然后根据action执行。所以整个思考过程(决定说/调用工具/等待/结束)是由LLM决定的。
StrictSalesEngine的状态转换:
在
process方法中,调用LLM生成StateMachineDecision,决定下一状态、动作、话术等。这是核心的状态机,由LLM基于当前状态、用户消息、对话历史等决策。在
processWithProactiveRequest中,同样使用LLM决策。注意:尽管状态转换由LLM决策,但状态枚举和部分约束是硬编码的。
StreamingThinkEngine:
thinkWithLLM方法中,调用LLM生成StreamThought,包含intent、message、nextThoughts等。这用于持续思考,也是LLM决策。
MessageGenerator的大部分消息生成:
所有生成回复的方法(
generateWithFallback、generate、generateNextSentence等)最终都调用LLM生成具体回复文本。虽然构建prompt时有大量硬编码,但最终的回复由LLM决定。
决策类服务:
EnhancedDecisionEngine.decide使用LLM判断是否主动跟进。ProactiveDecisionService.decide使用LLM决定主动联系。ConversationDecisionService.decide使用LLM决定是否说话及消息。DecisionModelService使用LLM做决策。IntentEvaluatorService使用LLM评估意图。
情绪分析:
EmotionAnalyzerLLM使用LLM分析情绪。EnhancedEmotionAnalyzer也使用LLM分析。
认知分析:
CognitiveEngine中调用了EnhancedCognitiveResult的增强分析,使用了LLM(通过analyzeWithDashScope或备用)。
意图分类:
BeautyIntentClassifier使用LLM进行意图分类。DynamicIntentClassifier可以选择使用ML或规则,但最终都会调用LLM或ML。
内容生成:
LLMRAGService使用LLM生成高质量回复。
条件判断:
AgentFlowEngine中的evaluateCondition使用LLM判断条件。
三、是否按照prompt.yaml中的SOP流程执行
prompt.yaml定义了完整的SOP流程,包括阶段配置、阶段目标、完成条件、禁止话题、话术模板等。这些内容在系统中如何被使用?
阶段定义和完成条件:
prompt.yaml中的stageConfigs定义了每个阶段的goal、completionCondition、forbiddenTopics等。在
StrictSalesEngine.init中,通过promptProperties.getTemplates().getStageConfigs()加载这些配置,并存入stageConfigsMap。在
buildStateTransitionPrompt中,会动态注入当前阶段的完成条件、阶段目标等,作为prompt的一部分给LLM。在
CustomerServiceAgent.buildConversationReplyPrompt中,也使用了promptService.getStageGoal(currentStage)和getForbiddenTopics来构建prompt。所以,阶段目标和完成条件是通过配置驱动的,但LLM仍然需要根据这些条件判断是否完成阶段。因此,系统会参考prompt.yaml中的SOP,但最终决策由LLM做出,LLM可能会偏离SOP。
话术模板:
prompt.yaml中的stageStateMachine定义了各阶段的标准话术(如STRICT_SALES_GREETING等)。在
StrictSalesEngine中,getStateTemplate会从promptProperties.getTemplates().getStageStateMachine()中获取对应状态的模板。当LLM没有提供消息时,会使用这些模板。此外,在
MessageGenerator中,也会使用promptService.get(key)获取各种模板(如greetGiftIntro等)。但注意,这些模板主要作为兜底或参考,实际回复仍由LLM生成(除非LLM未提供消息)。
主动跟进话术:
proactiveMessages在prompt.yaml中定义,用于主动跟进场景。在StrictSalesEngine中,getProactiveMessagesForState会读取这些,但似乎没有直接使用?实际在StrictSalesEngine.processWithProactiveRequest中,可能使用模板生成话术。
异议处理流程:
objectionHandlingFlow定义了不同异议类型的处理步骤。这些配置在ObjectionHandlingFlow类中通过buildFromConfig加载,但实际使用似乎不多?在SalesPolicyEngine中,有buildObjectionHandlingPrompt会使用这些配置,但也作为prompt的一部分。
关键点:
系统确实会读取prompt.yaml中的配置,并将其融入prompt中,引导LLM遵循SOP。但是,LLM的决策是自由的,理论上可能不遵守SOP。不过,由于prompt中强调了SOP的重要性(例如"你必须严格按照SOP流程引导客户"),且提供了阶段目标、完成条件等,LLM有较大可能遵循。但无法保证100%执行。
四、总结
硬编码规则主要集中在:循环次数、历史长度、默认兜底、某些工具逻辑、时间阈值、概率、字符串拼接构建prompt时的固定文本等。
LLM判断的规则包括:整体思考决策(说/等待/调用工具)、状态转换、消息生成、主动跟进判断、情绪分析、意图分类等。
SOP流程执行:系统通过读取prompt.yaml中的阶段配置、话术模板等,将其注入到LLM的prompt中,引导LLM按照SOP执行。因此,LLM会参考SOP,但不是硬编码强制执行的。若LLM输出不符合SOP,系统会有一些兜底(如使用默认话术),但不会强制纠正。
五、改进建议
如果想减少硬编码,可以进一步将更多配置移到prompt.yaml或数据库,例如:
将
AgentOrchestrator中的最大循环次数、默认兜底消息等配置化。将
MessageGenerator中的硬编码案例、思考标记等也配置化。将各种阈值、概率从代码中移到配置文件。
将阶段转移的规则更依赖LLM,减少硬编码的状态映射。
当前设计已经很好地结合了LLM和配置,使得流程灵活。但需注意LLM可能产生不符合SOP的结果,因此需要增加更多的验证和纠错机制(如输出格式校验、SOP合规检查)。目前已有一些检查(如StrictSalesEngine中解析JSON,但未做SOP合规性后置校验)。
建议:在LLM输出后,可以增加一个合规检查层,确保输出的nextState符合预期的阶段流程,如果不符则修正或重新生成。