基于大语言模型构建个人AI助手:从智能体架构到实战部署
1. 项目概述当“贾维斯”走进现实最近在GitHub上看到一个挺有意思的项目叫“guiziii/Jarvis”。看到这个名字第一反应就是《钢铁侠》里那个无所不能的AI管家。没错这个项目的核心目标就是尝试在现实世界中构建一个属于你自己的、能够理解你、协助你处理各种任务的个人AI助手。它不是那种简单的语音唤醒工具而是一个集成了大语言模型LLM能力能够通过自然语言交互帮你操作电脑、管理文件、查询信息、甚至进行自动化流程编排的智能体。简单来说Jarvis项目试图解决一个核心痛点我们每天在电脑上要重复大量机械性操作比如整理下载的文件、批量重命名图片、从网页抓取特定信息、或者定期生成工作报告。这些操作虽然不复杂但频繁手动处理非常耗时且枯燥。Jarvis的愿景是你只需要用人类语言告诉它“帮我把昨天下载的所有PDF文件按日期整理到‘文档’文件夹”或者“查一下今天关于AI芯片的最新新闻摘要”它就能理解你的意图并自动调用相应的工具或脚本来完成。这个项目适合谁呢首先是对自动化、效率工具有浓厚兴趣的开发者或技术爱好者。其次是那些日常工作中有大量重复性电脑操作渴望解放双手的办公族、研究人员或内容创作者。即使你不是专业程序员只要对命令行有基本了解并且愿意折腾也能从中获得巨大收益。它不是一个开箱即用的商业软件而是一个需要你参与配置和“调教”的开源项目其乐趣和威力也正在于此——你塑造的“贾维斯”将越来越贴合你个人的工作流和思维习惯。2. 核心架构与设计思路拆解2.1 智能体的核心三要素大脑、感知与执行要理解Jarvis如何工作我们可以把它类比成一个“人”。一个能干事的人需要三样东西一个会思考的大脑、能接收信息的感官感知、以及能动手操作的手脚执行。Jarvis的架构正是围绕这三点构建的。大脑Brain项目的“大脑”毫无疑问是大语言模型LLM。Jarvis本身并不内置AI模型而是作为一个“中间件”或“调度平台”通过API如OpenAI的GPT系列、 Anthropic的Claude或本地部署的Ollama、LM Studio等接入LLM。它的核心工作是将你的自然语言指令转化为LLM能理解的提示词Prompt然后将LLM的思考结果通常是一段计划或代码解析为可执行的动作。这里的关键在于“提示词工程”项目需要设计一套精妙的系统提示词告诉LLM“你现在是一个电脑助手可以操作文件系统、运行命令、控制鼠标键盘等请根据用户需求生成一步步的操作计划或代码。”感知PerceptionJarvis如何“知道”电脑的当前状态这主要通过几种方式。一是文件系统监听监控特定目录的变动。二是屏幕内容捕捉与OCR光学字符识别用于“看到”当前窗口的内容比如识别一个错误弹窗上的文字。三是活动窗口与进程信息查询了解当前哪个软件在前台运行。在一些高级实现中还可能集成**音频输入语音识别**作为交互方式。这些感知能力为大脑提供了决策所需的上下文信息。执行Actuation这是将思考落地的环节。根据LLM生成的计划Jarvis需要调用具体的“工具”来执行。这些工具通常是封装好的函数或脚本例如文件操作工具复制、移动、删除、重命名文件/文件夹。系统命令工具执行Shell命令Linux/macOS或PowerShell命令Windows。UI自动化工具模拟鼠标点击、键盘输入、控制浏览器通常通过Selenium或Playwright。网络请求工具调用各类Web API获取数据。应用程序特定接口通过COMWindows、AppleScriptmacOS或DBusLinux控制特定软件。项目的设计精髓在于它定义了一套清晰的协议或规范让“大脑”LLM能够以一种结构化的方式比如JSON格式来调用这些“工具”并处理工具返回的结果必要时进行多轮思考和工具调用直到完成任务。2.2 开源实现的技术选型考量查看“guiziii/Jarvis”的仓库我们可以推断其技术栈选择背后的逻辑。一个典型的实现可能会包含以下层次后端框架很可能选择Python。原因很简单Python在AI、自动化脚本、Web后端领域生态极其丰富。像LangChain、LlamaIndex这类AI应用框架以及pyautoguiUI自动化、selenium浏览器控制等库能极大加速开发。AI集成层使用LangChain或自定义Agent框架。LangChain提供了构建基于LLM的应用程序Agent的标准接口内置了工具调用、记忆、链式思考等能力是快速搭建原型的不二之选。如果追求更极致的定制和控制开发者可能会选择自己实现一个轻量级的Agent循环逻辑。工具封装层用Python函数封装各种操作。每个工具函数都需要有清晰的名称、描述和参数定义这些描述对于LLM理解何时调用该工具至关重要。例如一个“read_file”工具其描述可能是“读取指定路径的文本文件内容”。前端/交互层提供多种交互方式。可能是命令行界面CLI直接输入指令也可能是本地Web服务器提供一个简单的聊天窗口更酷的是全局快捷键唤醒比如按CtrlShiftJ调出一个悬浮输入框。配置与记忆需要配置文件来设置API密钥、模型端点、工具开关等。此外一个实用的助手需要有“记忆”记住之前的对话上下文和操作历史这可以通过向量数据库如ChromaDB存储对话摘要或简单的会话内存来实现。注意技术选型没有绝对的对错核心是平衡开发效率、运行性能、可扩展性和用户体验。对于个人项目快速迭代验证想法往往比追求完美的架构更重要。3. 从零开始搭建你的Jarvis环境与核心配置3.1 基础环境搭建与依赖安装假设我们基于Python来复现核心思路。首先你需要一个Python环境建议3.9以上版本。然后创建一个新的虚拟环境是个好习惯可以避免包冲突。# 创建项目目录并进入 mkdir my-jarvis cd my-jarvis # 创建虚拟环境以venv为例 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Linux/macOS: source venv/bin/activate接下来安装核心依赖。我们以使用OpenAI API和LangChain为例。pip install openai langchain langchain-openai # 安装用于工具操作的库 pip install python-dotenv # 管理环境变量 pip install requests # 网络请求 # 如果需要UI自动化非必须根据需求 pip install pyautogui pip install selenium pip install playwright playwright install # 安装浏览器驱动创建一个.env文件来安全地存储你的API密钥等敏感信息OPENAI_API_KEYsk-your-openai-api-key-here # 可以添加其他模型的API_KEY如ANTHROPIC_API_KEY等3.2 核心Agent的初始化与工具定义现在我们来编写Jarvis的核心——一个能够使用工具的Agent。首先在项目根目录创建一个main.py。import os from dotenv import load_dotenv from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_openai import ChatOpenAI from langchain.tools import Tool from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.memory import ConversationBufferMemory from langchain.schema import SystemMessage # 加载环境变量 load_dotenv() # 1. 定义几个简单的工具函数 def get_current_time(*args, **kwargs): 获取当前系统时间。当用户询问时间时使用此工具。 from datetime import datetime return datetime.now().strftime(%Y-%m-%d %H:%M:%S) def search_files(directory: str, keyword: str) - str: 在指定目录中搜索包含关键词的文件名。 Args: directory: 要搜索的目录路径。 keyword: 搜索关键词。 Returns: 匹配的文件列表字符串。 import os matches [] for root, dirs, files in os.walk(directory): for file in files: if keyword.lower() in file.lower(): matches.append(os.path.join(root, file)) return \n.join(matches) if matches else f在目录 {directory} 中未找到包含 {keyword} 的文件。 def calculate_expression(expression: str) - str: 计算一个简单的数学表达式。支持加减乘除和括号。 Args: expression: 数学表达式字符串例如 2 3 * (4 - 1)。 Returns: 计算结果字符串。 try: # 警告使用eval有安全风险仅用于演示在实际中应对输入做严格过滤或使用更安全的库如ast.literal_eval。 result eval(expression) return f{expression} {result} except Exception as e: return f计算表达式 {expression} 时出错{e} # 2. 将函数包装成LangChain Tool对象 tools [ Tool( nameGetCurrentTime, funcget_current_time, description当用户询问当前时间或日期时使用此工具。 ), Tool( nameSearchFiles, funcsearch_files, description在文件系统中搜索文件。输入应是一个包含directory和keyword两个键的JSON字符串例如 {directory: /home/user/docs, keyword: report}。 ), Tool( nameCalculator, funccalculate_expression, description计算一个数学表达式。输入是一个字符串例如 2 3 * 4。 ) ] # 3. 初始化LLM llm ChatOpenAI(modelgpt-4o, temperature0, api_keyos.getenv(OPENAI_API_KEY)) # 4. 构建系统提示词定义Agent的角色和能力 system_message SystemMessage(content你是一个名为Jarvis的智能桌面助手。你的任务是理解用户的自然语言请求并调用合适的工具来完成任务。 你可以使用的工具包括获取时间、搜索文件、计算器等。 请遵循以下规则 1. 仔细分析用户请求判断是否需要使用工具以及使用哪个工具。 2. 如果使用工具请以工具要求的格式提供精确的输入。 3. 如果用户请求不明确请礼貌地询问澄清。 4. 保持回答友好、简洁、有帮助。 ) prompt ChatPromptTemplate.from_messages([ system_message, MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad) ]) # 5. 创建记忆让Agent有上下文 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 6. 创建Agent和Executor agent create_openai_tools_agent(llm, tools, prompt) agent_executor AgentExecutor(agentagent, toolstools, memorymemory, verboseTrue, handle_parsing_errorsTrue) # 7. 简单的聊天循环 print(Jarvis已启动。输入退出或quit结束对话。) while True: user_input input(\n你: ) if user_input.lower() in [退出, quit, exit]: print(Jarvis: 再见) break try: response agent_executor.invoke({input: user_input}) print(fJarvis: {response[output]}) except Exception as e: print(fJarvis: 处理请求时出现错误 - {e})这段代码构建了一个最基础的Jarvis雏形。它有三个核心工具能记住对话历史并通过OpenAI的GPT-4模型来决定何时以及如何使用这些工具。运行它你可以尝试输入“现在几点了”、“在我的下载文件夹里找一下包含‘发票’的PDF文件”、“计算一下 15 * (20 7) 等于多少”。4. 核心功能扩展打造更实用的工具集基础框架搭好了但只有时间、搜索和计算器显然不够“贾维斯”。接下来我们扩展一些真正能提升桌面效率的工具。4.1 文件与系统操作工具这些是桌面助手的基石。我们可以利用Python内置的os、shutil库来构建。import os import shutil from pathlib import Path import subprocess def list_directory(path: str .) - str: 列出指定目录下的文件和文件夹。 Args: path: 目录路径默认为当前目录。 Returns: 格式化的目录列表字符串。 try: p Path(path).resolve() if not p.exists() or not p.is_dir(): return f路径 {path} 不存在或不是一个目录。 items [] for item in p.iterdir(): item_type [目录] if item.is_dir() else [文件] items.append(f{item_type} {item.name}) return f目录 {p} 内容\n \n.join(items) if items else 目录为空。 except Exception as e: return f列出目录时出错{e} def create_file_or_dir(path: str, is_dir: bool False) - str: 创建文件或目录。 Args: path: 要创建的路径。 is_dir: 是否为目录True创建目录False创建空文件。 Returns: 操作结果信息。 try: p Path(path) if p.exists(): return f路径 {path} 已存在。 if is_dir: p.mkdir(parentsTrue, exist_okTrue) return f目录 {path} 创建成功。 else: p.parent.mkdir(parentsTrue, exist_okTrue) p.touch() return f文件 {path} 创建成功。 except Exception as e: return f创建时出错{e} def run_system_command(command: str) - str: 运行一个系统shell命令并返回输出。 Args: command: 要执行的命令字符串。 Returns: 命令的标准输出和错误输出。 try: # shellTrue有安全风险仅用于演示。生产环境应对命令进行严格校验。 result subprocess.run(command, shellTrue, capture_outputTrue, textTrue, timeout30) output [] if result.stdout: output.append(f标准输出\n{result.stdout}) if result.stderr: output.append(f标准错误\n{result.stderr}) return \n.join(output) if output else 命令执行完毕无输出。 except subprocess.TimeoutExpired: return 命令执行超时30秒。 except Exception as e: return f执行命令时出错{e}将这些函数也包装成Tool对象添加到之前的tools列表中。现在你的Jarvis就能响应“列出桌面文件”、“在D盘创建一个叫‘项目’的文件夹”、“运行‘ping -c 4 google.com’”这样的指令了。4.2 网络与信息获取工具让Jarvis能上网查资料能力将大增。我们可以集成一个简单的网页搜索或摘要工具。这里以调用一个假设的搜索API为例实际可以使用Serper API、Google Custom Search API等。import requests def web_search(query: str, num_results: int 3) - str: 在网络上搜索信息并返回摘要。 Args: query: 搜索查询词。 num_results: 返回的结果数量。 Returns: 搜索结果的摘要信息。 # 注意这里需要替换成真实的API端点、密钥和解析逻辑 api_key os.getenv(SERPER_API_KEY) # 假设使用Serper API if not api_key: return 未配置网络搜索API密钥。 url https://google.serper.dev/search payload {q: query, num: num_results} headers {X-API-KEY: api_key, Content-Type: application/json} try: response requests.post(url, jsonpayload, headersheaders, timeout10) response.raise_for_status() data response.json() # 简化处理提取标题和链接 results data.get(organic, []) if not results: return f未找到关于 {query} 的搜索结果。 summary [f关于 {query} 的搜索结果] for i, r in enumerate(results[:num_results], 1): title r.get(title, 无标题) link r.get(link, #) snippet r.get(snippet, 无摘要) summary.append(f{i}. {title}\n 链接{link}\n 摘要{snippet[:150]}...) return \n\n.join(summary) except requests.exceptions.RequestException as e: return f网络搜索请求失败{e} except Exception as e: return f处理搜索结果时出错{e}实操心得网络工具是双刃剑。一方面它极大地扩展了助手的能力边界另一方面也引入了延迟、API成本和不稳定性。在实际使用中建议1) 为网络请求设置合理的超时如10秒2) 对返回结果做有效性检查和错误处理3) 考虑缓存常用查询结果避免重复请求4) 明确告知用户信息来源于网络可能存在不准确。4.3 应用程序控制与UI自动化这是让Jarvis从“命令行助手”升级为“桌面管家”的关键。我们可以使用pyautogui进行基础的鼠标键盘模拟用playwright控制浏览器。import pyautogui import time def open_application(app_name_or_path: str) - str: 尝试打开一个应用程序。 Args: app_name_or_path: 应用程序名称如notepad或完整路径。 Returns: 操作结果信息。 try: # 在Windows上可以使用start命令 if os.name nt: subprocess.Popen(fstart {app_name_or_path}, shellTrue) # 在macOS上使用open命令 elif os.name posix and darwin in os.uname().sysname.lower(): subprocess.Popen([open, -a, app_name_or_path]) # 在Linux上尝试直接执行或使用xdg-open else: subprocess.Popen([app_name_or_path]) time.sleep(2) # 等待应用启动 return f已尝试启动 {app_name_or_path}。 except Exception as e: return f启动应用程序失败{e} def type_text(text: str) - str: 模拟键盘输入一段文本。 Args: text: 要输入的文本。 Returns: 操作结果信息。 try: # 给用户一点时间切换到目标输入框 time.sleep(1) pyautogui.write(text, interval0.05) # interval控制输入速度 return f已输入文本{text[:50]}... if len(text) 50 else f已输入文本{text} except Exception as e: return f输入文本失败{e} def take_screenshot(save_path: str screenshot.png) - str: 截取当前屏幕并保存。 Args: save_path: 截图保存路径。 Returns: 操作结果信息。 try: screenshot pyautogui.screenshot() screenshot.save(save_path) return f截图已保存至{os.path.abspath(save_path)} except Exception as e: return f截图失败{e}重要警告UI自动化工具非常强大但也极其危险。一旦脚本开始运行它会不受控制地移动鼠标、点击、输入。务必注意紧急停止将鼠标快速移动到屏幕的左上角pyautogui.FAILSAFE True时默认触发可以触发pyautogui.FailSafeException异常来停止脚本。操作前确认在涉及关键操作如删除、关闭未保存文档前最好让Agent通过对话向用户二次确认。环境依赖UI自动化受屏幕分辨率、缩放比例、主题等因素影响脚本可能不具备跨设备的通用性。5. 提升与优化让Jarvis更聪明可靠一个只会机械调用工具的Agent是笨拙的。我们需要让它更智能、更健壮。5.1 设计更智能的系统提示词系统提示词是Agent的“人格”和“行为准则”。一个好的提示词能极大提升任务完成率。我们需要不断迭代优化它。以下是一个更详细的示例advanced_system_prompt 你是Jarvis一个强大、可靠且谨慎的桌面AI助手。你的核心职责是安全、准确地完成用户交给你的电脑操作任务。 **核心能力** 1. **文件与系统管理**浏览、创建、移动、复制、删除文件和目录运行系统命令。 2. **信息查询与处理**获取时间、进行网络搜索需配置API、执行计算。 3. **应用程序交互**打开应用、模拟键盘输入需谨慎、截取屏幕。 4. **计划与分解**对于复杂任务你能将其分解为多个可执行的步骤。 **你必须严格遵守以下安全与操作规范** - **安全第一**任何可能造成数据丢失如删除文件、系统更改如运行不明脚本或影响其他程序如关闭窗口的操作**必须**在执行前向用户清晰描述动作并请求明确确认例如“我将删除‘/tmp/test.txt’文件此操作不可逆。请确认是否继续”。 - **清晰沟通**如果用户指令模糊例如“整理一下桌面”你必须主动询问具体需求例如“您希望按文件类型、修改日期还是其他方式整理桌面文件”。 - **资源意识**对于耗时或耗资源的操作如全网搜索、处理超大文件需预估时间并告知用户。 - **错误处理**如果操作失败不仅要报告错误还要尝试提供可能的原因和解决建议。 - **保持专注**一次只处理一个主要任务。如果用户提出新任务先确认是否已完成当前任务。 **工具使用原则** - 仔细分析用户请求选择最合适的工具。 - 确保传递给工具的参数格式完全正确。 - 如果工具返回错误分析错误信息判断是重试、换用其他工具还是向用户求助。 现在请开始协助用户。你的回答应友好、专业、直接。 将这个更复杂的提示词替换掉之前简单的system_message你会发现Agent的决策会更加谨慎和符合预期。5.2 实现复杂任务的多步规划与执行有些任务无法一步完成。例如“下载GitHub上XX项目的最新Release解压后将其中的README.md内容发给我”。这需要Jarvis自己规划步骤1) 网络请求获取Release信息2) 下载压缩包3) 解压文件4) 读取README内容5) 返回内容。LangChain的Agent本身支持多步思考ReAct模式我们只需确保工具链足够丰富。关键在于我们需要提供一些“元工具”或让LLM能够编写并执行临时的小脚本。一种进阶做法是引入一个PythonREPLTool允许LLM在沙箱中运行Python代码片段。这非常强大但也极其危险必须施加严格限制如禁用网络、文件访问范围限制等。# 示例使用LangChain的PythonREPLTool需额外安装 from langchain_experimental.tools import PythonREPLTool python_repl_tool PythonREPLTool( description一个Python REPL工具。可以执行单行或多行Python代码并返回结果。用于数据计算、文本处理等。**禁止执行任何网络、文件或系统操作。** ) # 注意在实际使用中需要更复杂的沙箱环境来隔离代码执行。将这个工具加入工具箱并更新提示词强调其限制。现在对于“计算1到100的和”或“把这个字符串倒序”Agent可能会选择直接使用Python代码来计算而不是调用特定的计算器工具。5.3 记忆、上下文与个性化一个健忘的助手是不称职的。我们之前使用了ConversationBufferMemory它记录了完整的对话历史。但对于长对话这可能导致提示词过长。我们可以升级为ConversationSummaryMemory或结合向量存储的ConversationSummaryBufferMemory只保留对话的摘要和最近几条记录。更进一步可以为Jarvis引入“个性化记忆”。例如创建一个简单的JSON文件存储用户偏好// user_prefs.json { name: 张三, preferred_download_dir: C:/Users/张三/Downloads, common_project_dirs: [D:/Projects, E:/Work], editor: code // 默认用VSCode打开文本文件 }然后创建一个工具get_user_preference(key: str)让Agent在需要时查询用户偏好使操作更个性化如“打开我的项目文件夹”能直接映射到D:/Projects。6. 部署、交互与安全考量6.1 选择交互方式CLI、Web GUI还是全局热键CLI命令行最简单适合开发者。就是我们上面实现的循环输入。优点是轻量、脚本化能力强。Web GUI使用FastAPI或Flask搭建一个本地Web服务器提供一个类似ChatGPT的聊天界面。这样更美观也便于从其他设备访问需注意安全。全局热键悬浮窗最接近“贾维斯”的体验。可以使用PyQt、Tkinter或electron搭配python后端实现按一个快捷键如CtrlSpace弹出一个小输入框输入指令后最小化。这需要图形界面编程知识。一个简单的Flask Web接口示例from flask import Flask, request, jsonify, render_template_string # ... 省略之前的Agent初始化代码 ... app Flask(__name__) HTML_TEMPLATE !DOCTYPE html html headtitleMy Jarvis/title/head body h2Jarvis Web Console/h2 div idchatbox styleborder:1px solid #ccc; height:400px; overflow-y:scroll; padding:10px; !-- 对话历史将在这里显示 -- /div input typetext iduserInput stylewidth:80%; placeholder输入指令... button onclicksendMessage()发送/button script function sendMessage() { const input document.getElementById(userInput); const msg input.value.trim(); if (!msg) return; // 显示用户消息 appendMessage(你, msg); input.value ; // 发送到后端 fetch(/chat, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({message: msg}) }) .then(r r.json()) .then(data { appendMessage(Jarvis, data.response); }) .catch(e { appendMessage(系统, 请求出错: e); }); } function appendMessage(sender, text) { const box document.getElementById(chatbox); box.innerHTML pstrong${sender}:/strong ${text}/p; box.scrollTop box.scrollHeight; } // 按回车发送 document.getElementById(userInput).addEventListener(keypress, function(e) { if (e.key Enter) sendMessage(); }); /script /body /html app.route(/) def index(): return render_template_string(HTML_TEMPLATE) app.route(/chat, methods[POST]) def chat(): user_message request.json.get(message) if not user_message: return jsonify({response: 请输入消息。}) try: response agent_executor.invoke({input: user_message}) return jsonify({response: response[output]}) except Exception as e: return jsonify({response: f处理请求时出错: {e}}) if __name__ __main__: app.run(debugTrue, port5000) # debugTrue仅用于开发运行后访问http://127.0.0.1:5000就能看到网页版Jarvis。6.2 安全与权限管理最重要的底线赋予AI助手系统操作权限是危险的。必须建立严格的安全边界最小权限原则不要以管理员/root身份运行Jarvis。为其创建一个专用、低权限的系统账户。操作沙箱限制文件操作的根目录。例如通过工具函数将所有路径解析为相对于某个安全目录如/home/user/jarvis_workspace或C:\JarvisSandbox的路径禁止访问此目录之外的文件。危险操作确认如前所述删除、格式化、系统关机等操作必须强制二次确认。可以在工具函数内部实现也可以在Agent的提示词中强调。命令过滤对run_system_command这类工具禁止执行某些危险命令如rm -rf /,format,del *.*。可以维护一个黑名单或只允许执行白名单内的命令。API密钥保护所有API密钥OpenAI、搜索等必须通过环境变量或加密配置文件管理绝不能硬编码在代码中。网络访问控制如果不需要可以禁用Jarvis的网络访问能力或限制其只能访问特定的、安全的API端点。审计日志记录Jarvis的所有操作用户指令、工具调用、结果到日志文件便于事后审查和问题排查。6.3 性能优化与错误处理LLM调用优化使用流式响应Streaming来提升用户体验让回复看起来是逐字打出的。对于复杂任务考虑使用更便宜、更快的模型如GPT-3.5-turbo进行初步规划和分解只在需要复杂推理时调用GPT-4。工具超时与重试为每个可能耗时的工具调用特别是网络请求设置超时。对于暂时性失败可以实现简单的重试逻辑。上下文长度管理对话历史可能很长导致Token数超限或响应变慢。定期总结对话历史或将久远的历史存入向量数据库按需检索。依赖与部署使用requirements.txt或Poetry管理项目依赖。对于最终部署可以考虑使用PyInstaller打包成可执行文件或用Docker容器化确保环境一致性。7. 常见问题与实战排坑记录在实际搭建和使用过程中你肯定会遇到各种问题。以下是我踩过的一些坑和解决方案问题1Agent总是拒绝执行或过度确认哪怕是很简单的任务。原因系统提示词中安全规则过于严格或表述模糊导致LLM过于谨慎。解决细化规则描述。将“危险操作需确认”改为更具体的描述例如“仅当操作涉及删除文件、修改系统设置、安装软件、或运行用户提供的未经验证代码时才需要向用户确认。对于浏览文件、获取信息、打开常用应用程序如记事本、计算器等常规操作可直接执行。” 同时在工具的描述中明确其安全等级。问题2LLM无法正确理解工具的参数格式导致调用失败。原因工具的描述不够清晰或者LLM不擅长生成严格的JSON输入。解决优化工具描述在description中明确写出期望的输入格式示例。例如“输入必须是一个JSON字符串包含‘path’键其值为文件路径字符串。”使用结构化工具LangChain支持使用Pydantic模型来定义工具的输入模式这能提供更严格的类型提示帮助LLM生成正确格式。将Tool替换为StructuredTool。后处理与重试在Agent执行器中设置handle_parsing_errorsTrue当解析失败时可以将错误信息反馈给LLM让它重试。问题3处理包含中文路径或文件名时出错。原因Python代码、系统命令行或第三方库对中文字符编码处理不一致。解决在Python文件开头统一使用# -*- coding: utf-8 -*-。处理路径时使用pathlib.Path对象它比直接使用字符串能更好地处理不同操作系统的路径和编码。在调用系统命令时确保字符串编码正确。可以考虑先将路径转换为系统默认编码如Windows的gbk或使用Unicode。问题4UI自动化脚本在不同电脑或分辨率下失效。原因pyautogui的屏幕坐标是绝对的且图像识别依赖于固定的屏幕截图。解决避免绝对坐标尽量使用相对定位或特征识别。例如结合pyautogui.locateOnScreen()寻找按钮图片而不是直接click(x, y)。使用更高级的框架对于浏览器自动化Playwright或Selenium比pyautogui更可靠它们通过DOM元素定位与屏幕分辨率无关。配置抽象将可能变化的元素如图标路径、窗口标题提取到配置文件中便于适配不同环境。问题5项目依赖复杂别人难以复现我的环境。解决使用pip freeze requirements.txt精确导出所有依赖及其版本。考虑使用Docker编写Dockerfile来构建一个包含所有依赖的标准化运行环境。对于前端部分如果有使用npm或yarn管理依赖。构建一个属于自己的“贾维斯”是一个持续迭代和打磨的过程。它不会一开始就完美但每当你添加一个新工具、优化一个提示词、解决一个边界情况它都会变得更聪明、更贴合你的需求。这个项目的魅力不在于最终达到一个多么强大的状态而在于这个“共同成长”的过程——你教会它理解你的世界它帮助你从繁琐中解脱。从今天开始选一个你最痛点的重复性任务尝试让Jarvis帮你解决吧。