如果你的AI Agent能正确回答"本周是几号到几号",恭喜你,你已经跨过了企业级应用的第一道门槛。
这是一个真实的技术复盘。
在开发HR智能助手的过程中,一个看似简单的"导出本周考勤明细"功能,让我们的技术团队经历了从信心满满到怀疑人生,再到最终解决的完整历程。
01 案发现场:一个简单需求的复杂化
「需求描述」:用户在AI Chat中说"导出本周考勤明细",系统应该:
正确理解"本周"的时间范围 查询数据库获取考勤数据 生成Excel文件并下载
听起来很简单?实际上,我们团队花了整整一天时间才让它正常工作。
「问题现象」:
LLM返回的日期范围错误:说"本周"却返回4月7日-12日(实际应该是4月6日-12日) 导出的Excel只有部分数据:数据库有41条,Excel只有26条 导出的文件格式错误:生成的是Word而不是Excel 数据全是编造的假数据,而不是数据库真实数据
02 踩坑一:基础设施与业务代码的边界

开发过程中,我们的开发人员不断在Harness底座中添加业务逻辑:
在orchestrator.ts中硬编码考勤查询逻辑 在system-prompt.ts中写HR相关的日期示例 修改hr-queries.ts中的SQL查询
反复强调:"「不要在Harness底座写任何业务代码」",但开发人员为了业务实现还是一次次违反这个原则。
反思
企业级AI Agent架构应该是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Harness底座(纯基础设施)├── 核心引擎├── LLM接口├── Skill加载器├── 意图路由业务层(独立目录)├── HR查询处理器├── HR API路由├── 数据库SchemaSkills定义├── hr/attendance-stats├── hr/payroll-generator
「核心原则」:
Harness只负责调度,不负责业务 业务逻辑通过接口调用,不直接写SQL Skill定义在skills目录,通过metadata配置data_queries
03 踩坑二:日期计算的手写陷阱
问题
最初我们的技术人员用JS手写日期计算:
1 2 3 4 5
// 计算本周一const dayOfWeek = now.getDay();const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;const thisMonday = newDate(now);thisMonday.setDate(now.getDate() + mondayOffset);
这在周日时计算结果是错误的。
其实老大一直在反复强调说:"「为什么不用现成的库?date-fns、moment.js都是专门解决这个问题的」"

解决
安装date-fns,一行代码解决:
1 2
const { startOfWeek, format } = require('date-fns');const thisMonday = startOfWeek(now, { weekStartsOn: 1 });
「教训」:任何功能开发前,先问三个问题:
npm上有没有现成的包? GitHub上有没有开源方案? Stack Overflow上有没有最佳实践?
04 踩坑三:pageSize限制导致数据截断
问题
Agent查询考勤数据时,默认pageSize=20,但数据库有41条记录。LLM只拿到前20条,生成的Excel也只有20条。
解决
AI查询场景不需要分页,传递pageSize=10000或者pageSize=0忽略这个参数都可以直接获取全部数据:
1 2
// orchestrator.tsconst fullPayload = { ...payload, pageSize: 0 };
「教训」:AI Agent的数据查询场景与前端列表分页场景不同,需要根据上下文动态调整。
05 踩坑四:LLM不按指令生成invoke
问题
system prompt写了导出规则,但LLM:
直接返回JSON数据,不生成invoke标签 生成invoke但格式错误:sheets不是数组 只取部分数据放入Excel
解决
在system prompt中加强指令:
1 2 3 4 5 6 7 8 9 10 11 12
## 导出规则(必须遵守)用户说"导出"时,你必须输出以下格式:<invokename="excel-xlsx">{"sheets":[{"name":"本周考勤明细","columns":["日期","姓名","状态"],"data":[["2026-04-06","张三","normal"],...]}]}</invoke>关键点:1. sheets必须是数组2. data必须是二维数组(数组套数组)3. 数据必须来自"查询数据",不能编造
「教训」:给LLM的指令要具体到代码级别,不能只说"导出Excel"。
06 踩坑五:预查询与动态需求的矛盾
问题
Skill配置了data_queries预查询:
1 2 3 4 5 6
data_queries:-name:recent_attendancehandler:query_attendancedefault_params:start_date:"${current_week_start}"end_date:"${current_week_end}"
但用户说"上周"时,预查询还是本周数据,导致LLM用错误的数据生成Excel。
解决
将预查询范围改为两周(上周一到今天),覆盖本周和上周:
1 2 3
default_params:start_date:"${previous_week_start}"end_date:"${current_week_end}"
并在system prompt中明确告诉LLM上周的时间范围,让它自己筛选。
07 踩坑六:UTC时间转换问题
问题
数据库存储的日期是UTC时间,如2026-04-09T16:00:00.000Z,转换为北京时间后实际是4月10日。导出的Excel日期显示错误。
解决
在formatQueryResult中转换UTC时间:
1 2 3
const utcDate = newDate(formatted.date);utcDate.setHours(utcDate.getHours() + 8);formatted.date = utcDate.toISOString().slice(0, 10);
08 踩坑七:文件图标显示
问题
用户要求文件图标显示扩展名和颜色:
DOC:蓝色 XLS:绿色 PDF:红色
解决
使用开源库react-file-icon,而不是自己手写SVG:
1
npm install react-file-icon09 最终架构: Harness + Skills + 业务API
经过这次踩坑,我们再次修正了架构:
Harness职责
意图识别(关键词匹配 + LLM理解) Skill调度(加载SKILL.md,执行data_queries) System Prompt构建(动态注入时间、数据) Invoke解析和执行
Skill职责
定义触发关键词 配置data_queries(预查询数据) 定义输出格式(Markdown表格、Excel等)
业务API职责
数据查询接口(不在Harness里面写SQL) 数据格式转换 分页处理
10 开发铁律
总结这次踩坑,我给自己写下三条铁律:
铁律一:先搜索,再编码
编写任何代码前,必须先查有没有现有的成熟包、GitHub开源方案。默认假设已有现成解决方案。
铁律二:基础设施不写业务
Harness底座只负责调度,业务逻辑必须在独立目录,通过接口调用。
铁律三:给LLM的指令要代码级别
不能只说"导出Excel",要给出完整的JSON格式示例。

结语
企业级AI Agent开发,看似是技术问题,实际是架构问题。
「日期计算」、「数据截断」、「invoke格式」——这些看起来是代码bug,根源都在架构边界不清。
当你为一个小功能反复debug时,停下来问自己:是不是架构设计有问题?
好的架构让简单的问题保持简单,相反会让简单的问题变得复杂。
夜雨聆风