这是一个面向 ChatBot、Agent 和 AI 应用的纯 C++ AI SDK。当前仓库已经具备可本地构建、可运行真实 DeepSeek API 调用、可执行基础测试的最小闭环。
当前已经落地的重点包括:
- 根目录统一使用
CMake + vcpkg + CMake Presets include/、src/、examples/、tests/的模块化骨架DeepSeekProvider的真实chat/streamChat请求链路- 基于
.env、环境变量和 JSON 配置占位符的本地配置读取 - 本地 C++ 工具注册、稳定列举、串行执行与异常收敛
- 由
AIClient::executeToolCalls(...)暴露的显式单批 Tool Call 执行接口 - 显式
TraceSession、线程安全步骤快照、默认安全元数据与 JSON 导出 - 独立的
agent_runtime与ai_agent:提供显式会话、项目记忆、受限工作区文件工具、审批、资源治理和本地命令执行
ai_sdk/
CMakeLists.txt
CMakePresets.json
CMakeUserPresets.json
vcpkg.json
README.md
docs/
PRD.md
跨平台构建方案.md
include/
AIClient.h
core/
provider/
http/
tool/
trace/
src/
AIClient.cpp
core/
provider/
http/
tool/
trace/
agent/
include/agent_runtime/
WorkspaceFileTools.h
src/
cli/
tests/
examples/
01_chat_deepseek/
02_chat_minimax/
03_stream_chat/
04_register_tool/
05_tool_call/
07_trace/
tests/
smoke/
core/
provider/
tool/
http/
trace/
- CMake 3.23 及以上
- 支持 C++17 的编译器
- Ninja
- Git
- vcpkg
cprnlohmann-jsonspdloggtest
项目默认通过 CMakePresets.json 管理构建配置。
公共预设:
windows-debugwindows-releaselinux-debuglinux-release
本地预设:
local-windows-debuglocal-windows-bootstraplocal-windows-release
其中:
CMakePresets.json用于仓库共享配置CMakeUserPresets.json用于本机私有配置- 当前本机私有配置里,
VCPKG_ROOT指向D:/vcpkg
如果终端没有自动加载 Visual Studio 开发者环境,建议先进入 vcvars64.bat。
方式 A:先加载开发者环境,再使用本地预设
REM 加载 64 位 MSVC 编译工具链,使当前终端可以使用 cl.exe 等构建工具。
call D:\software\VS\Community\VC\Auxiliary\Build\vcvars64.bat
REM 使用本机的 Debug 预设检查依赖并生成 Ninja 构建文件。
cmake --preset local-windows-debug
REM 按 Debug 预设编译核心库、示例和测试,并输出完整构建命令。
cmake --build --preset local-windows-debug -v
REM 运行 Debug 预设对应的全部测试,并在失败时显示详细输出。
ctest --preset local-windows-debug --output-on-failure方式 B:一次性执行
REM 加载 64 位 MSVC 工具链,然后配置 Debug 构建目录。
call D:\software\VS\Community\VC\Auxiliary\Build\vcvars64.bat && cmake --preset local-windows-debug
REM 加载 64 位 MSVC 工具链,然后编译 Debug 目标并输出完整构建命令。
call D:\software\VS\Community\VC\Auxiliary\Build\vcvars64.bat && cmake --build --preset local-windows-debug -v
REM 加载 64 位 MSVC 工具链,然后运行全部测试并显示失败详情。
call D:\software\VS\Community\VC\Auxiliary\Build\vcvars64.bat && ctest --preset local-windows-debug --output-on-failureREM 加载 64 位 MSVC 编译工具链。
call D:\software\VS\Community\VC\Auxiliary\Build\vcvars64.bat
REM 使用本机的 Release 预设检查依赖并生成优化构建文件。
cmake --preset local-windows-release
REM 按 Release 预设编译核心库和示例,并输出完整构建命令。
cmake --build --preset local-windows-release -v如果只想验证核心库和依赖是否能正确配置,可以使用 bootstrap 预设:
REM 加载 64 位 MSVC 编译工具链。
call D:\software\VS\Community\VC\Auxiliary\Build\vcvars64.bat
REM 配置仅包含核心库的 bootstrap 构建目录,不启用示例和测试。
cmake --preset local-windows-bootstrap
REM 编译 bootstrap 目标,快速验证工具链、依赖和核心库入口。
cmake --build --preset local-windows-bootstrap -v这个预设会关闭 examples 和 tests,只验证核心库入口,适合排查工具链问题。
从 0.1.0 起,项目可安装为标准 CMake Config Package。推荐先构建 Release 版本,再指定一个独立安装前缀:
# 使用 Release 预设配置并编译 SDK,再把库、公开头文件和 CMake 包描述安装到指定目录。
cmake --preset local-windows-release
cmake --build --preset local-windows-release
cmake --install .\build\windows-release --prefix D:\sdk\ai_sdk安装前缀中会包含 include/、lib/ 和 lib/cmake/ai_sdk/。下游项目需要使用与 SDK 相同或兼容的 C++17 工具链,并让其包管理器提供 cpr、nlohmann-json、spdlog;Threads 由 CMake 平台模块解析。下游 CMakeLists.txt 的最小写法如下:
find_package(ai_sdk 0.1 CONFIG REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE ai_sdk::agent_runtime)
target_compile_features(my_app PRIVATE cxx_std_17)Windows 上使用 vcpkg 时,配置下游项目可传入与 SDK 一致的工具链文件和安装前缀:
cmake -S . -B build -G Ninja `
-DCMAKE_TOOLCHAIN_FILE=D:\vcpkg\scripts\buildsystems\vcpkg.cmake `
-DCMAKE_PREFIX_PATH=D:\sdk\ai_sdk
cmake --build build软件包导出 ai_sdk::ai_sdk(基础 SDK)与 ai_sdk::agent_runtime(会话、记忆、资源治理和代码 Agent 运行时)。不要链接仓库内部的裸目标,以便后续版本调整内部构建组织而不破坏消费者配置。
Linux 使用仓库共享的 linux-debug 和 linux-release 预设,不使用 Windows 专属的 local-windows-* 预设。开始构建前,请确保已经安装支持 C++17 的 GCC 或 Clang、CMake 3.23 及以上版本、Ninja、Git 和 vcpkg。
以下示例假设 vcpkg 安装在 $HOME/vcpkg。如果实际安装位置不同,请替换为对应的绝对路径。
# 设置 vcpkg 根目录,供 CMake 预设定位 vcpkg 工具链文件。
export VCPKG_ROOT="$HOME/vcpkg"
# 使用共享的 Linux Debug 预设检查依赖并生成 Ninja 构建文件。
cmake --preset linux-debug
# 按 Linux Debug 预设编译核心库、示例和测试,并输出完整构建命令。
cmake --build --preset linux-debug -v
# 运行 Linux Debug 预设对应的全部测试,并在失败时显示详细输出。
ctest --preset linux-debug --output-on-failure在同一个已经设置 VCPKG_ROOT 的终端中执行:
# 使用共享的 Linux Release 预设检查依赖并生成优化构建文件。
cmake --preset linux-release
# 按 Linux Release 预设编译核心库和示例,并输出完整构建命令。
cmake --build --preset linux-release -v当前仓库没有 Linux bootstrap 预设;如果只需要快速验证 Linux 核心库,应先在 CMakePresets.json 中补充对应预设,而不是复用 Windows 专属预设。
当前仓库已经支持从 .env 文件读取密钥和默认配置,主要覆盖三类入口:
examples/01_chat_deepseekexamples/03_stream_chatexamples/05_tool_callloadConfigFromFile(...)
这几个入口都会从当前目录向上查找最近的 .env 文件。也就是说:
- 你可以把
.env放在仓库根目录 - 即使从
build/windows-debug/...子目录启动示例,也能自动找到它
DEEPSEEK_API_KEY=你的_api_key
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-v4-flash如果你使用 loadConfigFromFile 加载 JSON 配置,还可以在 JSON 里继续写占位符:
timeout_ms 仅限制非流式请求的整体时长。stream_total_timeout_ms 可选地限制流式 SSE 的总时长;设为 0 表示关闭总时限,仍由建连超时、持续低速/无数据超时和累计响应大小上限治理。SDK 默认关闭该总时限,ai_agent 会显式设为 10 分钟,以容纳默认开启的高强度思考并在异常流上限到达时返回明确错误。
{
"providers": {
"deepseek": {
"api_key": "${DEEPSEEK_API_KEY}",
"base_url": "${DEEPSEEK_BASE_URL}",
"default_model": "${DEEPSEEK_MODEL}",
"thinking_mode": "enabled",
"thinking_effort": "high"
}
},
"default_provider": "deepseek",
"timeout_ms": 30000,
"connect_timeout_ms": 15000,
"stream_idle_timeout_seconds": 60,
"stream_max_response_bytes": 16777216,
"stream_total_timeout_ms": 0,
"enable_trace": true
}connect_timeout_ms:普通与流式请求共用的 TCP/TLS 建连上限。stream_idle_timeout_seconds:流式响应在持续低速或无数据时的中止窗口;底层按至少每秒 1 字节检测。stream_max_response_bytes:单次流式原始 SSE 响应的累计上限,默认 16 MiB。stream_total_timeout_ms:流式请求的可选总时限;0表示关闭,正整数表示毫秒数。thinking_mode:DeepSeek 思考模式;留空时使用服务端默认,enabled或disabled时显式发送thinking.type。thinking_effort:DeepSeek 思考强度;留空时使用服务端默认,支持low、high或max,请求中映射为thinking.reasoning_effort。
构建完成后运行:
.\build\windows-debug\examples\01_chat_deepseek\example_chat_deepseek.exe "请介绍一下你自己"如果不传命令行参数,示例会使用默认提示词。
.\build\windows-debug\examples\03_stream_chat\example_stream_chat.exe "请流式介绍一下你自己"该示例会实时输出模型返回的增量文本。
该示例不需要 API Key,用于验证工具定义、注册表和本地执行入口:
.\build\windows-debug\examples\04_register_tool\example_register_tool.exe配置 DEEPSEEK_API_KEY 后,可以运行真实 DeepSeek Tool Call 示例:
.\build\windows-debug\examples\05_tool_call\example_tool_call.exe "请查询当前本地时间"SDK 只负责模型协议适配和调用方显式指定的本地工具执行,不会自动形成 Agent Loop。基本调用关系如下:
AIClient client(config);
client.tools().registerTool(tool, handler);
ChatRequest request;
request.messages.push_back(UserMessage("请查询当前本地时间"));
request.tools = client.tools().listTools();
ChatResponse response = client.chat(request);
std::vector<ToolExecutionResult> results =
client.executeToolCalls(response.tool_calls);
// 是否追加 assistant/tool 消息并再次调用 chat,由上层应用决定。executeToolCalls(...) 保持模型返回顺序。未知工具或本地处理函数异常会转换为失败的 ToolResult,不会阻断同一批中的其他工具调用。
ai_agent 是仓库直接构建和安装的命令行代码 Agent,不是示例程序。未传入 --workspace 时,它以程序启动时的当前目录限定文件与命令范围;未传入 --state-dir 时,它将会话快照、JSONL 审计事件和项目记忆保存到当前用户主目录下的 .status(Linux 为 $HOME/.status,Windows 为 %USERPROFILE%\\.status)。显式传入任一选项可覆盖对应默认值,且运行时不会在工作区中创建隐藏状态文件。
未传入 --config 时,CLI 会从当前目录向上加载 .env,并读取 DEEPSEEK_API_KEY、可选的 DEEPSEEK_BASE_URL、DEEPSEEK_MODEL 和 DEEPSEEK_THINKING_MODE。后者默认 disabled,避免复杂工具任务将不可见的思考内容耗尽单轮输出;如需要更强推理可设为 enabled,不支持该字段的兼容代理可设为 inherit。CLI 同时把流式总时限设为 120 秒,并保留低速和响应大小边界。也可以用 --config 传入现有 SDK JSON 配置并自行设置这些字段。构建完成后可直接启动:
# 使用默认目录:当前目录为工作区,当前用户主目录下的 .status 保存运行状态。
.\build\windows-debug\agent\ai_agent.exe "阅读当前项目并修复失败的测试"
# 以一次性任务启动新会话;写文件、目录操作、记忆和命令均会在执行前询问本次批准。
.\build\windows-debug\agent\ai_agent.exe `
--workspace D:\work\project `
--state-dir D:\agent-state\project `
"阅读当前项目并修复失败的测试"
# 进入 REPL;/session 显示稳定会话 ID,/usage 显示最近一次资源治理用量,
# /requests [数量] 显示当前会话的脱敏模型请求账本,/exit 结束本次交互。
.\build\windows-debug\agent\ai_agent.exe `
--workspace D:\work\project `
--state-dir D:\agent-state\project
# 恢复指定会话,或继续当前工作区最近一次已保存会话。
.\build\windows-debug\agent\ai_agent.exe --workspace D:\work\project --state-dir D:\agent-state\project --resume <会话ID> "继续任务"
.\build\windows-debug\agent\ai_agent.exe --workspace D:\work\project --state-dir D:\agent-state\project --continue "继续任务"工具按三档风险治理:Low 的目录列举、读取、查找和搜索可自动执行;Medium 的文件创建、写入、补丁、移动、删除和 remember/forget 必须逐次批准;High 的 run_command 固定在工作区根目录启动,受超时、累计输出上限和取消令牌约束。命令默认总时限为 10 分钟;模型可以在本次工具参数中申请 timeout_seconds,但必须是 1 到 1800 的整数,并会随命令一起进入审计和批准记录。超时或取消仍会终止完整进程树,不支持无限等待。--plan 只将读取工具提供给模型,拒绝全部副作用工具。首期不接入 WebFetch 或 MCP。
REPL 的 /usage 不发起模型调用,展示当前会话最近一次任务的单次请求字节、本次运行新增上下文字节、实际发往主模型的请求次数、工具结果和命令输出上限;还会显示任务总耗时、主模型/审计/工具/人工确认等待的分段耗时、历史压缩次数,以及 Provider 返回的 prompt、completion、缓存与推理 Token 累计值。Provider 的实际 Token 与本地字节预算严格分开,不能将其中任一项理解为另一项。
ai_agent 默认模型为 deepseek-v4-flash:会显式开启思考模式(high),按 1,000,000 Token 上下文窗口和 384,000 Token 单轮输出上限运行。终端收到流式 reasoning_content 后会以 [思考] 前缀即时显示,最终回答和工具生命周期保持原有显示方式;完整工具参数与工具结果正文仍不显示。思考内容属于任务上下文,使用共享终端时请注意可见范围。
可在 .env 或启动环境中配置以下变量覆盖默认模型策略。切换到非 DeepSeek V4 Flash 模型时,必须同时收紧上下文窗口与输出上限,避免本地预算高于服务端能力:
# 默认 enabled;可选 disabled 或 inherit。
DEEPSEEK_THINKING_MODE=enabled
# 默认 high;可选 low、max 或 inherit。
DEEPSEEK_REASONING_EFFORT=high
# 默认 1000000;切换模型时设置其真实上下文窗口。
AGENT_MODEL_CONTEXT_TOKENS=1000000
# 默认 4194304(4 MiB);限制本地序列化请求体,独立于 Token 窗口。
AGENT_MAX_CONTEXT_BYTES=4194304
# 默认 384000;必须不超过所选模型的单轮最大输出。
AGENT_MAX_OUTPUT_TOKENS=384000
# 可选。未设置时分别默认保留 1024 和 2048 Token。
AGENT_MIN_COMPLETION_TOKENS=1024
AGENT_CONTEXT_SAFETY_TOKENS=2048max_tokens 是单轮最大生成量,不是上下文窗口;DeepSeek V4 Flash 的 1M 上下文由输入与生成 Token 共同占用,而单轮最大输出为 384K。运行时会先对完整请求进行保守本地 Token 估算,必要时删除最早的完整工具回合,并动态降低本轮 max_tokens;仍无法保留最小输出空间时以 context_tokens 拒绝,且不会调用模型或消耗主模型请求次数。这个估算不是 Provider 的官方 tokenizer,也不能从上一次 usage 推导“当前剩余窗口”;JSON 字节上限始终保留为第二道硬限制。
/requests [1-100] 只读取当前会话的 JSONL 事件,显示最近有限条主任务与审计模型调用的角色、模型、流式状态、成功状态、耗时、尝试次数、估算输入、动态输出上限、结束原因、工具数量与可选实测 Token。账本绝不保存或显示 Prompt、回答正文、密钥、命令或完整工具参数。
启用 --auto-audit 后,审计继续复用当前任务模型,但只发送独立的脱敏工具快照。审计请求固定低随机度;仅在首次回复格式无效时重试一次,并兼容单个 JSON Markdown 代码块。网络、认证和超时等模型不可用,以及两次格式错误或未知结论,都会保守地改为人工确认,绝不会自动放行。
agent_runtime 自动为每个有效工作区注册受限文件工具。list_directory、read_text_file、find_files 与 search_text 是 Low;创建、写入、替换、目录创建、补丁、移动和删除属于 Medium,会通过运行时的审批策略。所有路径必须相对工作区,工具拒绝绝对路径、越界路径、符号链接逃逸、.git、.env、常见私钥和非 UTF-8 文本。
需要在嵌入式程序中单独注册同一组工具时,包含 agent_runtime/WorkspaceFileTools.h 并链接 ai_sdk::agent_runtime:
aiSDK::agent::WorkspaceFileToolOptions options;
options.root = "D:/agent-workspace";
options.read_risk_level = aiSDK::ToolRiskLevel::Low;
options.write_risk_level = aiSDK::ToolRiskLevel::Medium;
options.enable_advanced_write_tools = true;
options.advanced_write_risk_level = aiSDK::ToolRiskLevel::Medium;
aiSDK::agent::registerWorkspaceFileTools(client.tools(), options);默认单个文件和写入内容最大为 64 KiB,目录列表最多返回 256 项;两项搜索默认最多返回 256 个命中,也可在单次调用中降低 max_results。search_text 会跳过超限或非 UTF-8 文件,并在结果中标记跳过数量和截断状态。生产调用应始终传入最小必要的专用目录。
Trace 默认关闭。开启 Config::enable_trace 后,调用方通过 startTrace() 创建显式会话,并把同一个会话传给需要关联的模型请求、工具执行和后续模型请求:
Config config;
config.enable_trace = true;
AIClient client(config);
TraceSession trace = client.startTrace();
ChatResponse first = client.chat(request, trace);
std::vector<ToolExecutionResult> results =
client.executeToolCalls(first.tool_calls, trace);
// 是否补充消息并再次请求仍由上层应用显式决定。
ChatResponse final = client.chat(request, trace);
Trace snapshot = trace.snapshot();
nlohmann::json trace_json = trace.toJson();每个公开操作都是同一 trace_id 下的新根步骤;Provider、HTTP、SSE 和单个工具步骤通过明确的 parent_step_id 形成内部层级。SDK 不会根据“上一次操作”推断父节点,也不会隐式形成 Agent Loop。
默认 Trace 只保存 Provider、Model、步骤类型、状态、HTTP 状态码、耗时、SSE 与工具增量数量、工具名称及成功计数等元数据。它不会自动保存以下内容:
- API Key 或完整
Authorization头 - URL、用户消息、完整请求体或响应正文
- SSE 文本增量、工具参数、工具结果或底层异常原文
确需业务详情时,可以提供返回 JSON 对象的脱敏器。TraceDetailContext::kind 表示原始输入类别,operation_name 表示当前操作名称:模型请求与响应使用 Provider 名称,工具参数与结果使用工具名称。只有脱敏器返回的顶层对象会写入 details:
TraceOptions options;
options.detail_sanitizer = [](const TraceDetailContext& context, const nlohmann::json& raw) {
if(context.kind == TraceDetailKind::ToolArguments &&
context.operation_name == "get_current_time") {
return nlohmann::json{{"field_count", raw.size()}};
}
return nlohmann::json{{"recorded", true}};
};
TraceSession trace = client.startTrace(options);每个已处理的详情槽位都固定为 {"status": ..., "value": {...}}。脱敏器正常返回对象时状态为 recorded;返回数组、标量或 null 时状态为 rejected;抛出异常时状态为 sanitizer_failed。后两种状态的 value 都是空对象,且不会保存异常文本或原始值。例如:
{
"details": {
"arguments": {
"status": "recorded",
"value": {
"field_count": 2
}
}
}
}脱敏器会接收四类原始输入,调用方必须按类别建立自己的字段白名单:
ModelRequest:chatRequestToJson(request)的完整对象,可能包含消息、工具定义和模型参数。ModelResponse:chatResponseToJson(response)的完整对象,可能包含正文、工具调用、用量和raw_response。ToolArguments:解析后的ToolCall::arguments对象,不传入raw_arguments。ToolResult:成功时为{"success": true, "data": ...},失败时为{"success": false, "error_message": ...}。
Trace JSON 的每个步骤都固定包含 error_code 和 error_summary。成功步骤的 error_code 为 none;失败步骤使用 SDK 固定枚举映射,禁止写入任意错误码或底层异常原文。
TraceSession 可复制,副本共享同一线程安全状态;并发追加、读取快照和 JSON 导出不会丢步骤,输出按步骤开始序号排序。自定义脱敏器自身的并发安全由调用方保证。ToolRegistry 仍不是线程安全容器,不能因为 Trace 会话线程安全而省略工具注册表的外部互斥。
离线示例不需要 API Key:
.\build\windows-debug\examples\07_trace\example_trace.exe迁移说明:早期预留的 TraceRecorder(Trace)、addStep(...) 和返回内部引用的 snapshot() 已移除。新代码应从 AIClient::startTrace() 获取会话,通过带 TraceSession& 的公开重载记录链路,并使用 TraceSession::snapshot() 按值读取稳定快照。
ctest --preset local-windows-debug --output-on-failuretests/provider/ai_sdk_provider_test 会优先加载最近的 .env。如果没有发现 DEEPSEEK_API_KEY,测试会自动跳过,而不是失败。
单独执行方式:
.\build\windows-debug\tests\provider\ai_sdk_provider_test.exetests/smoke/ai_sdk_smoke_test.cpptests/core/ai_sdk_core_testtests/provider/ai_sdk_provider_testtests/tool/ai_sdk_tool_testtests/http/ai_sdk_http_testtests/trace/ai_sdk_trace_testagent/agent_runtime_test:离线覆盖会话/记忆存储、工作区文件工具边界、资源与命令治理、批准策略、计划模式和多轮运行时闭环。
当前这台机器上的已知本地约定如下:
vcpkg路径:D:\vcpkg- Visual Studio 开发者环境入口:
D:\software\VS\Community\VC\Auxiliary\Build\vcvars64.bat - 本地调试预设:
local-windows-debug
如果更换机器,只需要同步修改自己的 CMakeUserPresets.json,不需要改共享的 CMakePresets.json。
当前仓库已经不是单纯的目录骨架,已经具备以下能力:
- 统一的根目录构建入口
- 模块化的
include/...头文件结构 - DeepSeek 真实 API 的普通请求与流式请求
- 基于
.env和环境变量的本地配置读取 - Tool Schema 请求序列化、Tool Call 响应解析
- 本地工具注册、单批串行执行和 Tool 结果消息转换
- 显式、线程安全、默认脱敏的内存 Trace 与 JSON 导出
- 可安装的
agent_runtime与真实ai_agentCLI:显式会话恢复、项目记忆、受限工作区文件工具、分级批准、资源治理和受控本地命令 - 可本地执行的核心测试与在线 Provider 测试入口
下一步的实现重点会是:
- 更完整的工具参数 Schema 校验
- 流式 Tool Call 增量聚合
- WebFetch、MCP 与其他外部工具适配;它们将复用已有会话、审批、资源与审计边界
MiniMaxProvider- Trace 持久化与 OpenTelemetry 适配(当前 Trace 只存在于内存中,支持 snapshot() 和 toJson();进程退出后数据就消失,也不会发送给外部监控系统。)