前言最近 AI Agent 这个概念火得不行各种框架LangChain、CrewAI、AutoGen层出不穷。但我发现很多新手一上来就啃框架源码结果被各种抽象层绕晕了。其实Agent 的核心原理非常简单——就是一个 while 循环。你完全可以从零手写一个不超过 200 行代码。这篇文章带你从零实现一个本地知识库 AI Agent它能自动搜索、阅读、整理你的 Markdown 笔记。全程 Python调用 DeepSeek API没有任何框架依赖。 完整代码已开源GitHub - Hao-max1/knowledge-agent · GitHub一、什么是 Agent1.1 普通 LLM vs Agent普通 ChatGPT 是一问一答你: 11等于几 AI: 2 → 结束Agent 是多轮思考你: 帮我找关于 Python 的笔记 AI: [思考] 用户想找笔记 → 我先搜一下 → 调用 search_notes(Python) ← 第一次 API 调用 → 结果: python-basics.md AI: [再思考] 搜到了但用户想要内容 → 读一下 → 调用 read_note(python-basics.md) ← 第二次 API 调用 → 结果: 文件内容是... AI: [最终] 拿到了可以回答了 → 你的笔记里讲了 Python 基础包括... ← 最终回复Agent LLM 工具 循环。就这么简单。1.2 为什么需要循环因为 LLM不知道工具的执行结果。它只能说我想用工具 X然后停下来等你执行。你把结果喂回去它才能继续思考。二、项目结构knowledge-agent/ ├── main.py # CLI 入口 ├── agent.py # ★ 核心Agent 循环 ├── tools.py # 工具定义 执行 ├── config.py # 配置加载 ├── requirements.txt # 仅 2 个依赖 ├── .env # API Key └── knowledge_base/ # 你的笔记目录技术选型项目选择理由语言Python 3.9生态最好LLM APIDeepSeekdeepseek-chat便宜、支持 tool calling、OpenAI 兼容SDKopenai标准 SDKDeepSeek 完全兼容存储本地 Markdown 文件零依赖即开即用依赖openai1.0.0 python-dotenv1.0.0仅两个依赖极简。三、核心代码Agent 循环这是整个项目的心脏agent.py里的核心逻辑核心 Agent 循环 — 思考 → 行动 → 观察 → 再思考 import json from openai import OpenAI from config import DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, MODEL, MAX_TOOL_ROUNDS from tools import TOOL_SCHEMAS, execute_tool client OpenAI(api_keyDEEPSEEK_API_KEY, base_urlDEEPSEEK_BASE_URL) SYSTEM_PROMPT 你是一个知识库助手 Agent帮助用户管理和检索笔记。 ## 你的能力 - search_notes搜索包含关键词的笔记 - list_notes列出知识库中所有笔记 - read_note读取一篇笔记的完整内容 - write_note创建或更新一篇 Markdown 笔记 ## 工作方式 1. 理解用户需求 2. 先搜索再阅读 —— 不要猜测文件内容 3. 基于实际内容回答不要编造 4. 用中文回复 def run_agent(user_query: str, on_tool_callNone) - str: 执行一次 Agent 对话。 # messages 就是 Agent 的记忆 messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_query}, ] # ★ Agent 循环 for round_num in range(1, MAX_TOOL_ROUNDS 1): # ① 调用 LLM response client.chat.completions.create( modelMODEL, messagesmessages, toolsTOOL_SCHEMAS, temperature0.1, ) choice response.choices[0] msg choice.message # ② 判断LLM 说完了还是想调工具 if choice.finish_reason stop: return msg.content or 未返回回复 elif choice.finish_reason tool_calls: # ③ 把 LLM 的回复加入记忆 messages.append(msg.to_dict()) # ④ 执行每个工具调用 for tc in msg.tool_calls: tool_name tc.function.name tool_input json.loads(tc.function.arguments) if on_tool_call: on_tool_call(tool_name, tool_input) result execute_tool(tool_name, tool_input) # ⑤ 把工具结果加入记忆 messages.append({ role: tool, tool_call_id: tc.id, content: result, }) # ⑥ 循环继续LLM 看到结果后会再次思考 return [WARNING] Agent 达到最大思考轮次。流程图用户输入 │ ▼ ┌─────────────────────┐ │ LLM 思考 │ ← chat.completions.create() │ (带上全部历史消息) │ └──────┬──────────────┘ │ ├─ finish_reasonstop ──→ 返回回复给用户 │ └─ finish_reasontool_calls │ ▼ ┌──────────────┐ │ 执行工具 │ ← execute_tool() └──────┬───────┘ │ ▼ ┌──────────────┐ │ 把结果加入 │ ← messages.append() │ messages │ └──────┬───────┘ │ └──→ 回到开头继续循环四、工具定义工具是 Agent 的手。用 JSON Schema 定义LLM 通过description字段理解每个工具该什么时候用。# tools.py — 以 search_notes 为例 TOOL_SCHEMAS [ { type: function, function: { name: search_notes, description: ( 在知识库中搜索包含指定关键词的笔记文件。 当用户问「有没有关于XX的笔记」「帮我找XX」时使用此工具。 ), parameters: { type: object, properties: { query: { type: string, description: 搜索关键词, }, }, required: [query], }, }, }, # ... list_notes, read_note, write_note ]关键点description非常非常重要它决定了 LLM 能不能在正确的时机调用工具。写得太笼统如用来搜索LLM 可能不知道该什么时候用。工具执行是纯 Python 文件操作def _search_notes(query: str) - str: 遍历知识库搜索包含关键词的文件。 query_lower query.lower() results [] for root, dirs, files in os.walk(KNOWLEDGE_BASE): for fname in files: if not fname.endswith((.md, .txt)): continue content Path(root, fname).read_text(encodingutf-8) if query_lower in content.lower(): # 提取匹配行作为摘要 matching_lines [ line.strip() for line in content.split(\n) if query_lower in line.lower() ] results.append(f[文件] {fname}\n {matching_lines[:5]}) return f找到 {len(results)} 篇:\n \n\n.join(results) if results \ else f未找到「{query}」相关笔记。五、安全设计5.1 路径逃逸防护LLM 是不可控的万一它尝试../../etc/passwd呢def _safe_path(relative_path: str) - Path: 确保 LLM 无法访问知识库外的路径。 full (KNOWLEDGE_BASE / relative_path).resolve() if not str(full).startswith(str(KNOWLEDGE_BASE.resolve())): raise ValueError(f不允许访问知识库外的路径: {relative_path}) return full5.2 防死循环MAX_TOOL_ROUNDS 10Agent 最多调用 10 轮工具后强制中断。六、Anthropic vs DeepSeek 对比我最初用的是 Claude API后来换成 DeepSeek。Agent 循环逻辑完全没变只是 API 格式不同项目Anthropic (Claude)DeepSeekSDKimport anthropicfrom openai import OpenAI调用方法client.messages.create()client.chat.completions.create()工具格式namedescriptioninput_schematype:functionfunction:{...}结束标志stop_reason end_turnfinish_reason stop工具调用标志stop_reason tool_usefinish_reason tool_calls工具参数block.input直接是 dictjson.loads(tc.function.arguments)结果回传role:usertype:tool_resultrole:toolSystem Prompt独立参数system...messages[0],role:system核心收获Agent 的灵魂是你写的循环逻辑不是某个具体的 API。换一家 LLM 只需改 API 调用格式循环不动。七、效果演示$ python main.py ╔══════════════════════════════════════════╗ ║ 知识库 AI Agent ║ ╠══════════════════════════════════════════╣ ║ 模型: deepseek-chat ║ ║ 知识库: .../knowledge_base ║ ║ 工具: search_notes, list_notes, ... ║ ╚══════════════════════════════════════════╝ 帮我找关于 Python 的笔记 Thinking... Tool: search_notes(queryPython) ← Agent 自动搜索 Tool: read_note(file_pathpy.md) ← Agent 自动读取 你的知识库中有一篇关于 Python 的笔记内容摘要如下 - Python 是一门解释型语言 - 语法简洁适合初学者 - 广泛应用于数据科学、Web 开发、自动化脚本等领域 帮我写一篇 Git 常用命令的笔记 Thinking... Tool: write_note(file_pathgit.md, content...) ← Agent 自动创建 [OK] 笔记已保存: git-cheatsheet.md856 字符八、如何扩展学完基础后你可以加工具网页搜索、天气查询、发邮件——在tools.py里加定义 实现即可加记忆把对话历史存到 SQLite下次启动恢复实现跨会话记忆加流式输出streamTrue让 LLM 回复逐字显示换 MCP 协议把工具标准化为 MCP Server其他 Agent 也能用做 Web UI用 Streamlit 或 Gradio 包一层网页界面加上 RAG引入向量数据库实现语义搜索九、总结AI Agent 开发不需要从啃框架开始。核心就三样东西Agent LLM 工具 while 循环理解了这三样什么 LangChain/CrewAI/AutoGen不过是在这个基础上加了更多抽象。建议的学习路径先用起来用 Claude Code、Cursor 等体验 Agent 能做什么手写一个像本文一样50-200 行代码写一个最小 Agent加复杂度多工具、记忆、流式输出回头看框架这时候你才能真正理解框架的价值纸上得来终觉浅绝知此事要躬行。直接动手吧。完整代码项目地址https://github.com/Hao-max1/knowledge-agent直接把代码拷到本地改.env里的 API Key 就能跑git clone https://github.com/Hao-max1/knowledge-agent.git cd knowledge-agent cp .env.example .env # 编辑 .env 填入你的 DeepSeek API Key pip install -r requirements.txt python main.py如果这篇文章对你有帮助欢迎点赞、收藏、关注。有问题可以在评论区留言交流。