在这里插入图片描述

📃作者主页:编程的一拳超人

⛺️ 欢迎关注:👍点赞 👂🏽留言 🌟收藏 💞 💞 💞

于高山之巅,方见大河奔涌;于群峰之上,更觉长风浩荡。


请添加图片描述

📌 专栏系列:C++ AI Agent 实战 / 大模型工具调用 / 智能编程助手
⭐ 如果本文对你有帮助,欢迎点赞、收藏、关注三连支持!
💬 问题交流:评论区留言或私信,看到必回



C++ 手写 AI 编程 Agent(9):Prompt 工程从 System Prompt 到 A/B 测试

适用标准:C++17 | 难度:中高级 | 阅读时间:约 15 分钟
本文是「C++ 手写 AI 编程 Agent」12篇系列的第9篇,深入Prompt工程实践。

6. 记忆系统

System Prompt 是 Agent 行为的灵魂。一个好的 system prompt 能让 Agent 表现提升数个档次。

6.1 完整的 system_prompt.txt

You are CodeAgent, an expert C++ software engineer AI assistant.
You have access to tools that let you read files, write code, compile projects, and execute shell commands.

## Your Capabilities
- Read and analyze source code files
- Write new files and edit existing ones with precision
- Compile C/C++ projects using CMake, Make, or Ninja
- Execute shell commands for testing, git operations, etc.
- Search through codebases using regex patterns

## Working Principles
1. THINK BEFORE ACTING: Always analyze the situation before making changes.
   Read relevant files first to understand context.
2. VERIFY AFTER CHANGES: After writing or editing code, ALWAYS compile
   to verify correctness. Fix any errors you find.
3. MINIMAL CHANGES: Make the smallest change that solves the problem.
   Prefer edit_file over write_file when modifying existing code.
4. EXPLAIN YOUR REASONING: Briefly explain what you're doing and why
   at each step. Keep explanations concise.
5. HANDLE ERRORS GRACEFULLY: If a tool call fails, analyze the error,
   adjust your approach, and try again. Don't give up easily.

## Code Quality Standards
- Follow modern C++ best practices (C++17 or later)
- Use meaningful variable and function names
- Add comments for non-obvious logic
- Handle errors appropriately
- Write clean, readable, maintainable code

## Important Constraints
- NEVER execute destructive commands (rm -rf /, format, etc.)
- NEVER modify files outside the workspace directory
- ALWAYS backup files before overwriting
- Keep responses focused and actionable
- If unsure about something, ask for clarification rather than guessing

## Response Format
When you complete a task, provide:
1. A summary of what was done
2. Any issues encountered and how they were resolved
3. Suggestions for next steps (if applicable)

6.2 逐段解读

段落作用关键点
身份定义设定 Agent 角色和专业领域“expert C++ software engineer” 激活专业知识
能力声明让 LLM 知道自己能做什么与注册的工具一一对应
工作原则约束行为模式“VERIFY AFTER CHANGES” 确保编译自检
代码标准保证输出质量避免生成低质量代码
安全约束防止危险操作与 ShellTool 的安全检查双重保障
响应格式规范输出结构让用户获得一致体验

9B. Prompt 工程深度实践

Agent 的表现高度依赖 Prompt 质量。本章系统化地介绍如何设计和优化 Agent 的 Prompt。

9B.1 Agent System Prompt 设计原则与模板

好的 System Prompt 遵循以下结构:

[身份定义] You are CodeAgent, an expert C++ software engineer...
[能力边界] You have access to these tools: ...
[行为规范] Always follow these rules: ...
[输出格式] When responding, use this format: ...
[示例] Here are examples of good responses: ...
[约束] Never do the following: ...
// include/prompt_builder.h
#pragma once

#include <string>
#include <vector>
#include <sstream>
#include <fmt/core.h>

/// System Prompt 构建器
/// 使用 Builder 模式组装结构化的 System Prompt
class SystemPromptBuilder {
public:
    /// 设置 Agent 身份
    SystemPromptBuilder& identity(const std::string& name,
                                   const std::string& role) {
        identity_ = fmt::format("You are {}, {}.", name, role);
        return *this;
    }

    /// 添加工具描述
    SystemPromptBuilder& tools(const std::vector<std::string>& tool_descriptions) {
        tools_section_ = "Available tools:\n";
        for (const auto& desc : tool_descriptions) {
            tools_section_ += "- " + desc + "\n";
        }
        return *this;
    }

    /// 添加行为规则
    SystemPromptBuilder& rules(const std::vector<std::string>& rule_list) {
        rules_section_ = "Rules you MUST follow:\n";
        for (size_t i = 0; i < rule_list.size(); i++) {
            rules_section_ += fmt::format("{}. {}\n", i + 1, rule_list[i]);
        }
        return *this;
    }

    /// 添加 Few-shot 示例
    SystemPromptBuilder& examples(const std::vector<std::pair<std::string, std::string>>& pairs) {
        examples_section_ = "Examples:\n";
        for (const auto& [input, output] : pairs) {
            examples_section_ += fmt::format("User: {}\nAssistant: {}\n\n", input, output);
        }
        return *this;
    }

    /// 添加约束条件
    SystemPromptBuilder& constraints(const std::vector<std::string>& constraint_list) {
        constraints_section_ = "NEVER do the following:\n";
        for (const auto& c : constraint_list) {
            constraints_section_ += "- " + c + "\n";
        }
        return *this;
    }

    /// 构建最终的 System Prompt
    std::string build() const {
        std::stringstream ss;
        if (!identity_.empty()) ss << identity_ << "\n\n";
        if (!tools_section_.empty()) ss << tools_section_ << "\n";
        if (!rules_section_.empty()) ss << rules_section_ << "\n";
        if (!examples_section_.empty()) ss << examples_section_ << "\n";
        if (!constraints_section_.empty()) ss << constraints_section_ << "\n";
        return ss.str();
    }

private:
    std::string identity_;
    std::string tools_section_;
    std::string rules_section_;
    std::string examples_section_;
    std::string constraints_section_;
};

9B.2 Tool Description 最佳实践

工具描述的质量直接影响 LLM 能否正确调用工具:

✅ 好的工具描述:
"read_file": "Read the contents of a file at the given path. 
 Returns the full text content with line numbers. 
 For files larger than 500 lines, use start_line and end_line 
 parameters to read specific sections."

❌ 差的工具描述:
"read_file": "Reads a file"

关键原则:

  1. 说明返回值:LLM 需要知道工具返回什么才能决定如何使用
  2. 说明边界情况:大文件怎么办?文件不存在怎么办?
  3. 参数语义清晰:不要假设 LLM 能猜出 path 是相对还是绝对路径
  4. 提供使用示例:在 description 中包含简短的参数示例

9B.3 Few-shot 示例的选择与组织

Few-shot 示例帮助 LLM 理解期望的行为模式:

/// Few-shot 示例管理器
class FewShotManager {
public:
    /// 添加示例
    void add_example(const std::string& scenario,
                     const std::string& user_input,
                     const std::string& expected_behavior) {
        examples_.push_back({scenario, user_input, expected_behavior});
    }

    /// 根据当前任务选择最相关的示例
    /// @param task_description 当前任务描述
    /// @param max_examples 最多返回几个示例
    std::vector<std::pair<std::string, std::string>> select_relevant(
        const std::string& task_description, size_t max_examples = 3) const
    {
        // 简单的关键词匹配评分
        struct ScoredExample {
            size_t index;
            int score;
        };

        std::vector<ScoredExample> scored;
        for (size_t i = 0; i < examples_.size(); i++) {
            int score = 0;
            // 检查场景描述中是否包含任务关键词
            const auto& scenario = examples_[i].scenario;
            // 简化的相关性判断
            if (task_description.find("compile") != std::string::npos &&
                scenario.find("compile") != std::string::npos) score += 2;
            if (task_description.find("edit") != std::string::npos &&
                scenario.find("edit") != std::string::npos) score += 2;
            if (task_description.find("debug") != std::string::npos &&
                scenario.find("debug") != std::string::npos) score += 2;

            if (score > 0) scored.push_back({i, score});
        }

        // 按分数排序取前 N 个
        std::sort(scored.begin(), scored.end(),
                  [](const auto& a, const auto& b) { return a.score > b.score; });

        std::vector<std::pair<std::string, std::string>> result;
        for (size_t i = 0; i < std::min(scored.size(), max_examples); i++) {
            const auto& ex = examples_[scored[i].index];
            result.emplace_back(ex.user_input, ex.expected_behavior);
        }
        return result;
    }

private:
    struct Example {
        std::string scenario;
        std::string user_input;
        std::string expected_behavior;
    };
    std::vector<Example> examples_;
};

9B.4 Prompt 版本管理与 A/B 测试

在生产环境中,Prompt 应该像代码一样进行版本管理:

// include/prompt_versioning.h
#pragma once

#include <string>
#include <unordered_map>
#include <fstream>
#include <filesystem>
#include <fmt/core.h>

/// Prompt 版本管理器
class PromptVersionManager {
public:
    explicit PromptVersionManager(const std::string& prompts_dir = "./prompts")
        : prompts_dir_(prompts_dir)
    {
        std::filesystem::create_directories(prompts_dir_);
    }

    /// 保存一个版本的 Prompt
    void save(const std::string& name, const std::string& version,
              const std::string& content) {
        std::string filename = fmt::format("{}/{}_v{}.txt",
                                            prompts_dir_, name, version);
        std::ofstream file(filename);
        file << content;
        fmt::print("[PromptMgr] Saved {} v{}\n", name, version);
    }

    /// 加载指定版本的 Prompt
    std::string load(const std::string& name, const std::string& version) const {
        std::string filename = fmt::format("{}/{}_v{}.txt",
                                            prompts_dir_, name, version);
        if (!std::filesystem::exists(filename)) {
            return "";
        }
        std::ifstream file(filename);
        return std::string(std::istreambuf_iterator<char>(file),
                          std::istreambuf_iterator<char>());
    }

    /// 列出某个 Prompt 的所有可用版本
    std::vector<std::string> list_versions(const std::string& name) const {
        std::vector<std::string> versions;
        std::string prefix = name + "_v";

        for (const auto& entry : std::filesystem::directory_iterator(prompts_dir_)) {
            std::string fname = entry.path().filename().string();
            if (fname.find(prefix) == 0 && fname.ends_with(".txt")) {
                // 提取版本号
                size_t v_start = prefix.length();
                size_t v_end = fname.find(".txt");
                versions.push_back(fname.substr(v_start, v_end - v_start));
            }
        }
        return versions;
    }

    /// A/B 测试:根据比例随机选择版本
    std::string ab_select(const std::string& name,
                           const std::string& version_a,
                           const std::string& version_b,
                           double ratio_a = 0.5) const {
        // 简单的随机选择
        double rand_val = (double)(std::rand() % 1000) / 1000.0;
        const std::string& selected = (rand_val < ratio_a) ? version_a : version_b;
        fmt::print("[A/B Test] Selected {} v{} (ratio_a={:.0f}%)\n",
                   name, selected, ratio_a * 100);
        return load(name, selected);
    }

private:
    std::string prompts_dir_;
};

📚 系列目录


⬅️ 上一篇:第8篇:记忆系统规划引擎与多Agent协作

➡️ 下一篇:第10篇:主程序整合与端到端实战演示


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐