120行代码实现一个极简 Agent
标签:#Python #AI #Agent #LLM #编程实战 日期:2026-06-04 摘要:本文介绍一个仅 120 行代码的极简 Agent 实现,包含记忆系统、工具系统,支持 LLM Function Calling,不依赖第三方 Agent 框架。适合作为 Agent 开发入门示例。
前言
最近在学习 Agent 开发,翻遍了市面上的框架文档,不是依赖 LangChain 就是需要安装各种 SDK。对于想理解 Agent 本质的新手来说,这些框架反而增加了理解成本。
于是我决定自己动手,用最朴素的方式写一个极简 Agent。120 行代码,涵盖了 Agent 的核心要素:记忆系统 、工具系统 、LLM 对接。
一、运行效果
先看一下实际运行效果:

可以看到:
- 对话循环:用户输入 → LLM 思考 → 工具调用 → 结果返回 → LLM 总结
- 工具调用 :LLM 自动识别需要调用
list_dir工具 - 记忆保持:多轮对话上下文被完整保留
二、整体架构
Agent 的核心逻辑其实很简单:
用户输入 → 记忆存储 → LLM 思考 → 工具调用(可选)→ LLM 总结 → 返回结果
核心组件
| 组件 | 职责 |
|---|---|
| LLM | 大脑,负责理解和生成 |
| Memory | 记忆,管理对话历史 |
| Tool | 工具,扩展 LLM 能力 |
| ToolRegistry | 工具注册表,管理所有可用工具 |
| Agent | 粘合剂,协调以上组件工作 |
三、核心代码解读
1. LLM 调用
python
class LLM:
def __init__(self, config: dict):
self.api_key = config["api_key"]
self.base_url = config["base_url"]
self.model = config["model"]
self.max_tokens = config.get("max_tokens", 4096)
self.temperature = config.get("temperature", 0.1)
def chat(self, messages: list[dict], tools: Optional[list] = None) -> dict:
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
payload = {"model": self.model, "messages": messages, "max_tokens": self.max_tokens, "temperature": self.temperature}
if tools: payload["tools"] = tools
resp = requests.post(f"{self.base_url}/chat/completions", headers=headers, json=payload, timeout=120)
resp.raise_for_status()
return resp.json()
要点:
- 兼容 OpenAI 格式 API(如 MiniMax、DeepSeek 等)
tools参数用于 Function Calling,让 LLM 知道有哪些工具可用
2. 记忆系统
python
class Memory:
def __init__(self, max_msgs: int = 50):
self.max_msgs = max_msgs
self.messages: list[dict] = []
def add(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
# 自动修剪:保留系统消息 + 最近 50 条
if len(self.messages) > self.max_msgs:
self.messages = [m for m in self.messages if m["role"] == "system"] + self.messages[-self.max_msgs:]
def add_user(self, content: str): self.add("user", content)
def add_assistant(self, content: str): self.add("assistant", content)
def add_tool(self, tool_call_id: str, content: str):
self.messages.append({"role": "tool", "tool_call_id": tool_call_id, "content": content})
要点:
- 支持
user、assistant、tool三种角色 - 自动修剪超过限制的旧消息
- 保留系统消息不被修剪
3. 工具系统
python
class Tool:
def __init__(self, name: str, desc: str, schema: dict, func: Callable):
self.name, self.desc, self.schema, self.func = name, desc, schema, func
def execute(self, **kwargs): return self.func(**kwargs)
def to_schema(self): return {"type": "function", "function": {"name": self.name, "description": self.desc, "parameters": self.schema}}
python
class ToolRegistry:
def __init__(self): self.tools: dict[str, Tool] = {}
def register(self, tool: Tool): self.tools[tool.name] = tool
def get(self, name: str): return self.tools.get(name)
def get_schemas(self): return [t.to_schema() for t in self.tools.values()]
要点:
- 每个 Tool 有
name、description、schema、func to_schema()生成 OpenAI Function Calling 格式- 注册表统一管理工具的注册和查找
4. 注册内置工具
python
registry = ToolRegistry()
registry.register(Tool("list_dir", "列出目录下的文件", {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]},
lambda path: "\n".join([f"{'📁' if p.is_dir() else '📄'} {p.name}" for p in sorted(Path(path).iterdir())]) if Path(path).exists() else "目录不存在"))
registry.register(Tool("read_file", "读取文件内容", {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]},
lambda path: Path(path).read_text(encoding="utf-8", errors="replace")[:5000] if Path(path).exists() else "文件不存在"))
registry.register(Tool("exec", "执行 Shell 命令", {"type": "object", "properties": {"command": {"type": "string"}}, "required": ["command"]},
lambda command: subprocess.run(command, shell=True, capture_output=True, text=True, encoding="utf-8", errors="replace").stdout or "(无输出)"))
内置三个工具:
list_dir:列出目录文件read_file:读取文件内容exec:执行 Shell 命令
5. Agent 核心逻辑
python
class Agent:
def __init__(self, config: dict):
self.llm = LLM(config)
self.memory = Memory()
def chat(self, user_input: str) -> str:
self.memory.add_user(user_input)
messages = [{"role": "system", "content": SYSTEM_PROMPT}] + self.memory.messages
# 第一次 LLM 调用
result = self.llm.chat(messages, registry.get_schemas())
msg = result["choices"][0]["message"]
# 如果 LLM 调用了工具
if "tool_calls" in msg and msg["tool_calls"]:
self.memory.messages.append(msg) # 保存 LLM 的调用
for tc in msg["tool_calls"]:
tool = registry.get(tc["function"]["name"])
args = eval(tc["function"]["arguments"])
result = tool.execute(**args) if tool else f"工具不存在: {tc['function']['name']}"
self.memory.add_tool(tc["id"], result) # 保存工具结果
# 第二次 LLM 调用,传入工具结果
result = self.llm.chat([{"role": "system", "content": SYSTEM_PROMPT}] + self.memory.messages, registry.get_schemas())
msg = result["choices"][0]["message"]
content = msg.get("content", "")
self.memory.add_assistant(content)
return content
核心流程:
markdown
用户输入
↓
记忆存储(add_user)
↓
第一次 LLM 调用(带工具 Schema)
↓
LLM 返回 ← 工具调用(可选)
↓
保存 LLM 回复
↓
执行工具(如果有)
↓
保存工具结果(add_tool)
↓
第二次 LLM 调用(传入工具结果)
↓
返回最终回复(add_assistant)
四、配置说明
只需要一个 config.json:
json
{
"api_key": "你的 API Key",
"base_url": "https://api.minimaxi.com/v1",
"model": "MiniMax-M2.7",
"max_tokens": 8192,
"temperature": 0.1
}
支持任何 OpenAI 兼容 API(MiniMax、DeepSeek、Qwen 等)。
五、完整代码
整个项目只有两个文件:
| 文件 | 行数 | 说明 |
|---|---|---|
miniagent.py |
120 | 全部代码 |
config.json |
1 | 配置文件 |
python
"""极简 Agent 原型"""
import json, requests, subprocess
from pathlib import Path
from typing import Optional, Callable
# ============ 配置 ============
def load_config():
with open(Path(__file__).parent / "config.json", encoding="utf-8") as f:
return json.load(f)
# ============ LLM 调用 ============
class LLM:
def __init__(self, config: dict):
self.api_key = config["api_key"]
self.base_url = config["base_url"]
self.model = config["model"]
self.max_tokens = config.get("max_tokens", 4096)
self.temperature = config.get("temperature", 0.1)
def chat(self, messages: list[dict], tools: Optional[list] = None) -> dict:
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
payload = {"model": self.model, "messages": messages, "max_tokens": self.max_tokens, "temperature": self.temperature}
if tools: payload["tools"] = tools
resp = requests.post(f"{self.base_url}/chat/completions", headers=headers, json=payload, timeout=120)
resp.raise_for_status()
return resp.json()
# ============ 记忆管理 ============
class Memory:
def __init__(self, max_msgs: int = 50):
self.max_msgs = max_msgs
self.messages: list[dict] = []
def add(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
if len(self.messages) > self.max_msgs:
self.messages = [m for m in self.messages if m["role"] == "system"] + self.messages[-self.max_msgs:]
def add_user(self, content: str): self.add("user", content)
def add_assistant(self, content: str): self.add("assistant", content)
def add_tool(self, tool_call_id: str, content: str):
self.messages.append({"role": "tool", "tool_call_id": tool_call_id, "content": content})
def clear(self):
self.messages = [m for m in self.messages if m["role"] == "system"]
# ============ 工具系统 ============
class Tool:
def __init__(self, name: str, desc: str, schema: dict, func: Callable):
self.name, self.desc, self.schema, self.func = name, desc, schema, func
def execute(self, **kwargs): return self.func(**kwargs)
def to_schema(self): return {"type": "function", "function": {"name": self.name, "description": self.desc, "parameters": self.schema}}
class ToolRegistry:
def __init__(self): self.tools: dict[str, Tool] = {}
def register(self, tool: Tool): self.tools[tool.name] = tool
def get(self, name: str): return self.tools.get(name)
def list(self): return list(self.tools.values())
def get_schemas(self): return [t.to_schema() for t in self.tools.values()]
registry = ToolRegistry()
# 注册内置工具(每个一行,避免歧义)
registry.register(Tool("list_dir", "列出目录下的文件", {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}, lambda path: "\n".join([f"{'📁' if p.is_dir() else '📄'} {p.name}" for p in sorted(Path(path).iterdir())]) if Path(path).exists() else "目录不存在"))
registry.register(Tool("read_file", "读取文件内容", {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}, lambda path: Path(path).read_text(encoding="utf-8", errors="replace")[:5000] if Path(path).exists() else "文件不存在"))
registry.register(Tool("exec", "执行 Shell 命令", {"type": "object", "properties": {"command": {"type": "string"}}, "required": ["command"]}, lambda command: subprocess.run(command, shell=True, capture_output=True, text=True, encoding="utf-8", errors="replace").stdout or "(无输出)"))
# ============ Agent 核心 ============
SYSTEM_PROMPT = """你是一个有用的 AI 助手。
可用工具:
- list_dir(path): 列出目录文件
- read_file(path): 读取文件
- exec(command): 执行命令"""
class Agent:
def __init__(self, config: dict):
self.llm = LLM(config)
self.memory = Memory()
def chat(self, user_input: str) -> str:
self.memory.add_user(user_input)
messages = [{"role": "system", "content": SYSTEM_PROMPT}] + self.memory.messages
result = self.llm.chat(messages, registry.get_schemas())
msg = result["choices"][0]["message"]
if "tool_calls" in msg and msg["tool_calls"]:
self.memory.messages.append(msg)
for tc in msg["tool_calls"]:
tool = registry.get(tc["function"]["name"])
args = eval(tc["function"]["arguments"])
result = tool.execute(**args) if tool else f"工具不存在: {tc['function']['name']}"
self.memory.add_tool(tc["id"], result)
result = self.llm.chat([{"role": "system", "content": SYSTEM_PROMPT}] + self.memory.messages, registry.get_schemas())
msg = result["choices"][0]["message"]
content = msg.get("content", "")
self.memory.add_assistant(content)
return content
def reset(self): self.memory.clear()
# ============ 入口 ============
if __name__ == "__main__":
config = load_config()
agent = Agent(config)
print("="*50, "\nMyAgent 已启动 (输入 q 退出, reset 清空历史)\n", "="*50)
while True:
try:
user_input = input("\n> ").strip()
if user_input.lower() == "q": break
if user_input.lower() == "reset": agent.reset(); print("已清空"); continue
if not user_input: continue
print(f"\n{agent.chat(user_input)}\n")
except KeyboardInterrupt: break
except Exception as e: print(f"错误: {e}")
六、总结
📌 要点回顾
- Agent 本质:一个 LLM + 记忆 + 工具的循环调用机制
- 工具调用:通过 Function Calling 让 LLM 知道有哪些工具可用
- 记忆系统:管理对话历史,自动修剪
- 朴素实现:120 行代码,不依赖任何第三方框架
💡 扩展方向
- 添加更多工具(搜索、数据库、API 调用等)
- 实现技能(Skill)系统,支持复杂任务
- 添加流式输出支持
- 接入向量数据库实现 RAG
本文为本人原创,首发于掘金。
代码仓库:github.com/你的仓库
如果你有任何问题或想法,欢迎在评论区交流!