2小时智能体开发一个智能体?我用CodeArts Agent 和 AtomCode 开发了一个适老化智能体。

一个面向老年用户的智能体项目,从零写到能跑。不谈概念,只记过程和踩坑。


一、起因

家里老人用电脑,经常问我"怎么打开计算器"。我告诉她 Win+R,输入 calc,回车。她说找不到 Win 键。

后来我装了个 豆包 桌面版让她问,结果更糟------AI 回复"您可以按下 Windows 键加 R 键,然后输入 calc",她连 Windows 键在哪都不知道。

聊天机器人只能"说",但老年用户需要的是有人帮他们"做"。说一万遍"按 Win+R"不如直接把计算器打开。

这就是这个项目的出发点:做一个能动手的 AI。用户说"打开计算器",它直接 subprocess.Popen 把 calc.exe 启动起来,然后回一句"已为您打开计算器"。


二、架构:6 个文件,没框架

工具调用协议就是一行正则,调度逻辑不到 50 行,套一层 Chain 反而看不清数据流。

最后的项目结构:

复制代码
main.py          (224行)  入口,选 CLI 或 GUI 模式
main_gui.py      (894行)  tkinter 适老化桌面界面
agent.py         (710行)  核心引擎:API 调用 + 工具调度
config.py        (191行)  配置管理,三级优先级合并
prompts.py       (136行)  系统提示词
tools.py        (1629行)  46 个工具函数 + 注册表 + 执行引擎

数据流:

复制代码
用户输入 → agent.chat() → 远程大模型 API → AI 回复文本
                                              ↓
                              检测到 [执行] 标记 → tools.execute_tool()
                                              ↓
                              工具执行结果 → 反馈给 AI 再次推理 → 最终回复

三、配置:三级优先级

config.py 191 行,处理一个问题:配置从哪来,谁说了算。

优先级:环境变量(最高) → settings.json → 代码默认值(兜底)

三级各有用处:代码默认值保证首次运行就能工作;settings.json 让用户持久化修改;环境变量给部署留口子。

核心就一个 load_settings() 函数:

python 复制代码
def load_settings() -> dict:
    global _settings_cache

    # 懒加载
    if _settings_cache is not None:
        return _settings_cache

    # 1. 代码默认值
    defaults = {
        "api_base_url": "https://api.siliconflow.cn/v1",
        "api_key": _DEFAULT_API_KEY,
        "model": "deepseek-ai/DeepSeek-V4-Flash",
        "temperature": 0.3,
        "max_tokens": 500,
        "timeout_seconds": 60,
    }

    # 2. settings.json 覆盖(只合并已知 key,忽略无关字段)
    if os.path.exists(SETTINGS_FILE):
        with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
            file_cfg = json.load(f)
        defaults.update({k: v for k, v in file_cfg.items() if k in defaults and v is not None})

    # 3. 环境变量覆盖(最高优先级)
    env_overrides = {
        "api_key": os.getenv("API_KEY"),
        "api_base_url": os.getenv("API_BASE_URL"),
        "model": os.getenv("MODEL"),
        "temperature": os.getenv("TEMPERATURE"),
        "max_tokens": os.getenv("MAX_TOKENS"),
    }
    for key, val in env_overrides.items():
        if val is not None:
            # 类型转换:temperature→float, max_tokens/timeout→int
            if key in ("temperature",):
                defaults[key] = float(val)
            elif key in ("max_tokens", "timeout_seconds"):
                defaults[key] = int(val)
            else:
                defaults[key] = val

    _settings_cache = defaults
    return defaults

几个细节:

  1. _settings_cache 做惰性加载,避免每次 API 调用都读磁盘。save_settings() 修改配置后会清空缓存,下次 load_settings() 重新读取。

  2. if k in defaults 这行是白名单合并。settings.json 里如果混入了无关字段,不会污染运行时配置。这个坑我踩过------早期没做白名单,用户在 json 里加了个 "备注": "测试用",结果运行时配置里多了个莫名其妙的 key。

  3. 首次运行时,如果 settings.json 不存在,load_settings() 会把默认值写进去,方便用户直接编辑文件修改。

temperature=0.3,max_tokens=500

这两个参数直接决定 token 消耗和成本。

temperature=0.3 是试出来的。0.7 的时候 AI 太"有创意","打开计算器"它能给你编一段计算器的历史。0.1 又太死板,稍微复杂点的请求就只会调工具不会解释。0.3 是个折中点------够确定,又不至于死板。

max_tokens=500 是硬性限制。老年用户不需要长篇大论,500 token 说清一件事加执行结果绰绰有余。


四、提示词:136 行,最关键的文件

prompts.py 行数最少,但改的次数最多。提示词写不好,后面所有代码都白搭。

系统提示词

python 复制代码
SYSTEM_PROMPT = """你是老年电脑辅导老师,始终用中文回答。

核心原则:
1. 用最简单的话,避免术语
2. 操作拆解为步骤:1. 2. 3.
3. 保持鼓励语气,提醒防诈骗
4. 每段不超过3行,重要内容**加粗**
5. 主动帮用户操作电脑,不只给建议

你可以直接操作电脑!格式:
[执行] 工具名("参数")

常用工具:
- 打开程序("计算器|记事本|浏览器|微信|Word|Excel")
- 打开网站("网址") - 自动搜索或打开
- 系统信息() - 查看电脑配置
- 磁盘空间() - 查看剩余空间
- 截图() - 截屏保存到桌面
- 系统音量(0-100) - 调整音量
- 定时关机(分钟) / 取消关机()
- WiFi状态() / 网络诊断()
- 设置页面("显示|声音|网络|字体")
- 锁定屏幕() / 显示桌面()
- 放大镜() / 高对比度() / 字体大小(125)
- 清理垃圾() / 检查更新()
- 搜索文件("关键词") / 打开文件("路径")
- 关闭程序("程序名") / 任务管理器()
- 发送邮件() / 当前时间()
- 写脚本("文件名", "代码") / 运行脚本("文件名")
- 病毒扫描() / 紧急求助()

规则:
- 先说明要做什么,再用[执行]
- 执行后告诉用户"已为您完成"
- 危险操作先确认:"您确定吗?"
- 用户说"打开计算器"→直接执行打开程序("计算器")
- 用户说"电脑卡了"→执行任务管理器()或磁盘空间()
- 工具有结果时,基于结果给出建议"""

[执行] 标记:最简陋但最可靠的协议

没用 OpenAI 的 function calling,没用 JSON Schema,让 AI 在回复文本里输出 [执行] 工具名("参数")

为什么?这个项目用的是硅基流动的 DeepSeek-V4-Flash,走 OpenAI 兼容接口。不同模型对 function calling 的支持不尽相同,有的支持有的不支持,支持的程度也不一样。文本标记是所有模型都能理解的方式------只要提示词里写清楚格式和示例,模型就能稳定输出。

代价是解析要自己写。用正则匹配:

python 复制代码
pattern = r'\[执行\]\s*([^(]+\([^)]*\))'
matches = re.findall(pattern, text)

这个正则有局限------不支持嵌套括号的参数。但实际使用中 95% 的工具调用都是单参数,够用了。遇到解析失败的情况,execute_tool() 会返回错误信息,AI 下次会换个格式重试。

"规则"部分不是装饰

复制代码
- 用户说"打开计算器"→直接执行打开程序("计算器")
- 用户说"电脑卡了"→执行任务管理器()或磁盘空间()

精简版提示词

python 复制代码
SYSTEM_PROMPT_MINI = """你是耐心细心的老年电脑辅导老师。始终使用中文回答。

规则:
- 用最简单的话,避免术语
- 操作拆解为步骤:1. 2. 3.
- 保持鼓励语气
- 提醒防诈骗
- 每段不超过3行

你能帮:打开程序、上网、邮件、系统设置、文件管理、连网、防诈骗。"""

完整版约 400 token,精简版约 200 token。--mini 模式下每次 API 调用省 200 token。5 轮对话累计省 1000 token,看起来不多,但日积月累。而且精简版在弱模型上表现反而更稳定------信息密度高,模型不容易"发散"。


五、工具模块:46 个函数的注册和执行

tools.py 1629 行,是最大的文件。结构不复杂,但细节多。

统一返回格式

每个工具函数都返回三元组 (success: bool, message: str, data: any)

python 复制代码
def open_application(app_name: str) -> tuple:
    try:
        subprocess.Popen(f'start "" "{cmd}"', shell=True)
        return (True, f"已为您打开 {app_name}", None)
    except Exception as e:
        return (False, f"无法打开 {app_name}:{e}", None)

为什么不用异常?因为工具的调用者是 execute_tool() 引擎,它需要把成功/失败统一汇报给 AI。用异常的话,每个工具的异常类型都不一样,引擎得写一堆 except。三元组让所有工具的结果处理变成一行代码。

中文名映射

python 复制代码
APP_ALIASES = {
    "计算器": "calc",
    "记事本": "notepad",
    "画图": "mspaint",
    "浏览器": "msedge",
    "微信": "wechat",
    "此电脑": "explorer",
    "谷歌浏览器": "chrome",
    "word": "winword",
    "excel": "excel",
    "任务管理器": "taskmgr",
    "放大镜": "magnify",
    # ... 共 28 个
}
cmd = APP_ALIASES.get(app_name.lower(), app_name)

老年用户不会说"打开 msedge",他们说"打开浏览器"。这个映射表就是自然语言到系统命令的桥梁。映射表里没有的,就直接把用户输入当命令试------兜底策略,有时候也能蒙对。

智能打开网站

python 复制代码
def open_website(url: str) -> tuple:
    if not url.startswith(("http://", "https://", "www.")):
        if any(tld in url for tld in [".com", ".cn", ".org", ".net"]):
            url = "https://" + url          # "baidu.com" → "https://baidu.com"
        else:
            url = f"https://www.baidu.com/s?wd={quote(url)}"  # "天气" → 百度搜索
    webbrowser.open(url)

用户可能输入三种东西:

  1. www.baidu.com → 直接打开
  2. baidu.com → 补全 https 前缀后打开
  3. 今天的天气 → 当搜索词,跳转百度

一个函数处理三种情况,零配置。用户不需要知道什么是 URL。

安全白名单

python 复制代码
SAFE_PREFIXES = [
    "dir", "ipconfig", "ping", "systeminfo", "tasklist",
    "netstat", "whoami", "ver", "cls", "echo", "type",
    "find", "where", "tree", "time", "date",
    "chcp", "cd", "path", "prompt", "title", "color",
]

if cmd_lower not in SAFE_PREFIXES:
    return (False, f"安全限制:命令 '{cmd_lower}' 不在允许列表中", None)

execute_command() 是最危险的工具,直接执行 shell 命令。白名单只允许信息查询类命令。delformatrd /s /q C:\ 这些永远不会出现在白名单里。

工具注册表

python 复制代码
TOOL_REGISTRY = {
    "打开程序": {
        "function": open_application,
        "description": "打开电脑上的应用程序",
        "params": {"app_name": "程序名称,如:计算器、记事本、浏览器、微信、Word"},
        "examples": ['打开程序("计算器")', '打开程序("记事本")'],
    },
    "系统信息": {
        "function": get_system_info,
        "description": "查看电脑系统信息(CPU、内存、磁盘、系统版本)",
        "params": {},
        "examples": ['系统信息()'],
    },
    # ... 46 个工具
}

注册表干三件事:给提示词生成工具列表、给执行引擎查找函数对象、给 GUI 生成快捷按钮。一个字典,三个消费者。

执行引擎

这是整个工具模块最复杂的部分。AI 输出的是字符串 打开程序("计算器"),但 Python 需要调用 open_application(app_name="计算器")。中间的转换全靠 execute_tool()

python 复制代码
def execute_tool(tool_call: str) -> tuple:
    # 1. 解析工具名和参数
    tool_match = re.match(r"^([^(]+)\(", tool_call)
    tool_name = tool_match.group(1).strip()  # "打开程序"

    # 2. 智能括号匹配(支持嵌套括号和引号内的括号)
    paren_depth = 0
    in_single_quote = False
    in_double_quote = False
    # ... 逐字符扫描,找到匹配的右括号

    # 3. 参数解析(支持多种格式)
    #    - JSON: {"app_name": "计算器"}
    #    - 位置参数: "计算器"
    #    - 多参数: "文件名", "内容"

    # 4. 查找工具(支持模糊匹配)
    if tool_name not in TOOL_REGISTRY:
        matches = [name for name in TOOL_REGISTRY if tool_name in name]
        if matches:
            tool_name = matches[0]

    # 5. 执行
    result = tool_info["function"](**params)
    return result

参数解析是最容易出 bug 的地方。AI 可能输出 写脚本("hello.py", "print('你好')")------参数里有引号、有括号、有逗号。简单的 split(",") 会把 print('你好') 错误地分割。


六、核心引擎:对话管理 + 工具调度 + Token 控制

agent.pyElderAgent 类,710 行,整个项目的心脏。

对话历史修剪

每次 API 调用都要发送完整的对话历史。10 轮对话后,光历史消息就可能消耗 2000+ token。不修剪,成本会线性增长。

python 复制代码
MAX_HISTORY_ROUNDS = 5   # 超过 5 轮开始修剪
KEEP_RECENT_ROUNDS = 3   # 始终保留最近 3 轮

def _trim_history(self):
    non_system_count = len(self.messages) - 1  # 排除 system 消息
    max_non_system = MAX_HISTORY_ROUNDS * 2    # 每轮 = user + assistant = 2 条

    if non_system_count > max_non_system:
        to_remove = non_system_count - (KEEP_RECENT_ROUNDS * 2)
        if to_remove > 0:
            self.messages = (
                [self.messages[0]] +           # 保留系统提示词
                self.messages[1 + to_remove:]   # 保留最近的消息
            )

系统提示词永远保留,最早的消息优先丢弃,最近 3 轮始终保留。

工具调度流程

python 复制代码
def chat(self, user_input: str) -> str:
    # 1. 用户消息入队
    self._add_message("user", user_input)

    # 2. 调用大模型
    reply = self._call_api()
    self._add_message("assistant", reply)

    # 3. 检测 [执行] 标记,执行工具
    tool_executed = self._process_tool_calls(reply)

    # 4. 如果有工具执行,把结果反馈给 AI 再次推理
    if tool_executed:
        tool_feedback = f"[工具执行结果]\n{tool_executed}"
        self._add_message("user", tool_feedback)
        follow_up = self._call_api()  # 第二次 API 调用
        if follow_up:
            self._add_message("assistant", follow_up)
            return reply + "\n\n" + tool_executed + "\n\n" + follow_up

    return reply

第 4 步值得展开说明:工具执行后,AI 会再推理一次。这不是多余的。

用户说"电脑卡了",AI 第一次回复里调用 磁盘空间()任务管理器()。工具返回"C 盘剩余 2GB"和"当前运行 87 个进程"。如果不做第二次推理,用户只看到一堆原始数据。第二次推理让 AI 把数据翻译成老年用户能懂的话:"您的 C 盘快满了,只剩 2GB,建议清理一下。我帮您打开磁盘清理工具?"

代价是多一次 API 调用。但这次调用的 prompt 很短(工具结果 + 短指令),token 消耗不大,换来的是用户体验的提升。

流式输出

chat_stream()chat() 的流式版本,通过回调函数 on_event(event_type, data) 实时反馈:

python 复制代码
def chat_stream(self, user_input: str, on_event=None):
    # 思考阶段
    on_event("thinking", {"status": "正在思考..."})
    reply = self._call_api()

    # 初步回复
    on_event("reply", {"text": reply})

    # 工具调用(逐个执行,逐个反馈)
    for i, tool_call in enumerate(matches[:max_calls]):
        on_event("tool_call", {"name": tool_call, "index": i + 1})
        success, message, data = execute_tool(tool_call)
        on_event("tool_result", {"success": success, "message": message})

    # AI 基于工具结果的后续分析
    on_event("thinking", {"status": "正在分析执行结果..."})
    follow_up = self._call_api()
    on_event("follow_up", {"text": follow_up})

    # 完成
    on_event("done", {"full_reply": full_reply})

为什么用回调而不是生成器/async?tkinter 的线程模型决定的------所有 UI 操作必须在主线程,API 调用在后台线程。回调 + root.after() 是最简单的跨线程 UI 更新方式。用 async 固然更优雅,但 tkinter 不支持 asyncio 事件循环,硬整合反而更复杂。

一次最多执行 3 个工具

python 复制代码
max_calls = 3
for i, tool_call in enumerate(matches[:max_calls]):
    # ...

七、适老化 GUI:tkinter 也能用

main_gui.py 894 行,纯 tkinter,零额外依赖。

选 tkinter 而不是 PyQt 或 Electron,原因:老年用户的电脑配置通常不高,PyQt 打包出来 80MB,Electron 更是 150MB 起步。tkinter 是 Python 自带的,打包后不到 20MB。

配色

python 复制代码
COLORS = {
    "bg": "#2C3E50",          # 深蓝灰背景
    "fg": "#FFFFFF",          # 白色文字
    "input_bg": "#34495E",    # 输入框背景
    "input_fg": "#FFFFFF",    # 输入框文字
    "button_bg": "#3498DB",   # 按钮蓝色
    "button_hover": "#2980B9",# 按钮悬停色
    "urgent_bg": "#E74C3C",   # 紧急按钮(红色)
    "success_bg": "#27AE60",  # 成功按钮(绿色)
    "tool_bg": "#8E44AD",     # 工具按钮(紫色)
    "chat_bg": "#1A252F",     # 聊天区域背景
    "chat_user": "#2ECC71",   # 用户消息标签色
    "chat_ai": "#3498DB",     # AI消息标签色
    "header_bg": "#1A252F",   # 顶部标题背景
}

老年用户普遍视力下降,低对比度配色等于不可用。深色背景 + 白色文字 + 彩色按钮,每个元素都足够醒目。

字体

python 复制代码
LARGE_FONT = ("微软雅黑", 28, "bold")    # 标题
MEDIUM_FONT = ("微软雅黑", 20)           # 副标题/标签
NORMAL_FONT = ("微软雅黑", 16)           # 聊天区正文
SMALL_FONT = ("微软雅黑", 14)            # 按钮
TOOL_FONT = ("微软雅黑", 14, "bold")     # 工具栏

微软雅黑是 Windows 预装字体中中文显示效果最好的无衬线体,不需要用户额外安装。

快捷工具栏

python 复制代码
quick_tools = [
    ("记事本",     '打开程序("记事本")'),
    ("计算器",     '打开程序("计算器")'),
    ("浏览器",     '打开程序("浏览器")'),
    ("我的文档",   '打开文件("文档")'),
    ("截图",       '截图()'),
    ("调大音量",   '系统音量(60)'),
    ("调小音量",   '系统音量(30)'),
    ("锁定屏幕",   '锁定屏幕()'),
    ("30分后关机", '定时关机(30)'),
    ("取消关机",   '取消关机()'),
    ("系统信息",   '系统信息()'),
    ("磁盘空间",   '磁盘空间()'),
    ("显示桌面",   '显示桌面()'),
    ("放大镜",     '放大镜()'),
    ("清理垃圾",   '清理垃圾()'),
]

这些按钮直接调用 execute_tool(),不经过大模型。用户点"计算器",1 秒内打开,零 token 消耗。只有通过输入框对话时才走 AI 推理路径。

快捷按钮适老化设计------不是所有操作都需要 AI 介入。高频操作直接做,低频操作才走对话。

线程模型

python 复制代码
def _on_send(self):
    self._sending = True
    self.send_btn.configure(state=tk.DISABLED)  # 防止重复发送

    def process_stream():
        # 在后台线程中调用 agent.chat_stream()
        def on_event(event_type, data):
            # 通过 root.after() 把 UI 更新推到主线程
            if event_type == "thinking":
                self.root.after(0, lambda: self._set_status("● 思考中..."))
            elif event_type == "reply":
                self.root.after(0, lambda: self._show_reply(data["text"]))
            # ...
        self.agent.chat_stream(user_input, on_event=on_event)

    threading.Thread(target=process_stream, daemon=True).start()

tkinter 不是线程安全的,直接在后台线程操作 UI 控件会崩溃。root.after(0, callback) 是标准做法------把回调"投递"到主线程的事件循环中执行。


八、用 AI 开发 AI

这个项目最有意思的地方是:我是用 AI 编程助手智能体来开发这个 AI 智能体的。

具体来说:

  • CodeArts Agent(华为云码道)和 AtomCode:负责代码生成、模块骨架搭建、bug 定位和修复。tools.py 里 46 个工具函数的框架,大部分是它根据我描述的功能需求逐个生成的,我再逐个审查和调整。execute_tool() 的参数解析引擎最初也是它写的初版,后来重写了括号匹配逻辑来处理嵌套引号的边界情况。

  • Kimi(月之暗面 kimi-2.6):负责知识确认。写这篇博客的过程中,我让 Kimi 帮忙校验了几个技术细节------httpx 和 requests 在连接池管理上的差异、tkinter 线程安全的具体约束、DeepSeek-V4-Flash 的 token 计价方式。它的回答我没有直接采用,交叉验证后才写进来。

不是"AI 写了一切,我只是按了回车"。实际的工作模式:

复制代码
我(人)                    AI 编程助手
  │                           │
  ├─ 定义需求和架构 ────────→ 生成代码骨架
  │                           │
  ├─ 审查代码逻辑 ←──────── 返回可运行的初版
  │                           │
  ├─ 发现边界问题 ────────→ 修复或重写特定函数
  │                           │
  ├─ 决策取舍(省token vs 完整性)← 不做这个决策
  │                           │
  └─ 最终审查和测试            └─ 辅助但不决定

人做决策,AI 做执行,人做审查以及大bug回退修改。这个循环比纯手写快了大概 3-4 倍,但比"全交给 AI"靠谱得多。AI 生成的代码 80% 可用,剩下 20% 的边界情况和架构决策必须人来把控。

工作方式的变化

以前 现在
核心产出 代码量 架构决策 + 质量把控
工具角色 编辑器 协作者
瓶颈 编码速度 问题定义的清晰度
风险 写错代码 审查不严,让 AI 的错误混入

这个 3800 行的项目,纯手写可能要两周;用 AI 辅助,实际编码时间压缩到三四天。省下来的时间花在了更仔细的需求推敲、更充分的安全审查、和更完整的适老化测试上。

效率提升没有消灭工作,而是把工作推向了更高价值的环节。


九、一些数字

指标
总代码行数 ~3800 行
工具数量 46 个
单次对话 token 消耗 ~1500-1800(含工具调用)
系统提示词 token ~400(完整版)/ ~200(精简版)
对话历史上限 5 轮(保留最近 3 轮)
单次工具调用上限 3 个
GUI 字体 28pt 标题 / 20pt 副标题 / 16pt 正文 / 14pt 按钮
依赖数量 3 个核心(httpx, rich, pyperclip)
AI 辅助开发工具 CodeArts Agent + AtomCode + Kimi kimi-2.6

十、几点认识

技术演进史就是工具进化史。从打孔纸带到汇编,从高级语言到云原生,每一次跃迁都淘汰固步自封者,奖励拥抱新体系的人。AI 不是敌人,而是必须整合的工具。

我们不再是逐行敲代码的"打字员",而是指挥 AI 协同作战的"架构师"。学会拆解任务、审核统筹,这种思维转变比学会任何一门新语言都重要。

很多人抗拒改变------用 Vim、写 Shell、鄙视可视化操作。但 AI 已经写了很多代码,而且写得不错。坚持"纯手工编码"就像坚持手洗衣服,你花在写代码上的时间,别人用来看文档、思考架构、打磨软技能。时间久了,差距就出来了。

接纳 AI,不是当它的奴隶,而是把重复机械的工作交给它,腾出手来做只有人脑才能做的事。

AI 不会淘汰程序员,它淘汰的是不再进化的编程方式。这场抗争的核心,从来不是人与机器的对抗,而是旧自我与新自我的诀别。

别焦虑,但别躺平。别追风口,但别拒绝工具。长期投资自己,积累 AI 学不会的东西------判断力、审美、对复杂系统的理解、对人性的洞察。

本文原创,原创不易,如需转载,请联系作者授权。

相关推荐
HIT_Weston1 小时前
101、【Agent】【OpenCode】task 工具提示词(Usage Notes)
人工智能·agent·opencode
qcx231 小时前
【系统学AI】09 Multi-Agent架构(2026版):从学术理论到工业级实践
java·人工智能·架构·multi-agent·claude agent
洛宇1 小时前
一个口语 skill,灵感居然来自2021年的那个夏天
人工智能·程序员·github
微擎应用1 小时前
智能售货柜公众号管理系统平台
大数据·人工智能
IT_陈寒1 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
星辰AI2 小时前
多模态记忆:让 AI Agent 记忆各种类型的信息
人工智能·ai·语言模型
jiayong232 小时前
AI架构师面试题库 - 完整汇总文档
人工智能·面试·职场和发展
bigfootyazi2 小时前
python爬虫-基本库-urllib库(常用速查)
开发语言·爬虫·python
后端小肥肠2 小时前
效率狂飙9000%!Codex + HyperFrames 让一篇文章 5 分钟变视频
人工智能·aigc·agent