分析 EVA 仓库的完整实现,包括架构设计、核心模块、扩展机制和设计哲学。

Summary

EVA 是一个极致轻量化的 AI Agent,核心代码仅 eva.py 单文件(768行),零外部依赖(仅用 Python 标准库),功能相当于低配版 Claude Code。它通过 OpenAI 兼容 API 接入任意 LLM(vLLM/Ollama/DeepSeek/OpenAI),为 LLM 提供 run_cli 工具来执行 shell 命令完成任务,支持会话持久化、记忆压缩、安全审查、跨平台运行,并通过 hints.md 机制实现自进化能力。

Detailed Findings

1. 核心架构:单文件 Agent Loop(eva.py:589-659)

整个 Agent 运行在一个经典的消息循环中:

  1. human_loop() (eva.py:662-692): 外层主循环,接收用户输入,调用 agent_single_loop()
  2. agent_single_loop() (eva.py:589-659): 内层循环,与 LLM 交互直到 LLM 不再返回 tool_calls
  3. LLM 返回 tool_calls → 执行工具 → 将 tool result 追加到 messages → 继续调用 LLM → 直到 LLM 返回纯文本回复

关键设计点:

  • 使用标准的 OpenAI chat completions API 格式(eva.py:321-339 _build_request_data()
  • 同时支持 deepseekvLLM 两种 thinking 参数格式
  • 流式输出实时打印到终端,包括 thinking/reasoning 过程(暗色显示)(eva.py:371-485

2. LLM 集成层(eva.py:17-65)

  • API 兼容性:通过 EVA_BASE_URLEVA_MODEL_NAMEEVA_API_KEY 三个环境变量配置,兼容所有 OpenAI 接口格式的 LLM
  • 启动时模型验证detect_model_len() 在启动时调用 /models 端点获取模型的最大上下文长度(eva.py:26-64
  • 强制 API KeyEVA_API_KEY 未设置则直接退出(eva.py:22-24
  • 移除了 requests 依赖:使用标准库 urllib.request(最近提交 491fe81)
  • 默认模型deepseek-v4-flash,要求使用 thinking 模型

3. 工具系统(eva.py:192-311)

EVA 定义了两个工具:

工具 功能 注册条件
run_cli 执行任意 shell 命令 始终可用
leave_memory_hints 记忆压缩,写入 hints 仅 COMPACT_PANIC 时暴露

run_cli 执行流程eva.py:239-263):

  1. 安全审查:调用 LLM 判断命令是否只读(CLI_REVIEW_PROMPTeva.py:186-190
  2. 非只读命令需要用户确认(eva.py:244-247
  3. 通过 subprocess.run() 执行命令
  4. 返回 exit code + stdout + stderr

安全审查机制eva.py:186-190):将命令发送给 LLM,要求其输出”放行”或”禁止”,只有读操作(cat/ls/grep 等)会被自动放行。

4. 会话管理(eva.py:494-585)

  • 目录级 Session:基于 os.getcwd() 的哈希值生成 session 文件名(eva.py:495-498
  • 锁机制:通过 .lock 文件防止同一目录启动多个 EVA 实例(eva.py:500-526
  • Session 文件格式:JSON,存储完整的 messages 数组
  • 加载时刷新 hints:加载 session 后重新读取 hints.md 更新 system prompt(eva.py:540-541
  • 清理机制:上次回复如果是纯 tool_calls(无 content),加载时自动清理(eva.py:543-548

5. 记忆压缩系统(eva.py:68-76, 172-184, 265-306)

这是项目最精巧的部分之一:

  • 触发条件:token 使用量达到 TOKEN_CAP * 3/4COMPACT_PANIC = Trueeva.py:648-651
  • 压缩流程leave_memory_hints()eva.py:265-306):
    1. 定位”紧急危机”提示和最后一条用户消息
    2. 保留中间片段,对 tool result 做 200 字符截断
    3. 重建 messages 为 [system提示 + 压缩记忆提示]
    4. 将 hints 写入 HINT_FILEeva.py:304-305
  • COMPACT_PROMPTeva.py:172-184):详细的压缩指引,要求 EVA 完成三步:保存记忆 → 保存技能/知识 → 留下线索

6. 环境探针系统(eva.py:86-131)

collect_env_info() 在启动时自动收集:

  • 系统信息(OS 版本)
  • 已安装工具(python/node/git/docker/curl/wget 等)
  • 当前目录文件列表(最多 100 条,总字符不超过 2000)

这些信息被嵌入到 system prompt 中,让 LLM 了解自己的运行环境。

7. 跨平台支持(eva.py:78-82)

支持 Windows 和 Linux:

  • Windows 使用 PowerShell,Linux 使用 Bash
  • 环境探针命令根据平台不同而有不同实现
  • Windows 下设置 POWERSHELL_OUTPUT_ENCODING=utf-8eva.py:228

8. 自进化机制

EVA 通过 **hints.md 记忆线索** 实现自进化:

  • hints.md 位于 EVA_HOME/hints.mdeva.py:72),内容被嵌入 system prompt 的 <memory_hints> 标签中
  • EVA 在执行任务时可以参考 hints 中的技能和知识
  • 记忆压缩时,EVA 更新 hints.md 留下进化线索
  • 实际进化通过 EVA 自己写文件(技能文件、知识文件)到 .eva/ 目录实现
  • System prompt 鼓励 EVA”将进化过程中学到的技能或知识保存下来”

9. 一键安装(eva.py:694-718)

非 Windows 系统首次运行时调用 setup_eva_script()

  • 创建 ~/.local/bin/eva 启动脚本
  • ~/.local/bin 加入 PATH(写入 ~/.bashrc
  • 之后只需输入 eva 即可启动

10. 命令行参数(eva.py:726-737)

参数 功能
-a / --allow-all 跳过安全审查,直接执行所有命令
-l / --list-session 列出所有 session
-c / --clear-session 清除当前目录 session
-u / --user-ask 单次问答模式(类似 -asu 则带 session)
-s / --with-session 搭配 -u 使用,加载并保存 session

11. Showcase 案例

暴走模式(showcase/eva暴走模式/)

  • EVA 通过 run_cli 派生子 EVA 实例实现并行处理
  • 关键技巧:分身子 EVA 需要 cd 到独立 workspace 避免锁冲突
  • 支持同步(阻塞等待)和异步(nohup 后台)两种模式
  • spawn-registry.json 管理后台分身状态
  • 分身可以递归再生子分身

微信 Bot(showcase/wechat-bot/)

  • 使用 wechatbot 库对接微信 iLink 协议
  • 通过 eva -asu 调用 EVA 处理用户消息
  • bot.py 仅 48 行,极简设计

Linux/Win运维(showcase/linux/, showcase/windows运维/)

  • 演示 EVA 在运维场景中的应用
  • Linux 下可以自动分析 CVE 漏洞

Code References

  • eva.py:1-16 - 入口和路径解析
  • eva.py:17-65 - LLM 配置、API key 验证、模型长度检测
  • eva.py:67-76 - EVA 配置(TOKEN_CAP、COMPACT_THRESH 等)
  • eva.py:78-82 - 跨平台 shell 配置
  • eva.py:86-131 - 环境探针 collect_env_info()
  • eva.py:134-170 - SYSTEM_PROMPT(含三大定律、进化指令)
  • eva.py:172-184 - COMPACT_PROMPT 记忆压缩提示
  • eva.py:186-190 - CLI_REVIEW_PROMPT 安全审查提示
  • eva.py:192-225 - 工具 schema 定义
  • eva.py:239-263 - run_cli() 执行 shell 命令
  • eva.py:265-306 - leave_memory_hints() 记忆压缩核心逻辑
  • eva.py:321-339 - _build_request_data() LLM 请求构建
  • eva.py:350-368 - llm_chat() 非流式调用
  • eva.py:371-485 - llm_chat_stream() 流式调用(含 thinking 过程渲染)
  • eva.py:494-585 - Session 会话管理全套
  • eva.py:589-659 - agent_single_loop() Agent 内循环
  • eva.py:662-692 - human_loop() 主循环
  • eva.py:694-718 - setup_eva_script() 一键安装
  • eva.py:720-767 - main() 入口函数

Architecture Insights

  1. 极致极简主义:整个 Agent 不到 800 行 Python,零外部依赖。这种设计使其”像病毒一样传播”——只需复制粘贴一个文件即可在任何有 Python 的环境中运行。
  2. LLM 驱动安全:安全审查不是基于规则白名单,而是让另一个 LLM 调用(temperature=0, thinking=False)来判断命令是否安全。这是一种”用 AI 约束 AI”的思路。
  3. 自进化闭环hints.md 形成了”学习→记录→检索→应用”的完整闭环。EVA 在压缩时提取知识,在日常执行时检索知识,体现了项目中强调的”发挥 EVA 自主性”的设计哲学。
  4. 分身递归:暴走模式展示了 Agent 自我复制的可能性——EVA 通过 run_cli 工具创建新的 EVA 实例,形成一个树状计算结构,可处理可并行的复杂任务。
  5. 无外部依赖的代价:所有 LLM 调用使用 urllib.request 手动构建 HTTP 请求,流式解析也是手动从 SSE 逐行解析,这减少了依赖但也意味着没有自动重试、连接池等能力。
  6. Windows 支持:项目认真处理了跨平台问题,PowerShell 和 Bash 两套命令体系,环境探针也做了平台差异化。

Open Questions

  • 当前记忆压缩采用简单的 token 阈值触发,是否存在 token 估算不准确的问题?(使用的是 LLM 返回的 usage 数据,依赖 API 上报)
  • 没有实现多轮对话的层次化压缩(类似 Claude Code 的 compact),是否会导致长任务中信息丢失?
  • 安全审查 LLM 调用增加了每次命令执行的延迟和成本,是否有更轻量的方案?