当前位置:首页>python>200 行 Python 手写 Coding Agent:能读项目、改代码、跑测试

200 行 Python 手写 Coding Agent:能读项目、改代码、跑测试

  • 2026-08-18 23:11:36
200 行 Python 手写 Coding Agent:能读项目、改代码、跑测试

普通 AI 只能在对话框里"建议你怎么改",Coding Agent 则会自己查看项目、定位文件、写入修改、运行测试,并根据报错继续修复。本文不使用 LangChain、AutoGen 等框架,只用 Python 和 OpenAI 兼容接口,手写一个真正能跑起来的极简 Coding Agent。

前言:会生成代码,不等于会完成开发任务

把需求发给大模型,让它返回一段代码,这件事已经不新鲜了。

真正让 Coding Agent 变得有用的,并不是"代码写得更长",而是它能把一个开发任务执行到底:

理解需求 → 查看项目结构 → 读取相关文件 → 修改代码 → 运行测试 → 读取报错 → 继续修复 → 直到测试通过

例如,我们给它这样一个任务:

给 calculator.py 增加 divide(a, b) 函数。除数为 0 时抛出 ValueError,并补充对应测试。

普通大模型会返回一段建议代码;本文实现的 Coding Agent 会直接在指定项目目录中完成下面几件事:

  • 查看项目中有哪些文件;
  • 读取 calculator.py 和测试文件;
  • 写入功能代码与测试代码;
  • 执行测试;
  • 如果失败,读取错误并继续修改;
  • 测试通过后输出任务总结。

本文目标:不用任何 Agent 框架,从零理解"模型决策、工具执行、结果回喂、循环纠错"是怎么连起来的。

这次模型调用没有分别接入多套 SDK,而是直接使用 Genvis 提供的 OpenAI 兼容接口。这样做的好处是:Agent 的文件工具和执行逻辑只写一遍,后面测试不同模型时,只需要修改 MODEL_NAME,不必跟着模型重写客户端代码。

本文使用的实测配置已经完整保留在源码中,API Key 对应的环境变量是 GENVIS_API_KEY。

一、Coding Agent 和代码生成有什么区别

很多人把"让模型写一段代码"也叫 Coding Agent,其实二者差别很大。

能力
普通代码生成
Coding Agent
理解单个问题
支持
支持
查看项目目录
不支持
支持
读取现有代码
需要手动粘贴
主动读取
修改真实文件
不支持
调用工具完成
执行测试
不支持
支持
根据报错继续修复
需要人工追问
自动循环
控制文件和命令权限
由运行时控制

因此,Coding Agent 不是某一个"更会写代码"的模型,而是一套运行系统:

Coding Agent = 大模型 + 文件工具 + 测试工具 + 上下文 + Agent Loop

模型负责判断下一步应该做什么,Python 程序负责真正执行文件读取、代码修改和测试命令。

二、先看最终架构

本文实现五个工具:

工具
作用
list_files
查看项目目录和文件
read_file
读取指定代码文件
write_file
创建或完整写入文件
replace_text
精确替换文件中的一段内容
run_tests
执行白名单内的测试命令

完整执行流程如下:

用户输入开发任务        ↓模型选择下一步动作        ↓返回结构化 JSON        ↓Python 调用对应工具        ↓工具结果写回对话        ↓模型继续判断   ┌────┴────┐调用工具   输出完成   └──继续循环

这里有一个非常关键的设计:

模型没有文件权限,也不能直接运行命令。它只能提出工具调用请求,真正的权限由 Python 程序掌握。

这也是 Coding Agent 与"让模型随便生成 Shell 命令并执行"的本质区别。

三、准备运行环境

建议使用 Python 3.10 或更高版本。

1. 安装依赖

pip install openai python-dotenv pytest

2. 创建环境变量

在 Coding Agent 所在目录创建 .env

GENVIS_API_KEY=替换成你的_API_KEY

不要把真实 API Key 写进源码,也不要把 .env 提交到公开仓库。

这里的 Key 使用统一模型入口,而不是和某个模型永久绑定。后续想比较不同模型在"读项目、修改代码、修复测试"上的表现,只需要更换模型名称,Agent 主循环和工具代码都不用动。

3. 为什么本文使用统一模型接口

Coding Agent 和普通聊天不一样。它完成一次任务,往往需要连续请求多轮:先读目录,再读文件,修改代码,运行测试,失败后还要继续修复。

如果每测试一个模型都重新配置 SDK、鉴权方式和请求格式,时间很容易浪费在接口适配上。因此本文直接使用 Genvis 的兼容接口:

  • 使用熟悉的 OpenAI Python SDK;
  • 一个 Key 可以切换不同的兼容模型;
  • 更换模型时通常只改 MODEL_NAME;
  • 可以查看每次任务实际消耗的 Token 和对应成本;
  • 后续增加代码审查、测试生成等 Agent,也能复用同一套客户端配置。

配置提示:本文实测使用的统一模型接口为 base_url=https://genvis.xyz/v1。复制代码时不要漏掉这段客户端配置。

4. 准备目录

项目结构如下:

mini-coding-agent/├── .env├── coding_agent.py└── workspace/    ├── calculator.py    └── test_calculator.py

其中,workspace 是 Agent 唯一允许操作的目录。

四、完整代码

新建 coding_agent.py,写入下面的代码:

import jsonimport osimport subprocessfrom pathlib import Pathfrom typing importAnyCallablefrom dotenv import load_dotenvfrom openai import OpenAIload_dotenv()API_KEY = os.getenv("GENVIS_API_KEY")ifnot API_KEY:raise RuntimeError("未读取到 GENVIS_API_KEY,请检查 .env 文件")client = OpenAI(    api_key=API_KEY,    base_url="https://genvis.xyz/v1")MODEL_NAME = "gpt-5.6-sol"WORKSPACE = Path("workspace").resolve()MAX_STEPS = 20MAX_FILE_SIZE = 100_000ALLOWED_SUFFIXES = {".py"".json"".toml"".yaml"".yml",".md"".txt"".html"".css"".js"".ts"}ALLOWED_TEST_COMMANDS = {"pytest": ["python""-m""pytest""-q"],"unittest": ["python""-m""unittest""discover""-v"]}defresolve_path(relative_path: str) -> Path:"""将相对路径限制在 workspace 内,阻止 ../ 路径穿越。"""    target = (WORKSPACE / relative_path).resolve()if target != WORKSPACE and WORKSPACE notin target.parents:raise ValueError("路径超出 workspace 范围")return targetdeflist_files(path: str = ".") -> dict[strAny]:"""列出目录内容,忽略隐藏目录和缓存目录。"""    target = resolve_path(path)ifnot target.exists():return {"success"False"error""目录不存在"}ifnot target.is_dir():return {"success"False"error""目标不是目录"}    ignored = {".git"".idea"".vscode""__pycache__"".pytest_cache"}    items = []for item insorted(target.rglob("*")):ifany(part in ignored for part in item.parts):continueif item.is_file():            items.append(str(item.relative_to(WORKSPACE)))iflen(items) >= 200:breakreturn {"success"True"files": items}defread_file(path: str) -> dict[strAny]:"""读取 workspace 内的文本文件。"""    target = resolve_path(path)ifnot target.exists() ornot target.is_file():return {"success"False"error""文件不存在"}if target.suffix.lower() notin ALLOWED_SUFFIXES:return {"success"False"error""不允许读取该文件类型"}if target.stat().st_size > MAX_FILE_SIZE:return {"success"False"error""文件过大"}try:        content = target.read_text(encoding="utf-8")return {"success"True"path": path, "content": content}except UnicodeDecodeError:return {"success"False"error""文件不是 UTF-8 文本"}defwrite_file(path: str, content: str) -> dict[strAny]:"""创建或完整覆盖 workspace 内的文本文件。"""    target = resolve_path(path)if target.suffix.lower() notin ALLOWED_SUFFIXES:return {"success"False"error""不允许写入该文件类型"}iflen(content.encode("utf-8")) > MAX_FILE_SIZE:return {"success"False"error""写入内容过大"}    target.parent.mkdir(parents=True, exist_ok=True)    target.write_text(content, encoding="utf-8")return {"success"True,"path": path,"bytes"len(content.encode("utf-8"))    }defreplace_text(path: str, old: str, new: str) -> dict[strAny]:"""精确替换文件中的唯一文本片段。"""    target = resolve_path(path)ifnot target.exists() ornot target.is_file():return {"success"False"error""文件不存在"}if target.suffix.lower() notin ALLOWED_SUFFIXES:return {"success"False"error""不允许修改该文件类型"}    content = target.read_text(encoding="utf-8")    count = content.count(old)if count == 0:return {"success"False"error""没有找到待替换内容"}if count > 1:return {"success"False"error""待替换内容不唯一,请提供更多上下文"}    updated = content.replace(old, new, 1)    target.write_text(updated, encoding="utf-8")return {"success"True"path": path, "replacements"1}defrun_tests(command: str = "pytest") -> dict[strAny]:"""只运行预先允许的测试命令。"""    args = ALLOWED_TEST_COMMANDS.get(command)if args isNone:return {"success"False"error""测试命令不在白名单中"}try:        result = subprocess.run(            args,            cwd=WORKSPACE,            capture_output=True,            text=True,            timeout=30,            check=False        )except subprocess.TimeoutExpired:return {"success"False"error""测试执行超时"}    output = (result.stdout + "\n" + result.stderr)[-12_000:]return {"success": result.returncode == 0,"returncode": result.returncode,"output": output    }TOOLS: dict[strCallable[..., dict[strAny]]] = {"list_files": list_files,"read_file": read_file,"write_file": write_file,"replace_text": replace_text,"run_tests": run_tests}SYSTEM_PROMPT = """你是一个运行在受限 workspace 中的 Coding Agent。你的任务是理解需求、查看项目、修改代码并运行测试。可用工具:1. list_files参数:{"path": "."}2. read_file参数:{"path": "相对路径"}3. write_file参数:{"path": "相对路径", "content": "完整文件内容"}4. replace_text参数:{"path": "相对路径", "old": "原文本", "new": "新文本"}5. run_tests参数:{"command": "pytest"} 或 {"command": "unittest"}需要调用工具时,只输出一个 JSON 对象:{  "type": "tool_call",  "tool": "工具名称",  "arguments": {}}任务完成时,只输出一个 JSON 对象:{  "type": "final",  "answer": "完成了什么、修改了哪些文件、测试是否通过"}规则:1. 开始修改前先查看目录和相关文件;2. 不要猜测未读取过的文件内容;3. 修改后必须运行测试;4. 测试失败时阅读错误并尝试修复;5. 只能输出合法 JSON,不要添加 Markdown 代码块;6. 不得要求执行白名单以外的命令;7. 没有测试通过时,不要声称任务已完成。"""defcall_model(messages: list[dict[strstr]]) -> dict[strAny]:"""调用模型并解析结构化动作。"""    response = client.chat.completions.create(        model=MODEL_NAME,        messages=messages,        temperature=0.1    )    content = response.choices[0].message.contentifnot content:raise RuntimeError("模型返回了空内容")try:return json.loads(content)except json.JSONDecodeError as error:raise RuntimeError(f"模型没有返回合法 JSON:{content}"from errordefexecute_tool(action: dict[strAny]) -> dict[strAny]:"""校验并执行一次工具调用。"""    tool_name = action.get("tool")    arguments = action.get("arguments", {})    tool = TOOLS.get(tool_name)if tool isNone:return {"success"False"error"f"未知工具:{tool_name}"}ifnotisinstance(arguments, dict):return {"success"False"error""arguments 必须是对象"}try:return tool(**arguments)except TypeError as error:return {"success"False"error"f"工具参数错误:{error}"}except Exception as error:return {"success"False"error"f"工具执行异常:{error}"}defrun_agent(task: str) -> str:"""运行 Coding Agent 主循环。"""    WORKSPACE.mkdir(parents=True, exist_ok=True)    tests_passed = False    messages = [        {"role""system""content": SYSTEM_PROMPT},        {"role""user""content": task}    ]for step inrange(1, MAX_STEPS + 1):print(f"\n[Step {step}/{MAX_STEPS}] 模型正在决策...")        action = call_model(messages)        action_type = action.get("type")if action_type == "final":if tests_passed:returnstr(action.get("answer""任务结束,但模型没有提供总结"))            tool_result = {"success"False,"error""尚未在最后一次代码修改后通过测试,不能结束任务"            }elif action_type != "tool_call":            tool_result = {"success"False,"error"f"无法识别的动作类型:{action_type}"            }else:print(f"[Tool] {action.get('tool')}{action.get('arguments', {})}")            tool_result = execute_tool(action)print(f"[Result] {json.dumps(tool_result, ensure_ascii=False)[:500]}")if action.get("tool"in {"write_file""replace_text"}:                tests_passed = Falseelif action.get("tool") == "run_tests"and tool_result.get("success"):                tests_passed = True        messages.append({"role""assistant","content": json.dumps(action, ensure_ascii=False)        })        messages.append({"role""user","content""工具执行结果:\n" + json.dumps(tool_result, ensure_ascii=False)        })returnf"任务未在 {MAX_STEPS} 步内完成,已停止运行"if __name__ == "__main__":print("Mini Coding Agent")print(f"Workspace: {WORKSPACE}")print("输入 exit 退出\n")whileTrue:        user_task = input("任务 > ").strip()if user_task.lower() in {"exit""quit"}:breakifnot user_task:continuetry:            result = run_agent(user_task)print(f"\nAgent:{result}")except Exception as error:print(f"\n运行失败:{error}")

这段客户端配置为什么值得单独注意

完整代码中真正与模型服务绑定的部分只有下面三项:

API_KEY = os.getenv("GENVIS_API_KEY")MODEL_NAME = "gpt-5.6-sol"base_url = "https://genvis.xyz/v1"

也就是说,文件读取、文本替换、测试执行和 Agent Loop 都与具体模型解耦。想测试另一个模型时,不需要重新搭建项目,只需确认接口支持对应模型名称,再调整 MODEL_NAME。

对 Coding Agent 来说,这一点很实用:同一个任务可以分别交给不同模型执行,再结合最终测试结果、执行步数和 Token 成本做对比,而不是只凭聊天体验判断模型是否适合写代码。

五、准备一个测试项目

在 workspace 中创建 calculator.py

defadd(a, b):return a + bdefsubtract(a, b):return a - b

再创建 test_calculator.py

from calculator import add, subtractdeftest_add():assert add(23) == 5deftest_subtract():assert subtract(52) == 3

先手动确认原项目测试正常:

cd workspacepython -m pytest -qcd ..

预期输出:

2 passed

六、让 Agent 完成第一次代码修改

启动程序:

python coding_agent.py

输入任务:

给 calculator.py 增加 divide(a, b) 函数。除数为 0 时抛出 ValueError,并在 test_calculator.py 中补充正常除法和除零测试。修改完成后运行 pytest,测试通过再结束。

一次典型的执行过程如下:

[Step 1/20] 模型正在决策...[Tool] list_files {'path': '.'}[Result] {'success': true, 'files': ['calculator.py', 'test_calculator.py']}[Step 2/20] 模型正在决策...[Tool] read_file {'path': 'calculator.py'}[Step 3/20] 模型正在决策...[Tool] read_file {'path': 'test_calculator.py'}[Step 4/20] 模型正在决策...[Tool] replace_text {...}[Step 5/20] 模型正在决策...[Tool] replace_text {...}[Step 6/20] 模型正在决策...[Tool] run_tests {'command': 'pytest'}[Result] {'success': true, 'returncode': 0, 'output': '4 passed'}Agent:已在 calculator.py 中增加 divide 函数,补充正常除法与除零测试,pytest 全部通过。

注意,模型每一轮只决定一个动作。它不是一次生成完整计划后盲目执行,而是根据最新工具结果继续判断。

七、核心代码拆解

1. 为什么必须限制工作目录

下面这行代码看似普通,却是整个工具层最重要的安全边界:

target = (WORKSPACE / relative_path).resolve()

紧接着检查目标路径是否仍然位于 workspace:

if target != WORKSPACE and WORKSPACE notin target.parents:raise ValueError("路径超出 workspace 范围")

这样即使模型尝试传入 ../../important.txt,程序也会拒绝访问。

风险警告:不要把模型输出直接拼接成系统路径,也不要默认"模型不会做危险操作"。权限必须由代码控制,而不是靠提示词保证。

2. 为什么用 replace_text,而不只用 write_file

write_file 适合创建新文件,但修改已有文件时,模型必须返回完整内容。文件越长,越容易发生以下问题:

  • 遗漏原有代码;
  • 改坏无关部分;
  • 浪费上下文和 Token;
  • 难以审查具体改了什么。

replace_text 要求旧内容在文件中只出现一次,相当于一个极简补丁工具。匹配不到或匹配多次时,它会拒绝修改,让模型读取更多上下文后重试。

3. 为什么不开放任意 Shell

最简单的 Coding Agent 往往会提供下面这种工具:

subprocess.run(command, shell=True)

这也意味着模型生成什么,电脑就执行什么。删除文件、读取环境变量、上传数据都可能发生。

本文只允许:

ALLOWED_TEST_COMMANDS = {"pytest": ["python""-m""pytest""-q"],"unittest": ["python""-m""unittest""discover""-v"]}

同时使用参数数组而不是 shell=True,减少 Shell 注入风险。

这会牺牲一部分自由度,却更适合作为能在本机运行的教学版本。

4. 测试结果为什么要回喂模型

run_tests 返回三项关键信息:

{"success":false,"returncode":1,"output":"AssertionError ..."}

Agent 将这段结果追加到消息历史,下一轮模型就能根据真实错误继续修复。

如果没有这一步,模型只是"写了代码";加入测试结果回喂之后,它才具备最基本的闭环纠错能力。

5. 为什么要设置 MAX_STEPS

模型可能反复读取同一个文件,也可能在测试失败后不断尝试。下面的限制可以防止无限循环:

MAX_STEPS = 20

达到最大步数后,程序会停止任务,避免持续消耗时间和 Token。

6. 为什么不能只靠提示词要求测试

提示词写着"测试通过才能结束",并不代表模型一定遵守。因此,主循环还维护了一个真实状态:

tests_passed = False

只有 run_tests 成功后,它才会变为 True;如果测试通过后又调用 write_file 或 replace_text,状态会重新变回 False。模型提前输出 final 时,程序也会拒绝结束并要求它继续测试。

这体现了一个重要原则:

能用代码强制执行的规则,就不要只写在提示词里。

八、这个 Agent 还不等于 Claude Code 或 Codex

本文实现的是用于理解原理的最小 Coding Agent,不是成熟产品的平替。

成熟的编码 Agent 通常还包含:

  • Git 状态检测和差异审查;
  • 按需搜索大型代码库;
  • 上下文压缩与缓存;
  • 命令沙箱和权限审批;
  • 流式输出与任务进度;
  • 补丁应用与回滚;
  • 项目级规则文件;
  • MCP、Skills 和子 Agent;
  • 任务中断与恢复。

但无论功能多复杂,最底层仍然是同一个循环:

观察项目 → 选择工具 → 执行动作 → 获取结果 → 继续判断

理解这个循环后,再看任何 Coding Agent 的架构都会清晰很多。

九、五个最值得继续升级的方向

1. 增加 Git Diff

修改完成后自动展示差异,让用户知道具体改了哪些行,并在确认后保留修改。

2. 用补丁替代完整写入

可以继续实现 unified diff 工具,让模型输出标准补丁,再由程序校验和应用。

3. 增加用户审批

在写文件或运行命令前显示动作:

Agent 准备修改 src/app.py,是否允许?[y/N]

这比单纯依靠系统提示词更可靠。

4. 增加项目规则文件

让 Agent 启动时读取项目中的规则文件,例如:

  • Python 使用 Ruff 格式化
  • 新功能必须补充测试
  • 禁止修改 migrations 目录
  • 所有公开函数必须有类型注解

这相当于给 Coding Agent 一份项目级开发规范。

5. 增加上下文压缩

任务执行步骤变多后,文件内容和测试日志会快速占满上下文。可以对旧工具结果生成摘要,只保留最近几轮的完整信息。

十、常见问题

1. 模型没有返回合法 JSON 怎么办

降低 temperature、强化输出约束,并增加有限次数重试。生产环境建议使用模型支持的原生工具调用或结构化输出能力。

2. 为什么不让 Agent 自动安装依赖

自动安装依赖涉及网络访问、供应链风险和环境污染。教学版本只负责修改项目与运行既有测试,更容易控制风险。

3. 能不能用其他模型

可以。本文采用统一兼容接口的目的,就是让模型切换与 Agent 工具层解耦。只要接口支持对应模型和当前请求格式,通常只需要修改 MODEL_NAME;API Key、文件工具、测试工具与 Agent Loop 都可以继续复用。

4. 为什么模型修改成功却一直不结束

通常是系统提示词中的完成条件不明确。本文明确要求"修改后必须运行测试,测试通过才能结束",同时用 MAX_STEPS 提供最终兜底。

5. 这套代码可以直接用于生产吗

不建议。生产环境至少还需要容器沙箱、细粒度审批、资源限制、审计日志、版本控制和可回滚机制。

十一、总结

本文用 Python 手写了一个能够操作真实项目的极简 Coding Agent,它已经具备完整的最小闭环:

  • 主动查看项目结构;
  • 按需读取代码文件;
  • 创建或修改代码;
  • 执行测试;
  • 根据报错继续修复;
  • 测试通过后输出总结。

真正重要的并不是这两百多行代码,而是背后的工程边界:

模型负责提出动作,程序负责校验权限;工具负责执行,测试负责验证;失败结果重新进入上下文,Agent 才能继续纠错。

当你理解这套机制后,就能继续加入 Git Diff、人工审批、项目规则、上下文压缩和 MCP,把这个最小版本逐步扩展为真正可用的 Coding Agent。

如果运行时需要切换模型,只需要调整客户端配置和 MODEL_NAME,文件工具、测试工具与 Agent Loop 都可以继续复用。

需要直接运行的读者,将 base_url 设置为 https://genvis.xyz/v1,再把申请到的 Key 写入 GENVIS_API_KEY 即可测试。后台还能查看每个 Coding Agent 任务实际消耗的 Token,比较不同模型完成同一任务的成本。


想直接拿到可运行的完整代码和最新模型配置?公众号菜单栏已放好入口,复制即可测试。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 14:34:47 HTTP/2.0 GET : https://f.mffb.com.cn/a/508278.html
  2. 运行时间 : 0.101657s [ 吞吐率:9.84req/s ] 内存消耗:4,910.24kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=4fb86647f0661eca58d28817eb8b297b
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000960s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001497s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000697s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000724s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001313s ]
  6. SELECT * FROM `set` [ RunTime:0.000603s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001458s ]
  8. SELECT * FROM `article` WHERE `id` = 508278 LIMIT 1 [ RunTime:0.002025s ]
  9. UPDATE `article` SET `lasttime` = 1787294087 WHERE `id` = 508278 [ RunTime:0.002242s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.000288s ]
  11. SELECT * FROM `article` WHERE `id` < 508278 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000440s ]
  12. SELECT * FROM `article` WHERE `id` > 508278 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001829s ]
  13. SELECT * FROM `article` WHERE `id` < 508278 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001564s ]
  14. SELECT * FROM `article` WHERE `id` < 508278 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.000568s ]
  15. SELECT * FROM `article` WHERE `id` < 508278 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.013236s ]
0.103028s