在这里插入图片描述

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

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

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


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


在这里插入图片描述


C++ 手写 AI 编程 Agent(10):主程序整合与端到端实战演示

适用标准:C++17 | 难度:中级 | 阅读时间:约 15 分钟
本文是「C++ 手写 AI 编程 Agent」12篇系列的第10篇,把所有模块组装起来跑通完整流程。

7. 主程序与交互界面

7.1 完整的 main.cpp

// src/main.cpp
#include "agent.h"
#include "file_tools.h"
#include "compile_tool.h"
#include "shell_tool.h"
#include <fmt/core.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>

/// 从文件加载 system prompt
std::string load_system_prompt(const std::string& path) {
    std::ifstream file(path);
    if (!file.is_open()) {
        fmt::print(stderr, "Warning: Cannot load system prompt from {}\n", path);
        return "You are a helpful C++ coding assistant.";
    }
    std::stringstream ss;
    ss << file.rdbuf();
    return ss.str();
}

/// 注册所有内置工具
void register_all_tools(Agent& agent) {
    // 文件操作工具
    agent.register_tool(make_read_file_tool());
    agent.register_tool(make_write_file_tool());
    agent.register_tool(make_edit_file_tool());
    agent.register_tool(make_list_directory_tool());
    agent.register_tool(make_search_in_files_tool());
    
    // 编译工具
    agent.register_tool(make_compile_tool());
    
    // Shell 工具
    agent.register_tool(make_shell_tool());
    
    fmt::print("\n✓ All tools registered.\n\n");
}

void print_banner() {
    fmt::print(R"(
╔══════════════════════════════════════════╗
║       C++ AI Agent v1.0                 ║
║   Read · Write · Compile · Self-Fix     ║
╚══════════════════════════════════════════╝

Commands:
  /reset    - Reset conversation
  /stats    - Show statistics
  /quit     - Exit

)");
}

int main() {
    // 从环境变量获取 API Key
    const char* api_key_env = std::getenv("OPENAI_API_KEY");
    if (!api_key_env) {
        fmt::print(stderr, 
            "Error: OPENAI_API_KEY environment variable not set.\n"
            "Please set it: export OPENAI_API_KEY=sk-...\n");
        return 1;
    }
    
    // 配置 Agent
    AgentConfig config;
    config.api_key = api_key_env;
    config.base_url = std::getenv("OPENAI_BASE_URL") 
        ? std::getenv("OPENAI_BASE_URL") 
        : "https://api.openai.com/v1";
    config.model = std::getenv("AGENT_MODEL") 
        ? std::getenv("AGENT_MODEL") 
        : "gpt-4o";
    config.system_prompt = load_system_prompt("system_prompt.txt");
    config.max_iterations = 20;
    config.verbose = true;
    
    // 创建 Agent 并注册工具
    Agent agent(config);
    register_all_tools(agent);
    
    // 设置回调(可选:自定义输出格式)
    AgentCallbacks callbacks;
    callbacks.on_think = [](int iter, const std::string& thought) {
        fmt::print("\n💭 [Think #{}] {}\n", iter, thought);
    };
    callbacks.on_tool_call = [](const std::string& tool, const json& args) {
        fmt::print("🔧 [Call] {}({})\n", tool, args.dump());
    };
    callbacks.on_tool_result = [](const std::string& tool, const ToolResult& r) {
        fmt::print("{} [Result] {}: {}\n", 
                  r.success ? "✅" : "❌", tool,
                  r.output.substr(0, 200));
    };
    callbacks.on_complete = [](const std::string& answer) {
        fmt::print("\n{'='*60}\n");
        fmt::print("🎯 FINAL ANSWER:\n{}\n", answer);
        fmt::print("{'='*60}\n");
    };
    agent.set_callbacks(std::move(callbacks));
    
    print_banner();
    
    // REPL 主循环
    std::string input;
    while (true) {
        fmt::print("\n👤 You: ");
        if (!std::getline(std::cin, input)) break;
        
        // 去除首尾空白
        auto trim = [](std::string& s) {
            s.erase(0, s.find_first_not_of(" \t\r\n"));
            s.erase(s.find_last_not_of(" \t\r\n") + 1);
        };
        trim(input);
        
        if (input.empty()) continue;
        
        // 特殊命令处理
        if (input == "/quit" || input == "/exit") {
            fmt::print("Goodbye!\n");
            break;
        }
        if (input == "/reset") {
            agent.reset();
            fmt::print("Conversation reset.\n");
            continue;
        }
        if (input == "/stats") {
            auto stats = agent.get_stats();
            fmt::print("Iterations: {}, Tool calls: {}, Tokens: {}\n",
                      stats.total_iterations, stats.total_tool_calls,
                      stats.total_tokens);
            continue;
        }
        
        // 运行 Agent
        try {
            std::string response = agent.run(input);
            // 最终回复已通过回调输出
        } catch (const std::exception& e) {
            fmt::print(stderr, "\n❌ Error: {}\n", e.what());
        }
    }
    
    return 0;
}

8. 完整操作流程演示

8.1 端到端示例:创建一个完整的 C++ 计算器项目

用户输入:

Create a simple calculator library with add, subtract, multiply, divide functions.
Include a main.cpp that demonstrates usage. Set up CMakeLists.txt.
Then compile and verify everything works.

Agent 思考过程逐步展示:

============================================================
Iteration 1/20
============================================================
💭 [Think #1] I need to create three files: the header, implementation,
main.cpp, and CMakeLists.txt. Let me start by creating the project structure.

🔧 [Call] write_file({"path": "include/calculator.h", "content": "#pragma once\n..."})
✅ [Result] write_file: Successfully wrote 245 bytes to include/calculator.h

🔧 [Call] write_file({"path": "src/calculator.cpp", "content": "#include ..."})
✅ [Result] write_file: Successfully wrote 389 bytes to src/calculator.cpp

🔧 [Call] write_file({"path": "src/main.cpp", "content": "#include ..."})
✅ [Result] write_file: Successfully wrote 512 bytes to src/main.cpp

🔧 [Call] write_file({"path": "CMakeLists.txt", "content": "cmake_minimum..."})
✅ [Result] write_file: Successfully wrote 328 bytes to CMakeLists.txt

============================================================
Iteration 2/20
============================================================
💭 [Think #2] All files created. Now I need to compile to verify correctness.

🔧 [Call] compile({"build_dir": "./build"})
❌ [Result] compile: Build FAILED (exit code 1).
  src/calculator.cpp:3:10: fatal error: 'calculator.h' file not found
  #include "calculator.h"

============================================================
Iteration 3/20
============================================================
💭 [Think #3] The include path is wrong. I need to fix the include directive
to use the correct relative path since headers are in include/.

🔧 [Call] edit_file({"path": "src/calculator.cpp", 
    "old_string": "#include \"calculator.h\"", 
    "new_string": "#include \"../include/calculator.h\""})
✅ [Result] edit_file: Replaced 1 occurrence(s) in src/calculator.cpp

============================================================
Iteration 4/20
============================================================
💭 [Think #4] Fixed the include path. Let me also update CMakeLists.txt to
properly set include directories, then recompile.

🔧 [Call] edit_file({"path": "CMakeLists.txt", 
    "old_string": "add_executable(calc src/main.cpp src/calculator.cpp)",
    "new_string": "add_executable(calc src/main.cpp src/calculator.cpp)\ntarget_include_directories(calc PRIVATE include)"})
✅ [Result] edit_file: Replaced 1 occurrence(s) in CMakeLists.txt

🔧 [Call] compile({"build_dir": "./build", "clean": true})
✅ [Result] compile: Build succeeded.

============================================================
Iteration 5/20
============================================================
💭 [Think #5] Build succeeded! Let me run the program to verify output.

🔧 [Call] shell_exec({"command": "./build/calc"})
✅ [Result] shell_exec: 
  Calculator Demo
  5 + 3 = 8
  10 - 4 = 6
  6 * 7 = 42
  15 / 3 = 5

🎯 FINAL ANSWER:
Successfully created a calculator project with the following files:
- include/calculator.h: Header with function declarations
- src/calculator.cpp: Implementation
- src/main.cpp: Demo program
- CMakeLists.txt: Build configuration

Encountered one issue: include path was incorrect initially.
Fixed by adding target_include_directories to CMakeLists.txt.
Project compiles and runs correctly. ✅

8.2 编译失败自修复的完整过程

这个例子展示了 Agent 最核心的价值——自动发现并修复编译错误

  1. Agent 编写代码 → 编译失败
  2. Agent 阅读错误信息 → 分析原因
  3. Agent 编辑代码 → 重新编译
  4. 如果仍然失败 → 重复步骤 2-3
  5. 编译通过 → 报告完成

关键在于 system prompt 中的 “VERIFY AFTER CHANGES” 原则,以及 LLM 对编译器错误的理解能力。

8.3 代码重构任务示例

User: Refactor the calculator to use a class-based design with operator overloading.

Agent 思考链:
1. read_file("include/calculator.h") → 了解当前接口
2. read_file("src/calculator.cpp") → 了解当前实现
3. read_file("src/main.cpp") → 了解使用方式
4. write_file("include/calculator.h") → 重写为类设计
5. write_file("src/calculator.cpp") → 重写实现
6. edit_file("src/main.cpp") → 更新使用方式
7. compile() → 验证编译
8. shell_exec("./build/calc") → 验证运行结果

8.4 Bug 定位与修复示例

User: The divide function returns wrong results for negative numbers. Fix it.

Agent 思考链:
1. read_file("src/calculator.cpp") → 查看 divide 实现
2. Thought: "I see the issue - integer division truncates toward zero,
   but the expected behavior might be floor division..."
3. read_file("src/main.cpp") → 查看测试用例
4. edit_file(...) → 修复逻辑
5. compile() → 验证
6. shell_exec("./build/calc") → 验证输出正确

📚 系列目录


⬅️ 上一篇第9篇:Prompt工程从System Prompt到AB测试

➡️ 下一篇第11篇:Reflexion与Tree-of-Thought等高级模式


Logo

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

更多推荐