第四次作业

NaiWa Agent:一个"能说会做"的通用任务型智能体

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS/homework/16760
这个作业的目标 用现代 AI 工具构建一个同时具备「语言交互(会说)」与「行动执行(会做)」的智能体:能听懂自然语言、理解任务意图,并自主调用工具把事情真正做完;技术栈需支持 MCP 或兼容框架;最终沉淀成可复用的工程,为期末大项目打底
学号 3124004138(马肇哲)、3124004125(陈绎谦)

第一次团队作业我们组提交的是一个通用任务型 Agent 的雏形。这次我们没有换题目,而是把它当正式产品重新做了一遍——补上多轮记忆、上下文压缩、工具防幻觉、桌面客户端、附件上传与视觉降级,并修掉了 5 个真实跑起来才会暴露的工程问题(详见 4.9)。它现在叫「NaiWA Agent」,有终端和桌面两种形态,241 个单元测试全部通过。


一、项目简介

一句话:NaiWa Agent 是一个基于 LangChain 1.x + ReAct 的通用任务型智能体。你和它说人话,它会自己拆解任务、挑工具、调工具、看结果、再决定下一步,直到把事情做完——产出的东西是真的落在你磁盘上的文件,而不是一段"你可以试试这样"的建议。

两种形态,一套后端:

  • CLI 终端版:python main.py,Rich 渲染的「思考与行动过程框」+ 结果面板,每轮 token 预估/实耗全程可见;
  • 桌面客户端:Electron 应用「NaiWa Agent」,开启动画、昼夜双主题、多会话管理、工作日记、运行状态侧栏。

它到底会做什么(都是实测过的真实场景):

场景 你说的话 它做的事
办公文档 "给我推荐一下广州的热门景点,并给一份一日游攻略文档,放在我的桌面上" 联网查天气与景点 → 写 Markdown → 调 gen_docx 生成带排版的 .docx,直接落到桌面
代码开发 "帮我写一个贪吃蛇游戏" 直接生成可运行的 HTML,再自己读回代码检查、用 edit_file 修 bug,最后告诉你双击打开就行
数据整理 "把这三份表格合并成一个 Excel,第一行是表头" gen_xlsx 生成 .xlsx,二维数据自动落表
环境操作 "帮我装一下 pypdf,然后读一下那个 PDF 讲了什么" run_shell 装依赖(自动用项目虚拟环境)→ read_file 读内容 → 总结
联网查询 "今天广州天气怎么样" search_web 走 Open-Meteo 天气源,拿真实数据回答,绝不编
外部工具 通过 MCP 接入任意 MCP Server load_mcp_tools() 把 MCP 工具编进同一套工具层,和内置工具平权

01-桌面端-生成广州一日游文档

图 1:一句自然语言 → 9 步思考与行动 → 桌面上的《广州一日攻略.docx》。右下角「本次会话用量 45,093 tokens」是 API 真实返回的累计消耗,右侧执行过程逐条可查。


二、需求描述

2.1 背景与问题

大模型"能说"已经是共识,但"会做"才是分水岭。一个只会聊天的模型遇到"帮我把这份数据整理成 Excel"时,只能给你一段 openpyxl 的示例代码;而一个真正的 Agent 应该自己写完代码、自己跑、自己看报错、自己改到跑通。

我们想验证的正是这件事:给它一个工具集,它能不能靠自己把一件跨步骤的事做完?

2.2 功能需求

编号 需求 优先级 状态
F1 自然语言多轮对话,理解上下文指代("它""刚才那个文件") 必须 ✅
F2 自主调用工具执行操作:读写文件、执行命令、生成文档、联网搜索 必须 ✅
F3 ReAct 循环:思考 → 行动 → 观察,直到任务完成 必须 ✅
F4 多轮对话记忆,跨进程重启不丢 必须 ✅
F5 长任务不因上下文耗尽而中断 重要 ✅
F6 外部 API / 数据库交互 重要 ✅
F7 简洁易用的前端界面 重要 ✅
F8 MCP 协议接入外部工具 重要 ✅
F9 工具调用防幻觉(调错名字要给纠正建议) 重要 ✅
F10 token 用量事前预估 + 事后实耗 + 成本折算 升级 ✅
F11 多模型热切换(对话中换模型,记忆保留) 升级 ✅
F12 附件上传(文件/照片),模型不支持视觉时明确降级 升级 ✅
、

2.3 技术要求对照

作业要求 我们的实现
自然语言对话(能说) 多轮对话 + 意图理解 + 追问澄清。遇到"整理一下""优化一下"这类没有判定标准的模糊指令,它会先反问确认标准,而不是瞎猜着动手
执行操作 / 调用工具(会做) 9 个内置工具(文件读写改、列目录、执行命令、Word/Excel/PPT 生成、联网搜索)+ MCP 动态扩展
推荐 MCP 或兼容框架 基于 LangChain 1.x create_agent + LangGraph,原生支持 MCP(langchain-mcp-adapters),一行 load_mcp_tools() 即可把任意 MCP Server 的工具挂进来
语言 / 框架自由 Python 3.10~3.13 + Node.js(Electron 客户端)

三、业务流描述

3.1 整体架构

┌────────────────────── 两种入口,一套后端 ──────────────────────┐
│                                                                │
│   main.py(CLI 终端)        client/(Electron 桌面客户端)      │
│        │                          │                            │
│        │                    main.js ──JSON-Lines── bridge.py   │
│        └───────────┬──────────────┘                            │
│                    ▼                                           │
│            agent/api.py        门面:模型列表/切换/重载/自动发现  │
│                    ▼                                           │
│            agent/runtime.py    切模型时重建 Agent,但复用同一个  │
│                    │           checkpointer → 记忆不丢          │
│                    ▼                                           │
│            agent/core.py       build_agent:项目心脏            │
│      ┌─────────┬─────────┬──────────┬─────────┬─────────┐     │
│      ▼         ▼         ▼          ▼         ▼         ▼     │
│    模型层    工具层    中间件链    会话记忆    缓存层    可观测  │
│  models.py  tools/   (6 层拦截) AsyncSqlite  memory/  agent.log│
│  多供应商   registry  Limit/Rate   Saver      LLM+TTL  /trace  │
│  自动发现   9 个工具  Error/Retry  (SQLite)  + RAG(可选)      │
└────────────────────────────────────────────────────────────────┘

3.2 一次完整任务的业务流程

以"给我整理一份广州一日游攻略文档"为例,从按下回车到文件落盘,经历 11 步:

用户输入
  │
  ├─① 前端捕获输入(含附件)→ IPC 交给主进程
  │
  ├─② main.js 以 JSON-Lines 写入 Python 子进程 stdin
  │
  ├─③ bridge.py 主循环只读请求,立刻派发到独立工作线程
  │     (asyncio 事件循环跑在守护线程里,UI 永远不会被阻塞)
  │
  ├─④ 发送前自检:repair_history() 清理孤儿 tool_calls,防接口 400
  │
  ├─⑤ agent.astream() 开始流式生成
  │     ├─ 模型返回「思考」文字 → 推给前端过程框
  │     └─ 模型返回 tool_calls → 交给 ToolNode 执行
  │
  ├─⑥ 工具执行:注册表严格校验工具名 → 执行 → TTL 缓存 → 结果回填
  │
  ├─⑦ 回到 ⑤,形成 ReAct 循环(本例界面显示 9 步思考与行动)
  │
  ├─⑧ 流式护栏:每 200 字符检测一次输出多样性,发现复读立即掐断
  │
  ├─⑨ 模型给出最终答案 → extract_answer() 抽取正文
  │
  ├─⑩ 检查点落库(SQLite)+ 会话文件更新 + token 实耗结算
  │
  └─⑪ 前端渲染答案,恢复输入框,工作日记记一笔

3.3 三个典型业务场景的差异

场景 工具链 关键点
文档生成 search_web ×2 → write_file → gen_docx 先生成 Markdown 源文件再转 Word,源文件保留可改
代码开发 write_file → read_file(自查)→ edit_file(修 bug)→ run_shell(验证) 自己写的代码自己读回来检查,形成闭环
环境操作 run_shell → read_file 命令走项目 .venv,超时/取消连子进程树一起杀

四、实现说明

4.1 技术选型

层次 选择 理由
Agent 编排 LangChain 1.x create_agent + LangGraph 官方中间件生态成熟,astream 天然支持流式
会话持久化 AsyncSqliteSaver(LangGraph Checkpoint) 单文件 SQLite,跨进程可用,无需额外服务
模型接入 langchain-deepseek + langchain-openai(兼容端点) 一套接口打通 DeepSeek / 通义千问 / Kimi / 本地 Ollama
配置管理 pydantic-settings .env 键名与字段一一对应,启动即校验
终端渲染 Rich 过程框、面板、进度一目了然
桌面端 Electron + 原生 JS(无框架) 体积可控,IPC 直连 Python 子进程
文档生成 python-docx / openpyxl / python-pptx 三个 Office 格式全覆盖

4.2 工具层:9 个工具 + 防幻觉注册表

工具不是写个函数就完事。模型最容易犯的错是把工具名调用错(read_files vs read_file),然后陷入无意义的重试。所以我们做了注册表:

@register          # 必须先注册才能被使用,重复注册直接报错
@tool
def read_file(path: str) -> str:
    ...

当模型调错名字时,用 difflib 编辑距离给出建议:

未找到工具 `read_files`。你是否想调用:`read_file`?请修正工具名后重试。

这条提示会作为 ToolMessage 回填给模型,模型下一轮基本都能自己改对——比让它瞎猜三次省下几万 token。

工具 能力
read_file 读文本,支持按行范围读取(大文件不整段灌上下文)
write_file 覆盖写,父目录自动创建
edit_file 精确替换一段文本(比整文件重写省 token)
list_dir 通配符列目录
run_shell 执行命令,异步子进程 + 进程树终止
gen_docx Markdown → 排版好的 Word
gen_xlsx 二维数组 → Excel
gen_pptx 内容 → PPT
search_web 联网搜索(多源级联,见 4.9.4)

4.3 中间件链:6 层拦截,越靠前越先省 token

ModelCallLimit / ToolCallLimit   安全阀:模型≤60 次、工具≤100 次,超了直接停
        ↓
RateLimit(自研)                令牌间隔 60 次/分钟 + 并发信号量 ≤4
        ↓
ToolError                        异常 → 模型能看懂的修正提示(含工具名纠错)
        ↓
ToolRetry / ModelRetry           指数退避重试(只重试瞬时网络故障)
        ↓
Summarization                    上下文压缩(见 4.5)
        ↓
TodoList                         复杂任务自动规划

中间件顺序是有讲究的:限流必须在重试之前,否则一次限流会触发三次重试,反而把限流打得更狠。

4.4 记忆:多轮对话不丢 + 切模型不丢

记忆这块有三件事要交代清楚:

  1. LangGraph Checkpointer:每条消息按 thread_id 落进 SQLite。这个 thread_id 不是另起的名字,就是会话自己的 id(形如 client-20261024-222844-e7a900),所以拿会话 id 去 SQLite 里查,能直接翻出这条对话的完整上下文。重启客户端后照样能接着聊。
  2. 会话清单另存一份:左侧那 3 个对话的标题、气泡原文和排序,存在 data/client_sessions.json 里;SQLite 只管模型看得见的上下文。两边靠同一个 id 对上号,各记各的账——列表条目下面那行灰色小字(「10月24日 · 12 条消息」)数的是 JSON 里存了几条,跟模型手上那份可能已被压缩过的历史不是一回事。一句话:列表在不在看 JSON,记不记得住看 SQLite。
  3. AgentRuntime 复用 checkpointer:切换模型时 Agent 实例要重建(模型对象变了),但我们把同一个 checkpointer 传进去——换了脑子,记忆还在。
/use deepseek-reasoner       # 对话中途换模型
> 已切换到 deepseek-reasoner(记忆保留,共 12 条历史)

这是用户最容易感知的一个细节:不用重新交代背景。

4.5 长任务不断线:上下文自动压缩

模型窗口是 131,072 tokens。历史接近窗口(约 110,576)时,Summarization 中间件会把前面对话凝练成任务摘要,在原会话里继续跑——你会看到一条「🧠 历史已凝练为摘要」提示。任务目标、已完成进度、待办都不丢。

截图 4 里 CLI 启动信息中的「上下文压缩:历史 ~110,576 tokens 触发,窗口 131,072」,就是这个阈值。

4.6 多模型热切换 + 自动发现

config/models.json 里配了 DeepSeek(chat / reasoner)、通义千问、Kimi,以及本地 Ollama。更有意思的是 /discover 命令:只要配了某家的 Key,它就去问这家 API"你有哪些模型",把全系模型自动拉下来,不用手写配置。

桌面端的模型下拉框(图 3)就是自动发现的结果。

4.7 MCP 接入

MCP 工具和内置工具平权——都是 LangChain Tool,都进同一个注册表:

from tools.mcp_client import load_mcp_tools

mcp_tools = await load_mcp_tools(
    ["npx", "-y", "@modelcontextprotocol/server-filesystem", "D:/workspace"]
)
agent = build_agent(extra_tools=mcp_tools)

这意味着接一个 MCP Server 就等于给 Agent 装了一套新技能,不用改 Agent 本体。

4.8 Token 计量与成本

每轮对话都显示两个数:

  • 事前预估:系统提示 + 工具定义 + 历史 + 输入,开跑前就告诉你大概烧多少;
  • 事后实耗:取 API 真实返回的 usage(包含 ReAct 中间步骤),并折算成人民币。

CLI 里还有 /usage、/context、/trace 三个命令,分别看累计用量、上下文占用、全过程日志。

4.9 五个真实踩坑(这部分才是工程)

写代码不难,难的是它跑起来之后出的问题。下面五个都是真实发生、真实定位、真实修复的:

4.9.1 新开对话后输入框点不动

现象:开新对话后,输入框锁死,打字没反应。
根因:send_message 在同一条链路上同步阻塞,模型卡住 = UI 卡死。
修复:桥接层并发化——stdin 主循环只读请求,每个请求派发到独立工作线程,asyncio 事件循环跑在守护线程;同时给单次任务加 900 秒硬超时和取消能力,前端配停止按钮与执行计时器。

4.9.2 接口 400:tool_calls 没有对应的工具回复

现象:An assistant message with 'tool_calls' must be followed by tool messages...
根因:用户中途取消、任务超时、上下文压缩,都会留下"AI 说我要调工具,但工具没回话"的孤儿消息。更糟的是这个错误会自我延续——下一轮请求还是带着它。
修复:新增 agent/history_repair.py,发送前扫描并清理孤儿 tool_calls(只删不补,避免伪造工具输出)。三处接入:发送前主动修 → 接口真报错了修完重试一轮 → 取消/超时兜底修。

4.9.3 run_shell 一执行就卡死

现象:pip install pypdf 这种 4 秒的命令,卡到天荒地老。
根因有仨,挖了很久:

  1. 同步 subprocess.run 会占住线程池,取消也杀不掉 → 改 asyncio.create_subprocess_shell,超时/取消时杀整棵进程树(Windows taskkill /F /T,POSIX killpg);
  2. ToolRetryMiddleware 默认重试所有异常——一个超时的命令被重试 3 次,再叠模型层重试,实测放大 40 倍。超时改为返回 exit_code=timeout 文本让模型自己换做法,retry_on 收窄为只重试瞬时网络故障;
  3. 模型执行的 python 解析到了系统 Python 而不是项目 .venv,装完的依赖 Agent 永远用不上。修复是把 .venv/Scripts 前置进 PATH 并清理 PYTHONHOME。

4.9.4 联网搜索突然全挂,连天气都查不了

现象:前一天还能查,第二天所有搜索都返回"搜索失败"。
根因:原实现依赖 DuckDuckGo Instant Answer,实测在大陆网络下 10 秒超时、HTTP 000;更坑的是旧版熔断器失败 2 次就永久熔断,要重启进程才恢复,而且失败文本还被缓存了 10 分钟。
修复:重写成多源级联——天气关键词走 Open-Meteo(免费、无需 Key、国内可达),通用查询走 Bing 中国站 RSS,DDG 仅作兜底;熔断改为 60 秒冷却自动半开;失败说明不进缓存。

4.9.5 模型陷入"好。执行。好。执行。"的复读循环

现象:让它打开之前写的贪吃蛇游戏,回复退化成 我调用。好。执行。好。(执行)好。执行…,实耗 34,480 tokens,一个工具都没调用。
根因:这是 LLM 的神经文本退化——模型卡在"直接开 HTML 还是开 exe"的二选一里决策瘫痪,temperature=0.2 又没有重复惩罚时,自回归输出会塌缩成短句循环。我们把这 17,193 字符的消息拉出来做了统计:2,570 行里只有 149 种(「好。」出现 1205 次)。而这段垃圾还会进会话历史,下一轮被完整喂回模型,自我强化。
修复:四道防线。

  1. 采样层:FREQUENCY_PENALTY=0.3 / PRESENCE_PENALTY=0.1,按词频惩罚已出现过的词(推理型模型自动跳过,避免接口报错);
  2. 提示层:新增准则「禁止决策瘫痪」——多个方案都低风险可逆时直接选一个执行,任何情况下不许连续两次只输出文字而不调工具;
  3. 流式层(核心):新建 agent/output_guard.py,用 4-gram 多样性塌缩 + 严格周期重复双判据,每 200 字符检测一次,命中立刻中止生成并清空过程框。这里踩了个坑:只做"严格周期"要拖到 6,099 字符才对齐(真实退化中间夹着「(执行)」「(停止过度思考)」变体),补上多样性指标才准(正常文本 4-gram 去重率 0.33~0.9,退化文本只有 0.02);
  4. 历史层:已膨胀的退化消息在发送前自动截断,客户端启动时一次性清理旧会话。

效果:同类退化在 6,920 字符处就被掐断(原本 17,193),省下 60% 输出 token,并自动带上纠正指令重试一轮。

4.10 安全设计

防线 做法
危险命令 rm -rf /、format c: 等黑名单直接拦截
凭据保护 读文件时 key/secret/token/password 赋值自动掩码;提示词内置凭据卫生准则
防幻觉 数据不足直说,严禁编造实时信息(天气、价格、新闻必须走工具)
调用上限 模型 60 次 / 工具 100 次,未执行就先省 token
模糊指令 没有判定标准的指令先反问确认,再动手

4.11 附件上传与视觉降级

桌面端支持上传/拖拽/粘贴文件与照片。文本自动摘录,docx/xlsx/pptx 自动抽正文。照片走多模态——但如果当前模型不支持视觉(比如 DeepSeek 全系是纯文本模型),它会明确告诉你"模型无法识别该照片",而不是假装看见了。这比悄悄忽略用户附件要诚实得多。

4.12 测试

  • 241 个单元测试全部通过,覆盖:工具注册表、shell 取消与进程树、历史修复、附件上传、搜索多源降级、输出退化检测、token 计量、上下文压缩、桥接层端到端;
  • 桌面端有冒烟测试(NAIWA_SMOKE_TEST=1),自动校验启动无报错、渲染无 console error。

五、使用示例(功能演示)

演示一:一句话 → 桌面上的一份 Word 攻略

输入(图 1 原文):

给我推荐一下广州的热门景点,并给一份一日游攻略文档,放在我的桌面上,要求有景点和路线还有通行方案

Agent 的执行过程(右下角"执行过程"面板实时可见):

  1. search_web 查广州当日天气(决定室内/室外路线)
  2. search_web 查热门景点与地铁线路
  3. write_file 写 广州一日攻略.md
  4. gen_docx 转成 Word("已完成…80 个段落")
  5. 输出文件路径

产出:桌面上的 广州一日攻略.docx(保留 Markdown 源文件可继续改),含热门景点分门别类、一日游路线(按"老城+地标"动线,附时间表)、通行方案(地铁换乘、公交、水上巴士价格)、5 条行前待办。

image

本次会话累计实耗:45,093 tokens(API 真实返回值)。

演示二:让 Agent 自己写一个贪吃蛇

输入:

帮我写一个贪吃蛇游戏

它做的事:生成 snake.html → 自己读回代码检查 → 发现边界判定有 bug → 用 edit_file 精确修正 → 告诉你双击打开即可。

最终成品(图 2)还主动加了不少东西:24×24 棋盘自适应屏幕、每吃 5 个食物自动提速、最高分 localStorage 持久化、禁止 180° 掉头、撞墙/撞自己双判定、圆形蛇身 + 圆形食物、手机端滑动转向。

这是最能说明"会做"的一个例子:它不是在给你讲怎么写贪吃蛇,而是真的写完、自己验完、交给你一个能玩的东西。

02-贪吃蛇增强版

演示三:多会话管理 + 模型热切换

左侧是会话列表(每个会话独立记忆),每条下面一行灰色小字是更新日期和消息条数;顶部下拉是自动发现出来的可用模型,切过去记忆不丢。

03-桌面端-多会话与模型切换

演示四:CLI 终端版

python main.py 启动后直接告诉你当前模型、工具数量、安全阀、限流、上下文压缩阈值、RAG 状态——所有关键参数开箱可见。/help 列出全部命令,/trace 能把整轮思考与工具调用日志翻出来。

04-CLI-启动与help


六、GitHub 链接

仓库:https://github.com/mazhaozhe/naiwa-agent

naiwa-agent/
├── main.py                 # CLI 入口
├── agent/
│   ├── core.py             # build_agent:模型 + 工具 + 中间件链组装
│   ├── runtime.py          # AgentRuntime:切模型重建 Agent,复用作记忆
│   ├── models.py           # 多供应商模型构造 + 自动发现 + 反退化采样参数
│   ├── prompts.py          # 系统提示词(能力边界/防幻觉/禁止决策瘫痪)
│   ├── observability.py    # 结构化日志与 /trace
│   ├── history_repair.py   # 孤儿 tool_calls 清理 + 退化消息截断
│   ├── output_guard.py     # 输出复读检测(4-gram 多样性 + 周期双判据)
│   ├── uploads.py          # 附件上传:暂存→归档、视觉能力判定
│   └── config.py           # pydantic-settings 配置
├── tools/
│   ├── registry.py         # 工具注册表 + 编辑距离纠错
│   ├── coding.py           # 文件读写/编辑/列目录/run_shell
│   ├── documents.py        # Word / Excel / PPT
│   ├── search.py           # 多源级联搜索(Open-Meteo / Bing RSS / DDG)
│   └── mcp_client.py       # MCP 工具加载
├── middleware/             # 自研限流中间件
├── memory/                 # 双层缓存 + 可选 RAG
├── client/                 # Electron 桌面客户端
├── tests/                  # 241 个单元测试
└── config/models.json      # 模型目录

运行方式见仓库 README.md。


七、小组分工

成员 学号 角色 具体交付
马肇哲 3124004138 组长 / 架构与内核 整体架构设计;Agent 编排;工具层全部 9 个工具的实现;会话记忆与上下文压缩;token 计量与成本折算;桌面客户端;5 个线上问题的定位与修复;241 个测试;GitHub 仓库与文档维护
陈绎谦 3124004125 需求与质量保障 需求拆解与功能清单编排;三个演示场景的设计与走查;系统提示词与界面文案打磨;验收用例设计;演示素材采集与截图整理;说明文档与博客校对

协作方式:两人共用一个公共仓库,改完各自跑一遍 pytest 再合;有争议的功能先写进"待验证清单",用实际跑一遍的结果决定去留——比如语音功能就是这么被推迟到下一期的。


八、心得体会

马肇哲

这次最大的收获不是"教会了模型用工具",而是学会了怎么和不确定性共处。

写代码的时候我以为最难的是 ReAct 循环怎么编排。真正上手才发现,编排那部分两小时就写完了,剩下的时间全花在"它为什么会这样"上——为什么输入框会锁死?为什么一个 4 秒的命令跑 40 秒?为什么搜索昨天还好今天全挂?为什么它开始复读?

第四个问题让我印象最深。我一开始的判断是"模型抽风了,重试一下就好",直到我把那条 17,193 字符的回复拉出来统计:2,570 行里只有 149 种,「好。」出现 1205 次。那一刻我才意识到这不是偶发,而是有明确统计特征的可检测状态。于是才有了"4-gram 多样性塌缩"这个判据——它不是从书上抄来的,是被真实数据逼出来的。中间还走了一次弯路:先只做严格周期检测,结果要拖到 6,099 字符才命中,因为真实的退化里面夹着「(执行)」「(停止过度思考)」这些变体。加了多样性指标才准。

另一个体会是别信"看起来对"。工具重试放大 40 倍那个 bug 藏得极深:代码逻辑完全正确,同步改异步也改对了,但 ToolRetryMiddleware 默认对所有异常重试,超时异常被重试 3 次再叠模型层重试——单看任何一层都没毛病,叠起来就是灾难。这类问题只能靠实测计时才能发现。

陈绎谦

我主要负责需求梳理、验收测试和文档,站在"使用者"这一侧看这个 Agent,感受和写代码的人很不一样。

最直接的体会是:"能说"和"会做"之间的差距,比想象中大得多。我一开始设计的验收用例很天真——问它"广州有什么好玩的",它答得头头是道,我以为成了。后来我换了个问法:"给我整理一份文档放桌面上",它就露馅了:文档是生成了,但路径写成了一段"你可以保存到…"的说明。这才明白,判断一个 Agent 好不好,不能看它说得多好,要看它交出来的东西在哪。

还有一件事让我印象很深。测试"上传一张图片"时,我问它图里是什么,它老老实实回答"当前模型无法识别照片,请换用支持视觉的模型"。我当时第一反应是"这是 bug 吧",去问马肇哲,他说这是故意做的降级——DeepSeek 是纯文本模型,与其假装看见然后编一段,不如直说。这件小事改变了我对"智能"的看法:知道自己不会什么,比假装什么都会更可信。

posted @ 2026-10-25 16:23  MaZhaozhe  阅读(12)  评论(0)    收藏  举报