深度挑战:设计一个具备‘自我学习能力’的 Agent,它能根据过去的失败案例自动调整未来的 Prompt 策略

各位同仁,各位技术爱好者,大家好!

今天,我们齐聚一堂,共同探讨一个充满挑战与机遇的议题:如何设计一个具备“自我学习能力”的Agent,使其能够根据过去的失败案例,自动调整未来的Prompt策略。在大型语言模型(LLM)日益普及的今天,Prompt工程的重要性不言而喻。然而,手动调整Prompt不仅效率低下,而且难以捕捉复杂场景下的细微差别。一个能够自主学习并优化的Agent,无疑将极大地提升我们与LLM交互的效率和效果。

一、引言:从静态Prompt到动态学习

在当今AI领域,大型语言模型(LLM)已经成为不可或缺的工具。它们在文本生成、代码辅助、知识问答等多个方面展现出惊人的能力。然而,LLM的性能并非一成不变,它高度依赖于我们如何“提问”,即如何构建“Prompt”。一个精心设计的Prompt能够引导LLM生成高质量、符合预期的输出,而一个不佳的Prompt则可能导致误解、偏离主题甚至“幻觉”。

传统的Prompt工程,往往是一个迭代、试错、人工优化的过程。工程师们凭借经验和直觉,不断修改Prompt的措辞、结构、示例,以期达到最佳效果。这种方法在面对少量、稳定任务时尚可接受,但当任务类型多样、场景复杂、需求动态变化时,其局限性便凸显无疑。每次失败都需要人工介入分析原因,并手动调整Prompt,这不仅耗时耗力,而且难以系统性地积累和复用经验。

我们的目标,正是要突破这种静态、人工的Prompt优化模式,构建一个能够从自身“失败”中学习的Agent。这个Agent不再是被动地执行指令,而是主动地观察、分析、反思,并根据积累的经验智能地调整其与LLM交互的策略。它将模拟人类学习和改进的过程,将每一次失败转化为下一次成功的垫脚石。

二、核心概念与Agent架构概览

要构建这样一个Agent,我们首先需要明确几个核心概念:

  1. 自我学习能力 (Self-Learning Capability):在这里,它并非指Agent具备通用人工智能意义上的自主意识或深度理解,而是特指Agent能够通过观察自身在与LLM交互过程中的表现,识别失败模式,并基于这些模式,系统性地调整其用于生成Prompt的策略。这是一种特定领域内的、目标导向的适应性行为。

  2. 失败案例 (Failure Case):什么是失败?它需要被明确定义和量化。失败可能表现为LLM输出不准确、不完整、离题、格式错误、未能满足特定约束条件等。检测失败是学习过程的第一步。

  3. Prompt策略 (Prompt Strategy):这不仅仅是单个Prompt字符串,而是一套生成Prompt的方法论和规则集。它可能包含:

    • Persona (角色):如“你是一个专业的编程专家”。
    • Task Definition (任务定义):清晰阐述LLM需要完成的具体任务。
    • Constraints (约束):对输出格式、长度、内容等的限制。
    • Examples (示例):Few-shot prompting中的输入-输出对。
    • Tone & Style (语气与风格):正式、非正式、技术化等。
    • Context (上下文):提供必要的背景信息。
    • Parameters (模型参数):如temperature, top_p, max_tokens等。

基于上述概念,我们可以勾勒出Agent的基本架构。它将是一个模块化的系统,各模块协同工作,形成一个闭环的学习过程。

Agent核心模块概览

模块名称 核心功能 关键输入 关键输出
任务调度与输入模块 接收外部任务请求,准备原始输入数据。 原始任务请求、原始输入数据 结构化任务数据
Prompt生成模块 根据当前策略和任务数据,构建LLM的Prompt。 当前Prompt策略、结构化任务数据 完整的Prompt字符串,LLM模型参数
LLM执行与响应模块 将Prompt发送给LLM,接收并记录LLM的原始响应。 Prompt字符串、LLM模型参数 LLM原始响应
结果评估与失败检测模块 对LLM响应进行评估,判断是否成功,并识别失败类型。 LLM原始响应、预期结果(或评估标准)、任务数据 评估结果(成功/失败)、失败类型、失败详情
失败分析与归因模块 深入分析失败原因,尝试定位是Prompt、LLM还是数据问题。 失败类型、LLM响应、Prompt、任务数据 失败根本原因分析、潜在的Prompt调整建议
策略学习与调整模块 根据失败分析结果,更新Prompt策略。 失败根本原因分析、当前Prompt策略 更新后的Prompt策略
经验库与记忆模块 存储所有Prompt、LLM响应、评估结果、失败案例及调整过程。 各模块生成的数据 历史数据、学习轨迹、成功/失败案例库

这个架构形成了一个反馈循环:Agent执行任务 -> 评估结果 -> 检测失败 -> 分析失败 -> 调整策略 -> 再次执行。通过不断迭代,Agent将逐步优化其Prompt策略,提高任务的成功率。

三、模块详解与代码实现

接下来,我们将深入探讨每个模块的具体实现细节,并辅以Python代码示例。

3.1 任务调度与输入模块 (Task Orchestration & Input Module)

这个模块是Agent的入口,负责接收外部的任务请求,并将其转化为Agent内部可以处理的结构化数据。

import uuid
from datetime import datetime
from typing import Dict, Any, Optional, List

class Task:
    """表示一个待处理的任务"""
    def __init__(self, task_id: str, task_type: str, input_data: Dict[str, Any],
                 expected_output: Optional[str] = None,
                 created_at: datetime = None):
        self.task_id = task_id if task_id else str(uuid.uuid4())
        self.task_type = task_type  # e.g., "summarization", "code_generation", "data_extraction"
        self.input_data = input_data  # 原始输入数据,如文章内容、需求描述等
        self.expected_output = expected_output # 可选的预期输出,用于精确评估
        self.created_at = created_at if created_at else datetime.now()
        self.status: str = "PENDING" # PENDING, PROCESSING, COMPLETED, FAILED

    def __repr__(self):
        return f"Task(id={self.task_id}, type={self.task_type}, status={self.status})"

class TaskScheduler:
    """管理任务的调度和基本状态"""
    def __init__(self):
        self.tasks: Dict[str, Task] = {}

    def add_task(self, task_type: str, input_data: Dict[str, Any], expected_output: Optional[str] = None) -> Task:
        task = Task(task_id=None, task_type=task_type, input_data=input_data, expected_output=expected_output)
        self.tasks[task.task_id] = task
        print(f"任务 {task.task_id} 已添加。")
        return task

    def get_task(self, task_id: str) -> Optional[Task]:
        return self.tasks.get(task_id)

    def update_task_status(self, task_id: str, status: str):
        if task_id in self.tasks:
            self.tasks[task_id].status = status

示例用法:

# scheduler = TaskScheduler()
# task_data = {"text": "这是一篇关于人工智能发展前景的文章。", "length": "short"}
# new_task = scheduler.add_task(task_type="summarization", input_data=task_data, expected_output="人工智能在未来具有广阔前景。")

3.2 经验库与记忆模块 (Experience & Memory Module)

这个模块是Agent的“大脑”和“历史记录”,存储了Agent与LLM交互的所有重要信息,包括原始Prompt、LLM响应、评估结果、失败详情以及策略调整过程。这对于后续的失败分析和策略学习至关重要。

class FailureCase:
    """记录一次失败的Prompt交互"""
    def __init__(self,
                 case_id: str,
                 task_id: str,
                 timestamp: datetime,
                 original_prompt: str,
                 llm_response: str,
                 expected_output: Optional[str],
                 failure_type: str, # e.g., "INCORRECT_CONTENT", "INCOMPLETE", "OFF_TOPIC", "FORMAT_ERROR"
                 analysis: str, # 失败原因的文字描述
                 suggested_adjustments: List[str], # 建议的调整方向,如"ADD_CONSTRAINT", "CHANGE_PERSONA"
                 adjusted_prompt_attempt: Optional[str] = None, # 实际尝试调整后的Prompt
                 adjusted_response: Optional[str] = None, # 尝试调整后LLM的响应
                 is_successful_adjustment: Optional[bool] = None # 调整是否成功
                ):
        self.case_id = case_id if case_id else str(uuid.uuid4())
        self.task_id = task_id
        self.timestamp = timestamp
        self.original_prompt = original_prompt
        self.llm_response = llm_response
        self.expected_output = expected_output
        self.failure_type = failure_type
        self.analysis = analysis
        self.suggested_adjustments = suggested_adjustments
        self.adjusted_prompt_attempt = adjusted_prompt_attempt
        self.adjusted_response = adjusted_response
        self.is_successful_adjustment = is_successful_adjustment

    def __repr__(self):
        return f"FailureCase(id={self.case_id}, task={self.task_id}, type={self.failure_type}, success_adj={self.is_successful_adjustment})"

class PromptStrategy:
    """定义一个Prompt策略,包含多个可调整的元素"""
    def __init__(self, name: str = "default_strategy"):
        self.name = name
        self.persona: str = "你是一个严谨的AI助手。"
        self.task_description_template: str = "请根据以下内容完成任务:{task_input}。"
        self.constraints: List[str] = [] # 如 "输出格式为JSON", "长度不超过200字"
        self.examples: List[Dict[str, str]] = [] # few-shot examples
        self.tone: str = "neutral" # neutral, formal, informal
        self.model_params: Dict[str, Any] = {
            "temperature": 0.7,
            "max_tokens": 500,
            "top_p": 1.0
        }
        self.meta_instructions: List[str] = [] # 对LLM的额外指导,如“请思考后给出答案”

    def to_dict(self):
        return {
            "name": self.name,
            "persona": self.persona,
            "task_description_template": self.task_description_template,
            "constraints": self.constraints,
            "examples": self.examples,
            "tone": self.tone,
            "model_params": self.model_params,
            "meta_instructions": self.meta_instructions
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]):
        strategy = cls(data.get("name", "default_strategy"))
        strategy.persona = data.get("persona", strategy.persona)
        strategy.task_description_template = data.get("task_description_template", strategy.task_description_template)
        strategy.constraints = data.get("constraints", strategy.constraints)
        strategy.examples = data.get("examples", strategy.examples)
        strategy.tone = data.get("tone", strategy.tone)
        strategy.model_params = data.get("model_params", strategy.model_params)
        strategy.meta_instructions = data.get("meta_instructions", strategy.meta_instructions)
        return strategy

class ExperienceDB:
    """存储Agent的所有经验和Prompt策略"""
    def __init__(self):
        self.failure_cases: Dict[str, FailureCase] = {}
        self.prompt_strategies: Dict[str, PromptStrategy] = {"default": PromptStrategy()}

    def add_failure_case(self, failure_case: FailureCase):
        self.failure_cases[failure_case.case_id] = failure_case
        print(f"失败案例 {failure_case.case_id} 已记录。")

    def get_failure_cases_by_type(self, failure_type: str) -> List[FailureCase]:
        return [case for case in self.failure_cases.values() if case.failure_type == failure_type]

    def get_recent_failure_cases(self, limit: int = 10) -> List[FailureCase]:
        sorted_cases = sorted(self.failure_cases.values(), key=lambda x: x.timestamp, reverse=True)
        return sorted_cases[:limit]

    def update_strategy(self, strategy_name: str, new_strategy: PromptStrategy):
        self.prompt_strategies[strategy_name] = new_strategy
        print(f"策略 '{strategy_name}' 已更新。")

    def get_strategy(self, strategy_name: str) -> Optional[PromptStrategy]:
        return self.prompt_strategies.get(strategy_name)

    # 实际应用中,这里需要加入持久化存储(如数据库、文件)的逻辑

3.3 Prompt生成模块 (Prompt Generation Module)

该模块负责根据当前任务的输入数据和Agent当前的Prompt策略,动态地构建发送给LLM的完整Prompt字符串。

class PromptGenerator:
    """根据Prompt策略和任务数据生成Prompt"""
    def __init__(self, experience_db: ExperienceDB):
        self.experience_db = experience_db

    def generate_prompt(self, task: Task, strategy_name: str = "default") -> (str, Dict[str, Any]):
        strategy = self.experience_db.get_strategy(strategy_name)
        if not strategy:
            raise ValueError(f"Prompt strategy '{strategy_name}' not found.")

        # 1. 构建角色和元指令
        prompt_parts = [f"你是一个{strategy.persona.strip()}。"]
        if strategy.meta_instructions:
            prompt_parts.extend(strategy.meta_instructions)

        # 2. 添加Few-shot示例 (如果存在)
        if strategy.examples:
            prompt_parts.append("n以下是一些输入和预期输出的示例:")
            for example in strategy.examples:
                prompt_parts.append(f"输入: {example['input']}n输出: {example['output']}")

        # 3. 添加任务描述和输入数据
        task_input_str = self._format_task_input(task.input_data)
        prompt_parts.append(strategy.task_description_template.format(task_input=task_input_str))

        # 4. 添加约束条件
        if strategy.constraints:
            prompt_parts.append("n请严格遵守以下约束:")
            for constraint in strategy.constraints:
                prompt_parts.append(f"- {constraint}")

        # 5. 调整语气
        if strategy.tone != "neutral":
            prompt_parts.append(f"n请以{strategy.tone}的语气进行回应。")

        final_prompt = "nn".join(prompt_parts).strip()
        return final_prompt, strategy.model_params

    def _format_task_input(self, input_data: Dict[str, Any]) -> str:
        """根据输入数据类型进行格式化,使其适合作为Prompt的一部分"""
        formatted_parts = []
        for key, value in input_data.items():
            if isinstance(value, str):
                formatted_parts.append(f"{key}: """{value}"""") # 使用三引号避免冲突
            elif isinstance(value, (int, float, bool)):
                formatted_parts.append(f"{key}: {value}")
            elif isinstance(value, (list, dict)):
                formatted_parts.append(f"{key}:n{json.dumps(value, indent=2)}") # JSON格式化
            else:
                formatted_parts.append(f"{key}: {value}")
        return "n".join(formatted_parts)

3.4 LLM执行与响应模块 (LLM Execution & Response Module)

此模块负责与实际的LLM API进行交互,发送生成的Prompt并接收响应。为了保持通用性,这里使用一个抽象接口。

import openai # 假设使用OpenAI API
import json

class LLMClient:
    """抽象的LLM客户端接口"""
    def __init__(self, api_key: str, model_name: str = "gpt-4"):
        self.api_key = api_key
        self.model_name = model_name
        # openai.api_key = api_key # 实际使用时设置

    def generate_response(self, prompt: str, model_params: Dict[str, Any]) -> str:
        """
        发送Prompt给LLM并获取响应。
        这是一个模拟实现,实际会调用OpenAI或其他LLM提供商的API。
        """
        print(f"n--- 发送Prompt给LLM ---")
        print(f"Prompt:n{prompt[:200]}...") # 打印部分Prompt
        print(f"Model Params: {model_params}")
        try:
            # 模拟LLM API调用
            # response = openai.chat.completions.create(
            #     model=self.model_name,
            #     messages=[{"role": "user", "content": prompt}],
            #     temperature=model_params.get("temperature", 0.7),
            #     max_tokens=model_params.get("max_tokens", 500),
            #     top_p=model_params.get("top_p", 1.0),
            #     # ... 其他参数
            # )
            # llm_response_content = response.choices[0].message.content

            # 模拟响应,实际应从LLM获取
            simulated_responses = {
                "summarization_success": "这是一篇关于人工智能的短摘要,强调了其未来发展潜力。",
                "summarization_incomplete": "人工智能...", # 模拟不完整
                "summarization_off_topic": "今天天气真好,适合出去玩。", # 模拟离题
                "code_generation_error": "def func(a,b):n    return a + b",
                "json_format_error": "{'name': 'test', 'value': 10" # 模拟JSON格式错误
            }
            # 简化模拟逻辑,实际需要更复杂的判断或根据任务类型返回特定模拟结果
            if "summarization" in prompt.lower() and "人工智能" in prompt.lower():
                if "长度不超过200字" in prompt and model_params.get("temperature", 0.7) < 0.5:
                    llm_response_content = simulated_responses["summarization_success"]
                elif "所有要点" in prompt and model_params.get("max_tokens", 500) < 100:
                     llm_response_content = simulated_responses["summarization_incomplete"]
                else:
                    llm_response_content = simulated_responses["summarization_off_topic"] # 默认给个错误响应
            elif "json" in prompt.lower():
                llm_response_content = simulated_responses["json_format_error"]
            else:
                llm_response_content = "这是一个模拟的LLM响应,表示任务已完成。"

            print(f"LLM Response:n{llm_response_content[:200]}...")
            return llm_response_content
        except Exception as e:
            print(f"LLM调用失败: {e}")
            return f"ERROR: {str(e)}"

3.5 结果评估与失败检测模块 (Result Evaluation & Failure Detection Module)

这是Agent实现自我学习的关键环节。它需要根据LLM的响应和预设的评估标准,判断任务是否成功,并识别失败的类型。

失败类型定义:

失败类型 描述 检测方法示例 调整方向建议 (供学习模块参考)
INCORRECT_CONTENT LLM输出内容与预期不符或事实错误。 关键词匹配、语义相似度比较 (Embedding)、外部知识库验证、人工校验。 增加约束、明确任务、提供更多示例、调整Persona、引入外部工具。
INCOMPLETE LLM输出遗漏了关键信息或部分内容。 检查特定关键词/实体缺失、长度检查、结构完整性检查。 增加“确保完整性”约束、增加max_tokens、提供完整示例。
OFF_TOPIC LLM输出偏离了任务主题。 语义相似度与任务描述比较、关键词检测。 明确任务范围、增强Persona职责、减少temperature
FORMAT_ERROR LLM输出格式不正确 (如JSON、Markdown、代码结构)。 正则表达式匹配、JSON解析失败、代码编译错误。 增加格式约束、提供格式化示例、使用更明确的格式指令。
AMBIGUOUS_RESPONSE LLM输出过于模糊、笼统,缺乏特异性。 检查特定关键词缺失、长度过短、通用性词汇过多。 增加“具体化”约束、要求给出细节、提供具体示例。
SAFETY_VIOLATION LLM输出包含不安全、有害或偏见内容。 内容审核API、关键词过滤、自定义规则。 增加安全约束、调整Persona、模型参数调整。
TOO_LONG LLM输出长度超过预期。 字符/词计数。 增加长度约束、调整max_tokens
import re
from sentence_transformers import SentenceTransformer, util
import numpy as np

# 假设使用一个预训练的Sentence Transformer模型进行语义相似度检测
# model = SentenceTransformer('all-MiniLM-L6-v2') # 实际应用中会加载
class SemanticSimilarityDetector:
    def __init__(self, model_name='all-MiniLM-L6-v2'):
        try:
            self.model = SentenceTransformer(model_name)
        except Exception as e:
            print(f"无法加载SentenceTransformer模型 {model_name}: {e}. 语义相似度检测将不可用。")
            self.model = None

    def get_embedding(self, text: str) -> Optional[np.ndarray]:
        if self.model:
            return self.model.encode(text, convert_to_tensor=True)
        return None

    def calculate_similarity(self, text1: str, text2: str) -> float:
        if self.model:
            embedding1 = self.get_embedding(text1)
            embedding2 = self.get_embedding(text2)
            if embedding1 is not None and embedding2 is not None:
                return util.pytorch_cos_sim(embedding1, embedding2).item()
        return 0.0 # 如果模型不可用,返回0

# semantic_detector = SemanticSimilarityDetector() # 实例化一次

class ResultEvaluator:
    """评估LLM响应,检测失败类型"""
    def __init__(self, semantic_detector: SemanticSimilarityDetector):
        self.semantic_detector = semantic_detector

    def evaluate_response(self, task: Task, llm_response: str, prompt: str) -> Dict[str, Any]:
        evaluation_result = {
            "is_success": True,
            "failure_type": None,
            "details": {}
        }

        # 1. 检查响应是否为空或错误
        if not llm_response or llm_response.startswith("ERROR:"):
            evaluation_result["is_success"] = False
            evaluation_result["failure_type"] = "LLM_ERROR"
            evaluation_result["details"]["message"] = llm_response
            return evaluation_result

        # 2. 根据任务类型和Prompt策略进行特定评估

        # 示例1: 总结任务 (summarization)
        if task.task_type == "summarization":
            # 检查是否离题 (OFF_TOPIC) - 简单关键词匹配或语义相似度
            original_text = task.input_data.get("text", "")
            if not any(keyword in llm_response for keyword in ["人工智能", "发展", "前景"]) and "人工智能" in original_text:
                if self.semantic_detector and self.semantic_detector.calculate_similarity(original_text, llm_response) < 0.3:
                    evaluation_result["is_success"] = False
                    evaluation_result["failure_type"] = "OFF_TOPIC"
                    evaluation_result["details"]["reason"] = "响应内容与原文主题不符或相关性低。"
                    return evaluation_result

            # 检查是否不完整 (INCOMPLETE) - 简单长度或关键词检查
            if "长度不超过" in prompt:
                max_len_match = re.search(r"长度不超过(d+)字", prompt)
                if max_len_match:
                    max_len = int(max_len_match.group(1))
                    if len(llm_response) > max_len * 1.2: # 允许少量浮动
                        evaluation_result["is_success"] = False
                        evaluation_result["failure_type"] = "TOO_LONG"
                        evaluation_result["details"]["reason"] = f"响应长度 ({len(llm_response)}字) 超过预期 ({max_len}字)。"
                        return evaluation_result

            # 检查是否包含预期的关键信息 (INCORRECT_CONTENT/INCOMPLETE)
            if task.expected_output and not self.semantic_detector.calculate_similarity(llm_response, task.expected_output) > 0.7:
                 evaluation_result["is_success"] = False
                 evaluation_result["failure_type"] = "INCORRECT_CONTENT"
                 evaluation_result["details"]["reason"] = "响应内容与预期输出的语义相似度过低。"
                 return evaluation_result

        # 示例2: JSON数据提取任务
        if "json" in prompt.lower() or "输出格式为JSON" in prompt:
            try:
                json.loads(llm_response)
            except json.JSONDecodeError:
                evaluation_result["is_success"] = False
                evaluation_result["failure_type"] = "FORMAT_ERROR"
                evaluation_result["details"]["reason"] = "响应不是有效的JSON格式。"
                return evaluation_result

        # 3. 兜底检查: 如果有明确的expected_output,进行精确匹配或高相似度匹配
        if task.expected_output:
            if llm_response.strip() != task.expected_output.strip():
                # 可以进一步细化是内容错误还是格式错误
                if self.semantic_detector and self.semantic_detector.calculate_similarity(llm_response, task.expected_output) < 0.8:
                    evaluation_result["is_success"] = False
                    evaluation_result["failure_type"] = "INCORRECT_CONTENT"
                    evaluation_result["details"]["reason"] = "响应内容与预期输出不符。"
                    return evaluation_result
                elif re.sub(r's+', '', llm_response) != re.sub(r's+', '', task.expected_output):
                    evaluation_result["is_success"] = False
                    evaluation_result["failure_type"] = "FORMAT_ERROR"
                    evaluation_result["details"]["reason"] = "响应格式与预期输出不符。"
                    return evaluation_result

        return evaluation_result

3.6 失败分析与归因模块 (Failure Analysis & Attribution Module)

当检测到失败时,仅仅知道失败类型是不够的,还需要分析“为什么”会失败。这个模块的目标是深入挖掘失败的根本原因,并提出针对性的Prompt调整建议。这通常是一个启发式规则、模式匹配和甚至Meta-Prompting(使用另一个LLM来分析)的结合。

class FailureAnalyzer:
    """分析失败案例,归因原因并提出调整建议"""
    def __init__(self, llm_client: LLMClient):
        self.llm_client = llm_client # 可以用一个更强大的LLM来做分析

    def analyze_failure(self, failure_case: FailureCase, prompt_strategy: PromptStrategy) -> Dict[str, Any]:
        analysis_result = {
            "root_cause": "未知原因",
            "suggested_adjustments": []
        }

        # 1. 基于失败类型进行启发式分析
        if failure_case.failure_type == "OFF_TOPIC":
            analysis_result["root_cause"] = "LLM理解任务范围不明确或被输入中的无关信息干扰。"
            analysis_result["suggested_adjustments"].append("CLARIFY_TASK_SCOPE")
            analysis_result["suggested_adjustments"].append("ADD_NEGATIVE_CONSTRAINTS") # 避免什么
            if prompt_strategy.model_params.get("temperature", 0.7) > 0.5:
                 analysis_result["suggested_adjustments"].append("DECREASE_TEMPERATURE")

        elif failure_case.failure_type == "INCOMPLETE":
            analysis_result["root_cause"] = "LLM在生成过程中提前停止或遗漏了关键信息。"
            analysis_result["suggested_adjustments"].append("ENSURE_COMPLETENESS_CONSTRAINT")
            if prompt_strategy.model_params.get("max_tokens", 500) < 1000:
                analysis_result["suggested_adjustments"].append("INCREASE_MAX_TOKENS")
            analysis_result["suggested_adjustments"].append("ADD_MORE_DETAILS_REQUEST")

        elif failure_case.failure_type == "FORMAT_ERROR":
            analysis_result["root_cause"] = "LLM未能严格遵循输出格式要求。"
            analysis_result["suggested_adjustments"].append("STRICT_FORMAT_CONSTRAINT")
            analysis_result["suggested_adjustments"].append("ADD_FORMAT_EXAMPLE")
            analysis_result["suggested_adjustments"].append("CHANGE_PERSONA_TO_STRICT_ENGINEER")

        elif failure_case.failure_type == "INCORRECT_CONTENT":
            analysis_result["root_cause"] = "LLM理解输入有误、知识不足或存在幻觉。"
            analysis_result["suggested_adjustments"].append("PROVIDE_MORE_CONTEXT")
            analysis_result["suggested_adjustments"].append("ADD_FEW_SHOT_EXAMPLES")
            analysis_result["suggested_adjustments"].append("ADJUST_PERSONA_FOR_ACCURACY")
            if prompt_strategy.model_params.get("temperature", 0.7) > 0.5:
                 analysis_result["suggested_adjustments"].append("DECREASE_TEMPERATURE")

        elif failure_case.failure_type == "TOO_LONG":
            analysis_result["root_cause"] = "LLM生成内容超出了期望的长度限制。"
            analysis_result["suggested_adjustments"].append("STRICT_LENGTH_CONSTRAINT")
            analysis_result["suggested_adjustments"].append("DECREASE_MAX_TOKENS_PARAM")
            analysis_result["suggested_adjustments"].append("ADD_CONCISE_TONE_INSTRUCTION")

        # 2. (高级) 使用LLM进行Meta-Prompting分析
        # 我们可以构建一个Prompt,让LLM自己分析为什么另一个LLM会失败
        try:
            meta_prompt = f"""
            你是一个Prompt工程专家。我提供一个失败的LLM任务案例。
            请分析原始Prompt、LLM的响应、预期输出以及失败类型,然后给出具体的Prompt调整建议。

            --- 失败案例 ---
            任务ID: {failure_case.task_id}
            失败类型: {failure_case.failure_type}
            原始Prompt:
        {failure_case.original_prompt}
        ```
        LLM响应:
        ```
        {failure_case.llm_response}
        ```
        预期输出 (如果存在):
        ```
        {failure_case.expected_output if failure_case.expected_output else 'N/A'}
        ```
        失败详情: {failure_case.analysis}

        --- 分析与建议 ---
        请分析以下问题:
        1. 失败的根本原因可能是什么?
        2. 针对这个失败,可以采取哪些具体的Prompt调整策略?请列出3-5条,例如:
           - 增加或修改Persona
           - 添加或修改约束条件
           - 增加Few-shot示例
           - 调整模型参数 (如temperature, max_tokens)
           - 修改任务描述的措辞
           - 增加元指令(如“请一步步思考”)
        请以JSON格式返回分析结果:
        {{
            "root_cause_llm_analysis": "...",
            "suggested_adjustments_llm": ["adjustment1", "adjustment2", ...]
        }}
        """
        # meta_llm_response = self.llm_client.generate_response(meta_prompt, {"temperature": 0.3, "max_tokens": 500})
        # 模拟meta LLM响应
        meta_llm_response = json.dumps({
            "root_cause_llm_analysis": f"LLM可能未能充分理解'{failure_case.failure_type}'失败的语境,导致输出偏离。",
            "suggested_adjustments_llm": [
                f"针对'{failure_case.failure_type}',强化相关约束",
                "在Prompt中明确指出需要避免的错误类型",
                "提供更多高质量的成功示例"
            ]
        })

        meta_analysis = json.loads(meta_llm_response)
        analysis_result["root_cause"] += " (LLM分析: " + meta_analysis.get("root_cause_llm_analysis", "") + ")"
        analysis_result["suggested_adjustments"].extend(meta_analysis.get("suggested_adjustments_llm", []))

    except Exception as e:
        print(f"Meta-Prompting分析失败: {e}")

    # 去重和清理建议
    analysis_result["suggested_adjustments"] = list(set(analysis_result["suggested_adjustments"]))
    return analysis_result

#### 3.7 策略学习与调整模块 (Strategy Learning & Adjustment Module)

这是Agent的核心智能所在,负责根据失败分析结果,更新并优化Agent的Prompt策略。

```python
class StrategyLearner:
    """根据失败分析结果,更新Prompt策略"""
    def __init__(self, experience_db: ExperienceDB):
        self.experience_db = experience_db

    def adjust_strategy(self, task_type: str, failure_analysis: Dict[str, Any], current_strategy: PromptStrategy) -> PromptStrategy:
        new_strategy = current_strategy.from_dict(current_strategy.to_dict()) # 创建副本进行修改
        suggested_adjustments = failure_analysis["suggested_adjustments"]

        print(f"--- 正在调整策略 '{new_strategy.name}' ---")
        print(f"原始策略参数: Temperature={new_strategy.model_params['temperature']}, Max_Tokens={new_strategy.model_params['max_tokens']}")

        # 1. 应用具体的调整建议
        for adjustment in suggested_adjustments:
            if adjustment == "CLARIFY_TASK_SCOPE":
                if "明确任务范围" not in new_strategy.constraints:
                    new_strategy.constraints.append("请严格限定在任务描述的范围内,不要发散。")
            elif adjustment == "ADD_NEGATIVE_CONSTRAINTS":
                if "避免无关信息" not in new_strategy.constraints:
                    new_strategy.constraints.append("输出中不应包含任何与主题无关的背景信息。")
            elif adjustment == "DECREASE_TEMPERATURE":
                # 降低temperature以减少随机性,使其更聚焦
                new_strategy.model_params["temperature"] = max(0.1, new_strategy.model_params.get("temperature", 0.7) - 0.1)
            elif adjustment == "ENSURE_COMPLETENESS_CONSTRAINT":
                if "确保所有关键信息完整" not in new_strategy.constraints:
                    new_strategy.constraints.append("请确保输出涵盖所有关键信息,不要遗漏。")
            elif adjustment == "INCREASE_MAX_TOKENS":
                new_strategy.model_params["max_tokens"] = min(4000, new_strategy.model_params.get("max_tokens", 500) + 200)
            elif adjustment == "ADD_MORE_DETAILS_REQUEST":
                if "请详细阐述" not in new_strategy.meta_instructions:
                    new_strategy.meta_instructions.append("请尽可能详细地阐述所有相关细节。")
            elif adjustment == "STRICT_FORMAT_CONSTRAINT":
                if "严格遵循指定格式" not in new_strategy.constraints:
                    new_strategy.constraints.append("请严格遵循指定的输出格式,不得有任何偏差。")
            elif adjustment == "ADD_FORMAT_EXAMPLE":
                # 这是一个复杂的操作,可能需要从历史成功案例中提取或根据规则生成
                # 简化处理:暂时只添加一个通用提示
                if "请参考以下格式示例" not in new_strategy.meta_instructions:
                     new_strategy.meta_instructions.append("请参考以下格式示例:[具体的格式示例]") # 实际需要动态生成或查找
            elif adjustment == "CHANGE_PERSONA_TO_STRICT_ENGINEER":
                new_strategy.persona = "你是一个严谨且注重细节的工程师AI助手。"
            elif adjustment == "PROVIDE_MORE_CONTEXT":
                # 这通常意味着原始输入数据可能不足,但Prompt策略可以加入引导LLM要求更多上下文的指令
                if "如果信息不足,请明确指出" not in new_strategy.meta_instructions:
                    new_strategy.meta_instructions.append("如果当前输入不足以完成任务,请明确指出还缺少哪些信息。")
            elif adjustment == "ADD_FEW_SHOT_EXAMPLES":
                # 动态添加few-shot示例,这需要从经验库中查找相关成功案例
                if len(new_strategy.examples) < 3: # 限制few-shot数量
                    # 简化:假设我们有一些预设的成功示例可以加入
                    # 实际需要从experience_db中根据task_type和成功案例动态选择
                    if task_type == "summarization" and {"input": "地球是蓝色的。", "output": "地球是一个蓝色的星球。"} not in new_strategy.examples:
                        new_strategy.examples.append({"input": "地球是蓝色的。", "output": "地球是一个蓝色的星球。"})
            elif adjustment == "ADJUST_PERSONA_FOR_ACCURACY":
                new_strategy.persona = "你是一个专注于准确性和事实核查的AI助手。"
            elif adjustment == "STRICT_LENGTH_CONSTRAINT":
                if "请严格控制输出长度" not in new_strategy.constraints:
                    new_strategy.constraints.append("请严格控制输出长度,力求简洁。")
            elif adjustment == "DECREASE_MAX_TOKENS_PARAM":
                new_strategy.model_params["max_tokens"] = max(50, new_strategy.model_params.get("max_tokens", 500) - 100)
            elif adjustment == "ADD_CONCISE_TONE_INSTRUCTION":
                new_strategy.tone = "concise"
            # LLM生成的更具体的调整建议
            elif adjustment.startswith("针对") and "强化相关约束" in adjustment:
                if "针对当前任务的特定约束已强化" not in new_strategy.constraints:
                    new_strategy.constraints.append("针对当前任务的特定约束已强化。") # 这是一个通用标记
            elif adjustment.startswith("在Prompt中明确指出需要避免的错误类型"):
                 if "避免出现与历史失败案例相似的错误" not in new_strategy.meta_instructions:
                    new_strategy.meta_instructions.append("请务必避免出现与历史失败案例相似的错误。")
            elif adjustment.startswith("提供更多高质量的成功示例"):
                if len(new_strategy.examples) < 5: # 再次尝试添加更多示例
                    if task_type == "summarization" and {"input": "太阳是恒星。", "output": "太阳是一颗恒星。"} not in new_strategy.examples:
                        new_strategy.examples.append({"input": "太阳是恒星。", "output": "太阳是一颗恒星。"})

        print(f"调整后的策略参数: Temperature={new_strategy.model_params['temperature']}, Max_Tokens={new_strategy.model_params['max_tokens']}")
        return new_strategy

3.8 自我学习Agent的整体协调器 (Self-Learning Agent Orchestrator)

最后,我们将所有模块整合起来,构建Agent的主循环和协调逻辑。

class SelfLearningAgent:
    def __init__(self, api_key: str, llm_model_name: str = "gpt-4"):
        self.experience_db = ExperienceDB()
        self.llm_client = LLMClient(api_key, llm_model_name)
        self.prompt_generator = PromptGenerator(self.experience_db)
        self.semantic_detector = SemanticSimilarityDetector() # 实例化语义检测器
        self.evaluator = ResultEvaluator(self.semantic_detector)
        self.analyzer = FailureAnalyzer(self.llm_client) # analyzer也可以使用LLMClient进行meta-prompting
        self.learner = StrategyLearner(self.experience_db)
        self.task_scheduler = TaskScheduler()

        # 初始化默认策略
        self.experience_db.update_strategy("default", PromptStrategy(name="default"))
        # 针对不同任务类型,可以有不同的初始策略
        self.experience_db.update_strategy("summarization", PromptStrategy(name="summarization_strategy", persona="你是一个专业的文章总结者。"))
        self.experience_db.update_strategy("json_extraction", PromptStrategy(name="json_extraction_strategy", persona="你是一个数据提取专家。", constraints=["输出必须是有效的JSON格式。"]))

    def run_task_with_learning(self, task: Task, strategy_name: str = "default", attempt: int = 1) -> str:
        current_strategy = self.experience_db.get_strategy(strategy_name)
        if not current_strategy:
            print(f"未找到策略 '{strategy_name}',使用默认策略。")
            current_strategy = self.experience_db.get_strategy("default")

        print(f"n--- 执行任务 {task.task_id} (尝试 {attempt}) ---")
        self.task_scheduler.update_task_status(task.task_id, "PROCESSING")

        # 1. 生成Prompt
        prompt, model_params = self.prompt_generator.generate_prompt(task, current_strategy.name)

        # 2. 执行LLM并获取响应
        llm_response = self.llm_client.generate_response(prompt, model_params)

        # 3. 评估结果
        evaluation_result = self.evaluator.evaluate_response(task, llm_response, prompt)

        if evaluation_result["is_success"]:
            print(f"任务 {task.task_id} 成功完成!")
            self.task_scheduler.update_task_status(task.task_id, "COMPLETED")
            # 记录成功案例 (可选,但在更复杂的RL场景下有用)
            # 也可以更新策略,比如增加该策略的权重
            return llm_response
        else:
            print(f"任务 {task.task_id} 失败:{evaluation_result['failure_type']}")

            # 4. 记录失败案例
            failure_case = FailureCase(
                case_id=None,
                task_id=task.task_id,
                timestamp=datetime.now(),
                original_prompt=prompt,
                llm_response=llm_response,
                expected_output=task.expected_output,
                failure_type=evaluation_result["failure_type"],
                analysis=evaluation_result["details"].get("reason", "未知原因"),
                suggested_adjustments=[] # 初始为空,稍后分析填充
            )

            # 5. 分析失败并提出调整建议
            failure_analysis = self.analyzer.analyze_failure(failure_case, current_strategy)
            failure_case.analysis = failure_analysis["root_cause"]
            failure_case.suggested_adjustments = failure_analysis["suggested_adjustments"]
            self.experience_db.add_failure_case(failure_case)

            # 6. 调整策略
            new_strategy = self.learner.adjust_strategy(task.task_type, failure_analysis, current_strategy)
            self.experience_db.update_strategy(strategy_name, new_strategy) # 更新当前策略

            # 7. 尝试使用新策略重试 (或在下一轮任务中应用)
            if attempt < 3: # 最多重试3次
                print(f"正在使用调整后的策略重试任务 {task.task_id}...")
                return self.run_task_with_learning(task, strategy_name, attempt + 1)
            else:
                print(f"任务 {task.task_id} 经过多次尝试仍失败。将任务标记为失败。")
                self.task_scheduler.update_task_status(task.task_id, "FAILED")
                return f"最终失败:{evaluation_result['failure_type']}"

    def get_current_strategy(self, strategy_name: str = "default") -> PromptStrategy:
        return self.experience_db.get_strategy(strategy_name)

# --- 运行示例 ---
# if __name__ == "__main__":
#     # 实例化Agent
#     agent = SelfLearningAgent(api_key="sk-YOUR_OPENAI_API_KEY") # 实际使用时请替换API Key

#     # 定义一个总结任务,期望输出是简短的
#     task1_input = {"text": "人工智能是计算机科学的一个分支,它试图让机器像人类一样思考和学习。近年来,随着深度学习和大数据技术的发展,人工智能取得了突破性进展,在图像识别、自然语言处理、自动驾驶等领域展现出巨大潜力。未来,人工智能有望在医疗、教育、金融等行业带来深刻变革,但也面临伦理、就业等挑战。", "length": "short"}
#     task1 = agent.task_scheduler.add_task(task_type="summarization", input_data=task1_input, expected_output="人工智能在深度学习和大数据驱动下取得突破,未来将在多领域带来变革,但也面临挑战。")

#     # 运行任务,观察Agent如何学习和调整
#     print("n--- 第一次运行任务 ---")
#     final_response1 = agent.run_task_with_learning(task1, strategy_name="summarization_strategy")
#     print(f"n任务 {task1.task_id} 最终响应: {final_response1}")

#     print("n--- 观察调整后的策略 ---")
#     current_summarization_strategy = agent.get_current_strategy("summarization_strategy")
#     print(f"总结策略当前的约束: {current_summarization_strategy.constraints}")
#     print(f"总结策略当前的温度: {current_summarization_strategy.model_params['temperature']}")
#     print(f"总结策略当前的最大tokens: {current_summarization_strategy.model_params['max_tokens']}")

#     # 定义一个需要JSON格式输出的任务
#     task2_input = {"text": "请提取以下文本中的人名和公司名:'张三在腾讯工作,李四在阿里巴巴。'"}
#     task2 = agent.task_scheduler.add_task(task_type="json_extraction", input_data=task2_input, expected_output='{"persons": ["张三", "李四"], "companies": ["腾讯", "阿里巴巴"]}')

#     print("n--- 第二次运行任务 (JSON提取) ---")
#     final_response2 = agent.run_task_with_learning(task2, strategy_name="json_extraction_strategy")
#     print(f"n任务 {task2.task_id} 最终响应: {final_response2}")

#     print("n--- 再次观察调整后的策略 (JSON提取) ---")
#     current_json_strategy = agent.get_current_strategy("json_extraction_strategy")
#     print(f"JSON提取策略当前的约束: {current_json_strategy.constraints}")
#     print(f"JSON提取策略当前的Persona: {current_json_strategy.persona}")

运行示例的预期行为:

  1. 第一次运行 task1 (总结任务):
    • 初始策略可能导致LLM响应不符合“长度短”或“关键信息完整”的预期,被ResultEvaluator标记为TOO_LONGINCOMPLETE
    • FailureAnalyzer分析原因,并建议如“增加长度约束”、“增加max_tokens”或“降低temperature”。
    • StrategyLearner根据建议调整summarization_strategy,例如降低temperature、增加max_tokens(如果之前太小)或添加新的长度约束。
    • Agent使用新策略重试。如果重试成功,则任务完成。如果重试仍失败,则再次调整策略,直到达到重试上限。
  2. 第二次运行 task2 (JSON提取任务):
    • 初始策略可能导致LLM输出的JSON格式不正确,被ResultEvaluator标记为FORMAT_ERROR
    • FailureAnalyzer分析原因,并建议如“增加严格格式约束”、“改变Persona为严谨工程师”、“添加格式示例”。
    • StrategyLearner调整json_extraction_strategy,可能将persona改为“严谨且注重细节的工程师AI助手”,并添加更明确的格式约束。
    • Agent使用新策略重试,有望获得正确的JSON输出。

通过这样的循环,Agent能够根据实际交互的反馈,不断迭代和优化其Prompt策略,从而提升其在各类任务中的表现。

四、挑战与考量

设计一个自我学习的Prompt Agent,虽然前景广阔,但同样面临诸多挑战:

  1. 失败定义的精度与量化:对于开放性任务,如何精确定义“成功”与“失败”?人工评估标准(如BLEU、ROUGE)往往不能完全捕捉语义的细微差别。自动化评估器自身的准确性也需要保证,否则可能导致错误的学习方向。
  2. 失败归因的复杂性:LLM的失败可能由多种因素引起:Prompt本身、LLM模型自身的局限性、输入数据质量、甚至模型推理时的随机性。准确归因是调整策略的前提,但往往是“牵一发而动全身”的难题。Meta-Prompting虽然有帮助,但其自身也依赖于LLM的理解能力。
  3. 策略调整的粒度与泛化能力:调整Prompt策略时,是应该针对特定任务进行微调,还是寻求更通用的调整?过度细致的调整可能导致过拟合,使Agent在新任务上表现不佳;而过于粗糙的调整则可能无法解决具体问题。如何平衡“探索”与“利用”是一个经典的强化学习问题。
  4. 计算资源与成本:每一次失败的检测、分析、策略调整,都可能涉及额外的LLM调用,这会显著增加计算成本和延迟。如何设计高效的学习循环,尤其是在资源受限的环境下,是一个实际问题。
  5. 知识表示与更新:如何有效地存储和检索历史经验?如何将失败案例转化为可操作的、可复用的Prompt调整规则或参数?随着经验的累积,知识库的维护和冲突解决也将成为挑战。
  6. 人类在环 (Human-in-the-Loop):在Agent早期学习阶段,人类的监督和纠正至关重要。Agent何时需要寻求人类帮助?人类如何有效地提供反馈?这需要良好的人机交互界面和流程。
  7. 迭代速度与收敛性:Agent需要多少次失败才能学会一个有效的策略?学习过程是否稳定?是否会陷入局部最优?这些都是衡量Agent效能的重要指标。

五、未来展望

展望未来,自我学习的Prompt Agent将沿着以下几个方向持续演进:

  1. 更智能的失败归因:结合因果推理、可解释AI技术,更精确地定位失败的根本原因,区分是Prompt问题、模型知识问题还是推理路径问题。
  2. 强化学习与元学习:将Prompt策略的调整视为一个强化学习问题,Agent通过与LLM交互获得奖励/惩罚信号,并通过Q-learning、PPO等算法优化策略。进一步,引入元学习(Meta-Learning),使Agent能够学会“如何学习”,从而加速在新任务上的适应能力。
  3. 多模态与多Agent协作:将Prompt策略扩展到多模态场景(如图像生成、视频理解),并引入多Agent协作,一个Agent负责生成Prompt,另一个Agent负责评估,甚至有Agent专门负责反思和学习。
  4. 知识图谱与外部工具集成:将Agent的经验库与结构化的知识图谱结合,利用外部工具(如搜索引擎、代码解释器、API调用)来增强LLM的能力,减少其“幻觉”和知识限制,从而使Prompt策略的调整更加精准和有效。
  5. 自动化A/B测试与演化算法:自动生成多种Prompt变体进行A/B测试,并采用演化算法(如遗传算法)来“进化”最佳Prompt策略,实现更高效、更具创造性的Prompt优化。

通过持续的技术创新和实践,我们有理由相信,具备自我学习能力的Prompt Agent将成为AI应用领域的重要基石,极大地提升我们驾驭大型语言模型的能力,并解锁更多前所未有的智能应用场景。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注