提示词也是代码

在LLM应用中,提示词是影响输出质量最关键的变量。但提示词往往散落在代码中、聊天记录里、文档中,缺乏系统的版本管理。将提示词纳入Git版本管理,是LLM工程化的基本要求。

提示词仓库结构

prompts/
├── system/
│   ├── assistant.md          # 通用助手系统提示
│   ├── coding_assistant.md   # 编程助手系统提示
│   └── rag_assistant.md      # RAG助手系统提示
├── templates/
│   ├── chat.j2               # 对话模板
│   ├── summarize.j2          # 摘要模板
│   └── extract.j2            # 信息提取模板
├── few_shot/
│   ├── classification.json   # 分类示例
│   └── extraction.json       # 提取示例
├── versions/
│   ├── v1.0/                 # 历史版本
│   └── v2.0/
└── config.yaml               # 提示词配置

提示词模板管理

from jinja2 import Environment, FileSystemLoader
import git

class PromptManager:
    def __init__(self, prompts_dir="./prompts"):
        self.env = Environment(loader=FileSystemLoader(prompts_dir))
        self.repo = git.Repo(prompts_dir)
    
    def get_prompt(self, template_name, **variables):
        """渲染提示词模板"""
        template = self.env.get_template(template_name)
        return template.render(**variables)
    
    def get_version(self, template_name, commit_hash):
        """获取指定版本的提示词"""
        blob = self.repo.commit(commit_hash).tree / template_name
        return blob.data_stream.read().decode()
    
    def diff_versions(self, template_name, v1, v2):
        """比较两个版本的差异"""
        diff = self.repo.git.diff(v1, v2, template_name)
        return diff
    
    def list_versions(self, template_name):
        """列出提示词的所有修改历史"""
        commits = list(self.repo.iter_commits(paths=template_name))
        return [{"hash": c.hexsha[:8], "message": c.message, "date": c.committed_datetime} for c in commits]

提示词配置

# config.yaml
prompts:
  assistant:
    template: "system/assistant.md"
    model: "qwen3-32b"
    temperature: 0.7
    max_tokens: 2048
    variables:
      - name: user_name
        required: true
      - name: context
        required: false
        default: ""
  
  summarize:
    template: "templates/summarize.j2"
    model: "qwen3-7b"  # 摘要用小模型
    temperature: 0.3    # 低温度保持一致性
    max_tokens: 512

提示词A/B测试

class PromptABTest:
    def __init__(self, prompt_manager, variant_a, variant_b, split=0.5):
        self.pm = prompt_manager
        self.variant_a = variant_a  # 版本A的commit hash
        self.variant_b = variant_b  # 版本B的commit hash
        self.split = split
        self.results = {"a": [], "b": []}
    
    def get_prompt(self, template_name, user_id, **variables):
        """基于用户ID确定性分流"""
        hash_val = int(hashlib.md5(user_id.encode()).hexdigest(), 16)
        variant = "a" if (hash_val % 100) / 100 < self.split else "b"
        
        commit = self.variant_a if variant == "a" else self.variant_b
        template_str = self.pm.get_version(template_name, commit)
        
        from jinja2 import Template
        return Template(template_str).render(**variables), variant
    
    def record_result(self, variant, score):
        self.results[variant].append(score)
    
    def get_winner(self):
        avg_a = sum(self.results["a"]) / len(self.results["a"]) if self.results["a"] else 0
        avg_b = sum(self.results["b"]) / len(self.results["b"]) if self.results["b"] else 0
        return "a" if avg_a >= avg_b else "b"

CI/CD集成

# .github/workflows/prompt-review.yml
name: Prompt Review
on:
  pull_request:
    paths: ['prompts/**']

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Validate prompt templates
        run: |
          python scripts/validate_prompts.py --dir prompts/
      - name: Run prompt tests
        run: |
          python scripts/test_prompts.py --model qwen3-7b --test-cases test_cases/
      - name: Compare with previous version
        run: |
          python scripts/compare_prompts.py --base main --head ${{ github.head_ref }}
      - name: Quality regression check
        run: |
          python scripts/quality_check.py --threshold 0.85

提示词评估

class PromptEvaluator:
    def __init__(self, llm, test_cases):
        self.llm = llm
        self.test_cases = test_cases  # 预标注的测试用例
    
    async def evaluate(self, prompt_template, prompt_version):
        """评估提示词版本的质量"""
        results = []
        
        for case in self.test_cases:
            # 渲染提示词
            prompt = self.render(prompt_template, prompt_version, case["input"])
            
            # 生成响应
            response = await self.llm.generate(prompt)
            
            # 评估
            score = self.score(response, case["expected"])
            results.append({
                "case_id": case["id"],
                "score": score,
                "response": response,
            })
        
        avg_score = sum(r["score"] for r in results) / len(results)
        return {"version": prompt_version, "avg_score": avg_score, "details": results}

提示词回滚

# 回滚到上一个版本
git log --oneline prompts/system/assistant.md
# a1b2c3d 优化系统提示措辞
# d4e5f6g 初始版本

# 查看差异
git diff d4e5f6g a1b2c3d prompts/system/assistant.md

# 回滚
git checkout d4e5f6g -- prompts/system/assistant.md
git commit -m "rollback: 回滚assistant提示词到初始版本"

实践建议

  1. 提示词与代码分离:提示词文件独立存放,不硬编码在代码中
  2. 模板化:使用Jinja2等模板引擎,支持变量注入
  3. 评审流程:提示词修改需要通过PR评审和自动化测试
  4. 版本标注:重要版本打tag,便于快速回滚
  5. 多语言管理:不同语言的提示词分目录管理
  6. 文档化:每个提示词文件包含描述、适用场景、注意事项

结语

提示词是LLM应用中投入产出比最高的优化点。将提示词纳入Git版本管理,配合模板化、A/B测试、自动化评估和CI/CD流程,可以让提示词迭代从"凭感觉改"变为"数据驱动改"。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。