# Cortex **Repository Path**: jonas218/cortex ## Basic Information - **Project Name**: Cortex - **Description**: 开源 AI 引擎 SDK,为任意 Rust 应用嵌入 AI Agent 能力。无需理解 LLM API、消息管理、流式解析、Tool Calling 等底层细节——注册业务工具、注入结构化上下文、调用 chat_stream(),即可获得全异步流式 AI 能力。支持 Ollama / DeepSeek / OpenAI 等所有 OpenAI 兼容后端。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-05 - **Last Updated**: 2026-07-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Cortex > 给 Rust 应用嵌入 AI agent 能力 — 双 Provider、完整 ReAct、开箱即用 [![Crates.io](https://img.shields.io/crates/v/cortex)](https://crates.io/crates/cortex) [![Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue)](#) **Cortex** 是 Rust 的 AI Agent SDK。不需要理解 LLM API、SSE 流解析、tool calling 协议。注册工具 → 创建会话 → `chat()`,三行代码获得 agent 能力。 ```rust let engine = Engine::new_openai(Config { .. })?; engine.register_tool(SearchTool).await; let session = manager.create("default").await; let mut stream = session.chat("帮我查一下最近的订单").await?; while let Some(event) = stream.next().await { // TextDelta / ToolCall / ToolResult / ReasoningDelta / Done ... } ``` --- ## 特性 - **🤖 双 Provider** — OpenAI 兼容(Ollama / DeepSeek / GPT)+ Anthropic(Claude),自动适配 - **🔄 完整 ReAct Loop** — Think → Act → Observe,工具并行执行、超时保护 - **🔧 Tool 系统** — `#[derive(Tool)]` 一行宏注册工具,支持 Option/Vec/HashMap - **💬 多会话** — 多标签页对话,各自独立历史,持久化自动存盘 - **🖼 Vision** — 图片理解(GPT-4V / Claude Vision),一条 `user_parts()` 搞定 - **🧠 Reasoning** — Claude Extended Thinking / DeepSeek R1 推理过程 - **⚡ 缓存优化** — 自动前缀对齐,Anthropic 显式 `cache_control`,长对话输入 cost 降 80% - **🔐 工具确认** — 执行前回调,"AI 要删文件,允许吗?" - **📊 Token 追踪** — 每会话累计 token 用量 - **🧪 可测试** — MockProvider,不连 API 跑全流程测试 --- ## 快速开始 ```toml [dependencies] cortex-engine = "1.0" tokio = { version = "1", features = ["full"] } futures = "0.3" ``` ### OpenAI / DeepSeek / Ollama ```rust use cortex_engine::prelude::*; use cortex_engine::memory::FileMemory; use futures::StreamExt; #[tokio::main] async fn main() -> Result<(), AgentError> { let engine = Engine::new_openai(Config { api_base: "https://api.deepseek.com/v1".into(), model: "deepseek-chat".into(), api_key: Some("sk-xxx".into()), ..Default::default() })?; let manager = SessionManager::new(&engine, FileMemory::new("./data")); let session = manager.create("default").await; let mut stream = session.chat("用三句话介绍 Rust").await?; while let Some(event) = stream.next().await { match event { StreamEvent::TextDelta(t) => print!("{t}"), StreamEvent::Done { .. } => break, _ => {} } } Ok(()) } ``` ### Anthropic / Claude ```rust let engine = Engine::new_anthropic(Config { api_base: "https://api.anthropic.com/v1".into(), // 默认值,可省略 model: "claude-sonnet-4-20250514".into(), api_key: Some("sk-ant-xxx".into()), // 必填 ..Default::default() })?; // 其余代码完全一样 — 同一个 SessionManager、同一个 session.chat() ``` --- ## 工具注册 ### Derive 宏(推荐) ```rust use cortex_engine::Tool; use serde_json::{json, Value}; #[derive(Tool)] #[tool(name = "search", desc = "搜索知识库")] struct SearchTool { /// 搜索关键词 query: String, /// 返回结果数量 limit: Option, } impl SearchTool { async fn __tool_execute_impl(&self, query: String, limit: Option) -> Result { let n = limit.unwrap_or(5) as usize; let results = search_kb(&query, n); Ok(json!({ "results": results })) } } engine.register_tool(SearchTool { query: String::new(), limit: None }).await; ``` ### 手动实现 ```rust #[async_trait] impl Tool for MyTool { fn name(&self) -> &str { "my_tool" } fn description(&self) -> String { "工具描述".into() } fn parameters(&self) -> Value { json!({"type": "object", "properties": {}}) } async fn execute(&self, args: Value) -> Result { Ok(json!({"ok": true})) } } ``` --- ## 多会话 + 配置覆盖 ```rust let session = manager.create("tab_1").await .with_model("claude-sonnet-4-20250514") // 这个标签用 Claude .with_temperature(0.3) .with_system_prompt("你是 Rust 专家"); let tab2 = manager.create("tab_2").await .with_model("gpt-4o"); // 这个标签用 GPT ``` --- ## Vision(图片理解) ```rust use cortex_engine::llm::types::{ChatMessage, ContentPart, ImageUrlDetail}; let msg = ChatMessage::user_parts(vec![ ContentPart::Text { text: "这张发票的金额是多少?".into() }, ContentPart::ImageUrl { image_url: ImageUrlDetail { url: "https://example.com/invoice.jpg".into(), detail: Some("high".into()), }, }, ]); let mut stream = session.chat_with_message(msg).await?; ``` --- ## 工具确认回调 ```rust engine.set_tool_confirm(|name, args| { // 返回 true = 允许执行, false = 取消 name != "delete_file" || ask_user_permission(name, args) }).await; ``` --- ## 事件流 `session.chat()` 返回 `StreamEvent` 流,共 17 种事件: | 事件 | 说明 | |------|------| | `Start` | 对话开始 | | `TextDelta(String)` | 文本增量输出 | | `ReasoningDelta(String)` | 模型推理/思考过程 | | `ToolCall { id, name, arguments }` | LLM 请求调用工具 | | `ToolResult { id, name, result }` | 工具执行完成 | | `Clarify { question, input_type, options }` | LLM 需要用户补充信息 | | `PlanProgress { plan, task_statuses, .. }` | 多步骤任务进度 | | `IterationDone { iteration }` | 一轮 ReAct 结束 | | `Done { output, usage }` | 对话完成 | | `Interrupted` | 用户中断 | | `Error(AgentError)` | 错误 | --- ## 配置 ```rust let config = ConfigBuilder::new("http://localhost:11434/v1", "qwen2.5:7b") .with_api_key("sk-xxx") .with_max_turns(20) .with_temperature(0.7) .with_max_tokens(4096) .with_max_context_tokens(128_000) .with_tool_timeout(Duration::from_secs(10)) .with_tool_choice(json!("auto")) .with_response_format(json!({"type": "json_object"})) .with_system_prompt("你是专业客服") .build()?; ``` | 字段 | 说明 | 默认值 | |------|------|--------| | `api_base` | API 地址 | 空(必填,Anthropic 默认 `api.anthropic.com`) | | `model` | 模型名称 | 空(必填) | | `api_key` | API 密钥 | `None` | | `max_turns` | 最大 ReAct 轮次 | `10` | | `temperature` | 采样温度 | `None` | | `max_tokens` | 最大生成 token | `None`(Anthropic 默认 4096) | | `max_context_tokens` | 上下文窗口上限 | `128_000` | | `tool_timeout` | 工具执行超时 | `30s` | | `tool_choice` | 工具调用策略 | `None`(auto) | | `request_timeout` | API 超时 | `60s` | | `max_retries` | API 重试次数 | `3` | | `system_prompt` | 全局 System Prompt | `None` | | `response_format` | 输出格式(JSON mode) | `None` | --- ## 架构 ``` App / UI │ ┌──────────────┐ ├─ StreamEvent 事件流 ───→│ Session │ ← 每标签独立 │ ├──────────────┤ │ │ Engine │ ← 全局一份(Provider + Tools) │ ├──────────────┤ │ │ ReAct Loop │ ← Think → Act → Observe │ ├──────────────┤ │ │ LlmProvider │ ← OpenAI / Anthropic │ └──────────────┘ │ ├── SessionManager │ ├── create / restore / delete │ ├── list() → [SessionInfo { title, created_at, message_count, .. }] │ └── memory: FileMemory / InMemoryMemory │ ├── cache 模块 │ ├── find_breakpoint() — 缓存断点检测 │ ├── validate_structure() — 结构校验 │ └── normalize_tools() — 工具排序 │ └── Tool 系统 ├── #[derive(Tool)] 宏 ├── tool_confirm 回调 └── 内置: update_todo / clarify ``` --- ## 运行测试 ```bash cargo test # 全部 50 测试 cargo test --lib # 24 单元测试 cargo test --test engine_test # 16 集成测试 cargo clippy --all-targets # 代码质量 ``` ## 运行 CLI ```bash cargo run # 交互 REPL cargo run -- "你是谁?" # 单次问答 cargo run -- --serve # Web UI(localhost:8080) ``` --- ## 许可证 Apache 2.0