在这里插入图片描述

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

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

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


请添加图片描述

📌 专栏系列: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社区

更多推荐