# libcai2 **Repository Path**: tinytaro/libcai2 ## Basic Information - **Project Name**: libcai2 - **Description**: 轻量级C语言AI Agent 框架 - **Primary Language**: C - **License**: GPL-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-08 - **Last Updated**: 2026-09-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # libcai — 轻量级 AI Agent 框架 `libcai` 是一个轻量级的 AI Agent 框架,用 C 语言实现,面向嵌入式场景设计:HTTP / TLS 能力随源码提供,无需安装额外依赖,在 Linux 上开箱即用;应用只需单线程和一个事件循环,不要求操作系统提供线程、锁或文件系统——内存分配、时间获取、日志输出留有可替换的接口,启动时经 setter 逐项注入,在 MCU 上替换为自身实现即可,库源码无需改动;库挂接到应用已有的事件循环或任务中,由应用决定何时调用 `cai_agent_poll()`,历史窗口按条数配置、请求超时按毫秒配置,流式回复边接收边处理,无需等待完整响应。仓库附带 ESP-IDF 完整工程,移植步骤见教程 12。 ## 快速上手 ```sh cmake -B build && cmake --build build && ctest --test-dir build ``` ```c #include "cai.h" #include #include static void on_text(void *user, const char *text, size_t len) { (void)user; /* text 仅在本次回调内有效,需保留请自行复制 */ fwrite(text, 1, len, stdout); /* 模型每输出一段即打印,无需等待整轮结束 */ fflush(stdout); } static void on_done(void *user, int err, const char *reply) { (void)user; (void)reply; /* 流式模式下正文已由 on_text 打印;reply 是本轮完整回复,仅在回调期内有效 */ printf("\n[%s]\n", err == CAI_OK ? "done" : "fail"); /* 回调内可发起下一轮对话,但不可调用 cai_agent_destroy() */ } int main(void) { /* agent 承担传输:连接、超时、CA 证书、工具表。字符串 setter 在调用点 * 深拷贝,传环境变量指针即可;api_base / model 缺失时在首次 chat 返回 * CAI_EINVAL(创建本身只在内存不足时失败) */ cai_agent_t *a = cai_agent_create(); if (a == NULL) return 1; cai_agent_set_api_base(a, "https://api.deepseek.com"); /* OpenAI 兼容基址(Chat 与 Responses 后端共用,路径由后端追加) */ cai_agent_set_model(a, "deepseek-flash"); /* 任意 OpenAI 兼容模型名 */ cai_agent_set_api_key(a, getenv("DEEPSEEK_API_KEY")); /* 未设置时不发送认证信息,服务端返回 401 */ /* 会话承担历史与回调;订阅 on_text 后请求自动走流式。历史窗口默认 * 20 条、请求超时默认 60 秒,均有对应 setter 可调 */ cai_session_t *s = cai_session_create(NULL); /* user 指针贯透该会话的全部回调 */ if (s == NULL) return 1; cai_session_set_text_cb(s, on_text); cai_session_set_done_cb(s, on_done); cai_agent_chat(a, s, "用一句话介绍你自己"); while (cai_agent_busy(a)) cai_agent_poll(a, 50); /* 网络收发、超时判定、回调分发均在 poll 内完成;busy 归零后可继续调用 chat */ cai_session_destroy(s); cai_agent_destroy(a); /* 丢弃在途请求,不触发回调 */ return 0; } ``` ```sh # 将上方代码保存为 quickstart.c 后编译运行: gcc quickstart.c -Iinclude build/libcai.a -o quickstart && ./quickstart ``` 一条 agent 连接可服务多个会话:`cai_agent_chat()` 带会话参数,会话间自由切换(同一会话同一时刻至多在一轮在途)。 ## TLS 加密 连接 LLM / MCP 服务器默认走 HTTPS。加密实现由 CMake 选项 `CAI_TLS` 选择,默认 `builtin`: | 选项 | 需要安装 | 适用 | | --------- | ----------- | ----------------------------------------------- | | `builtin` | 无 | 开箱即用;仅支持 TLS 1.3 和一种固定加密组合,个别只接受其他加密组合的服务器会拒绝连接 | | `openssl` | OpenSSL 开发库 | 加密组合最全、服务器兼容性最好;服务器拒绝连接时改用此档 | | `mbed` | mbedTLS | 资源受限平台常用 | | `none` | 无 | 不加密,仅用于连接本地服务调试 | 每个档位使用独立的构建目录: ```sh cmake -B build-openssl -DCAI_TLS=openssl && cmake --build build-openssl ``` 手工链接 `openssl` 档的库时,编译命令需补 `-lssl -lcrypto`。 ## 核心能力 | 能力 | 说明 | | --------- | -------------------------------------------------------------------------------------------------------------- | | 多后端 | `cai_agent_set_backend()` 选择服务端协议形态:OpenAI 兼容 Chat Completions(默认)或 OpenAI Responses;会话存储格式不受影响,切换不废弃存量对话 | | 多轮对话 | 历史自动携带;超过窗口上限(默认 20 条,`cai_session_set_max_history()` 可调)时丢弃最旧的消息(system 提示词保留);失败的一轮整体作废,不留残缺对话;历史、回调、请求参数按会话隔离 | | 会话提示词 | `cai_session_set_system()` 为会话设定 system 提示词,每轮对话自动携带 | | 工具调用 | `cai_tool_create()` 组装工具(名称与执行回调必填,用途描述、参数格式、透传指针可选),`cai_agent_add_tool()` 注册给 agent——注册时全部内容深拷贝,之后句柄即可销毁;模型发起调用时库自动执行并回传结果,每个调用在本地执行前触发一次 `on_tool_call` 观察回调;一轮内最多 5 次(`cai_session_set_max_tool_rounds()` 可调);工具函数内不可阻塞,也不可再调用库接口 | | 流式响应 | 订阅 `on_text` / `on_reasoning` 回调即按流式交付增量;都不订阅则整轮完成后一次性交付;60 秒无新内容判定超时(`cai_agent_set_timeout_ms()` 可调) | | 思考过程 | 订阅 `on_reasoning` 接收推理模型的思考增量,与正文分开交付,不混入回复渲染 | | 请求体参数 | `cai_session_set_json()` 合并 temperature 等请求体参数:值直接写 JSON 文法,非 JSON 文本整体按字符串嵌入 | | 工具 JSON | 工具回调收到参数 JSON 文本(转义已由库反转义)、交回结果 JSON 文本——内容归工具回调持有,库只读;解析与构建用你自选的 JSON 库,示例自带 vendored cJSON | | 图片 / 文件输入 | `cai_agent_chat_file()` 传入模型服务端可访问的公网 URL,用于看图或读取文件;MIME 必填;历史轮仅重发 URL | | 会话存储 | 订阅 `on_round` 回调:每轮成功结束库交付本轮消息的 JSON 数组(工具配对等协议细节由库保证),写入文件或数据库由应用决定;重启后 `cai_session_restore()` 逐轮喂回;`cai_session_clear()` 清空内存历史(存储的删除由应用处理) | | 取消对话 | `cai_agent_cancel()` 中止在途的一轮:已写入历史的消息整体回退、不触发收场回调;取消后可立即发起新一轮 | | MCP 工具 | `cai_mcp_create("名字")` 创建客户端、`cai_mcp_connect()` 连接服务器并发现其工具,`cai_mcp_attach()` 注册给 agent(工具名以创建时的名字开头,防重名);模型调用时库转发给服务器并回传结果;服务器重启使会话失效时自动重握手一次并重发原请求,对话不中断 | | 指定 DNS | 网络过滤 UDP 53 端口时,可用 `cai_set_dns_server()` 指定可达的解析服务器 | ## 教程 | 教程 | 内容 | | --------------------------------------------------------------------- | --------------------- | | [教程 01:第一个对话 Agent](docs/tutor/01-minimal-chat-agent.md) | 流式输出、回调接口 | | [教程 02:请求参数调优](docs/tutor/02-request-params.md) | set_json 注入请求体参数、value 文法与保留键 | | [教程 03:多模态对话(看图)](docs/tutor/03-multimodal.md) | 以公网 URL 传入图片 | | [教程 04:给 Agent 装上工具(Function Calling)](docs/tutor/04-tool-calling.md) | 定义注册工具、工具循环 | | [教程 05:让 Agent 执行 Shell 命令(真实工具)](docs/tutor/05-shell-tool.md) | 命令解析执行、超时处理与护栏 | | [教程 06:单 Agent 多会话](docs/tutor/06-multi-session.md) | 会话隔离与切换、busy 规则 | | [教程 07:重启续聊(会话存储)](docs/tutor/07-persistence.md) | 以 JSONL 文件保存并恢复对话上下文 | | [教程 08:长期记忆(remember/recall 工具)](docs/tutor/08-long-term-memory.md) | 工具组装跨重启记忆、system 注入策略、文件存储 | | [教程 09:错误处理与故障排查](docs/tutor/09-error-handling.md) | 错误码、整轮回滚、排查对照表 | | [教程 10:接入 MCP 工具服务器](docs/tutor/10-mcp.md) | 连接服务器、远程工具注册与调用 | | [教程 11:定时任务(到点自动发起对话)](docs/tutor/11-schedule.md) | 由工具设定定时任务并到点触发 | | [教程 12:MCU 移植(ESP32-S3 / ESP-IDF)](docs/tutor/12-mcu-port.md) | 移植到 MCU 平台的完整工程 | | [教程 13:调用 OpenAI Responses API](docs/tutor/13-responses-api.md) | set_backend 切换协议形态、端点组合规则 | | [教程 14:命令行非交互 Agent(脚本与批处理)](docs/tutor/14-headless-agent.md) | argv 输入、busy 等待收场、退出码与看门狗取消、-c 跨进程续聊 | ## 文档 `include/cai.h` 里的 Doxygen 注释是公开 API 的权威说明。执行 `doxygen Doxyfile` 生成 HTML,入口为 `docs/api/html/index.html`。 ## 已知限制 - **仅支持 OpenAI 系对话服务**:协议形态经 `cai_agent_set_backend()` 选择——OpenAI 兼容 Chat Completions(默认,DeepSeek/DashScope 兼容模式/Ollama 等均可)或 OpenAI Responses;Anthropic、Gemini 等其他接口形态,以及 Azure OpenAI 的专用路径与认证方式,均不受支持。 - **单个 agent 实例不能跨线程使用**:同一 agent 及其会话的对话、轮询、销毁必须发生在同一个线程内;每个线程可以各自创建并使用自己的 agent。 - **会话历史默认只存在内存中**:未订阅 `on_round` 回调时,进程退出即丢失;历史窗口满时被丢弃的消息无法恢复。 - **文件附件传的是 URL 引用**:URL 过期或被删除后,恢复的历史中该消息仅剩占位提示,模型无法获取原内容。 - **MCP 只做请求-响应**:仅支持 Streamable HTTP 传输的服务器,不支持以 stdio 方式启动的本地服务器;亦不支持服务器主动推送的通知、断线重放与 OAuth 授权流程。 - **文本按 C 字符串交付**:模型输出中出现空字符时,该处之后的内容会被截断。 ## 许可证 - `libcai`:GPL-2.0-only。 - mongoose:GPL-2.0/商业双许可。 - cJSON:MIT。