大家好,我是 JavaPub。

前面我们已经分别使用 Python、Node.js 手写过 AI Agent。

这一次来点更硬核的:

C++
+
Claude Opus 5
+
OpenAI Compatible API
+
Tool Calling
+
Agent Loop

我们不使用 LangChain。

不使用 LangGraph。

不使用任何成熟 Agent Framework。

直接使用:

C++17
libcurl
nlohmann/json

从 HTTP 请求开始,自己实现一个真正能够:

理解任务
↓
决定调用工具
↓
执行 C++ 函数
↓
读取工具返回值
↓
继续思考
↓
再次调用工具
↓
完成任务

的 AI Agent。

本文接口继续使用:

https://api.chongplus.plus

调用协议:

OpenAI Compatible API

模型:

claude-opus-5

Anthropic 官方当前公布的 Claude Opus 5 API model ID 也是:

claude-opus-5

并且官方将 Claude Opus 5 推荐用于复杂工具调用、Agent 和较模糊的多步骤任务。

下面默认你的 https://api.chongplus.plus 已经将 claude-opus-5 映射到对应上游模型。

最终,我们要让 C++ 程序实现:

你:

帮我计算 12345 * 6789,
然后把结果保存到笔记。


Claude Opus 5:

[Agent] 准备调用 calculator

[Tool] calculator
参数:
{
    "expression": "12345 * 6789"
}

返回:
83810205


Claude Opus 5:

[Agent] 准备调用 save_note

参数:
{
    "content": "12345 * 6789 = 83810205"
}

返回:
笔记保存成功


Agent:

计算完成:

12345 × 6789 = 83810205

已经保存到笔记。

最重要的是:

我们不会在 C++ 里面写死:

calculator();
save_note();

而是让:

Claude Opus 5

自己决定:

调用哪个工具?

传什么参数?

调用之后下一步干什么?

什么时候任务完成?

这才是真正的:

AI Agent


一、先理解整个 Agent

传统大模型调用:

User
 ↓
LLM
 ↓
Answer

Agent:

User
 ↓
Claude Opus 5
 ↓
Decision
 ↓
Tool Call
 ↓
C++ Tool
 ↓
Tool Result
 ↓
Claude Opus 5
 ↓
Decision
 ↓
Tool Call
 ↓
...
 ↓
Final Answer

所以一个最基础的 Agent 可以理解为:

Agent
=
LLM
+
Prompt
+
Tools
+
Memory
+
Agent Loop

今天我们一个一个把它写出来。


二、准备 C++ 环境

我们需要:

C++17

CMake

libcurl

nlohmann/json

Ubuntu:

sudo apt update

sudo apt install -y \
    build-essential \
    cmake \
    libcurl4-openssl-dev \
    nlohmann-json3-dev

macOS:

brew install cmake
brew install curl
brew install nlohmann-json

查看:

g++ --version

项目目录:

cpp-claude-agent/
├── CMakeLists.txt
└── main.cpp

三、CMakeLists.txt

这一份后面几个例子都可以使用。

cmake_minimum_required(VERSION 3.16)

project(claude_agent)

set(CMAKE_CXX_STANDARD 17)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(CURL REQUIRED)

add_executable(
    claude_agent
    main.cpp
)

target_link_libraries(
    claude_agent
    PRIVATE
    CURL::libcurl
)

编译:

mkdir build

cd build

cmake ..

cmake --build .

运行:

./claude_agent

四、第一个完整程序:C++ 调用 Claude Opus 5

先不要管 Agent。

第一步:

使用 C++ 成功调用一次 Claude Opus 5。

下面是一份完整代码

直接保存:

main.cpp

完整代码 1:最简单 Claude Opus 5 对话

#include <curl/curl.h>

#include <iostream>
#include <string>

#include <nlohmann/json.hpp>


using json = nlohmann::json;


/**
 * API 配置
 */
const std::string API_KEY =
    "sk-xxxxxxxxxxxxxxxx";

const std::string API_URL =
    "https://api.chongplus.plus/v1/chat/completions";

const std::string MODEL =
    "claude-opus-5";


/**
 * libcurl 回调
 *
 * HTTP 返回的数据会进入这里
 */
size_t WriteCallback(
    void* contents,
    size_t size,
    size_t nmemb,
    void* userp
) {

    size_t totalSize =
        size * nmemb;

    std::string* response =
        static_cast<std::string*>(userp);

    response->append(
        static_cast<char*>(contents),
        totalSize
    );

    return totalSize;
}


/**
 * 发送 HTTP POST
 */
std::string httpPost(
    const std::string& url,
    const std::string& body
) {

    CURL* curl =
        curl_easy_init();

    if (!curl) {

        throw std::runtime_error(
            "curl_easy_init failed"
        );
    }


    std::string response;


    struct curl_slist* headers =
        nullptr;


    headers = curl_slist_append(
        headers,
        "Content-Type: application/json"
    );


    std::string authHeader =
        "Authorization: Bearer "
        + API_KEY;


    headers = curl_slist_append(
        headers,
        authHeader.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_URL,
        url.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_HTTPHEADER,
        headers
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POST,
        1L
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POSTFIELDS,
        body.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEFUNCTION,
        WriteCallback
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEDATA,
        &response
    );


    curl_easy_setopt(
        curl,
        CURLOPT_TIMEOUT,
        300L
    );


    CURLcode result =
        curl_easy_perform(curl);


    if (
        result
        != CURLE_OK
    ) {

        std::string error =
            curl_easy_strerror(result);


        curl_slist_free_all(
            headers
        );

        curl_easy_cleanup(
            curl
        );


        throw std::runtime_error(
            error
        );
    }


    curl_slist_free_all(
        headers
    );


    curl_easy_cleanup(
        curl
    );


    return response;
}


/**
 * 调用 Claude
 */
std::string callClaude(
    const std::string& prompt
) {

    json request;


    request["model"] =
        MODEL;


    request["messages"] =
        json::array({

            {
                {
                    "role",
                    "user"
                },

                {
                    "content",
                    prompt
                }
            }

        });


    std::string rawResponse =
        httpPost(
            API_URL,
            request.dump()
        );


    json response =
        json::parse(
            rawResponse
        );


    if (
        response.contains(
            "error"
        )
    ) {

        throw std::runtime_error(
            response.dump(2)
        );
    }


    return response[
        "choices"
    ][0][
        "message"
    ][
        "content"
    ];
}


/**
 * main
 */
int main() {

    curl_global_init(
        CURL_GLOBAL_DEFAULT
    );


    try {

        std::string result =
            callClaude(
                "你好,请简单介绍一下你自己。"
            );


        std::cout
            << "Claude:"
            << std::endl
            << result
            << std::endl;

    }
    catch (
        const std::exception& e
    ) {

        std::cerr
            << "Error: "
            << e.what()
            << std::endl;
    }


    curl_global_cleanup();


    return 0;
}

编译:

mkdir build
cd build

cmake ..
cmake --build .

运行:

./claude_agent

可能得到:

Claude:

你好!我是 Claude,可以帮助你进行编程、分析、写作以及完成复杂任务。

到这里:

C++
        ↓
HTTPS
        ↓
api.chongplus.plus
        ↓
Claude Opus 5
        ↓
Response

已经跑通。

但是现在只是:

ChatBot

还不是:

Agent

五、第二个完整程序:让 Claude 调用 C++ Calculator

接下来进入核心:

Tool Calling

Anthropic 官方的工具调用机制本质也是:

模型决定调用工具
        ↓
应用程序执行工具
        ↓
工具结果交还模型
        ↓
模型继续完成任务

对于 client-side tool,工具真正执行的位置仍然是在我们的程序里,而不是模型服务器替你运行本地 C++ 函数。

假设我们的 C++ 有一个函数:

calculator()

用户:

12345 * 6789 是多少?

Claude 不直接计算。

而是返回:

我要调用 calculator

然后:

C++

真正执行。


六、完整代码 2:单 Tool Agent

下面还是一份完全独立的:

main.cpp

不用拼上一篇代码。

完整代码

#include <curl/curl.h>

#include <iostream>
#include <regex>
#include <stdexcept>
#include <string>

#include <nlohmann/json.hpp>


using json = nlohmann::json;


/**
 * ============================
 * Config
 * ============================
 */

const std::string API_KEY =
    "sk-xxxxxxxxxxxxxxxx";

const std::string API_URL =
    "https://api.chongplus.plus/v1/chat/completions";

const std::string MODEL =
    "claude-opus-5";


/**
 * ============================
 * HTTP
 * ============================
 */

size_t WriteCallback(
    void* contents,
    size_t size,
    size_t nmemb,
    void* userp
) {

    size_t total =
        size * nmemb;


    auto* response =
        static_cast<std::string*>(
            userp
        );


    response->append(
        static_cast<char*>(
            contents
        ),
        total
    );


    return total;
}


std::string httpPost(
    const std::string& url,
    const json& payload
) {

    CURL* curl =
        curl_easy_init();


    if (!curl) {

        throw std::runtime_error(
            "Unable to initialize curl"
        );
    }


    std::string response;


    struct curl_slist* headers =
        nullptr;


    headers = curl_slist_append(
        headers,
        "Content-Type: application/json"
    );


    std::string auth =
        "Authorization: Bearer "
        + API_KEY;


    headers = curl_slist_append(
        headers,
        auth.c_str()
    );


    std::string body =
        payload.dump();


    curl_easy_setopt(
        curl,
        CURLOPT_URL,
        url.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_HTTPHEADER,
        headers
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POSTFIELDS,
        body.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEFUNCTION,
        WriteCallback
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEDATA,
        &response
    );


    curl_easy_setopt(
        curl,
        CURLOPT_TIMEOUT,
        300L
    );


    CURLcode code =
        curl_easy_perform(
            curl
        );


    if (
        code
        != CURLE_OK
    ) {

        std::string error =
            curl_easy_strerror(
                code
            );


        curl_slist_free_all(
            headers
        );


        curl_easy_cleanup(
            curl
        );


        throw std::runtime_error(
            error
        );
    }


    curl_slist_free_all(
        headers
    );


    curl_easy_cleanup(
        curl
    );


    return response;
}


/**
 * ============================
 * Calculator Tool
 * ============================
 *
 * 为了教程简单:
 *
 * 支持:
 *
 * 10 + 20
 * 10 - 20
 * 10 * 20
 * 10 / 20
 *
 * 不使用 eval。
 */

std::string calculator(
    const std::string& expression
) {

    std::regex pattern(
        R"(^\s*(-?\d+(?:\.\d+)?)\s*([\+\-\*\/])\s*(-?\d+(?:\.\d+)?)\s*$)"
    );


    std::smatch match;


    if (
        !std::regex_match(
            expression,
            match,
            pattern
        )
    ) {

        return
            "计算失败:暂时只支持两个数字的 + - * / 运算";
    }


    double a =
        std::stod(
            match[1].str()
        );


    char op =
        match[2].str()[0];


    double b =
        std::stod(
            match[3].str()
        );


    double result;


    switch (op) {

        case '+':

            result =
                a + b;

            break;


        case '-':

            result =
                a - b;

            break;


        case '*':

            result =
                a * b;

            break;


        case '/':

            if (
                b == 0
            ) {

                return
                    "计算失败:除数不能为 0";
            }


            result =
                a / b;

            break;


        default:

            return
                "计算失败:未知运算符";
    }


    std::string value =
        std::to_string(
            result
        );


    while (
        value.size() > 1
        &&
        value.back() == '0'
    ) {

        value.pop_back();
    }


    if (
        !value.empty()
        &&
        value.back() == '.'
    ) {

        value.pop_back();
    }


    return value;
}


/**
 * ============================
 * Tool Schema
 * ============================
 */

json createTools() {

    return json::array({

        {

            {
                "type",
                "function"
            },

            {
                "function",

                {

                    {
                        "name",
                        "calculator"
                    },

                    {
                        "description",
                        "执行数学计算。当用户要求进行加减乘除计算时调用这个工具。不要自己猜测计算结果,应该调用 calculator 获取真正的计算结果。"
                    },

                    {
                        "parameters",

                        {

                            {
                                "type",
                                "object"
                            },

                            {
                                "properties",

                                {

                                    {
                                        "expression",

                                        {

                                            {
                                                "type",
                                                "string"
                                            },

                                            {
                                                "description",
                                                "数学表达式,例如 12345 * 6789"
                                            }

                                        }

                                    }

                                }

                            },

                            {
                                "required",

                                json::array({
                                    "expression"
                                })
                            }

                        }

                    }

                }

            }

        }

    });
}


/**
 * ============================
 * Main
 * ============================
 */

int main() {

    curl_global_init(
        CURL_GLOBAL_DEFAULT
    );


    try {

        json messages =
            json::array({

                {

                    {
                        "role",
                        "system"
                    },

                    {
                        "content",
                        "你是一个 AI Agent。需要数学计算时必须调用 calculator 工具。"
                    }

                },

                {

                    {
                        "role",
                        "user"
                    },

                    {
                        "content",
                        "帮我计算 12345 * 6789"
                    }

                }

            });


        json request;


        request["model"] =
            MODEL;


        request["messages"] =
            messages;


        request["tools"] =
            createTools();


        request["tool_choice"] =
            "auto";


        std::string raw =
            httpPost(
                API_URL,
                request
            );


        json response =
            json::parse(
                raw
            );


        if (
            response.contains(
                "error"
            )
        ) {

            throw std::runtime_error(
                response.dump(2)
            );
        }


        json assistantMessage =
            response[
                "choices"
            ][0][
                "message"
            ];


        std::cout
            << "第一次模型返回:"
            << std::endl
            << assistantMessage.dump(2)
            << std::endl;


        /**
         * 如果模型要调用 Tool
         */
        if (
            assistantMessage.contains(
                "tool_calls"
            )
        ) {

            messages.push_back(
                assistantMessage
            );


            for (
                const auto& toolCall :
                assistantMessage[
                    "tool_calls"
                ]
            ) {

                std::string toolName =
                    toolCall[
                        "function"
                    ][
                        "name"
                    ];


                std::string argumentsString =
                    toolCall[
                        "function"
                    ][
                        "arguments"
                    ];


                json arguments =
                    json::parse(
                        argumentsString
                    );


                std::string result;


                if (
                    toolName
                    ==
                    "calculator"
                ) {

                    result =
                        calculator(
                            arguments[
                                "expression"
                            ]
                        );
                }
                else {

                    result =
                        "未知工具";
                }


                std::cout
                    << std::endl
                    << "[Tool] "
                    << toolName
                    << std::endl;


                std::cout
                    << "参数:"
                    << arguments.dump(2)
                    << std::endl;


                std::cout
                    << "结果:"
                    << result
                    << std::endl;


                messages.push_back({

                    {
                        "role",
                        "tool"
                    },

                    {
                        "tool_call_id",
                        toolCall[
                            "id"
                        ]
                    },

                    {
                        "content",
                        result
                    }

                });
            }


            /**
             * 将 Tool Result
             * 再次发送给 Claude
             */
            json secondRequest;


            secondRequest["model"] =
                MODEL;


            secondRequest["messages"] =
                messages;


            secondRequest["tools"] =
                createTools();


            secondRequest[
                "tool_choice"
            ] =
                "auto";


            std::string secondRaw =
                httpPost(
                    API_URL,
                    secondRequest
                );


            json secondResponse =
                json::parse(
                    secondRaw
                );


            std::cout
                << std::endl
                << "Claude:"
                << std::endl
                << secondResponse[
                    "choices"
                ][0][
                    "message"
                ][
                    "content"
                ]
                << std::endl;
        }
        else {

            std::cout
                << "Claude:"
                << assistantMessage[
                    "content"
                ]
                << std::endl;
        }

    }
    catch (
        const std::exception& e
    ) {

        std::cerr
            << "Error: "
            << e.what()
            << std::endl;
    }


    curl_global_cleanup();


    return 0;
}

运行:

./claude_agent

第一次 Claude 可能返回:

{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_abc123",
      "type": "function",
      "function": {
        "name": "calculator",
        "arguments": "{\"expression\":\"12345 * 6789\"}"
      }
    }
  ]
}

C++ 执行:

[Tool] calculator

参数:

{
  "expression": "12345 * 6789"
}

结果:

83810205

然后我们把:

83810205

重新告诉 Claude。

Claude:

12345 × 6789 = 83810205。

现在已经出现第一个真正的:

Claude Tool Calling

七、这里发生了什么?

特别重要。

Claude 并没有真正执行:

calculator()

Claude 做的是:

“我决定调用 calculator。”

然后返回:

{
    "name": "calculator",
    "arguments": {
        "expression": "12345 * 6789"
    }
}

真正执行的是:

我们的 C++ 程序

所以:

Claude
负责决策

C++
负责执行

这就是 Agent 最核心的分工。


八、第三个完整程序:三个 Tools

现在继续升级。

增加:

calculator

get_current_time

save_note

其中:

calculator

负责计算。

get_current_time

获取当前时间。

save_note

把信息保存到:

notes.txt

现在用户就可以说:

计算 12345 * 6789,
然后把结果保存下来。

Agent 理论上需要:

calculator
↓
save_note

但这时候会出现一个问题。

我们的上一份代码:

最多只执行一轮工具。

真正复杂任务需要:

多轮 Tool Calling

所以先实现多工具。


九、完整代码 3:多 Tool C++ Agent

这一份依然:

完全独立、直接复制就能运行。

#include <curl/curl.h>

#include <chrono>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <string>

#include <nlohmann/json.hpp>


using json =
    nlohmann::json;


/**
 * ==========================
 * Config
 * ==========================
 */

const std::string API_KEY =
    "sk-xxxxxxxxxxxxxxxx";

const std::string API_URL =
    "https://api.chongplus.plus/v1/chat/completions";

const std::string MODEL =
    "claude-opus-5";


/**
 * ==========================
 * HTTP
 * ==========================
 */

size_t WriteCallback(
    void* contents,
    size_t size,
    size_t nmemb,
    void* userp
) {

    size_t total =
        size * nmemb;


    auto* output =
        static_cast<std::string*>(
            userp
        );


    output->append(
        static_cast<char*>(
            contents
        ),
        total
    );


    return total;
}


json httpPost(
    const json& request
) {

    CURL* curl =
        curl_easy_init();


    if (!curl) {

        throw std::runtime_error(
            "curl init failed"
        );
    }


    std::string response;


    struct curl_slist* headers =
        nullptr;


    headers = curl_slist_append(
        headers,
        "Content-Type: application/json"
    );


    std::string authorization =
        "Authorization: Bearer "
        + API_KEY;


    headers = curl_slist_append(
        headers,
        authorization.c_str()
    );


    std::string body =
        request.dump();


    curl_easy_setopt(
        curl,
        CURLOPT_URL,
        API_URL.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_HTTPHEADER,
        headers
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POSTFIELDS,
        body.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEFUNCTION,
        WriteCallback
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEDATA,
        &response
    );


    curl_easy_setopt(
        curl,
        CURLOPT_TIMEOUT,
        300L
    );


    CURLcode code =
        curl_easy_perform(
            curl
        );


    curl_slist_free_all(
        headers
    );


    curl_easy_cleanup(
        curl
    );


    if (
        code
        != CURLE_OK
    ) {

        throw std::runtime_error(
            curl_easy_strerror(
                code
            )
        );
    }


    return json::parse(
        response
    );
}


/**
 * ==========================
 * Calculator
 * ==========================
 */

std::string calculator(
    const std::string& expression
) {

    std::regex pattern(
        R"(^\s*(-?\d+(?:\.\d+)?)\s*([\+\-\*\/])\s*(-?\d+(?:\.\d+)?)\s*$)"
    );


    std::smatch match;


    if (
        !std::regex_match(
            expression,
            match,
            pattern
        )
    ) {

        return
            "暂时只支持两个数字之间的 + - * /";
    }


    double left =
        std::stod(
            match[1].str()
        );


    char op =
        match[2].str()[0];


    double right =
        std::stod(
            match[3].str()
        );


    double result = 0;


    switch (op) {

        case '+':

            result =
                left + right;

            break;


        case '-':

            result =
                left - right;

            break;


        case '*':

            result =
                left * right;

            break;


        case '/':

            if (
                right == 0
            ) {

                return
                    "除数不能为 0";
            }


            result =
                left / right;

            break;
    }


    std::ostringstream stream;


    stream
        << std::setprecision(15)
        << result;


    return stream.str();
}


/**
 * ==========================
 * Current Time
 * ==========================
 */

std::string getCurrentTime() {

    auto now =
        std::chrono::system_clock::now();


    std::time_t time =
        std::chrono::system_clock::to_time_t(
            now
        );


    std::tm tm{};


#ifdef _WIN32

    localtime_s(
        &tm,
        &time
    );

#else

    localtime_r(
        &time,
        &tm
    );

#endif


    std::ostringstream output;


    output
        << std::put_time(
            &tm,
            "%Y-%m-%d %H:%M:%S"
        );


    return output.str();
}


/**
 * ==========================
 * Save Note
 * ==========================
 */

std::string saveNote(
    const std::string& content
) {

    std::ofstream file(
        "notes.txt",
        std::ios::app
    );


    if (
        !file.is_open()
    ) {

        return
            "笔记保存失败";
    }


    file
        << content
        << std::endl;


    file.close();


    return
        "笔记保存成功";
}


/**
 * ==========================
 * Tool Schema
 * ==========================
 */

json createTools() {

    return json::array({

        {

            {
                "type",
                "function"
            },

            {
                "function",

                {

                    {
                        "name",
                        "calculator"
                    },

                    {
                        "description",
                        "执行数学计算。当用户明确要求计算数学表达式时调用。应该使用工具得到准确结果,而不是猜测答案。"
                    },

                    {
                        "parameters",

                        {

                            {
                                "type",
                                "object"
                            },

                            {
                                "properties",

                                {

                                    {
                                        "expression",

                                        {

                                            {
                                                "type",
                                                "string"
                                            },

                                            {
                                                "description",
                                                "数学表达式,例如 12345 * 6789"
                                            }

                                        }

                                    }

                                }

                            },

                            {
                                "required",

                                json::array({
                                    "expression"
                                })
                            }

                        }

                    }

                }

            }

        },


        {

            {
                "type",
                "function"
            },

            {
                "function",

                {

                    {
                        "name",
                        "get_current_time"
                    },

                    {
                        "description",
                        "获取程序当前运行环境的本地时间。当用户询问现在时间、当前日期或要求记录当前时间时调用。"
                    },

                    {
                        "parameters",

                        {

                            {
                                "type",
                                "object"
                            },

                            {
                                "properties",
                                json::object()
                            }

                        }

                    }

                }

            }

        },


        {

            {
                "type",
                "function"
            },

            {
                "function",

                {

                    {
                        "name",
                        "save_note"
                    },

                    {
                        "description",
                        "把指定文本保存到本地 notes.txt 文件。当用户明确要求保存、记录或写入笔记时调用。"
                    },

                    {
                        "parameters",

                        {

                            {
                                "type",
                                "object"
                            },

                            {
                                "properties",

                                {

                                    {
                                        "content",

                                        {

                                            {
                                                "type",
                                                "string"
                                            },

                                            {
                                                "description",
                                                "需要保存到笔记中的完整文本"
                                            }

                                        }

                                    }

                                }

                            },

                            {
                                "required",

                                json::array({
                                    "content"
                                })
                            }

                        }

                    }

                }

            }

        }

    });
}


/**
 * ==========================
 * Tool Executor
 * ==========================
 */

std::string executeTool(
    const std::string& name,
    const json& arguments
) {

    if (
        name
        ==
        "calculator"
    ) {

        return calculator(
            arguments.value(
                "expression",
                ""
            )
        );
    }


    if (
        name
        ==
        "get_current_time"
    ) {

        return getCurrentTime();
    }


    if (
        name
        ==
        "save_note"
    ) {

        return saveNote(
            arguments.value(
                "content",
                ""
            )
        );
    }


    return
        "未知工具:"
        + name;
}


/**
 * ==========================
 * Main
 * ==========================
 */

int main() {

    curl_global_init(
        CURL_GLOBAL_DEFAULT
    );


    try {

        json messages =
            json::array({

                {

                    {
                        "role",
                        "system"
                    },

                    {
                        "content",
                        R"(你是一个 AI Agent。

你拥有三个工具:

calculator:
进行数学计算。

get_current_time:
获取当前时间。

save_note:
保存笔记。

需要工具时必须调用工具。
不要伪造工具返回值。
工具执行完成以后,根据结果继续帮助用户。)"
                    }

                },

                {

                    {
                        "role",
                        "user"
                    },

                    {
                        "content",
                        "帮我计算 12345 * 6789"
                    }

                }

            });


        json request;


        request["model"] =
            MODEL;


        request["messages"] =
            messages;


        request["tools"] =
            createTools();


        request["tool_choice"] =
            "auto";


        json response =
            httpPost(
                request
            );


        if (
            response.contains(
                "error"
            )
        ) {

            throw std::runtime_error(
                response.dump(2)
            );
        }


        json message =
            response[
                "choices"
            ][0][
                "message"
            ];


        messages.push_back(
            message
        );


        if (
            message.contains(
                "tool_calls"
            )
        ) {

            for (
                const auto& call :
                message[
                    "tool_calls"
                ]
            ) {

                std::string name =
                    call[
                        "function"
                    ][
                        "name"
                    ];


                json arguments =
                    json::parse(
                        call[
                            "function"
                        ][
                            "arguments"
                        ].get<
                            std::string
                        >()
                    );


                std::cout
                    << "[Agent] 调用工具:"
                    << name
                    << std::endl;


                std::cout
                    << "[Agent] 参数:"
                    << arguments.dump(2)
                    << std::endl;


                std::string result =
                    executeTool(
                        name,
                        arguments
                    );


                std::cout
                    << "[Tool] 返回:"
                    << result
                    << std::endl;


                messages.push_back({

                    {
                        "role",
                        "tool"
                    },

                    {
                        "tool_call_id",
                        call[
                            "id"
                        ]
                    },

                    {
                        "content",
                        result
                    }

                });
            }


            json finalRequest;


            finalRequest["model"] =
                MODEL;


            finalRequest["messages"] =
                messages;


            finalRequest["tools"] =
                createTools();


            finalRequest[
                "tool_choice"
            ] =
                "auto";


            json finalResponse =
                httpPost(
                    finalRequest
                );


            std::cout
                << std::endl
                << "Agent:"
                << std::endl
                << finalResponse[
                    "choices"
                ][0][
                    "message"
                ][
                    "content"
                ]
                << std::endl;
        }
        else {

            std::cout
                << message[
                    "content"
                ]
                << std::endl;
        }

    }
    catch (
        const std::exception& e
    ) {

        std::cerr
            << "Error: "
            << e.what()
            << std::endl;
    }


    curl_global_cleanup();


    return 0;
}

这时候:

User
 ↓
Claude Opus 5
 ↓
选择 Tool
 ↓
C++
 ↓
Tool Result
 ↓
Claude

已经完全跑通。

但是:

现在仍然不能算一个完整 Agent。

因为:

它只执行一轮。

十、真正的 Agent 核心:Agent Loop

假设用户:

帮我计算 12345 * 6789,
然后把计算结果保存成笔记。

第一轮:

Claude
↓
calculator

结果:

83810205

这时候任务其实还没完成。

因为用户还要求:

保存结果

于是应该:

83810205
 ↓
Claude
 ↓
save_note
 ↓
保存成功
 ↓
Claude
 ↓
Final Answer

所以不能:

if (tool_calls) {

}

执行完一次就结束。

而应该:

while (true)

不断执行。

这就是:

Agent Loop


十一、第四个完整程序:真正的 Claude Opus 5 Agent

下面这份代码是本文最重要的一份。

它已经具备:

HTTP Client

Claude Opus 5

System Prompt

Tools

Tool Executor

Tool Calling

Agent Loop

最大执行次数

多 Tool

异常处理

完整代码 4:真正的 C++ Agent

#include <curl/curl.h>

#include <chrono>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <string>

#include <nlohmann/json.hpp>


using json =
    nlohmann::json;


/**
 * ==================================================
 * Config
 * ==================================================
 */

const std::string API_KEY =
    "sk-xxxxxxxxxxxxxxxx";


const std::string API_URL =
    "https://api.chongplus.plus/v1/chat/completions";


const std::string MODEL =
    "claude-opus-5";


const int MAX_AGENT_STEPS =
    20;


/**
 * ==================================================
 * libcurl callback
 * ==================================================
 */

size_t WriteCallback(
    void* contents,
    size_t size,
    size_t nmemb,
    void* userp
) {

    size_t total =
        size * nmemb;


    std::string* output =
        static_cast<std::string*>(
            userp
        );


    output->append(
        static_cast<char*>(
            contents
        ),
        total
    );


    return total;
}


/**
 * ==================================================
 * HTTP Client
 * ==================================================
 */

json postJson(
    const json& payload
) {

    CURL* curl =
        curl_easy_init();


    if (!curl) {

        throw std::runtime_error(
            "curl_easy_init failed"
        );
    }


    std::string response;


    struct curl_slist* headers =
        nullptr;


    headers =
        curl_slist_append(
            headers,
            "Content-Type: application/json"
        );


    std::string authorization =
        "Authorization: Bearer "
        + API_KEY;


    headers =
        curl_slist_append(
            headers,
            authorization.c_str()
        );


    std::string requestBody =
        payload.dump();


    curl_easy_setopt(
        curl,
        CURLOPT_URL,
        API_URL.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_HTTPHEADER,
        headers
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POST,
        1L
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POSTFIELDS,
        requestBody.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POSTFIELDSIZE,
        requestBody.size()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEFUNCTION,
        WriteCallback
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEDATA,
        &response
    );


    curl_easy_setopt(
        curl,
        CURLOPT_TIMEOUT,
        600L
    );


    CURLcode code =
        curl_easy_perform(
            curl
        );


    if (
        code
        != CURLE_OK
    ) {

        std::string message =
            curl_easy_strerror(
                code
            );


        curl_slist_free_all(
            headers
        );


        curl_easy_cleanup(
            curl
        );


        throw std::runtime_error(
            "HTTP Error: "
            + message
        );
    }


    long statusCode = 0;


    curl_easy_getinfo(
        curl,
        CURLINFO_RESPONSE_CODE,
        &statusCode
    );


    curl_slist_free_all(
        headers
    );


    curl_easy_cleanup(
        curl
    );


    if (
        statusCode < 200
        ||
        statusCode >= 300
    ) {

        throw std::runtime_error(
            "HTTP "
            + std::to_string(
                statusCode
            )
            + "\n"
            + response
        );
    }


    return json::parse(
        response
    );
}


/**
 * ==================================================
 * Calculator Tool
 * ==================================================
 */

std::string calculator(
    const std::string& expression
) {

    std::regex pattern(
        R"(^\s*(-?\d+(?:\.\d+)?)\s*([\+\-\*\/])\s*(-?\d+(?:\.\d+)?)\s*$)"
    );


    std::smatch match;


    if (
        !std::regex_match(
            expression,
            match,
            pattern
        )
    ) {

        return
            "计算失败:只支持两个数字之间的 + - * /";
    }


    double a =
        std::stod(
            match[1].str()
        );


    char operation =
        match[2].str()[0];


    double b =
        std::stod(
            match[3].str()
        );


    double result = 0;


    switch (
        operation
    ) {

        case '+':

            result =
                a + b;

            break;


        case '-':

            result =
                a - b;

            break;


        case '*':

            result =
                a * b;

            break;


        case '/':

            if (
                b == 0
            ) {

                return
                    "计算失败:除数不能为 0";
            }


            result =
                a / b;

            break;


        default:

            return
                "计算失败";
    }


    std::ostringstream output;


    output
        << std::setprecision(15)
        << result;


    return output.str();
}


/**
 * ==================================================
 * Time Tool
 * ==================================================
 */

std::string getCurrentTime() {

    auto now =
        std::chrono::system_clock::now();


    std::time_t current =
        std::chrono::system_clock::to_time_t(
            now
        );


    std::tm timeInfo{};


#ifdef _WIN32

    localtime_s(
        &timeInfo,
        &current
    );

#else

    localtime_r(
        &current,
        &timeInfo
    );

#endif


    std::ostringstream output;


    output
        << std::put_time(
            &timeInfo,
            "%Y-%m-%d %H:%M:%S"
        );


    return output.str();
}


/**
 * ==================================================
 * Save Note Tool
 * ==================================================
 */

std::string saveNote(
    const std::string& content
) {

    std::ofstream file(
        "notes.txt",
        std::ios::app
    );


    if (
        !file
    ) {

        return
            "保存失败:无法打开 notes.txt";
    }


    file
        << content
        << std::endl;


    file.close();


    return
        "笔记保存成功";
}


/**
 * ==================================================
 * Tool Schemas
 * ==================================================
 */

json buildTools() {

    json tools =
        json::array();


    tools.push_back({

        {
            "type",
            "function"
        },

        {
            "function",

            {

                {
                    "name",
                    "calculator"
                },

                {
                    "description",
                    "执行基础数学计算。当用户需要获得加减乘除计算结果时调用。不要自己估算或猜测数学结果,应优先使用该工具获取准确结果。"
                },

                {
                    "parameters",

                    {

                        {
                            "type",
                            "object"
                        },

                        {
                            "properties",

                            {

                                {
                                    "expression",

                                    {

                                        {
                                            "type",
                                            "string"
                                        },

                                        {
                                            "description",
                                            "要执行的数学表达式,例如 12345 * 6789"
                                        }

                                    }

                                }

                            }

                        },

                        {
                            "required",

                            json::array({
                                "expression"
                            })
                        }

                    }

                }

            }

        }

    });


    tools.push_back({

        {
            "type",
            "function"
        },

        {
            "function",

            {

                {
                    "name",
                    "get_current_time"
                },

                {
                    "description",
                    "读取运行 Agent 的计算机当前本地时间。当用户询问当前时间、日期,或者任务需要真实时间数据时调用。不要根据模型知识猜测当前时间。"
                },

                {
                    "parameters",

                    {

                        {
                            "type",
                            "object"
                        },

                        {
                            "properties",
                            json::object()
                        }

                    }

                }

            }

        }

    });


    tools.push_back({

        {
            "type",
            "function"
        },

        {
            "function",

            {

                {
                    "name",
                    "save_note"
                },

                {
                    "description",
                    "把指定文本追加保存到本地 notes.txt 文件。只有当用户要求保存、记录、写入笔记,或者前面的任务明确需要持久化结果时调用。"
                },

                {
                    "parameters",

                    {

                        {
                            "type",
                            "object"
                        },

                        {
                            "properties",

                            {

                                {
                                    "content",

                                    {

                                        {
                                            "type",
                                            "string"
                                        },

                                        {
                                            "description",
                                            "需要完整保存到笔记文件的内容"
                                        }

                                    }

                                }

                            }

                        },

                        {
                            "required",

                            json::array({
                                "content"
                            })
                        }

                    }

                }

            }

        }

    });


    return tools;
}


/**
 * ==================================================
 * Tool Executor
 * ==================================================
 */

std::string executeTool(
    const std::string& toolName,
    const json& arguments
) {

    if (
        toolName
        ==
        "calculator"
    ) {

        return calculator(
            arguments.value(
                "expression",
                ""
            )
        );
    }


    if (
        toolName
        ==
        "get_current_time"
    ) {

        return getCurrentTime();
    }


    if (
        toolName
        ==
        "save_note"
    ) {

        return saveNote(
            arguments.value(
                "content",
                ""
            )
        );
    }


    return
        "Tool Error:未知工具 "
        + toolName;
}


/**
 * ==================================================
 * Claude API
 * ==================================================
 */

json callClaude(
    const json& messages
) {

    json request;


    request["model"] =
        MODEL;


    request["messages"] =
        messages;


    request["tools"] =
        buildTools();


    request["tool_choice"] =
        "auto";


    return postJson(
        request
    );
}


/**
 * ==================================================
 * Agent
 * ==================================================
 */

std::string runAgent(
    const std::string& userInput
) {

    json messages =
        json::array();


    messages.push_back({

        {
            "role",
            "system"
        },

        {
            "content",

            R"(你是一个 Claude Opus 5 AI Agent。

你的目标不是简单回答用户问题,而是尽可能帮助用户真正完成任务。

你拥有以下工具:

1. calculator
负责数学计算。

2. get_current_time
负责获取真实的当前时间。

3. save_note
负责保存笔记。

工作规则:

1. 首先理解用户真正想完成什么。
2. 如果能够直接回答,可以直接回答。
3. 如果任务需要使用工具,就调用对应工具。
4. 不允许伪造工具执行结果。
5. 每次获得 Tool Result 以后继续判断任务是否已经完成。
6. 如果还需要其他工具,可以继续调用。
7. 一个任务可以连续调用多个工具。
8. 当任务真正完成以后,再返回最终答案。)"

        }

    });


    messages.push_back({

        {
            "role",
            "user"
        },

        {
            "content",
            userInput
        }

    });


    /**
     * Agent Loop
     */
    for (
        int step = 1;
        step <= MAX_AGENT_STEPS;
        ++step
    ) {

        std::cout
            << std::endl
            << "========== Agent Step "
            << step
            << " =========="
            << std::endl;


        json response =
            callClaude(
                messages
            );


        if (
            response.contains(
                "error"
            )
        ) {

            throw std::runtime_error(
                response.dump(2)
            );
        }


        json message =
            response[
                "choices"
            ][0][
                "message"
            ];


        /**
         * 保存 Assistant Message
         */
        messages.push_back(
            message
        );


        /**
         * 没有 Tool Call
         *
         * 说明 Claude 认为任务已经完成。
         */
        if (
            !message.contains(
                "tool_calls"
            )
            ||
            message[
                "tool_calls"
            ].empty()
        ) {

            if (
                message.contains(
                    "content"
                )
                &&
                !message[
                    "content"
                ].is_null()
            ) {

                return message[
                    "content"
                ].get<
                    std::string
                >();
            }


            return
                "Agent 已结束,但没有返回文本。";
        }


        /**
         * 处理所有 Tool Calls
         */
        for (
            const auto& toolCall :
            message[
                "tool_calls"
            ]
        ) {

            std::string toolName =
                toolCall[
                    "function"
                ][
                    "name"
                ];


            std::string argumentText =
                toolCall[
                    "function"
                ][
                    "arguments"
                ].get<
                    std::string
                >();


            json arguments;


            try {

                arguments =
                    json::parse(
                        argumentText
                    );

            }
            catch (...) {

                arguments =
                    json::object();
            }


            std::cout
                << "[Agent] 调用工具:"
                << toolName
                << std::endl;


            std::cout
                << "[Agent] 参数:"
                << arguments.dump(2)
                << std::endl;


            std::string toolResult;


            try {

                toolResult =
                    executeTool(
                        toolName,
                        arguments
                    );

            }
            catch (
                const std::exception& e
            ) {

                toolResult =
                    std::string(
                        "Tool Error: "
                    )
                    +
                    e.what();
            }


            std::cout
                << "[Tool] 返回:"
                << toolResult
                << std::endl;


            /**
             * Tool Result
             */
            messages.push_back({

                {
                    "role",
                    "tool"
                },

                {
                    "tool_call_id",
                    toolCall[
                        "id"
                    ]
                },

                {
                    "content",
                    toolResult
                }

            });
        }
    }


    throw std::runtime_error(
        "Agent 超过最大执行步数:"
        +
        std::to_string(
            MAX_AGENT_STEPS
        )
    );
}


/**
 * ==================================================
 * main
 * ==================================================
 */

int main() {

    curl_global_init(
        CURL_GLOBAL_DEFAULT
    );


    try {

        std::string result =
            runAgent(
                "帮我计算 12345 * 6789,然后把计算结果保存到笔记。"
            );


        std::cout
            << std::endl
            << "============================"
            << std::endl;


        std::cout
            << "Agent:"
            << std::endl
            << result
            << std::endl;

    }
    catch (
        const std::exception& e
    ) {

        std::cerr
            << std::endl
            << "Agent Error:"
            << e.what()
            << std::endl;
    }


    curl_global_cleanup();


    return 0;
}

运行:

./claude_agent

可能输出:

========== Agent Step 1 ==========

[Agent] 调用工具:calculator

[Agent] 参数:

{
  "expression": "12345 * 6789"
}

[Tool] 返回:

83810205

注意:

程序没有结束。

进入:

Agent Step 2

Claude 再次看到:

User:

计算并保存结果


Tool:

83810205

于是它发现:

还没有保存。

继续:

========== Agent Step 2 ==========

[Agent] 调用工具:save_note

[Agent] 参数:

{
  "content": "12345 × 6789 = 83810205"
}

[Tool] 返回:

笔记保存成功

然后:

========== Agent Step 3 ==========

Claude 发现:

计算完成

保存完成

不再产生:

tool_calls

最终:

Agent:

计算完成。

12345 × 6789 = 83810205。

计算结果已经保存到笔记。

同时生成:

notes.txt

内容:

12345 × 6789 = 83810205

现在:

我们已经真正实现了一个 C++ AI Agent。


十二、Agent Loop 才是核心

上面几百行代码看起来很多。

但真正的 Agent 核心其实只有:

for (
    int step = 0;
    step < MAX_AGENT_STEPS;
    ++step
) {

    auto response =
        callClaude(
            messages
        );


    if (
        response
        没有工具调用
    ) {

        return
            最终答案;
    }


    for (
        每一个 Tool Call
    ) {

        auto result =
            executeTool();


        messages.push_back(
            Tool Result
        );
    }
}

翻译成人话:

让 Claude 思考
       ↓
想调用工具?
       ↓
是
       ↓
执行工具
       ↓
告诉 Claude 工具结果
       ↓
继续思考
       ↓
还需要工具?
       ↓
继续
       ↓
直到任务完成

这就是:

Agent Loop

十三、第五个完整程序:加入 Memory + CLI

刚才还有一个问题。

我们的:

runAgent()

每调用一次:

messages

都会重新创建。

那么:

你:

我叫 JavaPub。


Claude:

好的。


你:

我叫什么?

第二次运行的时候:

Claude 已经忘了。

所以最后我们实现:

Conversation Memory

以及:

CLI Agent

最终效果:

Claude Opus 5 C++ Agent
================================

你:

我叫 JavaPub。

Agent:

好的,我记住了。


你:

帮我计算 111 * 222

Agent:

24642


你:

把刚才那个数字保存起来

Agent:

已经保存 24642。


你:

我叫什么?

Agent:

你叫 JavaPub。

十四、完整代码 5:最终版 C++ Claude Opus 5 Agent

下面就是最终完整版本。

这一份建议直接作为:

main.cpp

保存。

#include <curl/curl.h>

#include <chrono>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <string>

#include <nlohmann/json.hpp>


using json =
    nlohmann::json;


/**
 * ==================================================
 * Configuration
 * ==================================================
 */

const std::string API_KEY =
    "sk-xxxxxxxxxxxxxxxx";


const std::string API_URL =
    "https://api.chongplus.plus/v1/chat/completions";


const std::string MODEL =
    "claude-opus-5";


const int MAX_AGENT_STEPS =
    20;


/**
 * ==================================================
 * System Prompt
 * ==================================================
 */

const std::string SYSTEM_PROMPT =
    R"(你是一个 Claude Opus 5 AI Agent。

你的目标不是简单回答问题,而是帮助用户真正完成任务。

你拥有:

calculator
用于数学计算。

get_current_time
用于获取运行环境的当前时间。

save_note
用于把信息保存到本地笔记。

规则:

1. 先理解用户真正想完成的事情。
2. 可以直接回答的问题直接回答。
3. 需要工具时调用工具。
4. 不允许假装调用工具。
5. 不允许伪造工具返回结果。
6. 工具执行完成以后,根据真实结果继续分析。
7. 一个任务允许连续调用多个工具。
8. 当前任务没有完成时继续工作。
9. 完成任务以后,再向用户返回最终答案。)";


/**
 * ==================================================
 * CURL Callback
 * ==================================================
 */

size_t WriteCallback(
    void* contents,
    size_t size,
    size_t nmemb,
    void* userp
) {

    size_t bytes =
        size * nmemb;


    auto* result =
        static_cast<std::string*>(
            userp
        );


    result->append(
        static_cast<char*>(
            contents
        ),
        bytes
    );


    return bytes;
}


/**
 * ==================================================
 * HTTP JSON POST
 * ==================================================
 */

json postJson(
    const json& payload
) {

    CURL* curl =
        curl_easy_init();


    if (!curl) {

        throw std::runtime_error(
            "无法初始化 CURL"
        );
    }


    struct curl_slist* headers =
        nullptr;


    headers =
        curl_slist_append(
            headers,
            "Content-Type: application/json"
        );


    std::string authHeader =
        "Authorization: Bearer "
        + API_KEY;


    headers =
        curl_slist_append(
            headers,
            authHeader.c_str()
        );


    std::string requestBody =
        payload.dump();


    std::string responseBody;


    curl_easy_setopt(
        curl,
        CURLOPT_URL,
        API_URL.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_HTTPHEADER,
        headers
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POST,
        1L
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POSTFIELDS,
        requestBody.c_str()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_POSTFIELDSIZE,
        requestBody.size()
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEFUNCTION,
        WriteCallback
    );


    curl_easy_setopt(
        curl,
        CURLOPT_WRITEDATA,
        &responseBody
    );


    curl_easy_setopt(
        curl,
        CURLOPT_TIMEOUT,
        600L
    );


    CURLcode code =
        curl_easy_perform(
            curl
        );


    long httpCode = 0;


    curl_easy_getinfo(
        curl,
        CURLINFO_RESPONSE_CODE,
        &httpCode
    );


    curl_slist_free_all(
        headers
    );


    curl_easy_cleanup(
        curl
    );


    if (
        code
        != CURLE_OK
    ) {

        throw std::runtime_error(
            curl_easy_strerror(
                code
            )
        );
    }


    if (
        httpCode < 200
        ||
        httpCode >= 300
    ) {

        throw std::runtime_error(
            "HTTP "
            +
            std::to_string(
                httpCode
            )
            +
            "\n"
            +
            responseBody
        );
    }


    return json::parse(
        responseBody
    );
}


/**
 * ==================================================
 * Tool: calculator
 * ==================================================
 */

std::string calculator(
    const std::string& expression
) {

    std::regex pattern(
        R"(^\s*(-?\d+(?:\.\d+)?)\s*([\+\-\*\/])\s*(-?\d+(?:\.\d+)?)\s*$)"
    );


    std::smatch result;


    if (
        !std::regex_match(
            expression,
            result,
            pattern
        )
    ) {

        return
            "计算失败:当前计算器只支持两个数字之间的 + - * /";
    }


    double left =
        std::stod(
            result[1].str()
        );


    char operation =
        result[2].str()[0];


    double right =
        std::stod(
            result[3].str()
        );


    double answer = 0;


    switch (operation) {

        case '+':

            answer =
                left + right;

            break;


        case '-':

            answer =
                left - right;

            break;


        case '*':

            answer =
                left * right;

            break;


        case '/':

            if (
                right == 0
            ) {

                return
                    "计算失败:除数不能为 0";
            }


            answer =
                left / right;

            break;


        default:

            return
                "计算失败";
    }


    std::ostringstream stream;


    stream
        << std::setprecision(15)
        << answer;


    return stream.str();
}


/**
 * ==================================================
 * Tool: current time
 * ==================================================
 */

std::string getCurrentTime() {

    auto now =
        std::chrono::system_clock::now();


    std::time_t nowTime =
        std::chrono::system_clock::to_time_t(
            now
        );


    std::tm local{};


#ifdef _WIN32

    localtime_s(
        &local,
        &nowTime
    );

#else

    localtime_r(
        &nowTime,
        &local
    );

#endif


    std::ostringstream stream;


    stream
        << std::put_time(
            &local,
            "%Y-%m-%d %H:%M:%S"
        );


    return stream.str();
}


/**
 * ==================================================
 * Tool: save note
 * ==================================================
 */

std::string saveNote(
    const std::string& content
) {

    std::ofstream output(
        "notes.txt",
        std::ios::app
    );


    if (
        !output.is_open()
    ) {

        return
            "保存失败:notes.txt 无法打开";
    }


    output
        << content
        << '\n';


    output.close();


    return
        "笔记保存成功";
}


/**
 * ==================================================
 * Tool Definitions
 * ==================================================
 */

json buildTools() {

    return json::array({

        {

            {
                "type",
                "function"
            },

            {
                "function",

                {

                    {
                        "name",
                        "calculator"
                    },

                    {
                        "description",
                        "执行数学计算。用户要求计算、运算或者任务中需要得到准确数学结果时使用。当前工具支持两个数字之间的加、减、乘、除。"
                    },

                    {
                        "parameters",

                        {

                            {
                                "type",
                                "object"
                            },

                            {
                                "properties",

                                {

                                    {
                                        "expression",

                                        {

                                            {
                                                "type",
                                                "string"
                                            },

                                            {
                                                "description",
                                                "数学表达式,例如 12345 * 6789"
                                            }

                                        }

                                    }

                                }

                            },

                            {
                                "required",

                                json::array({
                                    "expression"
                                })
                            }

                        }

                    }

                }

            }

        },


        {

            {
                "type",
                "function"
            },

            {
                "function",

                {

                    {
                        "name",
                        "get_current_time"
                    },

                    {
                        "description",
                        "返回运行 Agent 的计算机当前本地时间。询问当前日期和时间,或者其他任务依赖真实当前时间时使用。"
                    },

                    {
                        "parameters",

                        {

                            {
                                "type",
                                "object"
                            },

                            {
                                "properties",
                                json::object()
                            }

                        }

                    }

                }

            }

        },


        {

            {
                "type",
                "function"
            },

            {
                "function",

                {

                    {
                        "name",
                        "save_note"
                    },

                    {
                        "description",
                        "把文字追加保存到当前程序目录的 notes.txt 文件。用户明确要求保存、记录或者持久化某个结果时使用。"
                    },

                    {
                        "parameters",

                        {

                            {
                                "type",
                                "object"
                            },

                            {
                                "properties",

                                {

                                    {
                                        "content",

                                        {

                                            {
                                                "type",
                                                "string"
                                            },

                                            {
                                                "description",
                                                "准备保存到 notes.txt 中的完整内容"
                                            }

                                        }

                                    }

                                }

                            },

                            {
                                "required",

                                json::array({
                                    "content"
                                })
                            }

                        }

                    }

                }

            }

        }

    });
}


/**
 * ==================================================
 * Tool Executor
 * ==================================================
 */

std::string executeTool(
    const std::string& name,
    const json& arguments
) {

    if (
        name
        ==
        "calculator"
    ) {

        return calculator(
            arguments.value(
                "expression",
                ""
            )
        );
    }


    if (
        name
        ==
        "get_current_time"
    ) {

        return getCurrentTime();
    }


    if (
        name
        ==
        "save_note"
    ) {

        return saveNote(
            arguments.value(
                "content",
                ""
            )
        );
    }


    return
        "Tool Error:不存在工具 "
        + name;
}


/**
 * ==================================================
 * Agent Class
 * ==================================================
 */

class Agent {

private:

    json messages;


public:

    Agent() {

        messages =
            json::array();


        messages.push_back({

            {
                "role",
                "system"
            },

            {
                "content",
                SYSTEM_PROMPT
            }

        });
    }


    /**
     * 一次用户任务
     */
    std::string run(
        const std::string& userInput
    ) {

        /**
         * Conversation Memory
         *
         * 不清空历史消息。
         */
        messages.push_back({

            {
                "role",
                "user"
            },

            {
                "content",
                userInput
            }

        });


        /**
         * Agent Loop
         */
        for (
            int step = 1;
            step <= MAX_AGENT_STEPS;
            ++step
        ) {

            std::cout
                << std::endl
                << "[Agent Step "
                << step
                << "]"
                << std::endl;


            json request;


            request["model"] =
                MODEL;


            request["messages"] =
                messages;


            request["tools"] =
                buildTools();


            request["tool_choice"] =
                "auto";


            json response =
                postJson(
                    request
                );


            if (
                response.contains(
                    "error"
                )
            ) {

                throw std::runtime_error(
                    response.dump(2)
                );
            }


            json assistant =
                response[
                    "choices"
                ][0][
                    "message"
                ];


            messages.push_back(
                assistant
            );


            /**
             * Claude 没有继续调用工具
             *
             * Agent Task Finished
             */
            if (
                !assistant.contains(
                    "tool_calls"
                )
                ||
                assistant[
                    "tool_calls"
                ].empty()
            ) {

                if (
                    assistant.contains(
                        "content"
                    )
                    &&
                    !assistant[
                        "content"
                    ].is_null()
                ) {

                    return assistant[
                        "content"
                    ].get<
                        std::string
                    >();
                }


                return
                    "Agent 已完成。";
            }


            /**
             * Tool Calls
             */
            for (
                const auto& toolCall :
                assistant[
                    "tool_calls"
                ]
            ) {

                std::string name =
                    toolCall[
                        "function"
                    ][
                        "name"
                    ];


                std::string rawArguments =
                    toolCall[
                        "function"
                    ][
                        "arguments"
                    ].get<
                        std::string
                    >();


                json arguments;


                try {

                    arguments =
                        json::parse(
                            rawArguments
                        );

                }
                catch (...) {

                    arguments =
                        json::object();
                }


                std::cout
                    << "[Agent] Tool:"
                    << name
                    << std::endl;


                std::cout
                    << "[Agent] Args:"
                    << arguments.dump(2)
                    << std::endl;


                std::string toolResult;


                try {

                    toolResult =
                        executeTool(
                            name,
                            arguments
                        );

                }
                catch (
                    const std::exception& e
                ) {

                    toolResult =
                        "Tool Error:"
                        +
                        std::string(
                            e.what()
                        );
                }


                std::cout
                    << "[Tool] Result:"
                    << toolResult
                    << std::endl;


                messages.push_back({

                    {
                        "role",
                        "tool"
                    },

                    {
                        "tool_call_id",
                        toolCall[
                            "id"
                        ]
                    },

                    {
                        "content",
                        toolResult
                    }

                });
            }
        }


        throw std::runtime_error(
            "Agent 已达到最大执行步数 "
            +
            std::to_string(
                MAX_AGENT_STEPS
            )
        );
    }
};


/**
 * ==================================================
 * Main CLI
 * ==================================================
 */

int main() {

    curl_global_init(
        CURL_GLOBAL_DEFAULT
    );


    Agent agent;


    std::cout
        << "===================================="
        << std::endl;


    std::cout
        << "Claude Opus 5 C++ AI Agent"
        << std::endl;


    std::cout
        << "API: "
        << API_URL
        << std::endl;


    std::cout
        << "Model: "
        << MODEL
        << std::endl;


    std::cout
        << "输入 exit / quit 退出"
        << std::endl;


    std::cout
        << "===================================="
        << std::endl;


    while (true) {

        std::cout
            << std::endl
            << "你:";


        std::string input;


        std::getline(
            std::cin,
            input
        );


        if (
            input.empty()
        ) {

            continue;
        }


        if (
            input == "exit"
            ||
            input == "quit"
        ) {

            std::cout
                << "Agent 已退出。"
                << std::endl;


            break;
        }


        try {

            std::string response =
                agent.run(
                    input
                );


            std::cout
                << std::endl
                << "Agent:"
                << std::endl
                << response
                << std::endl;

        }
        catch (
            const std::exception& e
        ) {

            std::cerr
                << std::endl
                << "Agent Error:"
                << e.what()
                << std::endl;
        }
    }


    curl_global_cleanup();


    return 0;
}

十五、运行最终 Agent

编译:

mkdir build

cd build

cmake ..

cmake --build .

运行:

./claude_agent

输出:

====================================
Claude Opus 5 C++ AI Agent
API: https://api.chongplus.plus/v1/chat/completions
Model: claude-opus-5
输入 exit / quit 退出
====================================

你:

输入:

帮我计算 99876 * 6677

运行:

[Agent Step 1]

[Agent] Tool:calculator

[Agent] Args:

{
  "expression": "99876 * 6677"
}

[Tool] Result:

666472052

第二轮:

[Agent Step 2]

最终:

Agent:

99876 × 6677 = 666472052。

十六、继续对话测试 Memory

不要关闭程序。

继续:

你:

把刚才的计算结果保存一下。

Claude 可以看到前面的:

Conversation History

所以知道:

刚才结果 = 666472052

然后:

[Agent Step 1]

[Agent] Tool:save_note

[Agent] Args:

{
  "content": "99876 × 6677 = 666472052"
}

[Tool] Result:

笔记保存成功

最终:

Agent:

已经把刚才的计算结果保存到 notes.txt。

这就是:

Short-Term Memory

十七、再测试一个真正的多步骤任务

输入:

现在几点?

计算 98765 * 4321,

把计算结果和当前时间一起保存到笔记。

Agent 可能调用:

Agent Step 1

get_current_time

返回:

2026-08-14 12:47:10

然后:

Agent Step 2

calculator

返回:

426741565

然后:

Agent Step 3

save_note

参数:

{
  "content": "时间:2026-08-14 12:47:10,98765 × 4321 = 426741565"
}

返回:

笔记保存成功

最后:

Agent Step 4

不再调用工具。

最终:

Agent:

任务完成。

当前时间:
2026-08-14 12:47:10

计算结果:
98765 × 4321 = 426741565

以上信息已经保存到 notes.txt。

这就是一个非常标准的:

Multi-Step Agent

十八、现在再看 Agent 架构

我们的完整 C++ 程序现在已经有:

┌──────────────────────────────┐
│             User             │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│        Conversation          │
│           Memory             │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│       Claude Opus 5          │
│                              │
│     Reason / Decision        │
└──────────────┬───────────────┘
               │
               │ Tool Call
               ▼
┌──────────────────────────────┐
│       Tool Executor          │
├──────────────────────────────┤
│ calculator                   │
│ get_current_time             │
│ save_note                    │
└──────────────┬───────────────┘
               │
               │ Tool Result
               ▼
┌──────────────────────────────┐
│       Claude Opus 5          │
└──────────────┬───────────────┘
               │
        Need More Tools?
          │          │
         YES         NO
          │          │
          ▼          ▼
      Tool Call   Final Answer

十九、Agent 最核心的五个组件

现在再看:

Agent
=
Model
+
Prompt
+
Tools
+
Memory
+
Loop

就很好理解了。


Model

我们的 Model:

Claude Opus 5

API model ID:

claude-opus-5

Anthropic 当前官方文档显示 Claude Opus 5 针对深度推理、Agentic Coding、长时间多步骤任务和工具使用进行了重点增强。

它相当于:

Agent 的大脑

Prompt

我们写:

SYSTEM_PROMPT

定义:

你是谁?

你有哪些工具?

什么时候调用?

什么情况下继续?

什么时候结束?

Tools

我们的工具:

calculator

get_current_time

save_note

相当于:

Agent 的手和脚

模型只能生成 Token。

Tools 才能让 AI:

真正执行操作。

官方 Claude 工具定义也强调了工具的:

name
description
input schema

其中工具描述越清楚,模型越容易正确选择和使用工具。


二十、Tools 可以继续变成什么?

现在只有:

calculator

time

note

但是原理完全一样。

可以继续写:

readFile()

对应:

read_file

可以写:

writeFile()

对应:

write_file

可以写:

runCommand()

对应:

run_shell

可以写:

queryDatabase()

对应:

query_database

可以写:

searchWeb()

对应:

search_web

然后 Agent 就可以变成:

Coding Agent

拥有:

read_file

write_file

list_files

run_command

git_diff

git_status

用户:

帮我检查这个 C++ 项目为什么编译失败。

Claude:

list_files
↓
read_file
↓
run_command
↓
看到 Compiler Error
↓
read_file
↓
write_file
↓
run_command
↓
测试通过

这就是:

Coding Agent

最基础的工作方式。


二十一、还可以做 DevOps Agent

工具:

docker_ps

docker_logs

restart_container

read_nginx_config

curl_url

check_port

用户:

为什么 api.silicogrove.com 返回 502?

Agent:

检查 Nginx
↓
检查 Docker
↓
检查端口
↓
查看日志
↓
发现 upstream 不通
↓
给出原因

如果再给予:

restart_container

权限。

它甚至可以:

发现服务挂了
↓
重启 Container
↓
再次 curl
↓
验证恢复

这就开始成为:

DevOps Agent

二十二、Agent 和传统 C++ 程序最大的区别

传统 C++:

auto result =
    calculator(
        "123 * 456"
    );


saveNote(
    result
);

流程完全由:

程序员

决定。

也就是:

calculator
↓
save_note

但 Agent:

while (true) {

    auto decision =
        claude(messages);

    if (
        decision.toolCalls
    ) {

        executeTool();

        continue;
    }

    return answer;
}

决定:

下一步执行什么

的不再完全是 C++。

而是:

Claude Opus 5

所以 AI Agent 一个非常重要的变化就是:

模型开始参与软件执行流程的控制。


二十三、Agent 与 Workflow

如果代码:

auto data =
    search();

auto article =
    writeArticle(
        data
    );

auto image =
    generateImage(
        article
    );

publish(
    article,
    image
);

这是:

Workflow

程序员已经规定:

搜索
↓
文章
↓
图片
↓
发布

Agent 则是:

用户:

帮我做一篇今天 AI 行业的重要新闻。

Claude 自己决定:

要不要搜索?

搜索什么?

资料够不够?

需不需要第二次搜索?

什么时候开始写?

要不要生成图片?

还缺什么?

可以简单理解:

Workflow

程序控制流程。
Agent

模型参与控制流程。

生产系统通常会:

Agent
+
Workflow

一起使用。


二十四、为什么一定要限制 MAX_AGENT_STEPS?

我们代码里面:

const int MAX_AGENT_STEPS =
    20;

非常重要。

如果直接:

while (true)

理论上 Claude 可能:

Tool
↓
Tool
↓
Tool
↓
Tool
↓
Tool

一直继续。

结果:

Token 不断消耗

API 不断调用

任务永远不结束

所以生产环境至少要有:

MAX_STEPS

MAX_TOKENS

TIMEOUT

MAX_TOOL_CALLS

RATE LIMIT

二十五、不要直接给 Agent Root 权限

这个也非常重要。

比如以后增加:

run_shell

千万不要直接:

system(
    command.c_str()
);

然后允许 Claude 任意执行:

rm -rf /

DROP DATABASE

shutdown

docker rm

生产 Agent 至少需要:

Tool 白名单

命令白名单

参数校验

Sandbox

目录隔离

权限控制

执行超时

Audit Log

Human Confirmation

尤其是:

删除数据

转账

付款

部署

数据库修改

服务器命令

这种操作。

最好:

Claude:

我准备执行:

DELETE FROM users

是否确认?

用户:

确认

程序才真正调用工具。

这就是:

Human in the Loop

二十六、为什么这篇没有直接用 Anthropic 原生协议?

Anthropic 原生 Messages API 的 Tool Schema 形式主要是:

{
  "name": "calculator",
  "description": "...",
  "input_schema": {
    "type": "object"
  }
}

官方文档目前也是按照 name + description + input_schema 定义 client-side tools。

但本文为了:

Python

Node.js

C++

几个版本保持统一,也方便中转平台接入,所以使用:

OpenAI Compatible API

也就是:

POST /v1/chat/completions

Tools:

{
  "type": "function",
  "function": {
    "name": "calculator",
    "parameters": {}
  }
}

这样你无论换:

GPT

Claude

Gemini

DeepSeek

只要你的中转平台实现了统一兼容协议,上层 Agent Runtime 就可以尽量保持一致。

这也是统一 API 协议很有价值的地方。


二十七、Claude Opus 5 为什么适合 Agent?

Anthropic 当前官方文档对 Claude Opus 5 的重点描述就包括:

Deep reasoning

Agentic coding

Long-horizon tasks

Multi-tool work

而且当前默认带有 thinking,并提供不同 effort 档位来控制推理投入。

这恰好对应 Agent 最容易遇到的问题:

不是回答一次问题。

而是连续工作很多步。

例如:

读代码
↓
修改代码
↓
运行
↓
报错
↓
分析
↓
重新修改
↓
测试
↓
继续修复

这种任务:

Tool Calling
+
Long Context
+
Long-Horizon Reasoning

才真正能发挥 Agent 的价值。


二十八、最终我们到底写出了什么?

回头看。

我们没有使用:

LangChain

LangGraph

CrewAI

AutoGen

只有:

C++17

libcurl

JSON

Claude Opus 5

但是已经实现:

用户输入
        ↓
Conversation Memory
        ↓
Claude Opus 5
        ↓
Tool Decision
        ↓
Tool Arguments
        ↓
C++ Tool Executor
        ↓
Tool Result
        ↓
Conversation Context
        ↓
Claude Opus 5
        ↓
继续 Tool Call
        ↓
或者 Final Answer

这已经是:

一个最小可用 Agent Runtime。

二十九、真正要记住的代码其实只有这一段

如果整篇文章只记一段代码:

for (
    int step = 0;
    step < MAX_STEPS;
    ++step
) {

    auto response =
        callClaude(
            messages
        );


    messages.push_back(
        response
    );


    if (
        !response.hasToolCalls()
    ) {

        return
            response.answer();
    }


    for (
        auto& call :
        response.toolCalls()
    ) {

        auto result =
            executeTool(
                call
            );


        messages.push_back(
            result
        );
    }
}

换成人话:

让 AI 思考
↓
AI 决定行动
↓
C++ 执行动作
↓
AI 查看结果
↓
继续思考
↓
继续行动
↓
直到完成

这就是:

Agent


三十、总结

今天我们使用:

C++17

从零实现了:

Claude Opus 5 AI Agent

模型:

claude-opus-5

API:

https://api.chongplus.plus

协议:

OpenAI Compatible API

整个 Agent 最核心的组成:

AI Agent
=
Model
+
Prompt
+
Tools
+
Memory
+
Agent Loop

其中:

Claude Opus 5

负责:

理解

分析

决策

选择工具

生成参数

判断下一步

而:

C++

负责:

HTTP

状态管理

Memory

执行 Tool

权限

异常处理

控制 Agent Loop

最大的变化不是:

AI 可以回答问题了。

而是:

AI 可以根据目标决定下一步应该执行什么。

当 Claude 第一次返回:

我要调用 calculator

C++ 执行:

83810205

再把结果返回 Claude。

Claude 又决定:

我要调用 save_note

最后才回答:

任务完成。

这时候:

它就已经不是一个普通聊天机器人,而是真正开始成为一个 Agent。

接下来如果继续给它增加:

文件系统

Shell

Git

GitHub

Browser

Database

HTTP

Docker

Kubernetes

搜索

图片生成

视频生成

这个 C++ Mini Agent 就能进一步发展成:

Coding Agent

DevOps Agent

Research Agent

Browser Agent

Data Agent

Enterprise Agent

Agent 工程真正难的部分,也会逐渐从:

“怎么调用一个 Tool?”

变成:

“怎么让模型在几十甚至几百个步骤中,
稳定、
安全、
可恢复、
低成本地完成任务?”

到了这里,才是真正的 AI Agent 工程。

一起成为勇猛精进的人类。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐