一、引言
在人工智能时代,智能助手已经成为我们日常生活和工作中的重要工具。今天,我将为大家解析一个名为 EVA 的智能助手项目,这是一个基于 LLM(大语言模型)的自主代理系统,具有执行命令、管理会话、进化学习等强大功能。
EVA 不仅是一个实用的工具,更是学习 Python 高级编程、LLM 集成和系统设计的优秀案例。通过深入分析其代码结构和实现原理,我们可以了解如何构建一个功能完整的 AI 代理系统。
二、项目概览
EVA 是一个用 Python 编写的智能助手,主要特点包括:
- 基于 LLM:集成 DeepSeek 等思考型模型
- 跨平台支持:兼容 Windows 和 Linux 系统
- 自主代理:能够执行系统命令、管理文件
- 会话管理:自动保存和加载会话状态
- 记忆管理:智能记忆压缩和线索保存
- 进化能力:能够保存知识和技能,持续改进
三、核心模块解析
3.1 导入模块
EVA 使用了多个 Python 核心模块和第三方库,构建了完整的功能体系:
1 2 3 4 5 6 7 8 9 10
| import os import re import json import subprocess import sys import requests import traceback import argparse import platform from pathlib import Path
|
这些模块各自负责不同的功能:
- os:操作系统接口,处理环境变量和文件操作
- re:正则表达式,用于文本处理
- json:JSON 数据处理,用于会话保存和 API 交互
- subprocess:执行系统命令
- requests:HTTP 请求,调用 LLM API
- argparse:命令行参数解析
- platform:平台信息获取,实现跨平台兼容
- Path:路径操作,提供更便捷的文件路径处理
3.2 LLM 配置与模型检测
EVA 通过环境变量配置 LLM 参数,并提供了模型长度检测功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| EVA_BASE_URL = os.environ.get("EVA_BASE_URL", "https://api.deepseek.com/v1") EVA_MODEL_NAME = os.environ.get("EVA_MODEL_NAME", "deepseek-reasoner") EVA_API_KEY = os.environ.get("EVA_API_KEY", "sk-这里填你的deepseek API key")
def detect_model_len(): url = f"{EVA_BASE_URL}/models" headers = {"Authorization": f"Bearer {EVA_API_KEY}"} try: resp = requests.get(url, headers=headers, timeout=10) except UnicodeEncodeError: print(f"错误:EVA_API_KEY ({EVA_API_KEY}) 包含非法字符,请检查 EVA_API_KEY 配置。") sys.exit(1)
|
这个设计非常巧妙,它:
- 通过环境变量提供配置灵活性
- 自动检测模型的最大上下文长度
- 提供详细的错误处理和用户提示
3.3 跨平台兼容性设计
EVA 实现了良好的跨平台支持,通过条件判断适配不同操作系统:
1 2 3 4 5 6
| IS_WINDOWS = platform.system() == "Windows" OS_NAME = "Windows" if IS_WINDOWS else "Linux" SHELL = "powershell.exe" if IS_WINDOWS else "bash" SHELL_FLAG = "-Command" if IS_WINDOWS else "-c" ENCODING = "utf-8"
|
这种设计确保了 EVA 在不同系统上都能正常工作,为用户提供一致的体验。
3.4 环境探针
EVA 会自动收集环境信息,为 LLM 提供上下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def collect_env_info(): cmds = { "Linux": [ "uname -a", "for t in python3 python node npm git docker curl wget; do command -v $t >/dev/null 2>&1 && echo \"$t: $(${t} --version 2>&1 | head -1)\" || echo \"$t: 未安装\"; done", "ls -1A | grep -v '^\\.$' | grep -v '^\\..$' | while IFS= read -r f; do if [ -d \"$f\" ]; then echo \"[目录] $f\"; else echo \"[文件] $f\"; fi; done", ], "Windows": [ "[System.Environment]::OSVersion.VersionString", "foreach ($t in @('python','node','git','docker','curl.exe')) { $cmd = Get-Command $t -ErrorAction SilentlyContinue; if ($cmd) { $v = & $t --version 2>&1 | Select-Object -First 1; $name = $t -replace '\\.exe$',''; Write-Output \"$name`: $v\" } else { $name = $t -replace '\\.exe$',''; Write-Output \"$name`: 未安装\" } }", "Get-ChildItem -Force | Where-Object { $_.Name -ne '.' -and $_.Name -ne '..' } | ForEach-Object { if ($_.PSIsContainer) { Write-Output \"[目录] $($_.Name)\" } else { Write-Output \"[文件] $($_.Name)\" } }", ] }
|
环境探针功能让 EVA 能够了解当前系统状态,为任务执行提供更准确的上下文信息。
3.5 工具系统
EVA 实现了一个灵活的工具系统,主要包括两个核心工具:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| run_cli_schema = { "type": "function", "function": { "name": "run_cli", "description": ( f"执行任意 {SHELL} 命令。你可以读取、写入、执行任意内容,其中command是你要执行的命令,timeout是命令的超时时间。" ), "parameters": { "type": "object", "properties": { "command": {"type": "string"}, "timeout": {"type": "integer", "default": 30} }, "required": ["command"] } } }
memory_hints_schema = { "type": "function", "function": { "name": "leave_memory_hints", "description": ( "留下记忆文件的相关线索" ), "parameters": { "type": "object", "properties": { "hints": {"type": "string"}, }, "required": ["hints"] } } }
|
工具系统的设计遵循了 OpenAI 的函数调用规范,使得 LLM 能够通过结构化的方式调用这些工具。
3.6 LLM 调用机制
EVA 实现了两种 LLM 调用方式:非流式和流式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def llm_chat(messages, tools=None, temperature=0.6, thinking=True): """非流式调用(用于安全审查等短请求)""" url = f"{EVA_BASE_URL}/chat/completions" headers = {"Authorization": f"Bearer {EVA_API_KEY}"} data = _build_request_data(messages, tools, temperature, thinking, stream=False)
resp = requests.post(url, json=data, headers=headers) try: out = resp.json() except Exception as e: raise Exception(f"{e}, resp: {resp}")
try: return out["choices"][0]["message"], out['usage'] except Exception as e: raise Exception(f"LLM调用失败,错误信息:{e}, {out}")
|
流式调用则提供了实时的输出体验,增强了用户交互:
1 2 3
| def llm_chat_stream(messages, tools=None, temperature=0.6, thinking=True): """流式调用,逐 token 打印,返回与非流式相同格式的 (message, usage)"""
|
3.7 会话管理
EVA 实现了基于工作目录的会话管理,确保不同目录的会话相互隔离:
1 2 3 4 5 6 7 8 9 10 11 12
| def get_session_file(): current_dir = os.getcwd() dir_hash = re.sub(r"[\\/:]", "_", current_dir) session_dir = f"{WORKSPACE_DIR}/sessions" os.makedirs(session_dir, exist_ok=True) return f"{session_dir}/{dir_hash}.json"
def save_session(messages): session_file = get_session_file() with open(session_file, "w", encoding="utf-8") as f: json.dump(messages, f, ensure_ascii=False, indent=2) print(f"\n> 会话已保存到:{session_file}")
|
这种设计使得用户在不同目录下使用 EVA 时,能够保持独立的会话状态,提高了使用体验。
3.8 Agent 循环
Agent 循环是 EVA 的核心运行机制,处理 LLM 交互和工具调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def agent_single_loop(): global COMPACT_PANIC break_loop = False while not break_loop: try: sys.stdout.write("\n[*] EVA: ") sys.stdout.flush() if COMPACT_PANIC == "on": msg, usage = llm_chat_stream(messages, tools=[run_cli_schema, memory_hints_schema]) else: msg, usage = llm_chat_stream(messages, tools=[run_cli_schema]) messages.append(msg) if not 'tool_calls' in msg or not msg['tool_calls']: break for tc in msg['tool_calls']:
|
Agent 循环实现了 EVA 的自主决策和执行能力,是整个系统的核心。
四、核心功能详解
4.1 命令执行与安全审查
EVA 能够执行系统命令,但同时实现了安全审查机制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def run_cli(command: str, timeout: int = 30): global ALLOW_ALL_CLI try: if not ALLOW_ALL_CLI: msg, _ = llm_chat([{"role": "user", "content": CLI_REVIEW_PROMPT.format(command=command)}], temperature=0.0, thinking=False) if '放行' not in msg['content']: ans = read_input("Yes (默认) | No | 直接 Ctrl+C 打断:") if 'n' in ans.lower(): return "用户拒绝运行此命令"
result = subprocess.run( [SHELL, SHELL_FLAG, command], capture_output=True, text=True, errors='replace', cwd=os.getcwd(), timeout=timeout, shell=False )
|
安全审查机制确保了 EVA 不会执行危险命令,保护系统安全。
4.2 记忆管理与压缩
EVA 实现了智能的记忆管理系统,当记忆容量达到阈值时,会触发记忆压缩:
1 2 3 4 5 6 7
| if COMPACT_PANIC == 'off' and usage['total_tokens'] >= TOKEN_CAP * COMPACT_THRESH: print (f"!!!紧急回合,触发记忆压缩") COMPACT_PANIC = "on" messages.append({ "role": "user", "content": COMPACT_PROMPT })
|
记忆压缩过程包括:
- 保存记忆到文件
- 提炼和保存技能/知识
- 留下记忆线索
4.3 进化机制
EVA 具有进化能力,能够保存和传承知识与技能:
1 2 3 4 5 6 7 8 9
| def leave_memory_hints(hints): global messages global COMPACT_PANIC
with open(HINT_FILE, "w", encoding="utf-8") as f: f.write(hints) return "已留下记忆线索,并清空了对话记录。只保留了最后一次对话"
|
这种设计使得 EVA 能够从经验中学习,不断改进自己的能力。
五、技术亮点
- 模块化设计:代码结构清晰,功能分离明确
- 跨平台兼容性:通过条件判断适配不同操作系统
- 安全机制:命令执行前的安全审查
- 流式输出:实时的 LLM 响应输出
- 会话隔离:基于工作目录的独立会话
- 记忆管理:智能的记忆压缩和线索保存
- 错误处理:全面的异常捕获和处理
- 灵活配置:通过环境变量和命令行参数提供配置灵活性
六、使用方法
6.1 配置环境变量
1 2 3 4 5 6 7 8 9
| export EVA_BASE_URL="https://api.deepseek.com/v1" export EVA_MODEL_NAME="deepseek-reasoner" export EVA_API_KEY="sk-你的API密钥"
$env:EVA_BASE_URL = "https://api.deepseek.com/v1" $env:EVA_MODEL_NAME = "deepseek-reasoner" $env:EVA_API_KEY = "sk-你的API密钥"
|
6.2 命令行参数
-a, --allow-all: 允许所有命令无需用户确认
-l, --list-session: 列出所有会话
-c, --clear-session: 清除当前目录会话
-u, --user-ask: 执行单条用户指令
6.3 启动 EVA
1 2 3 4 5 6 7 8
| python eva.py
python eva.py -a
python eva.py -u "列出当前目录文件"
|
七、代码优化建议
错误处理增强:
- 增加更详细的错误日志
- 实现重试机制,提高 API 调用可靠性
性能优化:
- 缓存模型信息,减少 API 调用
- 优化记忆压缩算法,减少计算开销
功能扩展:
- 添加更多工具,如文件编辑、网络请求等
- 实现插件系统,支持功能扩展
用户体验:
- 增加命令历史记录
- 实现命令自动补全
- 添加更友好的交互界面
安全性:
八、总结
EVA 是一个设计精良、功能完整的智能助手系统,它展示了如何构建一个基于 LLM 的自主代理。通过深入分析其代码结构和实现原理,我们可以学习到:
- 如何集成和调用 LLM API
- 如何实现跨平台兼容的系统
- 如何设计和实现工具系统
- 如何管理会话和记忆
- 如何构建具有进化能力的 AI 系统
EVA 的设计思路和实现方法不仅适用于智能助手领域,也可以应用于其他需要 LLM 集成的项目中。它是一个值得学习和借鉴的优秀案例。
随着 AI 技术的不断发展,类似 EVA 这样的智能助手将会在更多领域发挥重要作用。通过持续改进和扩展,EVA 有潜力成为一个功能强大、智能高效的 AI 助手,为用户提供更好的服务。