解析 ‘Self-Writing Prompts’:让 Agent 根据任务成功率,自主重写并优化自己的系统指令(System Message)

各位来宾,各位对人工智能充满热情的开发者们:

欢迎来到今天的技术讲座。今天,我们将深入探讨一个引人入胜且极具潜力的领域——“自写指令”(Self-Writing Prompts)。在大型语言模型(LLM)日益普及的今天,我们都深知系统指令(System Message)对于引导LLM行为、确保其输出质量的重要性。然而,手动编写和优化这些指令是一项耗时且往往难以捉摸的工作。

想象一下,如果我们的Agent能够根据它完成任务的实际成功率,自主地学习、重写并优化自己的系统指令,那将是多么强大的能力!这正是“自写指令”的核心思想,也是我们今天讲座的主题。我们将从概念、原理、架构到代码实践,全面解析这一前沿技术。


第一章:系统指令的困境与“自写指令”的兴起

1.1 系统指令:Agent 的“宪法”与“指南”

在基于LLM构建的Agent中,系统指令扮演着至关重要的角色。它定义了Agent的身份、角色、行为准则、输出格式要求以及其他关键约束。一个精心设计的系统指令能够:

  • 明确角色定位:例如,“你是一个专业的编程助手。”
  • 设定行为规范:例如,“你的回答必须简洁明了,专注于技术细节。”
  • 指定输出格式:例如,“请以Markdown代码块的形式提供所有代码,并附上简短解释。”
  • 引导推理过程:例如,“在回答前,请先列出你的思考步骤。”

然而,系统指令的编写并非易事。它往往需要:

  • 经验与直觉:优秀的指令往往是资深Prompt Engineer经验的结晶。
  • 试错与迭代:通过反复测试和微调才能找到最佳表达。
  • 领域知识:特定任务需要对领域有深入理解才能写出有效的指令。
  • 难以泛化:一个针对特定场景优化的指令,可能在其他场景下表现不佳。

更重要的是,随着任务需求的变化、Agent能力的演进,或者底层LLM模型的更新,原有的系统指令可能不再是最优解,甚至会失效。

1.2 手动优化的局限性

传统上,我们依赖人工对系统指令进行优化。这个过程通常是:

  1. 编写初始指令
  2. 测试 Agent 表现
  3. 分析失败案例
  4. 根据分析结果修改指令
  5. 重复上述步骤

这种手动循环存在几个显著问题:

  • 效率低下:尤其是在处理大量任务或需要频繁调整时。
  • 主观性强:优化的方向和效果高度依赖于人工的判断和经验。
  • 难以探索最优解:人工很难系统性地探索所有可能的指令变体,往往只能在局部最优解附近徘徊。
  • 成本高昂:需要投入大量人力进行测试和分析。

1.3 “自写指令”:Agent 的自我进化之路

“自写指令”正是为了解决上述困境而提出的。其核心思想是让Agent具备一种元学习能力,即它不再仅仅是执行任务的工具,而是能够自主地思考如何更好地执行任务,并主动优化自身的行为准则(系统指令)

这个过程可以理解为Agent的一种自我进化:

  1. Agent 接收任务并尝试执行。
  2. Agent 评估任务执行的成功率或效果。
  3. 根据评估结果,Agent 提出新的、可能更优的系统指令。
  4. Agent 采用新指令再次执行任务,并继续评估和优化。

通过这种自动化、数据驱动的迭代过程,Agent 能够超越人工优化的局限,发现更高效、更鲁棒的系统指令,从而持续提升其在各种任务上的表现。这不仅大幅提升了Prompt Engineering的效率,也为构建更智能、更自适应的Agent打开了大门。


第二章:核心机制:Agent 如何重写与优化系统指令

要实现Agent的“自写指令”能力,我们需要构建一个闭环反馈系统。这个系统至少包含以下几个核心组件和机制:

  1. 任务定义与成功率评估机制:Agent 需要明确知道“成功”意味着什么,并能客观地衡量其表现。
  2. 系统指令的变异与生成机制:Agent 需要有能力基于当前表现和反馈,生成新的、潜在更优的系统指令。
  3. 优化策略与选择机制:Agent 需要一套策略来决定何时、如何采纳新的指令,以及如何平衡探索(尝试新指令)和利用(使用已知最优指令)。

2.1 任务定义与成功率评估

这是整个自优化过程的基石。如果Agent无法准确评估其任务成功率,那么所有的优化都将是盲目的。

2.1.1 任务定义

每个任务都应有一个清晰的定义,包括:

  • 输入(Input):Agent 需要处理的原始数据或用户请求。
  • 期望输出(Expected Output):任务成功时应产生的输出形式、内容或属性。
  • 成功标准(Success Criteria):明确界定输出达到何种程度才算成功。

2.1.2 成功率评估方法

评估方法可以从简单到复杂,取决于任务的性质:

  • 基于规则或正则表达式:对于输出格式、关键词匹配等明确的任务,可以直接编写规则进行判断。
    • 例如:检查输出是否包含特定的代码块、是否以“答案是:”开头等。
  • 基于语义相似度:对于文本生成任务,可以使用嵌入向量(embeddings)计算生成文本与参考文本之间的相似度。
    • 例如:使用余弦相似度衡量生成摘要与人工摘要的匹配程度。
  • 基于外部工具或API:如果Agent的任务是调用外部API或工具,可以通过检查API调用的成功与否、返回结果的有效性来评估。
    • 例如:代码生成任务,可以通过运行生成的代码并检查其是否通过测试用例来评估。
  • 基于LLM的评估:让另一个LLM(或Agent自身,但通常使用一个独立的、带有特定评估指令的LLM)作为裁判,对Agent的输出进行评分或判断。
    • 例如:提供Agent的输出、任务要求和成功标准,让评估LLM给出0-10分或“成功/失败”的判断。这是最灵活但也可能最昂贵的方法。
  • 人工反馈:在某些复杂或初期阶段,人工标注或评分仍然是不可或缺的。

示例:Python 代码生成任务的评估

假设Agent的目标是根据自然语言描述生成可运行的Python代码。

  • 输入"编写一个函数,接收一个整数列表,并返回所有偶数的和。"
  • 期望输出:一个Python函数,例如 def sum_even(numbers): ...
  • 成功标准
    1. 生成的代码是有效的Python语法。
    2. 生成的函数能够正确处理各种测试用例(例如,sum_even([1, 2, 3, 4]) 应返回 6)。
import traceback

class TaskEvaluator:
    def evaluate(self, task_description: str, generated_code: str) -> bool:
        """
        评估生成的代码是否满足任务描述。
        这里我们假设任务是生成一个求偶数和的函数。
        """
        try:
            # 1. 尝试执行代码,检查语法错误
            exec_globals = {}
            exec(generated_code, exec_globals)

            # 2. 检查特定函数是否存在 (根据任务描述,预期生成一个名为 sum_even 的函数)
            if 'sum_even' not in exec_globals:
                print("Error: Function 'sum_even' not found.")
                return False

            sum_even_func = exec_globals['sum_even']

            # 3. 运行测试用例
            test_cases = [
                ([1, 2, 3, 4], 6),
                ([], 0),
                ([7, 9, 11], 0),
                ([2, 4, 6], 12),
                ([-1, -2, -3, -4], -6)
            ]

            all_tests_passed = True
            for input_list, expected_output in test_cases:
                actual_output = sum_even_func(input_list)
                if actual_output != expected_output:
                    print(f"Test failed for input {input_list}: Expected {expected_output}, got {actual_output}")
                    all_tests_passed = False
                    break

            return all_tests_passed

        except SyntaxError as e:
            print(f"Syntax Error in generated code: {e}")
            return False
        except Exception as e:
            print(f"Runtime Error during execution: {e}")
            print(traceback.format_exc())
            return False

# 示例使用
# evaluator = TaskEvaluator()
# # 假设 Agent 生成了以下代码
# good_code = """
# def sum_even(numbers):
#     total = 0
#     for num in numbers:
#         if num % 2 == 0:
#             total += num
#     return total
# """
# bad_code = """
# def sum_odd(numbers): # 错误的函数名
#     return sum(n for n in numbers if n % 2 != 0)
# """
# syntax_error_code = """
# def sum_even(numbers)
#     return 1
# """
# print(f"Good code evaluation: {evaluator.evaluate('sum_even', good_code)}") # 应该为 True
# print(f"Bad code evaluation: {evaluator.evaluate('sum_even', bad_code)}")   # 应该为 False
# print(f"Syntax error evaluation: {evaluator.evaluate('sum_even', syntax_error_code)}") # 应该为 False

2.2 系统指令的变异与生成

一旦我们能够评估Agent的表现,下一步就是如何生成新的、潜在更优的系统指令。这需要Agent具备一定的“创造性”和“反思能力”。

2.2.1 变异策略

我们可以通过多种策略来对现有系统指令进行“变异”或“启发式生成”:

  1. 基于反馈的微调
    • 如果Agent经常出现某种类型的错误(例如,输出格式不正确),则在系统指令中明确添加或加强对该格式的要求。
    • 如果Agent在特定约束下表现不佳,则尝试放松或修改该约束。
    • 如果Agent的输出过于冗长,则添加“请简洁”等指令。
  2. 探索性变异
    • 增加/删除/修改规则:随机添加、删除或修改指令中的某个句子、短语或关键词。
    • 改变语气/风格:将“你是一个专家”改为“你是一个严谨的专家”,或从命令式改为建议式。
    • 调整权重/优先级:如果指令中包含多个目标,尝试调整它们的重要性。
    • 引入新的约束/提示:例如,添加“在回答前请思考”或“请一步步思考”。
  3. 基于LLM的指令生成:这是最强大的方法。让LLM自身根据任务描述、Agent的历史表现和评估反馈来生成新的系统指令。

    • Prompt for Prompt Generation (P4PG)
      • 输入给LLM
        • 原始任务描述
        • Agent 当前使用的系统指令
        • Agent 在该指令下的表现报告(成功率、失败案例分析)
        • 目标:生成一个更好的系统指令,以提高成功率。
      • LLM 的任务:根据上述信息,生成一个新的、优化的系统指令。
from typing import List, Dict, Any

# 模拟 LLM API 调用
class MockLLM:
    def generate(self, prompt: str, system_message: str = None, max_tokens: int = 500) -> str:
        print(f"n--- LLM Called ---")
        print(f"System Message: {system_message}")
        print(f"User Prompt: {prompt}")
        # 这是一个模拟,实际应调用真正的LLM API
        if "优化系统指令" in prompt:
            if "输出格式不正确" in prompt:
                return "你是一个严谨的编程助手。请确保所有代码都用Markdown代码块包裹。如果需要额外解释,请在代码块下方提供。输出必须简洁且只包含代码和必要的解释。"
            elif "代码质量不高" in prompt:
                return "你是一个经验丰富的编程专家。请生成高质量、可读性强、并且经过充分测试的Python代码。在生成代码前,请考虑多种实现方案并选择最优解。"
            else:
                return "你是一个专业的AI助手。请根据用户请求提供准确、有用的信息。确保你的回答清晰、简洁,并遵循所有指定的格式要求。"
        else:
            return "模拟LLM回答: " + prompt

class PromptGenerator:
    def __init__(self, llm_api: MockLLM):
        self.llm_api = llm_api
        self.generation_system_message = (
            "你是一个Prompt工程专家。你的任务是分析Agent的表现报告和当前的系统指令,"
            "然后提出一个新的、优化的系统指令,以提高Agent在特定任务上的成功率。"
            "请直接输出新的系统指令,不要包含任何解释或额外的对话。"
        )

    def generate_new_prompt(self, current_system_message: str, performance_report: Dict[str, Any]) -> str:
        """
        根据当前系统指令和性能报告,生成新的系统指令。
        """
        feedback_summary = f"Agent在过去的任务中表现如下:n" 
                           f"任务成功率: {performance_report['success_rate']:.2f}%n" 
                           f"主要失败原因: {performance_report['failure_reasons']}n" 
                           f"当前系统指令: '{current_system_message}'nn" 
                           f"请根据以上信息,生成一个能够解决上述问题并提高成功率的新的系统指令。"

        new_system_message = self.llm_api.generate(
            prompt=feedback_summary,
            system_message=self.generation_system_message
        )
        return new_system_message

# 示例使用
# llm = MockLLM()
# prompt_generator = PromptGenerator(llm)
# 
# current_sys_msg = "你是一个编程助手,请生成Python代码。"
# performance = {
#     "success_rate": 60.0,
#     "failure_reasons": ["输出格式不正确", "代码缺乏注释"]
# }
# 
# new_sys_msg = prompt_generator.generate_new_prompt(current_sys_msg, performance)
# print(f"nGenerated New System Message:n{new_sys_msg}")

2.3 优化策略:探索与利用

生成了新的系统指令之后,Agent需要一个策略来决定如何将其整合到其行为中。这涉及到探索(尝试新的、未经验证的指令)和利用(使用已知表现最佳的指令)之间的权衡。

2.3.1 常见的优化策略

  1. A/B 测试

    • 将传入的任务流分割成两组或多组。
    • 一组使用当前最优指令(A),另一组使用新的候选指令(B)。
    • 在一段时间后,比较两组的成功率,选择表现更好的指令。
    • 可以扩展到多臂老虎机(Multi-Armed Bandit)问题,动态调整流量分配。
  2. 进化算法(Evolutionary Algorithms)

    • 维护一个系统指令的“种群”(Population)。
    • 每个指令都有一个“适应度”(Fitness)分数(即其成功率)。
    • 通过“选择”(优胜劣汰)、“交叉”(组合两个指令的特点)和“变异”(随机修改)操作,生成下一代指令种群。
    • 这种方法可以探索更广阔的指令空间。
  3. 强化学习(Reinforcement Learning, RL)

    • 将系统指令的选择视为一个RL问题。
    • Agent:选择系统指令的机制。
    • 环境:任务执行过程和评估器。
    • 状态:当前Agent的表现、历史指令及它们的成功率。
    • 动作:生成或选择一个新的系统指令。
    • 奖励:任务成功率的提升。
    • 通过学习一个策略,Agent 可以学会如何在不同状态下选择(或生成)最佳的系统指令。

2.3.2 优化循环

无论采用哪种策略,核心都是一个持续的优化循环:

  1. 初始化:从一个基础系统指令开始。
  2. 执行任务:使用当前系统指令处理一批任务。
  3. 评估表现:计算任务成功率并分析失败原因。
  4. 生成候选指令:根据评估结果,生成一个或多个新的候选系统指令。
  5. 选择与更新:根据预设的优化策略(A/B测试、进化算法等),从候选指令中选择最优者,并将其设置为新的当前系统指令。
  6. 迭代:重复步骤2-5。
优化策略 优点 缺点 适用场景
A/B 测试 直观、易于实现,结果易于解释 需要足够流量,探索效率较低,可能陷入局部最优 稳态系统微调,比较少量候选指令
进化算法 能有效探索复杂指令空间,发现非直观优化 实现复杂度较高,计算成本可能较高,收敛速度不确定 需要大规模探索,对初始指令依赖小
强化学习 理论上最灵活,能处理动态环境和序列决策 实现最复杂,需要设计状态、动作、奖励,训练困难 高度自适应、长期优化的复杂Agent系统
LLM 自生成(启发式) 结合LLM的语言理解和生成能力,智能性高 每次生成成本较高,LLM本身的性能和指令影响大 快速迭代和生成新颖指令,对失败原因敏感

第三章:架构设计与实现细节

要将“自写指令”落地,我们需要一个清晰的系统架构。

3.1 系统架构概览

以下是一个典型的“自写指令”Agent的系统架构图,我们将用文字描述其主要组件:

  1. 任务调度器 (Task Scheduler):接收外部任务请求,并将其分配给Agent。
  2. Agent 核心 (Agent Core)
    • LLM 接口 (LLM Interface):与底层大型语言模型进行交互,发送Prompt,接收响应。
    • 工具调用 (Tool Usage):如果Agent需要使用外部工具(例如,代码解释器、搜索引擎、数据库),则在此处集成。
  3. 系统指令存储 (System Message Store):存储当前以及历史的系统指令及其表现数据。
  4. 任务执行器 (Task Executor)
    • 结合当前系统指令和用户任务Prompt,构建完整的LLM输入。
    • 调用Agent核心执行任务。
    • 捕获Agent的输出。
  5. 评估器 (Evaluator)
    • 接收Agent的输出和原始任务请求。
    • 根据预定义的成功标准,判断任务是否成功,并计算成功率。
    • 生成详细的性能报告(例如,失败原因、错误类型)。
  6. 指令优化器 (Prompt Optimizer)
    • Prompt 生成器 (Prompt Generator):根据评估器的性能报告和当前系统指令,利用LLM生成新的候选系统指令。
    • 策略管理器 (Strategy Manager):实现前面讨论的优化策略(A/B测试、进化算法等),决定何时采纳新指令,如何管理指令种群。
  7. 监控与日志 (Monitoring & Logging):记录所有任务的输入、输出、所用指令、评估结果等,以便调试和分析。
graph TD
    A[外部任务请求] --> B(任务调度器);
    B --> C{系统指令存储};
    C --> D[任务执行器];
    D --> E[Agent 核心 (LLM + Tools)];
    E --> F[Agent 输出];
    F --> G[评估器];
    G --> H[性能报告];
    H --> I[指令优化器];
    I -- 新的候选指令 --> J[Prompt 生成器];
    I -- 优化策略 --> K[策略管理器];
    J --> K;
    K -- 选定的新系统指令 --> C;
    G --> L[监控与日志];
    E --> L;
    D --> L;

(注:根据要求,这里不插入图片,仅用Mermaid语法表示架构图,但在实际讲座中会用语言描述其组件关系。)

3.2 代码实践:核心组件实现

我们将使用Python来模拟实现上述架构的关键部分。为了简化,我们不会构建一个完整的分布式系统,而是专注于核心逻辑。

3.2.1 LLM 接口模拟

我们用一个简单的类来模拟与LLM的交互。在实际项目中,这里会集成OpenAI、Anthropic、HuggingFace等API。

import time
import random

class LLMInterface:
    def __init__(self, model_name: str = "gpt-4"):
        self.model_name = model_name
        print(f"Initialized LLMInterface with model: {self.model_name}")

    def chat_completion(self, messages: List[Dict[str, str]], temperature: float = 0.7, max_tokens: int = 500) -> str:
        """
        模拟 LLM 的 chat completion API 调用。
        messages 格式: [{"role": "system", "content": "..."}, {"role": "user", "content": "..."}]
        """
        # 模拟网络延迟和处理时间
        time.sleep(0.5 + random.random() * 0.5) 

        # 提取系统指令和用户提示
        system_message = ""
        user_prompt = ""
        for msg in messages:
            if msg["role"] == "system":
                system_message = msg["content"]
            elif msg["role"] == "user":
                user_prompt = msg["content"]

        print(f"n--- LLM Call ---")
        print(f"System: {system_message[:100]}...") # 打印部分指令
        print(f"User: {user_prompt[:100]}...") # 打印部分提示

        # 简单的模拟响应逻辑
        if "sum_even" in user_prompt and "Python" in system_message:
            return f"```pythonndef sum_even(numbers):n    total = 0n    for num in numbers:n        if num % 2 == 0:n            total += numn    return totaln```n这是一个计算列表中偶数和的Python函数。"
        elif "优化系统指令" in system_message:
            if "输出格式不正确" in user_prompt:
                return "你是一个严谨的编程助手。请确保所有代码都用Markdown代码块包裹。如果需要额外解释,请在代码块下方提供。输出必须简洁且只包含代码和必要的解释。"
            elif "代码质量不高" in user_prompt:
                return "你是一个经验丰富的编程专家。请生成高质量、可读性强、并且经过充分测试的Python代码。在生成代码前,请考虑多种实现方案并选择最优解。"
            else:
                return "你是一个专业的AI助手。请根据用户请求提供准确、有用的信息。确保你的回答清晰、简洁,并遵循所有指定的格式要求。"
        else:
            return f"LLM模拟响应: {user_prompt}"

3.2.2 任务执行器

负责调用Agent核心,并获取其输出。

class TaskExecutor:
    def __init__(self, llm_interface: LLMInterface):
        self.llm_interface = llm_interface

    def execute_task(self, system_message: str, user_prompt: str) -> str:
        """
        使用给定的系统指令和用户提示执行任务。
        """
        messages = [
            {"role": "system", "content": system_message},
            {"role": "user", "content": user_prompt}
        ]
        response = self.llm_interface.chat_completion(messages)
        return response

3.2.3 评估器

使用之前定义的 TaskEvaluator 类,并扩展其功能,使其能够生成更详细的报告。

import re

class TaskEvaluator:
    def evaluate(self, task_description: str, generated_output: str) -> Dict[str, Any]:
        """
        评估生成的输出是否满足任务描述,并返回详细报告。
        这里我们假设任务是生成一个求偶数和的Python函数,并检查其代码质量。
        """
        report = {
            "success": False,
            "reason": "Unknown",
            "score": 0.0, # 0.0 - 1.0
            "details": {}
        }

        # 1. 尝试提取代码块
        code_match = re.search(r"```pythonn(.*?)```", generated_output, re.DOTALL)
        if not code_match:
            report["reason"] = "Output does not contain a Python code block."
            return report

        generated_code = code_match.group(1).strip()
        report["details"]["extracted_code"] = generated_code

        try:
            # 2. 尝试执行代码,检查语法错误
            exec_globals = {}
            exec(generated_code, exec_globals)

            # 3. 检查特定函数是否存在 (根据任务描述,预期生成一个名为 sum_even 的函数)
            if 'sum_even' not in exec_globals:
                report["reason"] = "Function 'sum_even' not found in generated code."
                return report

            sum_even_func = exec_globals['sum_even']

            # 4. 运行测试用例
            test_cases = [
                ([1, 2, 3, 4], 6),
                ([], 0),
                ([7, 9, 11], 0),
                ([2, 4, 6], 12),
                ([-1, -2, -3, -4], -6)
            ]

            all_tests_passed = True
            failed_tests = []
            for input_list, expected_output in test_cases:
                actual_output = sum_even_func(input_list)
                if actual_output != expected_output:
                    all_tests_passed = False
                    failed_tests.append(f"Input: {input_list}, Expected: {expected_output}, Got: {actual_output}")

            if not all_tests_passed:
                report["reason"] = "Generated function failed one or more test cases."
                report["details"]["failed_tests"] = failed_tests
                return report

            # 5. (可选) 检查代码质量或格式 (例如,是否有注释,是否简洁)
            # 这里简单检查是否有注释
            if "#" not in generated_code and len(generated_code.splitlines()) > 5: # 假设超过5行代码就应该有注释
                report["reason"] = "Code lacks comments."
                report["score"] = 0.8 # 即使功能正确,但质量有损
                report["details"]["quality_issue"] = "lacks comments"
                # 如果我们允许部分成功,这里可以返回True,或者根据阈值判断
                # return report # 返回部分成功

            report["success"] = True
            report["reason"] = "All tests passed and code quality is acceptable."
            report["score"] = 1.0
            return report

        except SyntaxError as e:
            report["reason"] = f"Syntax Error in generated code: {e}"
            report["details"]["error_type"] = "SyntaxError"
            return report
        except Exception as e:
            report["reason"] = f"Runtime Error during execution: {e}"
            report["details"]["error_type"] = "RuntimeError"
            report["details"]["traceback"] = traceback.format_exc()
            return report

3.2.4 指令优化器:生成器与策略管理器

我们将 PromptGeneratorStrategyManager 合并到一个 PromptOptimizer 类中,以简化示例。

class PromptOptimizer:
    def __init__(self, llm_interface: LLMInterface, initial_system_message: str):
        self.llm_interface = llm_interface
        self.current_system_message = initial_system_message
        self.history_performance: List[Dict[str, Any]] = [] # 存储历史表现
        self.generation_system_message = (
            "你是一个Prompt工程专家。你的任务是分析Agent在过去任务中的表现报告和当前的系统指令,"
            "然后提出一个新的、优化的系统指令,以提高Agent在特定任务上的成功率。"
            "请直接输出新的系统指令,不要包含任何解释或额外的对话。"
        )

    def record_performance(self, task_prompt: str, system_message_used: str, evaluation_report: Dict[str, Any]):
        """记录每次任务的性能数据。"""
        self.history_performance.append({
            "timestamp": time.time(),
            "task_prompt": task_prompt,
            "system_message_used": system_message_used,
            "evaluation_report": evaluation_report
        })

    def _summarize_performance_for_llm(self) -> Dict[str, Any]:
        """
        总结最近的任务表现,供LLM生成新指令时参考。
        这里我们只看最近的几条记录,并提取失败原因。
        """
        recent_tasks = self.history_performance[-5:] # 只看最近5条
        total_success = sum(1 for p in recent_tasks if p["evaluation_report"]["success"])
        success_rate = (total_success / len(recent_tasks)) * 100 if recent_tasks else 0

        failure_reasons = []
        for p in recent_tasks:
            if not p["evaluation_report"]["success"]:
                reason = p["evaluation_report"]["reason"]
                if reason not in failure_reasons:
                    failure_reasons.append(reason)

        return {
            "success_rate": success_rate,
            "failure_reasons": failure_reasons if failure_reasons else ["No specific failures observed recently."]
        }

    def propose_new_system_message(self) -> str:
        """
        利用LLM根据历史表现和当前指令,提出新的系统指令。
        """
        performance_summary = self._summarize_performance_for_llm()
        feedback_summary = (
            f"Agent在过去的任务中表现如下:n"
            f"任务成功率: {performance_summary['success_rate']:.2f}%n"
            f"主要失败原因: {', '.join(performance_summary['failure_reasons'])}n"
            f"当前系统指令: '{self.current_system_message}'nn"
            f"请根据以上信息,生成一个能够解决上述问题并提高成功率的新的系统指令。"
        )

        print(f"n--- Proposing New System Message ---")
        print(f"Feedback to LLM:n{feedback_summary}")

        new_sys_msg = self.llm_interface.chat_completion(
            messages=[
                {"role": "system", "content": self.generation_system_message},
                {"role": "user", "content": feedback_summary}
            ]
        )
        return new_sys_msg.strip()

    def update_system_message(self, new_message: str):
        """
        更新当前系统指令。在实际应用中,这里会有更复杂的策略。
        """
        print(f"n--- System Message Updated ---")
        print(f"Old: {self.current_system_message}")
        print(f"New: {new_message}")
        self.current_system_message = new_message

    def get_current_system_message(self) -> str:
        return self.current_system_message

3.2.5 自优化 Agent 主循环

现在,我们将所有组件整合到一个主循环中,模拟Agent的自我优化过程。

class SelfOptimizingAgent:
    def __init__(self, initial_system_message: str, llm_interface: LLMInterface):
        self.llm = llm_interface
        self.executor = TaskExecutor(llm_interface)
        self.evaluator = TaskEvaluator()
        self.optimizer = PromptOptimizer(llm_interface, initial_system_message)
        self.task_queue: List[str] = []

    def add_task(self, user_prompt: str):
        self.task_queue.append(user_prompt)

    def run_optimization_cycle(self, num_tasks_per_cycle: int = 5):
        print(f"n--- Starting Optimization Cycle ---")

        # 1. 使用当前系统指令执行一批任务
        current_system_message = self.optimizer.get_current_system_message()
        print(f"Current System Message for tasks: {current_system_message}")

        cycle_reports = []
        for i in range(min(num_tasks_per_cycle, len(self.task_queue))):
            task_prompt = self.task_queue.pop(0) # 从队列中取出任务
            print(f"nExecuting task {i+1}/{num_tasks_per_cycle}: '{task_prompt}'")

            # Agent 执行任务
            agent_output = self.executor.execute_task(current_system_message, task_prompt)
            print(f"Agent Output: {agent_output[:200]}...") # 打印部分输出

            # 评估任务结果
            evaluation_report = self.evaluator.evaluate(task_prompt, agent_output)
            print(f"Evaluation: Success={evaluation_report['success']}, Reason='{evaluation_report['reason']}'")

            # 记录性能
            self.optimizer.record_performance(task_prompt, current_system_message, evaluation_report)
            cycle_reports.append(evaluation_report)

        # 2. 根据本轮任务表现,生成新的系统指令(如果需要)
        # 这里我们简化:如果本轮成功率低于某个阈值,或者我们运行了足够多的任务,就尝试优化
        success_count = sum(1 for r in cycle_reports if r["success"])
        current_cycle_success_rate = (success_count / len(cycle_reports)) * 100 if cycle_reports else 0

        print(f"nCycle Summary: Processed {len(cycle_reports)} tasks, Success Rate: {current_cycle_success_rate:.2f}%")

        # 简单的优化触发条件
        if current_cycle_success_rate < 90 and len(self.optimizer.history_performance) >= num_tasks_per_cycle:
            print(f"Triggering prompt optimization due to low success rate ({current_cycle_success_rate:.2f}%) or enough history.")
            new_candidate_message = self.optimizer.propose_new_system_message()

            # 3. 策略:直接替换(简化版,实际可A/B测试)
            if new_candidate_message and new_candidate_message != current_system_message:
                self.optimizer.update_system_message(new_candidate_message)
            else:
                print("No significant new system message proposed or current one is already optimal.")
        else:
            print("No optimization triggered this cycle (success rate high or not enough history).")

# --- 运行示例 ---
if __name__ == "__main__":
    llm_api = LLMInterface()

    initial_sys_msg = "你是一个编程助手,请生成Python代码。"
    agent = SelfOptimizingAgent(initial_sys_msg, llm_api)

    # 添加一些任务
    tasks = [
        "编写一个函数,接收一个整数列表,并返回所有偶数的和。", # 预期成功
        "创建一个Python函数,计算一个列表中所有奇数的乘积。", # 预期失败,因为LLM模拟器只认sum_even
        "编写一个函数,接收一个字符串,并返回其反转版本。", # 预期失败
        "编写一个Python函数,接收一个整数列表,并返回所有偶数的和。", # 预期成功
        "请生成一个Python函数,接收一个列表,返回其最大值。", # 预期失败
        "编写一个函数,接收一个整数列表,并返回所有偶数的和,确保代码有详细注释。", # 预期成功 (可能触发优化代码质量)
        "生成一个Python函数,接收一个整数列表,并返回所有偶数的和,且必须以Markdown代码块形式输出。", # 预期成功
        "编写一个函数,接收一个整数列表,并返回所有偶数的和。代码应高效且考虑边缘情况。", # 预期成功
    ]
    for t in tasks:
        agent.add_task(t)

    # 运行几个优化循环
    for cycle in range(3):
        print(f"n====== Running Optimization Cycle {cycle + 1} ======")
        agent.run_optimization_cycle(num_tasks_per_cycle=3) # 每轮处理3个任务
        print(f"Current System Message after Cycle {cycle + 1}: {agent.optimizer.get_current_system_message()}")
        time.sleep(1) # 稍作等待

    print("n--- Final System Message ---")
    print(agent.optimizer.get_current_system_message())

这段代码模拟了一个简化的自优化Agent。在实际运行中,你会看到Agent最初可能在某些任务上失败,然后通过 PromptOptimizer 总结失败原因,并让 LLMInterface 生成一个新的、更精细的系统指令,以期望在后续任务中表现更好。例如,如果Agent频繁因“输出格式不正确”而失败,PromptOptimizer 可能会生成一个包含“请确保所有代码都用Markdown代码块包裹”等明确指令的系统消息。


第四章:挑战、考量与展望

“自写指令”虽然前景广阔,但在实际落地过程中也面临诸多挑战和需要深入考量的问题。

4.1 技术挑战

  1. 评估器的准确性与鲁棒性:这是最关键的一环。如果评估器无法准确判断任务的成功与否,或存在偏见,那么整个优化过程都将是无效的。对于复杂、开放性任务的评估尤其困难。
  2. LLM 生成指令的质量与稳定性:LLM在生成新指令时,其创造性、逻辑性和遵循指令的能力本身就是一个挑战。生成的指令可能冗余、模糊甚至有害。
  3. 探索与利用的平衡:如何有效地探索新的指令空间,同时又不会因为尝试不佳的指令而严重损害Agent的短期表现?多臂老虎机和进化算法等策略可以缓解,但仍需精心设计。
  4. 优化成本:每次生成和测试新的系统指令都需要调用LLM,这会产生显著的API费用和计算资源消耗。如何降低优化过程的成本是一个实际问题。
  5. 收敛性与局部最优:优化过程是否能收敛到全局最优指令?Agent是否会陷入某个局部最优解而无法跳出?
  6. 指令冲突与冗余:随着时间的推移,生成的系统指令可能会变得越来越长、越来越复杂,甚至出现相互冲突的指令,导致Agent行为不稳定。

4.2 资源与成本考量

  • API 调用成本:每次LLM生成新指令、Agent执行任务、甚至LLM辅助评估,都会产生调用费用。在大规模应用中,这可能是一笔巨大的开销。
  • 计算资源:运行大量测试用例、模拟环境、并行评估等都需要计算资源。
  • 时间成本:优化过程是迭代的,可能需要运行很长时间才能达到满意的效果。

4.3 伦理与安全

  • 有害指令的生成:LLM在生成新指令时,有可能无意中生成带有偏见、不安全或鼓励不道德行为的指令。必须有强大的安全防护机制来过滤和阻止此类指令。
  • 不可预测的行为:自写指令可能导致Agent的行为变得难以预测和解释,这在关键应用中是不可接受的。
  • 泛化性与过拟合:优化后的指令可能在训练(测试)数据集上表现优秀,但在新的、未见过的数据上表现不佳,产生过拟合。

4.4 未来发展方向

  1. 多目标优化:除了成功率,还可以将成本、延迟、安全性等纳入优化目标。
  2. 跨任务泛化:研究如何让Agent学习到的指令优化策略能够泛化到相似或全新的任务中。
  3. 人类在环(Human-in-the-Loop):在关键决策点引入人工审核,例如对新生成指令的安全性进行人工评估。
  4. 更智能的Prompt表示:不仅仅是纯文本,可以探索结构化、可组合的Prompt表示方式,便于LLM进行更精细的修改。
  5. 模型蒸馏与微调:将自优化过程中的最佳实践,通过数据蒸馏或微调的方式固化到更小、更高效的模型中。
  6. 结合思维链(Chain-of-Thought):让Agent在生成新指令时,也能输出其思考过程,提高可解释性。

总结与展望

“自写指令”代表了Agent自我进化和自适应能力的一个重要方向。通过构建一个能够自主评估、生成和选择系统指令的闭环系统,我们可以极大地提升Agent的性能和鲁棒性,同时解放Prompt Engineer的生产力。尽管当前仍面临诸多挑战,但其在提高AI系统智能性、降低开发成本方面的巨大潜力,无疑使其成为未来几年LLM应用领域的一个热点。让我们共同期待并投身于这一激动人心的技术浪潮。

发表回复

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