跳到主要内容

gptme 是什么 · 全景与阅读地图

30 秒导读: gptme 是一个跑在终端里的 AI agent——你在命令行里跟它说话,它能读写文件、跑 shell、执行 Python、开浏览器,像一个坐在你旁边、有手有脚的助手。它不绑定某一家模型(Anthropic / OpenAI / 本地 llama.cpp 都行),数据和会话都留在你自己机器上。本章带你零基础认识它、看懂它的顶层结构,并告诉你想深入哪个机制该读哪一章。


1. 这是什么(零基础也能懂)

一句话定义: gptme 是一个通用型 + 编码型的命令行 AI agent——把大语言模型接上「一套能真正动手的工具」,让它在你的终端里替你干活。

它给自己的注音是 /ʤiː piː tiː miː/,README 里的自我介绍是「a personal AI agent that runs anywhere a terminal runs」(见 README.md 顶部简介)。

解决什么问题 / 给谁用。 想象你在终端里,想让 AI 帮你改一个项目的代码、跑测试、查日志、总结一个网页——但纯聊天的模型只会「说」,不会「做」:它给不了你一个真正被修改的文件,也跑不了一条命令。gptme 补的正是这一步:把模型说的话,落成真实的动作。它面向:

  • 想在终端 / SSH / tmux / CI 里用 agent 的工程师;
  • 想要一个不锁定厂商、数据留本地的 Claude Code / Cursor / Codex 替代品的人;
  • 想把「agent 循环」这套东西读明白、甚至二次开发的人。

它能做什么(功能):

  • 在对话里执行 shell 命令、运行 Python 代码;
  • 读取、保存、打补丁式地编辑文件;
  • 浏览网页、看图(vision)、截图;
  • 换用不同的模型提供商(Anthropic / OpenAI / Google / xAI / DeepSeek / OpenRouter / 本地);
  • 通过钩子(hooks)插件、**技能(skills)**扩展行为。

用起来什么样。 一个最小的真实交互——你在命令行敲:

$ gptme "把 README 里的拼写错误修好" README.md

gptme 会:把 README.md 拉进上下文 → 让模型思考 → 模型回一段话,里面夹着一个 shell 或 patch 代码块 → gptme 就地执行这个代码块 → 把执行结果贴回对话 → 继续,直到任务完成。CLI 的帮助文本本身就点明了这个定位:「gptme is a chat-CLI for LLMs, empowering them with tools to run shell commands, execute code, read and manipulate files」(gptme/cli/main.py:285-286,docstring)。

一句话直觉 / 类比。 把普通聊天模型当成「只有嘴、没有手」的大脑;gptme 给它接上了手脚(工具)记忆(会话日志)一条不断循环的神经(主循环)。它最巧妙的一点是:模型不需要特殊的函数调用协议——它只要在回答里写一个 Markdown 代码块,gptme 就把那当成一次工具调用去执行。


2. 顶层全景(它大概怎么转)

这一节讲「大盘」:gptme 由哪些部件组成、一个用户输入是怎么端到端走完的。

2.1 部件职责一览

部件干什么在哪(主要文件/符号)
CLI 入口解析命令行参数、装配配置与工具,最后调用 chat()gptme/cli/main.py:525 main:1170 chat(...)
聊天循环会话主循环:取输入 → 生成 → 执行工具 → 判断是否继续gptme/chat.py:47 chat:176 _run_chat_loop:333 _process_message_conversation
单步 step一次「生成 + 执行工具」的原子步骤gptme/chat.py:521 step
LLM 抽象把统一的消息发给任意提供商,拿回一条 assistant 消息gptme/llm/__init__.py:263 reply:629 _reply_stream / :394 _chat_complete
工具系统把回复里的代码块解析成 ToolUse、判断可否运行、执行gptme/tools/base.py:662 ToolUsegptme/tools/__init__.py:316 execute_msg
内置工具shell / python / 文件编辑 / 浏览器等具体「手脚」gptme/tools/(shell.pypython.pypatch.pybrowser.py …)
提示与上下文组装分层系统提示;发送前做上下文注入/压缩gptme/prompts/__init__.py:445 get_promptgptme/logmanager/manager.py:769 prepare_messages
消息与持久化消息数据模型 + 会话日志(JSONL / TOML / 事件日志)gptme/message.py:189 Messagegptme/logmanager/(manager.pyeventlog.py)
钩子系统在循环各阶段挂载确认、护栏、上下文注入等gptme/hooks/registry.py:654 trigger_hookgptme/hooks/types.py:66 HookType

2.2 端到端走一个 turn(顶层流程图)

怎么读这张图: 从上往下是一次用户输入引发的完整过程;右侧的循环箭头是关键——只要模型这一步还留着「可运行的工具」,就不回头问用户,而是自动再走一圈。

用户在终端输入一句话


┌──────────────────────────────────────────────┐
│ 聊天主循环 _run_chat_loop (chat.py:176) │
│ 取到用户消息 → append 进会话日志 │
└───────────────┬────────────────────────────────┘


┌──────────────────────────────────────────────┐
│ 处理一个 turn _process_message_conversation │◀──────────────┐
│ (chat.py:333) │ │
│ ┌────────────────────────────────────────┐ │ │
│ │ 单步 step (chat.py:521) │ │ │
│ │ ① prepare_messages 组装/压缩上下文 │ │ │
│ │ ② reply 生成 assistant 回复 │ │ │
│ │ ③ execute_msg 解析并执行工具块 │ │ │
│ └──────────────┬─────────────────────────┘ │ │
│ │ 工具结果回灌进日志(append) │ │
│ ▼ │ │
│ has_runnable? 回复里还有可运行的工具吗? │ 是,继续下一步 │
│ (chat.py:433, ToolUse.iter_from_content)├───────────────┘
└───────────────┬────────────────────────────────┘
│ 否:这一 turn 结束

回到主循环,等下一次用户输入

2.3 主线走一遍(高层,不进代码)

把上图翻成一句话叙述,分三段看:

① 准备。 用户输入被包成一条 Message,追加进会话日志;发给模型前,prepare_messages 会把系统提示、文件内容等上下文注入进来,并在超预算时做压缩/裁剪(prepare_messages,gptme/logmanager/manager.py:769)。

② 生成。 reply 把这批消息交给对应提供商的后端(流式走 _reply_stream,非流式走 _chat_complete),拿回一条 assistant 消息——里面可能夹着一个或多个工具代码块(reply,gptme/llm/__init__.py:263)。

③ 执行并决定是否继续。 execute_msg 从回复内容里 iter_from_content 出所有 ToolUse,逐个执行,把结果作为新消息回灌;然后 _process_message_conversation 检查最后一条 assistant 消息里还有没有可运行的工具(has_runnable)——有就自动再走一步,没有才把控制权还给用户(gptme/chat.py:428-437)。


3. 这套设计的精华速览

不必读代码也能带走的三个「为什么」:

  • 代码块即工具调用。 gptme 不强依赖各家的 function-calling 协议:模型只要写一个带语言标签的 Markdown 代码块(如 ```shell),ToolUse._from_codeblock 就按语言标签找到对应工具并执行(gptme/tools/base.py:804 _from_codeblock:837 iter_from_content)。这让它天然 provider-agnostic——换模型不换执行机制。详见 02-tool-system.md

  • 「有没有可运行工具」是循环的方向盘。 一个 turn 要不要继续,唯一判据是 has_runnable:模型自己通过「是否再写一个工具块」来决定要不要继续动手。这就是 agent「自主推进」的最小内核(gptme/chat.py:433-436)。详见 01-agent-loop.md

  • 提示分层 + 发送前才组装。 系统提示分成核心身份、用户偏好、工具说明、项目上下文等若干层(get_prompt 的文档字符串,gptme/prompts/__init__.py:457-503);而 file 内容/RAG 等易变上下文是在每次发送前prepare_messages 动态注入并压缩的,历史日志本身保持干净。详见 04-prompt-context.md


4. 阅读地图(想深入哪块读哪章)

本子库分六章,按由浅入深排序。各章一句话:

章节讲什么什么时候读
index.md(本章)gptme 是什么、顶层结构、阅读地图先读我,建立全局认知
01-agent-loop.md主循环如何 generate → 执行工具 → 回灌,has_runnable 如何决定继续/停止想理解「agent 为什么能自主多步推进」
02-tool-system.md为什么代码块等于工具调用;ToolUse 的解析、ToolSpec 的注册与分发想理解工具机制、或想写一个自定义工具
03-builtin-tools.mdshell / python / 文件编辑(patch/save) / 浏览器等具体工具的行为与边界想知道 agent 的「手脚」各自能干什么、怎么落地
04-prompt-context.md系统提示分层、prepare_messages 的上下文注入与压缩想理解「模型到底看到了什么」以及上下文预算
05-hooks-extensibility.md钩子在循环各阶段的挂载点、确认(confirm)护栏、插件/技能想给 gptme 加护栏、加行为、做二次开发
06-message-persistence.mdMessage 模型、会话日志(JSONL/TOML)、事件日志与分支想理解会话如何存盘、恢复、可审计

建议顺序: index → 01 → 02 → 03,是「主干」;想扩展/定制再看 04 → 05 → 06。


5. 边界与说明(读之前先知道)

  • 本章是导航层,刻意不深入任何单一机制的实现细节——那些留给各章。这里只帮你低成本判断「该读哪章」。
  • gptme 是活跃开发中的大项目(仓库还含 server/webui/tauri/acp/eval/mcp/ 等本子库未覆盖的子系统);本子库聚焦终端 agent 的核心链路(CLI → 循环 → 工具 → LLM → 提示 → 持久化),不覆盖 Web UI、桌面壳、评测框架等。
  • 所有引用均以 sourceCommit: 8d974ca1 为准;上游更新后行号可能漂移,请优先用符号名(下表)定位。

6. 代码地图(导航索引)

一张跳转表——想读源码时,按「符号名」grep 最抗行号漂移。

主题文件路径符号名
CLI 入口(装配后调 chat)gptme/cli/main.pymain / chat(...) 调用点
聊天主循环gptme/chat.pychat / _run_chat_loop
一个 turn 的处理gptme/chat.py_process_message_conversation
单步:生成+执行gptme/chat.pystep
是否继续的判据gptme/chat.pyhas_runnable(用 ToolUse.iter_from_content)
LLM 统一入口gptme/llm/__init__.pyreply / _reply_stream / _chat_complete
工具执行分发gptme/tools/__init__.pyexecute_msg / get_tools / get_available_tools
工具调用数据模型gptme/tools/base.pyToolUse / iter_from_content / _from_codeblock / is_runnable
工具规格与注册gptme/tools/base.pyToolSpec
系统提示组装gptme/prompts/__init__.pyget_prompt
发送前消息准备gptme/logmanager/manager.pyprepare_messages
消息数据模型gptme/message.pyMessage / to_toml / from_toml
会话日志与持久化gptme/logmanager/manager.pyLog / LogManager(load / append / write_jsonl)
事件日志gptme/logmanager/eventlog.pyappend_event(events.jsonl)
钩子触发gptme/hooks/registry.pytrigger_hook
钩子类型枚举gptme/hooks/types.pyHookType
会话初始化gptme/init.pyinit