1. 项目概述为什么我们要“手写”一个AI编程助手最近和几个做全栈开发的朋友聊天大家不约而同地提到了一个痛点市面上的AI编程助手比如Cursor、GitHub Copilot确实好用但总觉得隔着一层。它们像是一个功能强大的黑盒你知道它能帮你写代码、改bug但你不知道它内部是怎么“思考”的更别提按照你自己的业务逻辑去深度定制了。比如你想让它不仅能生成代码还能自动调用你内部的API文档库、执行特定的代码质量检查、或者集成你们团队独有的脚手架工具这些需求在通用产品里往往很难实现。这就是我动手做这个项目的初衷。与其依赖一个“知其然不知其所以然”的外部工具不如自己动手从零开始构建一个“迷你 Cursor”。我们的目标不是复刻一个商业级产品而是深入其核心机制打造一个完全可控、可深度定制的AI编程助手原型。通过这个项目你将彻底理解现代AI编程助手背后的两大核心技术支柱LangChain提供的Agent编排框架以及Tool Calling工具调用能力如何让大语言模型LLM真正“长出手脚”去操作外部世界。这个项目非常适合有一定Python和Web开发基础熟悉React并对AI应用开发感兴趣的开发者。你将学到的不只是调用API而是如何设计一个能够理解用户意图、自主选择工具、并执行复杂任务的智能体Agent。整个构建过程我们会从前端React界面开始连接到后端的FastAPI服务最后驱动由LangChain构建的AI大脑。下面这张图概括了我们的核心架构接下来我们就一步步把它实现出来。注此处原计划放置架构图但根据要求不使用Mermaid故改为文字描述架构流用户在前端React界面输入自然语言指令 - 请求发送至后端FastAPI服务 - FastAPI调用LangChain Agent - Agent分析指令并决定调用哪个工具Tool- 工具执行如运行代码、查询数据库等- 结果返回给Agent - Agent组织语言回复 - 通过FastAPI返回给前端React界面展示。2. 核心架构与工具链选型在动手写第一行代码之前花点时间想清楚架构和选型能避免后期大量的返工。我们这个“迷你 Cursor”的核心目标是让AI能根据我们的指令安全、可靠地执行编程相关操作。因此整个系统需要分成清晰的三层交互层、逻辑层和执行层。2.1 前端交互层为什么是React Vite用户需要一个界面来和AI助手对话。我选择React和Vite的组合原因很直接高效和现代。React的组件化思想非常适合构建这种实时交互的聊天应用状态管理清晰。而Vite作为构建工具其极快的冷启动和热更新速度能让开发体验非常流畅省去了等待打包的烦恼。对于UI组件库我没有选择庞大的Ant Design或MUI而是选了Shadcn/ui或Tailwind CSS自行构建。这样做的好处是打包体积小样式完全可控并且能更好地与我们的应用设计风格融合。前端的关键组件就是一个聊天窗口包含消息列表、输入框和一个执行代码的特殊区域。注意前端的主要职责是渲染和用户交互不包含任何核心业务逻辑。所有对AI的请求、工具的调用都必须通过后端API进行。这是保证安全性的底线防止API密钥或敏感操作暴露在客户端。2.2 后端逻辑层FastAPI LangChain 的黄金组合后端是整个系统的大脑我选择FastAPI因为它异步性能好、编写简洁并且能自动生成交互式API文档调试起来非常方便。它负责接收前端的请求协调LangChain Agent工作并返回结果。核心中的核心是LangChain。你可以把它理解为AI应用的“操作系统”或“中间件”。它抽象了与不同大模型OpenAI, Anthropic, 本地模型等的交互更重要的是它提供了构建Agent智能体的框架。Agent的本质是一个能根据目标自主决定调用哪些工具Tools并串联执行这些工具的循环系统。这正是我们实现复杂任务自动化的关键。为什么不用更底层的直接调用因为LangChain帮我们处理了繁琐的部分对话历史管理、提示词Prompt模板化、工具的标准化封装以及最重要的——Tool Calling的解析与分发。自己从零实现这些复杂度会呈指数级上升。2.3 执行层与工具Tools设计这是让AI“长出手脚”的部分。Tool Calling是一种让大模型以结构化格式通常是JSON请求调用外部函数的能力。我们需要定义一系列工具每个工具都是一个Python函数有明确的名称、描述和参数。对于编程助手我设计了以下几类核心工具代码执行工具在一个安全的沙箱环境如Docker容器或subprocess配合严格限制中运行Python/Shell代码并返回输出。这是最危险也最强大的工具必须做好隔离和超时控制。文件读写工具允许AI读取项目文件内容、创建新文件或修改现有文件。必须严格限制可访问的目录范围如限定在项目工作区内。Git操作工具封装常用的Git命令如git status,git diff,git add,git commit等让AI可以管理代码版本。网络搜索工具可选集成SerpAPI或类似服务让AI能获取最新信息来解答问题。自定义查询工具例如连接到你团队的内部知识库API查询特定的开发规范或API用法。工具的设计原则是功能单一、描述清晰、安全可控。每个工具的函数文档字符串docstring至关重要因为LangChain会用它来生成工具的描述供大模型理解何时该调用此工具。3. 实战一步步构建核心Agent理论说再多不如动手。我们从一个最简单的“回显”Agent开始逐步增加复杂度最终形成一个能写代码、跑代码、管理文件的智能助手。3.1 环境搭建与基础依赖首先创建一个新的项目目录并初始化虚拟环境这是保证依赖隔离的好习惯。mkdir mini-cursor cd mini-cursor python -m venv venv # Windows: venv\Scripts\activate # Mac/Linux: source venv/bin/activate接着安装核心依赖。这里我固定了一些版本以确保兼容性。pip install fastapi0.104.1 uvicorn0.24.0 pip install langchain0.0.340 langchain-openai0.0.2 # 使用LangChain官方OpenAI集成 pip install python-dotenv1.0.0 # 用于管理环境变量你需要一个OpenAI的API密钥或其他兼容OpenAI API的模型服务密钥。在项目根目录创建.env文件来保存它OPENAI_API_KEYsk-your-api-key-here OPENAI_BASE_URLhttps://api.openai.com/v1 # 如果使用其他兼容服务可修改此处3.2 实现第一个工具与基础Agent让我们从定义一个最简单的工具开始计算器工具。在tools/calculator.py中from langchain.tools import tool tool def calculator(expression: str) - str: Evaluates a mathematical expression. Use this tool when you need to perform calculations. The expression must be a string containing only numbers and basic operators (, -, *, /, **, ()). try: # 警告直接使用eval有安全风险仅用于演示。生产环境应用ast.literal_eval或专用库。 # 此处为简化我们假设输入是安全的且来自可信的AI模型。 result eval(expression) return fThe result of {expression} is: {result} except Exception as e: return fError evaluating expression: {e}现在在agent/core.py中创建我们的第一个Agentimport os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.tools import Tool from tools.calculator import calculator # 加载环境变量 load_dotenv() # 1. 初始化大模型 llm ChatOpenAI( modelgpt-3.5-turbo-1106, # 或 gpt-4注意需要支持tool calling的模型版本 temperature0, # 编程任务要求确定性高temperature设为0 api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL, https://api.openai.com/v1) ) # 2. 定义工具列表 tools [calculator] # 3. 构建提示词模板。这是指导Agent行为的关键。 prompt ChatPromptTemplate.from_messages([ (system, You are a helpful programming assistant. You have access to tools. When you need to perform a calculation, use the calculator tool. Always respond in Chinese.), MessagesPlaceholder(variable_namechat_history), # 预留位置存放对话历史 (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 预留位置存放Agent的思考过程 ]) # 4. 创建Agent agent create_openai_tools_agent(llmllm, toolstools, promptprompt) # 5. 创建Agent执行器它负责运行Agent的循环 agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) # 测试函数 if __name__ __main__: response agent_executor.invoke({input: 请计算 (15 7) * 3 的值是多少}) print(response[output])运行这个脚本你会看到类似以下的输出它展示了Agent的思考链因为verboseTrue Entering new AgentExecutor chain... 我需要计算一个数学表达式。用户要求计算 (15 7) * 3。 我应该使用计算器工具。 Action: calculator Action Input: {expression: (15 7) * 3} The result of (15 7) * 3 is: 66 Observation: The result of (15 7) * 3 is: 66 Thought:我已经得到了计算结果可以回答用户了。 Final Answer: (15 7) * 3 的计算结果是 66。 Finished chain. (15 7) * 3 的计算结果是 66。恭喜你已经创建了一个能使用工具的AI Agent。create_openai_tools_agent是LangChain提供的高阶封装它内部处理了Tool Calling的格式协商OpenAI的function calling或tool_calls。AgentExecutor则负责运行“思考-行动-观察”的循环直到Agent认为任务完成并给出最终答案。3.3 实现代码执行与文件操作工具基础框架搭好了现在来添加编程助手的灵魂工具。安全是重中之重。首先我们实现一个在子进程中安全执行代码的工具放在tools/code_executor.pyimport subprocess import tempfile import os from pathlib import Path from langchain.tools import tool import signal tool def execute_python_code(code: str, timeout: int 10) - str: Executes provided Python code in a subprocess and returns the output or error. Use this tool when the user asks to run, test, or execute Python code. Args: code: The Python code string to execute. timeout: Maximum execution time in seconds. # 创建一个临时文件来存放代码 with tempfile.NamedTemporaryFile(modew, suffix.py, deleteFalse) as f: f.write(code) temp_file_path f.name try: # 使用子进程运行代码并设置超时 result subprocess.run( [python, temp_file_path], capture_outputTrue, textTrue, timeouttimeout, cwdos.path.dirname(temp_file_path) # 在临时文件所在目录运行 ) output result.stdout error result.stderr final_output fSTDOUT:\n{output} if output else if error: final_output f\n\nSTDERR:\n{error} if result.returncode ! 0: final_output f\n\nProcess exited with return code: {result.returncode} return final_output.strip() or Code executed (no output to stdout/stderr). except subprocess.TimeoutExpired: return fError: Code execution timed out after {timeout} seconds. except Exception as e: return fError running subprocess: {e} finally: # 清理临时文件 try: os.unlink(temp_file_path) except: pass重要安全警告上述execute_python_code工具使用subprocess在主机上直接运行代码存在严重安全风险如执行import os; os.system(rm -rf /)。仅适用于完全可信的环境或演示。生产环境必须使用Docker沙箱。一个简单的Docker沙箱示例会在后续“高级话题”中提及。接下来实现文件读写工具放在tools/file_ops.pyfrom langchain.tools import tool from pathlib import Path import os # 定义一个安全的工作区根目录限制AI只能操作此目录下的文件 WORKSPACE_ROOT Path(./workspace).absolute() WORKSPACE_ROOT.mkdir(exist_okTrue) # 确保目录存在 tool def read_file(file_path: str) - str: Reads the content of a file within the workspace. Args: file_path: The path to the file, relative to the workspace root. full_path (WORKSPACE_ROOT / file_path).resolve() # 安全检查确保目标路径在工作区内 if not str(full_path).startswith(str(WORKSPACE_ROOT)): return fError: Access to path {file_path} is not allowed (outside workspace). try: return full_path.read_text(encodingutf-8) except FileNotFoundError: return fError: File {file_path} not found. except Exception as e: return fError reading file: {e} tool def write_file(file_path: str, content: str) - str: Writes content to a file within the workspace. Creates the file if it doesnt exist, overwrites if it does. Args: file_path: The path to the file, relative to the workspace root. content: The content to write. full_path (WORKSPACE_ROOT / file_path).resolve() if not str(full_path).startswith(str(WORKSPACE_ROOT)): return fError: Access to path {file_path} is not allowed (outside workspace). try: full_path.parent.mkdir(parentsTrue, exist_okTrue) # 创建父目录 full_path.write_text(content, encodingutf-8) return fSuccessfully wrote to {file_path}. except Exception as e: return fError writing file: {e}3.4 组装完整的编程助手Agent现在我们将所有工具集成起来并优化提示词让AI更好地扮演编程助手的角色。更新agent/core.pyimport os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.memory import ConversationBufferMemory from tools.calculator import calculator from tools.code_executor import execute_python_code from tools.file_ops import read_file, write_file load_dotenv() llm ChatOpenAI(modelgpt-3.5-turbo-1106, temperature0, api_keyos.getenv(OPENAI_API_KEY)) # 集成所有工具 tools [calculator, execute_python_code, read_file, write_file] # 更专业的系统提示词 system_prompt 你是一个专业的编程助手名为“迷你Cursor”。你被赋予了执行代码、读写文件等工具来帮助用户进行编程任务。 你的工作区根目录是 ./workspace。所有文件操作都限制在此目录下。 请遵循以下原则 1. 当用户要求运行或测试代码时使用代码执行工具。 2. 当用户需要查看或修改文件内容时使用文件读写工具。 3. 对于数学计算使用计算器工具。 4. 在行动前先明确用户的需求。如果用户的需求模糊请先询问澄清。 5. 你的最终输出应该是清晰、有帮助的并包含必要的工具执行结果。 请用中文与用户交流。 prompt ChatPromptTemplate.from_messages([ (system, system_prompt), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ]) # 添加记忆功能让AI能记住对话上下文 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) agent create_openai_tools_agent(llmllm, toolstools, promptprompt) agent_executor AgentExecutor( agentagent, toolstools, memorymemory, verboseTrue, # 开发时开启生产环境关闭 handle_parsing_errorsTrue, max_iterations5 # 防止Agent陷入死循环 ) def ask_assistant(question: str) - str: 向助手提问的便捷函数 response agent_executor.invoke({input: question}) return response[output] # 测试复杂任务 if __name__ __main__: # 测试1让AI创建一个文件并写入内容 print(测试1创建文件) print(ask_assistant(请在workspace下创建一个名为hello.py的文件内容写一个打印Hello, Mini Cursor!的函数并调用它。)) print(\n *50 \n) # 测试2让AI读取并执行它刚创建的文件 print(测试2读取并执行文件) print(ask_assistant(请读取hello.py文件的内容然后执行这个文件里的代码。))运行这个测试你会看到AI助手能够连贯地完成“创建文件 - 读取文件 - 执行代码”这一系列任务。ConversationBufferMemory让AI记住了之前的对话知道我们刚刚创建了hello.py文件。4. 构建前后端通信桥梁现在我们的AI大脑Agent已经能工作了需要给它配上眼睛和嘴巴前端界面和传输神经后端API。4.1 使用FastAPI创建后端服务在项目根目录创建main.pyfrom fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from typing import List, Optional import uvicorn from agent.core import agent_executor # 导入我们之前构建的Agent执行器 app FastAPI(titleMini Cursor API) # 配置CORS允许前端React应用访问 app.add_middleware( CORSMiddleware, allow_origins[http://localhost:3000], # React开发服务器默认端口 allow_credentialsTrue, allow_methods[*], allow_headers[*], ) # 定义请求和响应模型 class ChatMessage(BaseModel): role: str # user or assistant content: str class ChatRequest(BaseModel): message: str chat_history: Optional[List[ChatMessage]] None # 前端可传递历史记录 class ChatResponse(BaseModel): reply: str # 可以扩展例如包含工具调用详情、状态等 app.post(/chat, response_modelChatResponse) async def chat_with_agent(request: ChatRequest): 处理用户消息调用LangChain Agent并返回助手的回复。 try: # 这里简化处理直接使用Agent的memory。更复杂的实现需要将会话ID与memory关联。 response agent_executor.invoke({input: request.message}) return ChatResponse(replyresponse[output]) except Exception as e: raise HTTPException(status_code500, detailfAgent execution failed: {str(e)}) app.get(/health) async def health_check(): return {status: healthy} if __name__ __main__: uvicorn.run(main:app, host0.0.0.0, port8000, reloadTrue)运行python main.py后端服务就在http://localhost:8000启动了。访问http://localhost:8000/docs可以看到自动生成的API文档。4.2 构建React前端界面在前端项目目录例如frontend/中我们使用Vite快速搭建一个React应用。npm create vitelatest frontend -- --template react cd frontend npm install npm install axios lucide-react # axios用于HTTP请求lucide-react用于图标接下来创建核心的聊天组件src/components/ChatInterface.jsximport React, { useState, useRef, useEffect } from react; import axios from axios; import { Send, Bot, User, Code } from lucide-react; const API_BASE_URL http://localhost:8000; // 后端API地址 const ChatInterface () { const [messages, setMessages] useState([ { role: assistant, content: 你好我是你的迷你Cursor编程助手。我可以帮你运行代码、读写文件、进行计算。有什么可以帮你的吗 } ]); const [input, setInput] useState(); const [isLoading, setIsLoading] useState(false); const messagesEndRef useRef(null); // 自动滚动到最新消息 useEffect(() { messagesEndRef.current?.scrollIntoView({ behavior: smooth }); }, [messages]); const handleSend async () { if (!input.trim() || isLoading) return; const userMessage { role: user, content: input }; setMessages(prev [...prev, userMessage]); setInput(); setIsLoading(true); try { const response await axios.post(${API_BASE_URL}/chat, { message: input }); const assistantMessage { role: assistant, content: response.data.reply }; setMessages(prev [...prev, assistantMessage]); } catch (error) { console.error(Chat error:, error); const errorMessage { role: assistant, content: 抱歉请求出错${error.response?.data?.detail || error.message} }; setMessages(prev [...prev, errorMessage]); } finally { setIsLoading(false); } }; const handleKeyDown (e) { if (e.key Enter !e.shiftKey) { e.preventDefault(); handleSend(); } }; return ( div classNameflex flex-col h-screen bg-gray-50 {/* 标题栏 */} header classNamebg-white border-b shadow-sm p-4 div classNamecontainer mx-auto flex items-center gap-3 Code classNameh-8 w-8 text-blue-600 / h1 classNametext-2xl font-bold text-gray-800迷你Cursor编程助手/h1 span classNametext-sm bg-blue-100 text-blue-800 px-2 py-1 rounded-fullLangChain Tool Calling/span /div /header {/* 聊天消息区域 */} div classNameflex-1 overflow-y-auto p-4 container mx-auto div classNamespace-y-6 max-w-3xl mx-auto {messages.map((msg, idx) ( div key{idx} className{flex gap-3 ${msg.role user ? flex-row-reverse : }} div className{flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${msg.role user ? bg-green-100 : bg-blue-100}} {msg.role user ? User classNamew-5 h-5 text-green-600 / : Bot classNamew-5 h-5 text-blue-600 /} /div div className{max-w-[70%] rounded-2xl px-4 py-3 ${msg.role user ? bg-green-500 text-white : bg-white border border-gray-200 text-gray-800}} div classNamewhitespace-pre-wrap{msg.content}/div /div /div ))} {isLoading ( div classNameflex gap-3 div classNameflex-shrink-0 w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center Bot classNamew-5 h-5 text-blue-600 / /div div classNamebg-white border border-gray-200 rounded-2xl px-4 py-3 div classNameflex gap-2 div classNamew-2 h-2 bg-gray-400 rounded-full animate-bounce/div div classNamew-2 h-2 bg-gray-400 rounded-full animate-bounce style{{ animationDelay: 0.1s }}/div div classNamew-2 h-2 bg-gray-400 rounded-full animate-bounce style{{ animationDelay: 0.2s }}/div /div /div /div )} div ref{messagesEndRef} / /div /div {/* 输入区域 */} div classNameborder-t bg-white p-4 div classNamecontainer mx-auto max-w-3xl div classNameflex gap-2 textarea classNameflex-1 border border-gray-300 rounded-xl p-3 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none placeholder输入你的指令例如写一个Python函数计算斐波那契数列 或 运行workspace下的test.py文件... rows2 value{input} onChange{(e) setInput(e.target.value)} onKeyDown{handleKeyDown} disabled{isLoading} / button onClick{handleSend} disabled{isLoading || !input.trim()} classNameself-end bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-xl px-6 py-3 font-medium transition-colors Send classNamew-5 h-5 / /button /div p classNametext-xs text-gray-500 mt-2 提示我可以执行Python代码、读写workspace目录下的文件、进行数学计算。请清晰描述你的需求。 /p /div /div /div ); }; export default ChatInterface;最后在src/App.jsx中引入这个组件并运行前端开发服务器(npm run dev)。现在打开浏览器访问http://localhost:3000你就可以通过一个漂亮的界面与你的“迷你Cursor”对话了5. 避坑指南与高级技巧走到这一步一个基础可用的AI编程助手已经搭建完成。但在实际开发和部署中你会遇到各种各样的问题。下面是我在开发过程中总结的一些关键陷阱和进阶思路。5.1 常见问题与排查技巧问题现象可能原因解决方案Agent报错OpenAIInvalidRequestError: ... is not a valid tool1. 工具函数缺少tool装饰器或导入错误。2. 传递给Agent的tools列表与提示词中描述的工具不匹配。1. 检查工具模块是否正确导入并添加到tools列表。2. 确保create_openai_tools_agent和AgentExecutor使用的tools列表是同一个对象。Agent陷入循环不断调用同一个工具1. 工具描述不清导致LLM误解其功能。2. 工具执行结果未能让LLM判断任务已完成。3.max_iterations设置过高。1. 优化工具函数的文档字符串使其职责单一、描述精确。2. 在工具返回结果中增加明确的完成状态语句。3. 适当调低max_iterations如设为10并在提示词中要求Agent在得到答案后明确结束。前端调用API时出现CORS错误后端FastAPI未正确配置CORS中间件或允许的源allow_origins不包含前端地址。确保main.py中正确配置了CORSMiddleware并将前端的开发服务器地址如http://localhost:3000加入allow_origins列表。代码执行工具超时或被系统杀死用户提交了死循环或耗时极长的代码。1. 在subprocess.run中设置合理的timeout参数。2.强烈建议使用Docker沙箱它提供了更强的资源隔离和限制能力。LLM不理解复杂指令或调用工具顺序混乱系统提示词system_prompt不够清晰未能有效引导Agent的推理过程。细化提示词。明确告诉Agent“你是一个编程助手。首先分析用户需求是计算、写代码还是读文件。然后选择对应的工具。最后整合结果并回复。” 赋予其明确的“思考框架”。5.2 提升安全性实现Docker代码沙箱生产环境中绝对不能让用户代码直接在主服务器上运行。下面是一个极简的Docker沙箱实现思路准备一个安全的Docker镜像创建一个只包含Python和必要基础库的轻量级镜像如python:3.11-slim。编写一个工具函数这个函数将用户代码写入临时文件然后使用docker run命令在一次性容器中执行它并获取输出。严格限制容器资源通过Docker的--memory,--cpus,--read-only等参数限制容器的内存、CPU和文件系统权限。# tools/docker_executor.py (概念示例) import docker import tempfile client docker.from_env() tool def execute_code_in_docker(code: str, language: str python) - str: Executes code in an isolated Docker container. # 1. 将代码写入宿主机临时文件 with tempfile.NamedTemporaryFile(modew, suffix.py, deleteFalse) as f: f.write(code) host_code_path f.name # 2. 在容器内挂载并执行 try: container client.containers.run( imagepython:3.11-slim, # 使用安全的基础镜像 commandfpython /tmp/code.py, # 容器内执行命令 volumes{host_code_path: {bind: /tmp/code.py, mode: ro}}, # 只读挂载 mem_limit100m, # 限制内存100MB cpuset_cpus0, # 限制使用1个CPU核心 network_disabledTrue, # 禁用网络 removeTrue, # 执行后自动删除容器 detachFalse, stdoutTrue, stderrTrue ) # container 是执行结果的字节流 output container.decode(utf-8) if isinstance(container, bytes) else container return output except docker.errors.ContainerError as e: return fContainer error: {e.stderr.decode() if hasattr(e, stderr) else str(e)} except Exception as e: return fExecution error: {str(e)} finally: # 清理宿主机临时文件 os.unlink(host_code_path)警告即使使用Docker也需要持续关注安全最佳实践如使用非root用户运行容器、使用Seccomp/AppArmor安全配置文件等这超出了本文范围但至关重要。5.3 扩展方向从“助手”到“智能体工作流”目前的Agent是单次对话触发一系列工具调用。更复杂的场景需要工作流Workflow这就是LangGraph或LangChain Expression Language (LCEL)的用武之地。LangGraph允许你以图Graph的形式定义Agent的工作流节点可以是工具调用、条件判断、LLM推理等边定义了执行流向。这非常适合需要多步骤、有条件分支的复杂任务例如“分析项目结构 - 如果缺少依赖则安装 - 运行测试 - 生成报告”。LCEL提供了一种声明式的链式组合方式让你能更精细地控制Prompt、LLM、工具、解析器之间的数据流。例如你可以构建一个“代码审查Agent”工作流1. 读取指定文件2. 调用LLM分析代码风格和潜在bug3. 调用工具运行静态检查如pylint4. 综合两者结果生成报告。这用基础的Agent循环实现起来会很笨拙而用LangGraph则会清晰得多。5.4 模型选择与成本优化大模型选择本项目使用OpenAI API但你完全可以替换为其他支持Tool Calling的模型如Anthropic Claude、Google Gemini或开源的Llama 3通过llama.cpp或vLLM部署并提供兼容OpenAI的API。只需更换ChatOpenAI为对应的LangChain集成类如ChatAnthropic、ChatGoogleGenerativeAI。提示词工程好的提示词能极大提升工具调用的准确率。多给示例Few-shot Prompting在系统提示词中明确工具的使用规范和边界。成本控制对于工具调用频繁的场景可以考虑使用更小、更快的模型如gpt-3.5-turbo作为“路由器Router”只负责分析意图和选择工具而让更大模型如gpt-4处理需要深度推理的复杂任务。构建这个“迷你Cursor”的过程本质上是在深入理解如何将大语言模型的“思考”能力与外部工具的“执行”能力安全、有效地连接起来。它不再是一个简单的聊天机器人而是一个能真正帮你干活的数字同事。虽然目前它还很简陋但整个架构和理念是通用的。你可以在此基础上不断添加新的工具连接数据库、调用云服务API、集成Jira/钉钉、优化交互逻辑、引入工作流最终打造出一个完全贴合你个人或团队工作流的超级助手。