














前面12篇主要是“读懂OpenClaw”,这一篇番外咱们换个姿势:
自己用Python做一个迷你版,只保留命令行交互。
先说清楚边界,避免预期过高:
/new、/history、/exit这篇的目标不是替代OpenClaw,而是让你亲手把核心思想跑通。
mini_openclaw/
├── main.py
├── session.py
├── agent.py
└── requirements.txt
requirements.txt内容:
import json
from pathlib import Path
from typing import Dict, List
class SessionStore:
"""会话存储,负责历史消息的加载、追加和重置。"""
def __init__(self, file_path: str) -> None:
"""初始化会话存储对象。"""
self.file_path = Path(file_path)
self.file_path.parent.mkdir(parents=True, exist_ok=True)
if not self.file_path.exists():
self.file_path.touch()
def load_messages(self) -> List[Dict[str, str]]:
"""加载历史消息,返回消息列表。"""
messages: List[Dict[str, str]] = []
with self.file_path.open("r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
messages.append(json.loads(line))
return messages
def append_message(self, role: str, content: str) -> None:
"""追加单条消息到JSONL文件。"""
record = {"role": role, "content": content}
with self.file_path.open("a", encoding="utf-8") as f:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
def reset(self) -> None:
"""重置会话,清空历史文件。"""
with self.file_path.open("w", encoding="utf-8"):
pass
import time
from typing import Dict, List
from openai import OpenAI
class MiniAgent:
"""迷你Agent,负责调用模型并返回回复。"""
def __init__(self, model: str, max_retries: int = 2) -> None:
"""初始化Agent,默认带简单重试。"""
self.client = OpenAI()
self.model = model
self.max_retries = max_retries
def chat(self, messages: List[Dict[str, str]]) -> str:
"""调用模型进行对话,失败时进行有限次重试。"""
last_error: Exception | None = None
for attempt in range(self.max_retries + 1):
try:
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=0.3,
)
return response.choices[0].message.content or ""
except Exception as e:
last_error = e
if attempt == self.max_retries:
break
print(f"[提示] 第{attempt + 1}次请求失败,准备重试: {e}")
time.sleep(1.5)
raise RuntimeError(f"模型调用失败: {last_error}")
from pathlib import Path
from typing import Dict, List
from agent import MiniAgent
from session import SessionStore
SYSTEM_PROMPT = (
"你是一个中文技术助手,回答要准确、可执行、简洁。"
"如果不确定,请先说明假设。"
)
def build_context(history: List[Dict[str, str]], limit: int = 12) -> List[Dict[str, str]]:
"""组装上下文,保留最近N条历史,避免上下文无限膨胀。"""
trimmed = history[-limit:]
return [{"role": "system", "content": SYSTEM_PROMPT}, *trimmed]
def print_help() -> None:
"""打印命令帮助。"""
print("可用命令:")
print(" /new 重置当前会话")
print(" /history 查看历史条数")
print(" /exit 退出程序")
def run() -> None:
"""运行命令行主循环。"""
data_file = Path(".mini_openclaw/session.jsonl")
store = SessionStore(str(data_file))
agent = MiniAgent(model="gpt-4o-mini")
print("Mini OpenClaw 启动成功(仅CLI模式)")
print_help()
while True:
user_input = input("\n你: ").strip()
if not user_input:
continue
if user_input == "/exit":
print("助手: 再见,欢迎下次继续调试。")
break
if user_input == "/new":
store.reset()
print("助手: 会话已重置。")
continue
if user_input == "/history":
print(f"助手: 当前历史消息条数: {len(store.load_messages())}")
continue
store.append_message("user", user_input)
history = store.load_messages()
context = build_context(history)
try:
answer = agent.chat(context)
except Exception as e:
print(f"助手: 请求失败,请稍后重试。错误信息: {e}")
continue
answer = answer.strip() or "(模型返回了空内容)"
store.append_message("assistant", answer)
print(f"助手: {answer}")
if __name__ == "__main__":
run()
export OPENAI_API_KEY="你的key"
python3 main.py
示例交互:
你: 解释一下什么是事件循环
助手: ...
你: /history
助手: 当前历史消息条数: 2
你: /new
助手: 会话已重置。
有意省略了很多“工程硬骨头”:
但核心思想是一致的:
输入 -> 会话上下文 -> 模型回合 -> 输出 -> 历史落盘。
如果你能把这一版跑通,再回头看OpenClaw源码,会更容易理解为什么它需要那么多工程模块。
因为大型系统本质上不是“更聪明的聊天”,而是“更稳的运行”。
系列到这里就告一段落啦,后续如果你希望,我可以继续出:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。