快手 AI应用开发 一面
1. 自我介绍
2. 介绍你的实习项目,你做了哪些事情以及你的思考
3. 升级之后 tool 调用准确率提升了多少,怎么衡量
答案:
tool 调用准确率不能只看模型有没有调用工具,而要看调用的工具是否正确、参数是否正确、调用顺序是否正确、结果是否被正确使用。我们会把一次工具调用拆成几个指标:工具选择准确率、参数填充准确率、无效调用率、重复调用率、最终任务成功率。
比如升级前模型经常把“查询保单责任”和“查询历史理赔”混淆,或者漏传 policyId。后来通过工具分域、意图路由、参数 schema 校验和少量高质量样例,工具选择准确率从大概 82% 提升到 92% 左右,关键参数完整率从 88% 提升到 96% 左右。最终不是只看离线集,还要看线上人工审核纠错率有没有下降。
CREATE TABLE tool_call_eval (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
trace_id VARCHAR(64) NOT NULL,
intent VARCHAR(64) NOT NULL,
expected_tool VARCHAR(128) NOT NULL,
actual_tool VARCHAR(128) NOT NULL,
param_valid TINYINT NOT NULL,
order_valid TINYINT NOT NULL,
final_success TINYINT NOT NULL,
created_at DATETIME NOT NULL
);
评估时按 trace 聚合:
SELECT
COUNT(*) AS total,
SUM(expected_tool = actual_tool) / COUNT(*) AS tool_accuracy,
SUM(param_valid) / COUNT(*) AS param_accuracy,
SUM(final_success) / COUNT(*) AS task_success_rate
FROM tool_call_eval
WHERE created_at >= '2026-05-01';
4. 为什么考虑做成 Skill 流程,而不是普通 Workflow
答案:
Workflow 更像固定流程,适合步骤稳定、分支明确的任务,比如“提交理赔申请 -> 校验材料 -> 人工审核 -> 打款”。Skill 更像可复用能力,适合被不同 Agent、不同流程按需调用,比如“解析发票”“匹配医保目录”“生成拒赔解释”“压缩会话记忆”。
在理赔场景里,如果所有东西都做成 Workflow,会导致流程越来越多、重复节点很多,而且难以组合。比如门诊理赔、住院理赔、药品理赔都需要“药品目录匹配”能力,这个能力就应该沉淀成 Skill,而不是每个 workflow 里复制一份。
Workflow:面向业务流程,强调顺序、状态、审批、重试 Skill:面向能力复用,强调输入输出、可组合、可编排
Skill 的定义会更像一个稳定接口:
{
"skillName": "medical_catalog_match",
"input": {
"drugName": "string",
"diagnosisCode": "string",
"hospitalLevel": "string"
},
"output": {
"covered": "boolean",
"matchedRuleId": "string",
"reason": "string"
}
}
5. 你怎么理解 Skill,它和 Tool、Agent 的区别是什么
答案:
Tool 是最底层的可调用动作,比如查数据库、查知识库、调用 OCR、查询保单。Skill 是对一组工具和逻辑的封装,它有明确业务语义,比如“判断药品是否可赔”“生成理赔材料缺失说明”。Agent 则是具备任务理解、计划和协调能力的执行主体。
举个例子,query_policy 是 Tool,claim_liability_check 是 Skill,ClaimAuditAgent 是 Agent。Agent 可以调用多个 Skill,Skill 内部可以调用多个 Tool。这样分层后,工具不会直接暴露给模型太多,复杂能力也能复用。
Agent:负责理解任务、制定计划、协调执行 Skill:负责完成一个稳定业务能力 Tool:负责执行一个确定性动作
Java 中可以这样抽象:
public interface Skill<I, O> {
String name();
O execute(I input, SkillContext context);
}
public class LiabilityCheckSkill implements Skill<LiabilityInput, LiabilityOutput> {
@Override
public String name() {
return "liability_check";
}
@Override
public LiabilityOutput execute(LiabilityInput input, SkillContext context) {
Policy policy = context.policyTool().queryPolicy(input.policyId());
RuleResult rule = context.ruleTool().match(policy, input.diagnosisCode());
return LiabilityOutput.from(rule);
}
}
6. 除了 RAG 长期记忆,有没有做用户偏好类记忆,压缩后的 token 大概多大
答案:
有做,但不会把所有历史对话都存成长期记忆。长期记忆分两类,一类是事实记忆,比如用户常用保单、家庭成员关系、常见就诊城市;另一类是偏好记忆,比如用户希望解释更口语化、是否需要展示详细条款、是否偏好短信通知。模型临时总结出来的猜测不能直接写入长期记忆,必须有明确行为或用户确认。
记忆压缩后一般控制在几百 token 到一千 token 以内,核心是“可用”而不是“完整”。如果一个用户的历史对话很多,会按稳定程度、更新时间、业务相关性排序,只取当前任务需要的部分。
{
"userMemory": {
"defaultPolicyId": "P****123",
"frequentClaimType": "outpatient",
"preferredExplainStyle": "simple",
"familyMembers": [
{"relation": "child", "maskedId": "U****88"}
]
}
}
记忆读取时会按场景裁剪:
public UserMemoryView buildMemoryView(String userId, ClaimScene scene) {
UserMemory memory = memoryRepo.findByUserId(userId);
return UserMemoryView.builder()
.defaultPolicyId(memory.getDefaultPolicyId())
.preferredExplainStyle(memory.getPreferredExplainStyle())
.recentClaimType(memory.getRecentClaimType(scene))
.build();
}
7. 产品的用户量、每日 token 使用量、底层模型怎么估算
答案:
这类问题不能只报一个数字,要能说清估算方式。假设日活 5 万,20% 用户会触发 AI 审核或解释,也就是 1 万次 AI 会话;每次会话平均 3 轮,每轮输入上下文 1500 token,输出 500 token,那么每天大概是:
1 万会话 * 3 轮 * (1500 输入 + 500 输出) = 6000 万 token / 天
底层模型不会只用一个。简单意图识别、关键词抽取、格式修复可以用小模型;复杂理赔解释、条款归因、多证据综合用大模型;RAG embedding 用专门的 embedding 模型。这样可以控制成本和延迟。
小模型:意图识别、槽位抽取、JSON 修复 大模型:复杂解释、多证据综合、争议场景总结 Embedding 模型:知识库向量化 Rerank 模型:召回结果重排
如果 P95 延迟要求严格,还要做模型路由和降级:大模型超时后返回模板化解释或进入人工审核队列。
8. 用户在线反馈怎么做,不同模型和提示词的 AB 测试如何体现效果
答案:
在线反馈会分显式反馈和隐式反馈。显式反馈是用户点“有帮助 / 没帮助”、客服标记“可直接发送 / 需要修改”;隐式反馈是用户是否继续追问、客服修改比例、理赔工单是否被退回、人工复核是否改判。
AB 测试时不能只看点赞率。理赔场景更关注准确性和风险,所以会看证据引用率、人工修改率、投诉率、审核耗时、最终改判率。不同模型和 prompt 要随机分流,但要保证同一用户或同一工单稳定落到同一实验组,避免体验混乱。
CREATE TABLE llm_ab_eval (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
request_id VARCHAR(64),
user_id VARCHAR(64),
experiment_key VARCHAR(64),
group_name VARCHAR(32),
model_name VARCHAR(64),
prompt_version VARCHAR(64),
helpful TINYINT,
manual_edit_rate DECIMAL(6,4),
evidence_valid TINYINT,
created_at DATETIME
);
分流可以这样做:
public String assignGroup(String userId, String experimentKey) {
int hash = Math.abs(Objects.hash(userId, experimentKey));
return hash % 100 < 50 ? "A" : "B";
}
9. 讲一下你的 Agent Runtime 设计
答案:
Agent Runtime 我会拆成 Request Layer、Planner、Tool Router、Executor、Memory Manager、Context Builder、Verifier、Trace Logger。请求进来后先做鉴权和意图识别,再构建上下文,然后由 Planner 生成计划。计划不会直接执行,要经过权限、预算、工具白名单和依赖关系校验。Executor 负责真正执行工具,最后 Verifier 校验模型输出是否合规。
Runtime 的关键是把模型的不确定性控制在边界内。比如模型可以建议调用哪个 Skill,但不能越权访问用户保单;模型可以生成解释,但不能编造赔付结论;模型可以要求补充材料,但必须来自规则命中结果。
Request -> Auth / RateLimit -> Intent Router -> Memory Manager -> Context Builder -> Planner -> Plan Verifier -> Tool / Skill Executor -> Evidence Merger -> LLM Generator -> Output Verifier -> Trace Log
计划结构示例:
{
"intent": "claim_audit",
"steps": [
{"id": "s1", "skill": "policy_liability_check"},
{"id": "s2", "skill": "medical_catalog_match"},
{"id": "s3", "skill": "claim_explanation_generate"}
]
}
10. Agent Runtime 中上下文爆炸怎么处理
答案:
上下文爆炸一般来自历史对话、工具结果、RAG 文档、用户材料和系统提示词都不断累积。解决方式是分层压缩和预算控制。每次请求进入模型前,要先定义 token budget,比如 system prompt 800,用户问题 500,历史摘要 1000,工具证据 2000,RAG 文档 2000。
历史对话不直接全量塞入,而是压缩成任务状态和用户偏好;工具结果不塞完整 JSON,而是提取证据字段;RAG 文档只保留 topK 片段;低价值上下文直接丢弃。对于超长任务,分阶段调用模型,每阶段只处理局部上下文。
public class ContextBudget {
int systemTokens = 800;
int userTokens = 500;
int memoryTokens = 800;
int evidenceTokens = 2000;
int ragTokens = 2000;
}
证据压缩示例:
public EvidenceView compress(ClaimToolResult result) {
return new EvidenceView(
result.getEvidenceId(),
result.getSource(),
result.getKeyConclusion(),
result.getRuleId()
);
}
11. Agent 循环调用、重复调用怎么处理
答案:
Agent 循环调用通常是模型没有得到满意结果,反复调用同一个工具,或者工具结果为空后不断换参数试探。生产里不能让这种情况发生,必须在 Runtime 层加 harness。常见限制包括最大调用轮数、最大工具调用次数、相同工具相同参数只允许调用一次、工具失败后按错误类型决定是否重试。
还要记录工具调用指纹,用工具名和参数 hash 判断重复。如果模型连续两次计划没有产生新信息,就终止并返回“需要补充信息”或转人工。
public class ToolCallGuard {
private final Set<String> fingerprints = new HashSet<>();
private final int maxCalls;
public ToolCallGuard(int maxCalls) {
this.maxCalls = maxCalls;
}
public void check(String toolName, String argsJson) {
if (fingerprints.size() >= maxCalls) {
throw new RuntimeException("TOOL_CALL_LIMIT_EXCEEDED");
}
String fp = toolName + ":" + DigestUtils.md5Dig
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏聚焦 AI-Agent 面试高频考点,内容来自真实面试与项目实践。系统覆盖大模型基础、Prompt工程、RAG、Agent架构、工具调用、多Agent协作、记忆机制、评测、安全与部署优化等核心模块。以“原理+场景+实战”为主线,提供高频题解析、标准答题思路与工程落地方法,帮助你高效查漏补缺.

华为HUAWEI工作强度 1362人发布