C++ 手写 AI 编程 Agent(9):Prompt 工程从 System Prompt 到 A/B 测试
·
📃作者主页:编程的一拳超人
⛺️ 欢迎关注:👍点赞 👂🏽留言 🌟收藏 💞 💞 💞
于高山之巅,方见大河奔涌;于群峰之上,更觉长风浩荡。

📌 专栏系列: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"
关键原则:
- 说明返回值:LLM 需要知道工具返回什么才能决定如何使用
- 说明边界情况:大文件怎么办?文件不存在怎么办?
- 参数语义清晰:不要假设 LLM 能猜出
path是相对还是绝对路径 - 提供使用示例:在 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_;
};
📚 系列目录
- 第1篇:AI Agent概念入门与ReAct架构设计
- 第2篇:环境搭建与CMake依赖管理
- 第3篇:工具注册表与文件操作工具集
- 第4篇:编译诊断工具与Shell执行引擎
- 第5篇:工具超时缓存与链式组合模式
- 第6篇:Agent核心循环消息管理与LLM调用
- 第7篇:Token窗口管理与错误恢复策略
- 第8篇:记忆系统规划引擎与多Agent协作
- ✅ 第9篇:Prompt工程从System Prompt到AB测试(当前阅读)
- 第10篇:主程序整合与端到端实战演示
- 第11篇:Reflexion与Tree-of-Thought等高级模式
- 第12篇:性能优化安全防护与FAQ总结
⬅️ 上一篇:第8篇:记忆系统规划引擎与多Agent协作
➡️ 下一篇:第10篇:主程序整合与端到端实战演示
更多推荐




所有评论(0)