自定义 Prompt

深入了解 CrewAI 中底层 Prompt 的自定义方式,以支持适配不同模型和语言的高度定制化、复杂用例。

为什么要自定义 Prompt?

尽管 CrewAI 的默认 Prompt 在许多场景下都表现良好,但底层自定义能够让 Agent 的行为变得更加灵活和强大。你可能希望利用这种更深层控制的原因包括:

  1. 针对特定 LLM 进行优化 —— 不同模型(如 GPT-4、Claude 或 Llama)在针对其独特架构量身定制的 Prompt 格式下往往表现更好。
  2. 切换语言 —— 构建完全使用英语以外语言运行的 Agent,并精准处理细微差异。
  3. 面向复杂领域进行专业化 —— 为医疗、金融或法律等高度专业化行业调整 Prompt。
  4. 调整语气与风格 —— 让 Agent 更正式、更随意、更有创意,或更偏分析型。
  5. 支持高度定制的用例 —— 使用高级 Prompt 结构与格式来满足复杂、项目特定的需求。

本指南将介绍如何从更底层访问 CrewAI 的 Prompt 系统,从而让你能够精细控制 Agent 的思考与交互方式。

理解 CrewAI 的 Prompt 系统

在底层,CrewAI 使用的是一个模块化 Prompt 系统,你可以对其进行广泛自定义:

  • Agent templates —— 控制每个 Agent 如何处理其被分配的角色。
  • Prompt slices —— 控制任务、工具使用和输出结构等特定行为。
  • Error handling —— 指导 Agent 如何应对失败、异常或超时。
  • Tool-specific prompts —— 定义调用或使用工具时的详细说明。

你可以查看 CrewAI 仓库中的原始 Prompt 模板,了解这些元素是如何组织的。然后,你可以根据需要覆盖或调整它们,以解锁更高级的行为能力。

理解默认系统指令

生产环境透明性问题:CrewAI 会自动向你的 Prompt 中注入默认指令,而你可能并没有意识到这一点。本节将解释底层实际发生了什么,以及如何获得完全控制权。

当你通过 rolegoalbackstory 定义一个 Agent 时,CrewAI 会自动附加额外的系统指令,以控制格式和行为。理解这些默认注入内容,对于需要完整 Prompt 透明性的生产系统至关重要。

CrewAI 会自动注入什么

根据你的 Agent 配置,CrewAI 会添加不同的默认指令:

对于没有工具的 Agent

  1. "I MUST use these formats, my job depends on it!"

对于带工具的 Agent

  1. "IMPORTANT: Use the following format in your response:
  2. Thought: you should always think about what to do
  3. Action: the action to take, only one name of [tool_names]
  4. Action Input: the input to the action, just a simple JSON object...

对于结构化输出(JSON / Pydantic)

  1. "Ensure your final answer contains only the content in the following format: {output_format}
  2. Ensure the final output does not include any code block markers like ```json or ```python."

查看完整系统 Prompt

如果你想准确看到发送给 LLM 的 Prompt 内容,可以检查生成后的 Prompt:

  1. from crewai import Agent, Crew, Task
  2. from crewai.utilities.prompts import Prompts
  3. # Create your agent
  4. agent = Agent(
  5. role="Data Analyst",
  6. goal="Analyze data and provide insights",
  7. backstory="You are an expert data analyst with 10 years of experience.",
  8. verbose=True
  9. )
  10. # Create a sample task
  11. task = Task(
  12. description="Analyze the sales data and identify trends",
  13. expected_output="A detailed analysis with key insights and trends",
  14. agent=agent
  15. )
  16. # Create the prompt generator
  17. prompt_generator = Prompts(
  18. agent=agent,
  19. has_tools=len(agent.tools) > 0,
  20. use_system_prompt=agent.use_system_prompt
  21. )
  22. # Generate and inspect the actual prompt
  23. generated_prompt = prompt_generator.task_execution()
  24. # Print the complete system prompt that will be sent to the LLM
  25. if "system" in generated_prompt:
  26. print("=== SYSTEM PROMPT ===")
  27. print(generated_prompt["system"])
  28. print("\n=== USER PROMPT ===")
  29. print(generated_prompt["user"])
  30. else:
  31. print("=== COMPLETE PROMPT ===")
  32. print(generated_prompt["prompt"])
  33. # You can also see how the task description gets formatted
  34. print("\n=== TASK CONTEXT ===")
  35. print(f"Task Description: {task.description}")
  36. print(f"Expected Output: {task.expected_output}")

覆盖默认指令

你有几种方式可以获得 Prompt 的完全控制权:

方案 1:自定义模板(推荐)

  1. from crewai import Agent
  2. # Define your own system template without default instructions
  3. custom_system_template = """You are {role}. {backstory}
  4. Your goal is: {goal}
  5. Respond naturally and conversationally. Focus on providing helpful, accurate information."""
  6. custom_prompt_template = """Task: {input}
  7. Please complete this task thoughtfully."""
  8. agent = Agent(
  9. role="Research Assistant",
  10. goal="Help users find accurate information",
  11. backstory="You are a helpful research assistant.",
  12. system_template=custom_system_template,
  13. prompt_template=custom_prompt_template,
  14. use_system_prompt=True # Use separate system/user messages
  15. )

方案 2:自定义 Prompt 文件

创建一个 custom_prompts.json 文件,用于覆盖特定 Prompt slice:

  1. {
  2. "slices": {
  3. "no_tools": "\nProvide your best answer in a natural, conversational way.",
  4. "tools": "\nYou have access to these tools: {tools}\n\nUse them when helpful, but respond naturally.",
  5. "formatted_task_instructions": "Format your response as: {output_format}"
  6. }
  7. }

然后在你的 crew 中这样使用:

  1. crew = Crew(
  2. agents=[agent],
  3. tasks=[task],
  4. prompt_file="custom_prompts.json",
  5. verbose=True
  6. )

方案 3:为 o1 模型禁用系统 Prompt

  1. agent = Agent(
  2. role="Analyst",
  3. goal="Analyze data",
  4. backstory="Expert analyst",
  5. use_system_prompt=False # Disables system prompt separation
  6. )

使用可观测性工具进行调试

为了实现生产环境透明性,可集成可观测性平台来监控所有 Prompt 和 LLM 交互。这使你能够准确看到发送给 LLM 的 Prompt 内容(包括默认指令)。

详细的集成指南可参考我们的 可观测性文档,其中包含 Langfuse、MLflow、Weights & Biases 以及自定义日志方案等多个平台的说明。

面向生产环境的最佳实践

  1. 在部署到生产环境之前,始终检查生成后的 Prompt
  2. 当你需要完全控制 Prompt 内容时,使用自定义模板
  3. 集成可观测性工具,持续监控 Prompt(参见 可观测性文档
  4. 针对不同 LLM 进行测试,因为默认指令在不同模型上的表现可能不同
  5. 记录你的 Prompt 自定义内容,以提高团队透明度
默认指令的存在是为了保证 Agent 行为的一致性,但它们也可能干扰领域特定需求。使用上面的自定义方式,可以让你在生产系统中始终保持对 Agent 行为的完全控制。

管理 Prompt 文件的最佳实践

在进行底层 Prompt 自定义时,请遵循以下建议,以保持内容有序且易于维护:

  1. 保持文件分离 —— 将自定义 Prompt 存放在独立的 JSON 文件中,而不是混在主代码中。
  2. 版本控制 —— 在仓库中跟踪这些文件的变更,确保能够清晰记录 Prompt 调整历史。
  3. 按模型或语言组织 —— 使用诸如 prompts_llama.jsonprompts_es.json 的命名方式,以快速识别特定配置。
  4. 记录变更 —— 通过注释或 README 说明自定义内容的目的和范围。
  5. 尽量少改动 —— 只覆盖你确实需要调整的 slice,其余部分尽量保留默认行为。

自定义 Prompt 最简单的方式

一种直接的方法是创建一个 JSON 文件,写入你想覆盖的 Prompt,然后在 Crew 中引用这个文件:

  1. 编写一个包含更新后 Prompt slice 的 JSON 文件。
  2. 通过 Crew 的 prompt_file 参数引用该文件。

CrewAI 会将你的自定义内容与默认内容合并,因此你不需要重新定义所有 Prompt。示例如下:

示例:基础 Prompt 自定义

创建一个 custom_prompts.json 文件,写入你要修改的 Prompt。请确保其中列出了它应包含的所有顶层 Prompt,而不仅仅是你改动的部分:

  1. {
  2. "slices": {
  3. "format": "When responding, follow this structure:\n\nTHOUGHTS: Your step-by-step thinking\nACTION: Any tool you're using\nRESULT: Your final answer or conclusion"
  4. }
  5. }

然后像这样集成:

  1. from crewai import Agent, Crew, Task, Process
  2. # Create agents and tasks as normal
  3. researcher = Agent(
  4. role="Research Specialist",
  5. goal="Find information on quantum computing",
  6. backstory="You are a quantum physics expert",
  7. verbose=True
  8. )
  9. research_task = Task(
  10. description="Research quantum computing applications",
  11. expected_output="A summary of practical applications",
  12. agent=researcher
  13. )
  14. # Create a crew with your custom prompt file
  15. crew = Crew(
  16. agents=[researcher],
  17. tasks=[research_task],
  18. prompt_file="path/to/custom_prompts.json",
  19. verbose=True
  20. )
  21. # Run the crew
  22. result = crew.kickoff()

通过这些简单修改,你就可以获得对 Agent 如何沟通和完成任务的底层控制能力。

针对特定模型进行优化

不同模型更适合不同结构的 Prompt。进行更深层的调整,能够通过适配模型特性显著提升性能。

示例:Llama 3.3 Prompt 模板

例如,在处理 Meta 的 Llama 3.3 时,更底层的自定义可以参考以下推荐结构: https://www.llama.com/docs/model-cards-and-prompt-formats/llama3_1/#prompt-template

下面的示例展示了如何通过代码对 Agent 进行微调,以更好地利用 Llama 3.3:

  1. from crewai import Agent, Crew, Task, Process
  2. from crewai_tools import DirectoryReadTool, FileReadTool
  3. # Define templates for system, user (prompt), and assistant (response) messages
  4. system_template = """<|begin_of_text|><|start_header_id|>system<|end_header_id|>{{ .System }}<|eot_id|>"""
  5. prompt_template = """<|start_header_id|>user<|end_header_id|>{{ .Prompt }}<|eot_id|>"""
  6. response_template = """<|start_header_id|>assistant<|end_header_id|>{{ .Response }}<|eot_id|>"""
  7. # Create an Agent using Llama-specific layouts
  8. principal_engineer = Agent(
  9. role="Principal Engineer",
  10. goal="Oversee AI architecture and make high-level decisions",
  11. backstory="You are the lead engineer responsible for critical AI systems",
  12. verbose=True,
  13. llm="groq/llama-3.3-70b-versatile", # Using the Llama 3 model
  14. system_template=system_template,
  15. prompt_template=prompt_template,
  16. response_template=response_template,
  17. tools=[DirectoryReadTool(), FileReadTool()]
  18. )
  19. # Define a sample task
  20. engineering_task = Task(
  21. description="Review AI implementation files for potential improvements",
  22. expected_output="A summary of key findings and recommendations",
  23. agent=principal_engineer
  24. )
  25. # Create a Crew for the task
  26. llama_crew = Crew(
  27. agents=[principal_engineer],
  28. tasks=[engineering_task],
  29. process=Process.sequential,
  30. verbose=True
  31. )
  32. # Execute the crew
  33. result = llama_crew.kickoff()
  34. print(result.raw)

通过这种更深层的配置方式,你可以对基于 Llama 的工作流进行全面、底层的控制,而无需单独创建 JSON 文件。

结论

CrewAI 中底层 Prompt 自定义为高度定制化、复杂场景打开了大门。通过建立组织良好的 Prompt 文件(或直接使用内联模板),你可以适配不同模型、语言以及专业领域。这种灵活性使你能够精确塑造所需的 AI 行为,同时在未进行覆盖时,依然可以依赖 CrewAI 提供的稳定默认配置。

你现在已经具备了在 CrewAI 中进行高级 Prompt 自定义的基础。无论你是为了适配特定模型结构,还是为了满足特定领域约束,这种底层方式都能让你以高度专业化的方式塑造 Agent 交互。