# agentkit **Repository Path**: liyuzuo/agentkit ## Basic Information - **Project Name**: agentkit - **Description**: 通用 agent 仓库 - **Primary Language**: Python - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-24 - **Last Updated**: 2026-07-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # agentkit 通用本地 AI Agent 部署框架。支持 GLM / DeepSeek / MiniMax 等 OpenAI 兼容 API 的一键切换,内置工具调用、JSON 文件记忆,提供 FastAPI 服务与 CLI 双入口。 ## 快速开始 ```bash # 安装依赖(含开发依赖) uv sync # 配置 cp .env.example .env # 填入 AGENTKIT_PROVIDER / MODEL / API_KEY / BASE_URL # config.yaml 已含默认配置,一般不用改(provider 走环境变量) # 跑测试 uv run pytest # 启动 HTTP 服务 uv run agentkit serve # 或用 CLI 单次对话 uv run agentkit chat "你好" ``` ## 切换 Provider agentkit 有两种调用方式,通过 `.env` 的 `AGENTKIT_PROVIDER` 控制,**不配置默认走 API**: | `AGENTKIT_PROVIDER` | 方式 | 说明 | |---------------------|------|------| | `openai` / `glm` / `deepseek` / `minimax` / 留空 | **API(OpenAI 兼容)** | 默认。通用,改 env 即切模型,零代码 | | `glm_native` | **SDK(官方 zai-sdk)** | 需厂商独家能力时用,要 `uv add zai-sdk` | 切换只需改 `.env`,重启即可,不动代码和 `config.yaml`: ```bash # 切到 DeepSeek(走 API) AGENTKIT_PROVIDER=deepseek AGENTKIT_MODEL=deepseek-chat AGENTKIT_API_KEY=sk-你的-deepseek-key AGENTKIT_BASE_URL=https://api.deepseek.com/v1 ``` ```bash # 切回 GLM(走 API) AGENTKIT_PROVIDER=glm AGENTKIT_MODEL=glm-5.2 AGENTKIT_API_KEY=你的-glm-key AGENTKIT_BASE_URL=https://open.bigmodel.cn/api/paas/v4 ``` > API 模式下 `MODEL` 和 `BASE_URL` 必填(没有子类提供默认值了)。`glm` / `deepseek` / `minimax` / `openai` 都路由到同一个通用 OpenAI 兼容实现,只是别名,方便识别。 ## 接入其他模型 agentkit 的 Provider 架构:**默认用 OpenAI 兼容协议(零代码),少数需要原生 SDK 的走抽象基类**。 `core/agent.py` 只通过 `LLMProvider` 抽象基类调用 `provider.chat()`,不感知底层差异。因此接入新模型永远不会影响对话逻辑、工具调用、记忆和入口层。 ### 方式 1:OpenAI 兼容的模型(默认,零代码) GLM、DeepSeek、MiniMax、Moonshot(月之暗面)、通义千问、百川、硅基流动、OpenRouter 等绝大多数模型都兼容 OpenAI 协议。**不需要写任何代码**,直接在 `.env` 配地址和模型即可: ```bash # 接入 Moonshot(月之暗面) AGENTKIT_PROVIDER=moonshot # 名字随便取,仅用于识别(都走同一套兼容实现) AGENTKIT_MODEL=moonshot-v1-8k AGENTKIT_API_KEY=sk-你的-moonshot-key AGENTKIT_BASE_URL=https://api.moonshot.cn/v1 ``` ```bash # 接入通义千问 AGENTKIT_PROVIDER=qwen AGENTKIT_MODEL=qwen-plus AGENTKIT_API_KEY=sk-你的-key AGENTKIT_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 ``` > **聚合 API 提示:** 使用 OpenRouter、硅基流动等聚合服务时,连 `AGENTKIT_PROVIDER` 都不用纠结 —— 它们都路由到同一个兼容实现,只填 `BASE_URL` 和 `MODEL` 即可。 ### 方式 2:用厂商官方 SDK 接入(需要独家能力时) 当你需要 OpenAI 协议覆盖不到的**厂商独家能力**(如文生图、视频生成、检索增强、特殊参数)时,用官方 SDK 实现 `LLMProvider`,并在 factory 注册。 > **先了解官方推荐:** 两家厂商其实都**官方推荐优先用 OpenAI 兼容方式**(即方式 1): > - **GLM(智谱):** 官方文档设「OpenAI API 兼容」专章,明确「仅需更换 `api_key` 与 `base_url`,即可用 OpenAI SDK 调用」。 > - **MiniMax:** 官方同时提供 OpenAI SDK 兼容接口与 Anthropic SDK 接入,OpenAI 兼容为主流。 > > 除非你需要独家能力,否则保持默认(API)更省心:依赖少、接口统一、换厂商零成本。 **示例:用智谱官方 `zai-sdk` 接入 GLM(框架已内置)** 官方包名是 **`zai-sdk`**(对应 Z.ai 开放平台,仓库 `github.com/zai-org/z-ai-sdk-python`)。注意不是旧版的 `zhipuai`。 ```bash uv add zai-sdk ``` 设 `.env` 的 `AGENTKIT_PROVIDER=glm_native` 即可启用,无需改代码。框架已内置 `src/agentkit/providers/glm_native.py`,支持国内/海外双客户端(region 参数)。 **自己接入新的原生 SDK(如 Anthropic Claude)** 协议不兼容 OpenAI 的模型,直接实现 `LLMProvider` 抽象基类: ```python # src/agentkit/providers/claude_native.py from agentkit.core.provider import LLMProvider from agentkit.core.types import ChatResponse, Message, ToolSpec class ClaudeProvider(LLMProvider): def __init__(self, api_key: str, model: str, ...): ... async def chat(self, messages, tools=None) -> ChatResponse: # 用 anthropic SDK 或 httpx 实现 ... return ChatResponse(content=..., tool_calls=...) async def stream(self, messages, tools=None): ... yield chunk ``` 在 `factory.py` 的 `_NATIVE_REGISTRY` 注册一行: ```python _NATIVE_REGISTRY: dict[str, str] = { "glm_native": "agentkit.providers.glm_native:GLMNativeProvider", "claude_native": "agentkit.providers.claude_native:ClaudeProvider", # ← 加这行 } ``` 然后 `.env` 设 `AGENTKIT_PROVIDER=claude_native`。**Agent 编排器、工具循环、记忆、HTTP/CLI 入口都不需要改动**。 ### 方式 3:兼容协议但需定制行为 某家 API 流式格式略不同,或需要额外参数时,继承 `OpenAICompatProvider` 并**只覆写需要的那一个方法**: ```python class CustomProvider(OpenAICompatProvider): async def chat(self, messages, tools=None): # 前置处理(比如这家要求特定参数) ... # 调父类的标准逻辑 return await super().chat(messages, tools) ``` 特殊隔离,通用共享。注册方式同方式 2。 ### 为什么能这么容易扩展 | 方式 | 做法 | 成本 | |------|------|------| | OpenAI 兼容 | 改 `.env`,零代码 | 5 分钟 | | 原生 SDK | 实现 ABC + factory 注册 | 较多,但接口固定 | | 兼容但需定制 | 继承基类 + 覆写单方法 | 约 30 行 | 详见 `docs/design.md` 的 Provider 抽象层设计一节。 ## 替换 Memory 存储(改用数据库 / Java 接口) 默认的记忆实现是 `JsonMemoryStore`(每会话一个 JSON 文件,零依赖)。如果要把历史存到**数据库**,或经过**Java 服务**读写,只需实现 `Memory` 抽象基类的四个方法,然后在入口注入即可。对话逻辑、工具调用、Provider 都不受影响。 ### Memory 接口(实现这四个方法即可) ```python # src/agentkit/core/memory.py class Memory(ABC): def load(self, session_id: str) -> list[Message]: ... # 读取历史,无则返回 [] def save(self, session_id: str, messages: list[Message]) -> None: ... # 覆盖写 def clear(self, session_id: str) -> None: ... # 清除某会话 def list_sessions(self) -> list[str]: ... # 列出全部会话 id(可选,默认返回 []) ``` 接入点:入口处(`_build_from_config` 或 `run_server.py`)把 `JsonMemoryStore(...)` 换成你的实现,其余代码不动。 ### 方式 1:直连数据库(PostgreSQL 示例) Python 直接连数据库,不经过 Java。适合不需要额外业务逻辑的场景。先建表: ```sql CREATE TABLE chat_messages ( id BIGSERIAL PRIMARY KEY, session_id VARCHAR(64) NOT NULL, role VARCHAR(16) NOT NULL, -- system | user | assistant | tool content TEXT NOT NULL, seq INT NOT NULL, -- 同会话内顺序 created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_chat_session ON chat_messages(session_id); ``` 实现 `DbMemory`(新建 `src/agentkit/memory/db_store.py`): ```python """基于 PostgreSQL 的记忆实现。需先 uv add "psycopg[binary]"。""" from agentkit.core.memory import Memory from agentkit.core.types import Message, Role import psycopg class DbMemory(Memory): def __init__(self, dsn: str): # dsn 形如 postgresql://user:pass@host:5432/dbname self._dsn = dsn def load(self, session_id: str) -> list[Message]: with psycopg.connect(self._dsn) as conn, conn.cursor() as cur: cur.execute( "SELECT role, content FROM chat_messages " "WHERE session_id = %s ORDER BY seq", (session_id,), ) return [ Message(role=Role(r), content=c) for r, c in cur.fetchall() ] def save(self, session_id: str, messages: list[Message]) -> None: with psycopg.connect(self._dsn) as conn, conn.cursor() as cur: cur.execute("DELETE FROM chat_messages WHERE session_id = %s", (session_id,)) cur.executemany( "INSERT INTO chat_messages (session_id, role, content, seq) " "VALUES (%s, %s, %s, %s)", [ (session_id, m.role.value, m.content, i) for i, m in enumerate(messages) ], ) conn.commit() def clear(self, session_id: str) -> None: with psycopg.connect(self._dsn) as conn, conn.cursor() as cur: cur.execute("DELETE FROM chat_messages WHERE session_id = %s", (session_id,)) conn.commit() def list_sessions(self) -> list[str]: with psycopg.connect(self._dsn) as conn, conn.cursor() as cur: cur.execute("SELECT DISTINCT session_id FROM chat_messages ORDER BY session_id") return [row[0] for row in cur.fetchall()] ``` ### 方式 2:调用 Java 接口(RemoteMemory) Java 起一个 HTTP 服务负责读写历史(可加鉴权、业务逻辑、写自己的库)。Python 端通过 HTTP 调它。假设 Java 暴露如下 REST 接口: | 方法 | 路径 | 说明 | |------|------|------| | `GET` | `/api/sessions/{id}/messages` | 返回 `[{role, content}, ...]` | | `PUT` | `/api/sessions/{id}/messages` | body 为 `[{role, content}, ...]`,覆盖写 | | `DELETE` | `/api/sessions/{id}` | 清除该会话 | | `GET` | `/api/sessions` | 返回 `["id1", "id2", ...]` | 实现 `RemoteMemory`(新建 `src/agentkit/memory/remote_store.py`): ```python """通过 HTTP 调用 Java 服务的记忆实现。需先 uv add httpx。""" import httpx from agentkit.core.memory import Memory from agentkit.core.types import Message, Role class RemoteMemory(Memory): def __init__(self, base_url: str, token: str | None = None): # base_url 形如 http://localhost:8080/api self._base = base_url.rstrip("/") self._headers = {"Authorization": f"Bearer {token}"} if token else {} def load(self, session_id: str) -> list[Message]: r = httpx.get(f"{self._base}/sessions/{session_id}/messages", headers=self._headers) r.raise_for_status() return [ Message(role=Role(item["role"]), content=item["content"]) for item in r.json() ] def save(self, session_id: str, messages: list[Message]) -> None: payload = [{"role": m.role.value, "content": m.content} for m in messages] r = httpx.put( f"{self._base}/sessions/{session_id}/messages", json=payload, headers=self._headers, ) r.raise_for_status() def clear(self, session_id: str) -> None: r = httpx.delete(f"{self._base}/sessions/{session_id}", headers=self._headers) r.raise_for_status() def list_sessions(self) -> list[str]: r = httpx.get(f"{self._base}/sessions", headers=self._headers) r.raise_for_status() return r.json() ``` > Java 端接口契约见上表。你提到会提供一个 Java 分支,届时可直接对接。 ### 如何启用 **入口注入(改两处即可)**。编辑 `run_server.py`(HTTP)或 `run_chat.py`(CLI),把 `JsonMemoryStore(...)` 换成你的实现: ```python # run_server.py 改动示例 from agentkit.memory.db_store import DbMemory # 或 remote_store.RemoteMemory import os # 原来: # memory = JsonMemoryStore(dir=cfg.memory.dir) # 改成: memory = DbMemory(dsn=os.environ["DATABASE_URL"]) # 或: memory = RemoteMemory(base_url="http://localhost:8080/api", token=os.environ.get("JAVA_TOKEN")) ``` `cli.py` 的 `_build_from_config` 同理。改完即可,`Agent`、`Provider`、工具调用、API 路由全部不受影响——因为它们只依赖 `Memory` 抽象,不感知底层是文件、数据库还是 HTTP。 ### 为什么能这么容易扩展 和 Provider 一样,接口固定、实现可换。`core/agent.py` 只通过 `Memory` 抽象基类调用 `load()/save()`,不关心数据存哪。成本对比: | 方式 | 做法 | 成本 | |------|------|------| | 直连数据库 | 实现 Memory ABC + 入口注入 | 约 40 行 | | 调 Java 接口 | 实现 Memory ABC + 入口注入 | 约 35 行 |