Agent Q&A

使用方式:面试时先答 结论,再按 流程/控制点/总结 展开。加粗部分是必须说到的关键词。

上下文压缩是怎么做的?

结论:上下文压缩不是简单截断,而是 近期对话保留原文,早期历史沉淀为结构化摘要,RAG 证据和工具结果按引用保留

整体由 devmate-conversation 管理会话历史,devmate-agent-runtime 在编排时决定哪些内容进入本轮 Prompt。

关键流程:

  1. 保留最近上下文:最近 3-5 轮 用户问题、助手回答和追问澄清保留原文。
  2. 历史转摘要快照:更早历史写入 context_snapshot,保留用户目标、已确认事实、关键约束、工具结果、引用来源和待解决问题。
  3. 证据结构化压缩:RAG 和工具结果不长期塞原文,只保留 结论 + 来源编号 + 关键字段
  4. 触发压缩:token 接近阈值、深度研究多轮工具调用后、长会话历史膨胀时触发。
  5. 可追溯恢复:完整消息、原始文档、工具日志仍落库,后续可按 DTS 编号、chunkId、traceId 回查。

安全控制:

  • 摘要必须区分 事实、推断、待确认事项
  • 从 RAG 或工具得到的事实必须保留 来源编号
  • 压缩后重新检索或回查工具,仍然要走 权限过滤

面试总结:DevMate 的上下文压缩是“完整数据留存 + Prompt 裁剪 + 结构化摘要 + 引用恢复”。这样既控制 token 成本,又保证多轮任务连续性和审计可追溯。

上下文压缩的阈值设置的多大?为什么设置这个值?

结论:我们按 Qwen2.5-72B Instruct + vLLM 设计,线上上下文窗口控制在 32K token,不会直接打满理论最大窗口。

阈值配置:

场景 触发阈值 处理方式
普通知识问答 12K-14K 保留最近 3-5 轮,早期历史压缩
RAG 问答 16K-18K 优先给 RAG 证据片段留空间
深度研究 20K-22K 生成阶段性研究快照
强制保护线 24K-26K 必须压缩或裁剪

为什么这样设置:

  • DevMate 面向约 1000 名内部用户,峰值 100-150 路并发会话
  • 普通问答要求 首 token P95 小于 3 秒
  • 长上下文会增加 vLLM 的 prefill 耗时KV Cache 显存占用
  • Prompt 里还要放系统提示词、安全约束、当前问题、RAG 证据、工具结果和引用格式,不能让历史对话挤占证据空间。

典型 32K 预算:

  • 1K-2K:系统提示词和安全约束。
  • 3K-5K:最近对话。
  • 1K-2K:历史摘要。
  • 8K-12K:RAG 证据。
  • 2K-4K:工具结果摘要。
  • 剩余给当前问题和模型生成。

面试总结:普通问答 12K-14K 压缩,RAG 16K-18K 压缩,深度研究 20K-22K 压缩,24K-26K 是强制保护线。核心目的是给证据留空间,同时控制首 token 延迟、显存和并发成本。

你们的 MCP 是怎么对接的?

结论:Agent 不直接访问内部系统,而是通过 devmate-toolhub MCP 工具网关 统一对接 DTS、需求平台、W3、CronSchedule、代码仓库和 CI/CD。

整体链路:

用户提问 -> Agent Runtime 识别意图 -> MCP Client 调 ToolHub -> ToolHub 适配 HTTP/RPC/SDK -> 内部系统返回 -> ToolHub 裁剪结果 -> Agent 生成回答

ToolHub 负责:

  • 工具注册:工具名、描述、入参 JSON Schema、出参结构、权限级别、是否只读、超时、重试策略。
  • 协议适配:把 MCP 调用转换成内部系统接口。
  • 权限校验:继承用户 SSO 身份、项目权限、文档 ACL、仓库权限。
  • 参数校验:所有入参先过 JSON Schema 和业务规则。
  • 结果裁剪:只返回必要字段、摘要和引用链接。
  • 审计追踪:记录 tool_call_log 和 traceId。

典型工具:

  • dts.search:查询问题单、缺陷趋势、修复记录。
  • requirement.query:查询需求详情、负责人、状态流转。
  • wiki.search:查询 W3 / Wiki 文档和论坛帖子。
  • cron.jobStatus:查询定时任务状态和失败原因。
  • repo.searchCode:查询代码接口定义和提交记录。
  • ci.pipelineStatus:查询流水线状态和失败日志。

面试总结:Agent Runtime 负责决策,ToolHub 负责工具注册、协议适配、权限校验、参数校验、结果裁剪和审计。这样 Agent 不和内部系统强耦合,也不会绕过安全边界。

Agent 是怎么知道该调用哪个工具的?

结论:工具选择不是模型随便决定,而是 意图识别 + 候选工具收敛 + 模型选择 + ToolHub 执行前校验

流程:

  1. 意图识别:判断是知识问答、DTS 查询、需求查询、W3 检索、CronSchedule 排查、代码查询还是深度研究。
  2. 候选工具收敛:根据意图只暴露少量相关工具给模型,不把所有工具都塞进上下文。
  3. 工具描述匹配:模型根据工具 description、JSON Schema、当前问题和会话上下文选择工具。
  4. 结构化参数生成:模型按 schema 生成参数。
  5. ToolHub 校验执行:校验工具名、参数、权限、风险等级,通过后才执行。

例子:

  • “DTS-10234 修复到哪个版本了” -> dts.detail
  • “这个需求当前流转到哪一步” -> requirement.query
  • “最近一个月缓存模块 P1/P2 问题集中在哪些原因” -> dts.search,复杂时进入深度研究。
  • “这个定时任务为什么失败” -> cron.jobStatus

面试总结:模型负责语义理解和工具选择,但工程上先收敛候选工具,再由 ToolHub 做参数、权限和风险校验。模型有建议权,ToolHub 有执行权。

工具参数是怎么约束的?

结论:工具参数通过 JSON Schema + 服务端二次校验 + 业务规则校验 约束,不能把自然语言直接透传给内部系统。

参数约束包括:

  • 字段名、类型、必填项。
  • 枚举范围,例如优先级只能是 P0-P4。
  • 长度限制和默认值。
  • 时间范围、返回数量、项目范围等业务限制。
  • 用户权限和风险等级。

执行流程:

  1. Agent Runtime 根据工具 schema 生成结构化参数。
  2. ToolHub 做 schema 校验,拦截字段缺失、类型错误、非法枚举。
  3. ToolHub 做 权限校验,确认用户能访问对应项目或系统。
  4. ToolHub 做 业务校验,限制时间跨度、limit、查询范围。
  5. 通过后才调用内部系统。

例子:

1
2
3
4
5
6
7
8
9
10
{
"projectId": "storage-flash",
"module": "cache",
"priority": ["P1", "P2"],
"dateRange": {
"start": "2026-04-12",
"end": "2026-05-12"
},
"limit": 20
}

如果模型被 Prompt Injection 诱导生成 projectId="*"priority=["ALL"]limit=10000,ToolHub 会因为 枚举非法、越权、范围过大、超过 limit 上限 拒绝执行。

面试总结:模型只生成候选参数,真正的参数合法性、权限边界和查询范围由 ToolHub 控制。这样可以把大模型的不确定性挡在业务系统外面。

用户权限是怎么继承到工具调用里的?

结论:Agent 不能因为接入工具就拥有比用户更高的权限。权限从 SSO 登录态一路透传到 Agent Runtime 和 ToolHub。

权限链路:

  1. 用户从 Web、IDE 插件或企业 IM 进入 DevMate。
  2. Gateway 接入公司 SSO,通过 OAuth2 / OIDC 获取用户身份。
  3. devmate-auth 同步部门、角色、项目组、文档 ACL、仓库权限。
  4. Agent Runtime 选择工具时带上用户权限上下文。
  5. ToolHub 调内部系统时透传员工工号或用户 token。
  6. 如果底层只能用服务账号,ToolHub 必须按用户权限做二次过滤。

不同工具:

  • DTS:按项目权限过滤问题单。
  • W3 / Wiki:按文档 ACL 过滤。
  • 代码仓库:继承仓库权限。
  • CronSchedule:只有授权运维人员能查看或操作。

两种权限模式:

  • 源系统鉴权:ToolHub 透传可信员工工号,例如 X-Employee-No,由源系统判断可访问范围。
  • ToolHub 二次过滤:如果源系统只支持服务账号,ToolHub 根据用户权限过滤结果。

面试总结:权限必须前置。无权限数据不能进入工具返回结果,更不能进入模型上下文。ToolHub 要么透传用户身份让源系统鉴权,要么在服务账号模式下做二次过滤。

内部系统怎么避免被模型乱调?

结论:我们把模型定位为 决策和编排层,真正的执行控制放在 ToolHub 工具网关

控制措施:

  1. 网关隔离:Agent 不能直接访问 DTS、需求平台、W3、CronSchedule,只能通过 ToolHub。
  2. 只读优先:初期只开放查询类工具。
  3. 读写分级:创建、修改、删除、重跑流水线、变更 Cron 任务默认不开放;开放也要二次确认或审批。
  4. 执行前拦截:校验身份、权限、参数 schema、业务范围和风险等级。
  5. 高风险工具控制:生产调度类操作只允许运维角色使用,并展示动作让用户确认。
  6. 结果裁剪脱敏:不把内部系统原始响应直接给模型。
  7. 全量审计:每次调用写 tool_call_log,可回放、可追责。

面试总结:模型只能提出工具调用意图,不能绕过 ToolHub 直接操作系统。通过只读优先、权限校验、风险分级、二次确认和审计追踪,避免模型乱调内部系统。

工具调用失败后怎么做超时、重试和降级?

结论:工具失败要 分类处理,不能所有失败都重试。ToolHub 为每个工具配置超时、重试和降级策略。

失败处理:

  • 超时 / 5xx 临时错误:短间隔有限重试,一般 1-2 次
  • 参数校验失败:不重试,让 Agent 修正参数或反问用户。
  • 权限不足:不重试,明确提示无权限。
  • 系统不可用:降级到 RAG、替代数据源或返回有限回答。
  • 高风险写操作失败:不自动重试,避免重复执行。

降级策略:

  • DTS 不可用:用知识库故障文档或 W3 复盘补充,但说明无法实时查询问题单。
  • W3 不可用:用 RAG 知识库和历史摘要支撑回答。
  • CI/CD 或 CronSchedule 不可用:说明实时状态不可查,不编造结果。
  • 深度研究中某个工具失败:记录失败原因,尝试替代数据源,最终报告标注证据缺口。

面试总结:能重试的是临时错误,权限和参数错误不重试;工具不可用时可以降级,但不能假装查到了实时数据。

工具调用记录怎么审计追踪?

结论:每次 MCP / Function Tool 调用都会写入 **tool_call_log**,并通过 traceId 串联 Gateway、Agent、ToolHub、RAG 和 ModelGateway。

审计字段:

  • 用户 ID、部门、角色。
  • 会话 ID、traceId。
  • 工具名称、工具版本。
  • 参数摘要、结果摘要。
  • 耗时、状态码、失败原因。
  • 调用时间和来源入口。

注意点:

  • 参数和结果通常记录 摘要而不是完整明文
  • 敏感字段要脱敏。
  • DTS 查询可以记录项目、关键词、时间范围、返回条数,不记录完整问题单内容。

trace 链路:

Gateway -> Conversation -> Agent Runtime -> ToolHub -> RAG -> ModelGateway

排查时可以回答:

  • 模型为什么选这个工具。
  • 传了什么参数。
  • ToolHub 是否通过权限校验。
  • 内部系统返回了什么摘要。
  • 耗时卡在哪一段。
  • 最终回答引用了哪些工具结果。

面试总结:审计不是简单记日志,而是用 tool_call_log + traceId 把用户、工具、参数、结果、耗时和最终回答串起来,服务于安全合规、问题排查、性能优化和工具治理。

工具返回结果怎么裁剪,避免 token 膨胀?

结论:工具结果裁剪不是简单截断,而是 结构化摘要 + 字段白名单 + TopN 截断 + 聚合统计 + 引用保留

裁剪原则:只返回回答当前问题必要的信息,同时保留追溯所需的 ID 和链接

典型字段:

  • DTS:问题单编号、标题、模块、状态、负责人、创建时间、修复版本、根因摘要、链接。
  • 需求:需求编号、标题、版本、负责人、状态、验收标准摘要、链接。
  • W3 / Wiki:标题、摘要、更新时间、来源链接、权限标签。
  • CI/CD:流水线状态、失败阶段、关键错误日志摘要、构建链接。
  • CronSchedule:任务名、最近执行状态、失败原因摘要、执行时间、日志链接。

大结果处理:

  • 查询结果多时先 TopN 截断
  • 趋势类问题先按模块、版本、状态、根因类型做 聚合摘要
  • 深度研究只保留 结论 + 来源编号 + 关键字段 + 未解决问题
  • 原始结果保留在源系统或日志中,用户追问时再按编号回查。

面试总结:裁剪的目标是控制 token 成本、降低噪声,同时保证引用可追溯。模型看到的是干净结构化结果,不是内部系统原始大对象。

介绍一下从用户提问到工具调用整个流程

结论:从用户提问到工具调用,可以分成 入口鉴权、会话加载、意图识别、工具选择、参数生成、ToolHub 校验、源系统调用、结果裁剪、模型回答 九步。

完整流程:

  1. 入口鉴权:用户从 Web、IDE 插件或企业 IM 提问,请求进入 devmate-gateway,完成登录态校验、SSO 身份解析、限流和 trace 初始化。
  2. 会话加载devmate-conversation 加载最近对话、摘要快照和用户上下文。
  3. 模式判断:普通问答走同步 SSE;复杂任务转给 devmate-research 进入异步深度研究。
  4. 意图识别devmate-agent-runtime 判断是知识问答、DTS 查询、需求查询、W3 检索、CronSchedule 排查、代码查询还是多工具研究。
  5. 候选工具选择:根据意图收敛工具,例如 dts.detailrequirement.querydts.searchcron.jobStatus
  6. 参数生成:模型根据 Function Tool / MCP Tool 描述和 JSON Schema 生成结构化参数。
  7. ToolHub 校验devmate-toolhub 校验工具是否存在、参数是否合法、用户身份是否可信、权限是否满足、是否高风险。
  8. 源系统调用:ToolHub 把 MCP 调用转换成 DTS、需求平台、W3、CronSchedule、代码仓库或 CI/CD 的 HTTP/RPC/SDK 调用。
  9. 结果裁剪和回答:ToolHub 做字段白名单、脱敏、TopN 截断、聚合摘要和引用保留;Agent 再组装 Prompt,通过 devmate-model-gateway 生成回答。

同时会记录:

  • tool_call_log:工具调用审计。
  • model_call_log:模型调用审计。
  • traceId:全链路排查。

面试总结:Gateway 管身份入口,Conversation 管会话上下文,Agent Runtime 管意图和工具选择,ToolHub 管参数、权限、源系统适配、结果裁剪和审计,ModelGateway 负责模型调用。

你们有自己写过什么 Function Call 吗?功能是什么?

结论:有。我们自己封装过一批面向内部研发场景的 Function Tool / MCP Tool,比如 DTS 查询、需求查询、W3/Wiki 检索、CronSchedule 状态查询和知识库检索。

典型例子是 dts.search

功能:根据项目、模块、优先级、状态、时间范围查询 DTS 问题单,用于 故障排查、问题趋势分析和深度研究

用户问题:

“帮我查一下最近一个月缓存模块有哪些 P1/P2 问题单,并总结主要原因。”

模型生成参数:

1
2
3
4
5
6
7
8
9
10
{
"projectId": "storage-flash",
"module": "cache",
"priority": ["P1", "P2"],
"dateRange": {
"start": "2026-04-12",
"end": "2026-05-12"
},
"limit": 20
}

执行过程:

  1. Agent 识别为 DTS 查询场景,选择 dts.search
  2. 模型按 JSON Schema 生成结构化参数。
  3. ToolHub 校验参数和用户项目权限。
  4. ToolHub 透传员工工号给 DTS,或按用户权限做二次过滤。
  5. DTS 返回原始结果。
  6. ToolHub 裁剪为问题单编号、标题、优先级、状态、模块、根因摘要、修复版本和链接。
  7. 模型基于结构化结果总结主要原因,并附引用。

其他 Function Tool:

  • requirement.query:查需求详情、负责人、状态流转、验收标准。
  • wiki.search:查 W3 / Wiki 文档和论坛帖子。
  • cron.jobStatus:查定时任务最近执行状态、失败原因和日志链接。
  • knowledge.retrieve:做企业知识库 RAG 检索,返回重排后的片段和引用编号。

面试总结:我们写的 Function Call 不是简单把自然语言转发给内部系统,而是把内部能力包装成结构化、可校验、可权限控制、可审计的工具。Agent 负责选择工具,ToolHub 负责执行治理。